fix(semantic): mark declared class heritage as type references (#24237)

## Summary

- resolve declared class heritage expressions through ValueAsType so their final references are Type
- allow type-only namespace imports in declared heritage while preserving Read for runtime class heritage
- add regression coverage for type-only namespace imports, value namespace imports, local bases, and a runtime control
- update semantic conformance snapshots, yielding two additional TypeScript passes
This commit is contained in:
camc314 committed 2026-07-06 21:58:56 +00:00
1 parent df828933ef
commit 42d00d383e
4 files changed
+149 -28

No files matched your search

+4
View File
@@ -957,7 +957,11 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
self.visit_ts_type_parameter_declaration(type_parameters);
}
if let Some(super_class) = &class.super_class {
if class.declare {
self.current_reference_flags = ReferenceFlags::ValueAsType;
}
self.visit_expression(super_class);
self.current_reference_flags = ReferenceFlags::empty();
}
if let Some(super_type_parameters) = &class.super_type_arguments {
self.visit_ts_type_parameter_instantiation(super_type_parameters);
@@ -0,0 +1,130 @@
---
source: crates/oxc_semantic/tests/main.rs
input_file: crates/oxc_semantic/tests/fixtures/oxc/ts/declare-class-heritage.ts
---
[
{
"children": [
{
"children": [],
"flags": "ScopeFlags(StrictMode)",
"id": 1,
"node": "Class(<anonymous>)",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(StrictMode)",
"id": 2,
"node": "Class(Declared)",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(StrictMode)",
"id": 3,
"node": "Class(NamespaceDeclared)",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(StrictMode)",
"id": 4,
"node": "Class(LocalDeclared)",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(StrictMode)",
"id": 5,
"node": "Class(Runtime)",
"symbols": []
}
],
"flags": "ScopeFlags(StrictMode | Top)",
"id": 0,
"node": "Program",
"symbols": [
{
"flags": "SymbolFlags(TypeImport)",
"id": 0,
"name": "TypeOnlyNamespace",
"node": "ImportNamespaceSpecifier",
"references": [
{
"flags": "ReferenceFlags(Type)",
"id": 0,
"name": "TypeOnlyNamespace",
"node_id": 17,
"scope_id": 2
}
]
},
{
"flags": "SymbolFlags(Import)",
"id": 1,
"name": "RuntimeNamespace",
"node": "ImportNamespaceSpecifier",
"references": [
{
"flags": "ReferenceFlags(Type)",
"id": 1,
"name": "RuntimeNamespace",
"node_id": 23,
"scope_id": 3
},
{
"flags": "ReferenceFlags(Read)",
"id": 3,
"name": "RuntimeNamespace",
"node_id": 33,
"scope_id": 5
}
]
},
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 2,
"name": "LocalBase",
"node": "VariableDeclarator(LocalBase)",
"references": [
{
"flags": "ReferenceFlags(Type)",
"id": 2,
"name": "LocalBase",
"node_id": 28,
"scope_id": 4
}
]
},
{
"flags": "SymbolFlags(Class | Ambient)",
"id": 3,
"name": "Declared",
"node": "Class(Declared)",
"references": []
},
{
"flags": "SymbolFlags(Class | Ambient)",
"id": 4,
"name": "NamespaceDeclared",
"node": "Class(NamespaceDeclared)",
"references": []
},
{
"flags": "SymbolFlags(Class | Ambient)",
"id": 5,
"name": "LocalDeclared",
"node": "Class(LocalDeclared)",
"references": []
},
{
"flags": "SymbolFlags(Class)",
"id": 6,
"name": "Runtime",
"node": "Class(Runtime)",
"references": []
}
]
}
]
@@ -0,0 +1,9 @@
import type * as TypeOnlyNamespace from "type-only";
import * as RuntimeNamespace from "runtime";
const LocalBase = class {};
declare class Declared extends TypeOnlyNamespace.Base {}
declare class NamespaceDeclared extends RuntimeNamespace.Base {}
declare class LocalDeclared extends LocalBase {}
class Runtime extends RuntimeNamespace.Base {}
@@ -2,7 +2,7 @@ commit: 7964e22f
semantic_typescript Summary:
AST Parsed : 4720/4720 (100.00%)
Positive Passed: 3242/4720 (68.69%)
Positive Passed: 3244/4720 (68.73%)
semantic Error: tasks/coverage/typescript/tests/cases/compiler/APISample_Watch.ts
Bindings mismatch:
after transform: ScopeId(0): ["console", "formatHost", "os", "process", "reportDiagnostic", "reportWatchStatusChanged", "ts", "watchMain"]
@@ -4190,11 +4190,6 @@ Symbol flags mismatch for "Enum":
after transform: SymbolId(0): SymbolFlags(RegularEnum)
rebuilt : SymbolId(0): SymbolFlags(BlockScopedVariable)
semantic Error: tasks/coverage/typescript/tests/cases/compiler/declarationEmitCrossFileCopiedGeneratedImportType.ts
Unresolved references mismatch:
after transform: ["Number"]
rebuilt : []
semantic Error: tasks/coverage/typescript/tests/cases/compiler/declarationEmitDestructuringArrayPattern3.ts
Namespaces exporting non-const are not supported by Oxc. Change to const or see: https://oxc.rs/docs/guide/usage/transformer/typescript.html#partial-namespace-support
Symbol flags mismatch for "M":
@@ -5271,7 +5266,7 @@ Reference symbol mismatch for "getVariableValues":
after transform: SymbolId(6) "getVariableValues"
rebuilt : <None>
Unresolved references mismatch:
after transform: ["Error"]
after transform: []
rebuilt : ["getVariableValues"]
semantic Error: tasks/coverage/typescript/tests/cases/compiler/discriminatedUnionJsxElement.tsx
@@ -8985,9 +8980,6 @@ semantic Error: tasks/coverage/typescript/tests/cases/compiler/jsxComplexSignatu
Bindings mismatch:
after transform: ScopeId(0): ["React", "ReactSelectClass", "_jsxFileName", "_objectSpread", "createReactSingleSelect"]
rebuilt : ScopeId(0): ["React", "_jsxFileName", "_objectSpread", "createReactSingleSelect"]
Symbol reference IDs mismatch for "React":
after transform: SymbolId(0): [ReferenceId(44), ReferenceId(242)]
rebuilt : SymbolId(0): [ReferenceId(0)]
Reference symbol mismatch for "ReactSelectClass":
after transform: SymbolId(20) "ReactSelectClass"
rebuilt : <None>
@@ -14809,9 +14801,6 @@ semantic Error: tasks/coverage/typescript/tests/cases/compiler/tsxReactPropsInfe
Bindings mismatch:
after transform: ScopeId(0): ["Button", "CustomButton", "React", "_jsxFileName", "_objectSpread"]
rebuilt : ScopeId(0): ["CustomButton", "React", "_jsxFileName", "_objectSpread"]
Symbol reference IDs mismatch for "React":
after transform: SymbolId(0): [ReferenceId(3), ReferenceId(14)]
rebuilt : SymbolId(0): [ReferenceId(0)]
Reference symbol mismatch for "Button":
after transform: SymbolId(3) "Button"
rebuilt : <None>
@@ -22956,11 +22945,6 @@ Unresolved references mismatch:
after transform: ["A"]
rebuilt : []
semantic Error: tasks/coverage/typescript/tests/cases/conformance/externalModules/typeOnly/cjsImportInES2015.ts
Unresolved references mismatch:
after transform: ["Error"]
rebuilt : []
semantic Error: tasks/coverage/typescript/tests/cases/conformance/externalModules/typeOnly/exportDeclaration.ts
Bindings mismatch:
after transform: ScopeId(0): ["A", "a"]
@@ -23768,11 +23752,8 @@ rebuilt : ["A", "require"]
semantic Error: tasks/coverage/typescript/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter1.tsx
Bindings mismatch:
after transform: ScopeId(0): ["MyComp", "React", "_jsxFileName", "_reactJsxRuntime", "x"]
rebuilt : ScopeId(0): ["React", "_jsxFileName", "_reactJsxRuntime", "x"]
Symbol reference IDs mismatch for "React":
after transform: SymbolId(0): [ReferenceId(1)]
rebuilt : SymbolId(2): []
after transform: ScopeId(0): ["MyComp", "_jsxFileName", "_reactJsxRuntime", "x"]
rebuilt : ScopeId(0): ["_jsxFileName", "_reactJsxRuntime", "x"]
Reference symbol mismatch for "MyComp":
after transform: SymbolId(2) "MyComp"
rebuilt : <None>
@@ -23782,11 +23763,8 @@ rebuilt : ["MyComp", "require"]
semantic Error: tasks/coverage/typescript/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter2.tsx
Bindings mismatch:
after transform: ScopeId(0): ["MyComp", "React", "_jsxFileName", "_reactJsxRuntime", "x", "x1"]
rebuilt : ScopeId(0): ["React", "_jsxFileName", "_reactJsxRuntime", "x", "x1"]
Symbol reference IDs mismatch for "React":
after transform: SymbolId(0): [ReferenceId(1)]
rebuilt : SymbolId(2): []
after transform: ScopeId(0): ["MyComp", "_jsxFileName", "_reactJsxRuntime", "x", "x1"]
rebuilt : ScopeId(0): ["_jsxFileName", "_reactJsxRuntime", "x", "x1"]
Reference symbol mismatch for "MyComp":
after transform: SymbolId(2) "MyComp"
rebuilt : <None>