mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
feat(semantic): add SymbolFlags::Ambient for declaration with declare modifier (#10355)
Part of https://github.com/oxc-project/oxc/issues/7951. After we have a `SymbolFlags::Ambient` within a Symbol that is declared by the `declare` modifier, we can determine whether to remove an `ExportSpecifier` by tracing its referent and examining its `SymbolFlags`.
This commit is contained in:
1 parent
dd2aef0bf2
commit
1a37e3fa37
8 files changed
+76
-41
No files matched your search
@@ -20,7 +20,12 @@ pub trait Binder<'a> {
|
||||
|
||||
impl<'a> Binder<'a> for VariableDeclarator<'a> {
|
||||
fn bind(&self, builder: &mut SemanticBuilder<'a>) {
|
||||
let (includes, excludes) = match self.kind {
|
||||
let is_declare = builder
|
||||
.nodes
|
||||
.parent_kind(builder.current_node_id)
|
||||
.is_some_and(|kind| matches!(kind, AstKind::VariableDeclaration(decl) if decl.declare));
|
||||
|
||||
let (mut includes, excludes) = match self.kind {
|
||||
VariableDeclarationKind::Const
|
||||
| VariableDeclarationKind::Using
|
||||
| VariableDeclarationKind::AwaitUsing => (
|
||||
@@ -35,6 +40,10 @@ impl<'a> Binder<'a> for VariableDeclarator<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
if is_declare {
|
||||
includes |= SymbolFlags::Ambient;
|
||||
}
|
||||
|
||||
if self.kind.is_lexical() {
|
||||
self.id.bound_names(&mut |ident| {
|
||||
let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes);
|
||||
@@ -117,13 +126,14 @@ impl<'a> Binder<'a> for VariableDeclarator<'a> {
|
||||
|
||||
impl<'a> Binder<'a> for Class<'a> {
|
||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||
let includes = if self.declare {
|
||||
SymbolFlags::Class | SymbolFlags::Ambient
|
||||
} else {
|
||||
SymbolFlags::Class
|
||||
};
|
||||
let Some(ident) = &self.id else { return };
|
||||
let symbol_id = builder.declare_symbol(
|
||||
ident.span,
|
||||
&ident.name,
|
||||
SymbolFlags::Class,
|
||||
SymbolFlags::ClassExcludes,
|
||||
);
|
||||
let symbol_id =
|
||||
builder.declare_symbol(ident.span, &ident.name, includes, SymbolFlags::ClassExcludes);
|
||||
ident.symbol_id.set(Some(symbol_id));
|
||||
}
|
||||
}
|
||||
@@ -152,30 +162,32 @@ fn is_function_part_of_if_statement(function: &Function, builder: &SemanticBuild
|
||||
|
||||
impl<'a> Binder<'a> for Function<'a> {
|
||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||
let includes = if self.declare {
|
||||
SymbolFlags::Function | SymbolFlags::Ambient
|
||||
} else {
|
||||
SymbolFlags::Function
|
||||
};
|
||||
|
||||
if let Some(ident) = &self.id {
|
||||
if is_function_part_of_if_statement(self, builder) {
|
||||
let symbol_id = builder.scoping.create_symbol(
|
||||
ident.span,
|
||||
ident.name.into(),
|
||||
SymbolFlags::Function,
|
||||
includes,
|
||||
ScopeId::new(u32::MAX - 1), // Not bound to any scope.
|
||||
builder.current_node_id,
|
||||
);
|
||||
ident.symbol_id.set(Some(symbol_id));
|
||||
} else {
|
||||
let symbol_id = builder.declare_symbol(
|
||||
ident.span,
|
||||
&ident.name,
|
||||
SymbolFlags::Function,
|
||||
if builder.source_type.is_typescript() {
|
||||
SymbolFlags::FunctionExcludes
|
||||
} else {
|
||||
// `var x; function x() {}` is valid in non-strict mode, but `TypeScript`
|
||||
// doesn't care about non-strict mode, so we need to exclude this,
|
||||
// and further check in checker.
|
||||
SymbolFlags::FunctionExcludes - SymbolFlags::FunctionScopedVariable
|
||||
},
|
||||
);
|
||||
let excludes = if builder.source_type.is_typescript() {
|
||||
SymbolFlags::FunctionExcludes
|
||||
} else {
|
||||
// `var x; function x() {}` is valid in non-strict mode, but `TypeScript`
|
||||
// doesn't care about non-strict mode, so we need to exclude this,
|
||||
// and further check in checker.
|
||||
SymbolFlags::FunctionExcludes - SymbolFlags::FunctionScopedVariable
|
||||
};
|
||||
let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes);
|
||||
ident.symbol_id.set(Some(symbol_id));
|
||||
}
|
||||
}
|
||||
@@ -336,10 +348,15 @@ impl<'a> Binder<'a> for TSImportEqualsDeclaration<'a> {
|
||||
|
||||
impl<'a> Binder<'a> for TSTypeAliasDeclaration<'a> {
|
||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||
let includes = if self.declare {
|
||||
SymbolFlags::TypeAlias | SymbolFlags::Ambient
|
||||
} else {
|
||||
SymbolFlags::TypeAlias
|
||||
};
|
||||
let symbol_id = builder.declare_symbol(
|
||||
self.id.span,
|
||||
&self.id.name,
|
||||
SymbolFlags::TypeAlias,
|
||||
includes,
|
||||
SymbolFlags::TypeAliasExcludes,
|
||||
);
|
||||
self.id.symbol_id.set(Some(symbol_id));
|
||||
@@ -348,10 +365,15 @@ impl<'a> Binder<'a> for TSTypeAliasDeclaration<'a> {
|
||||
|
||||
impl<'a> Binder<'a> for TSInterfaceDeclaration<'a> {
|
||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||
let includes = if self.declare {
|
||||
SymbolFlags::Interface | SymbolFlags::Ambient
|
||||
} else {
|
||||
SymbolFlags::Interface
|
||||
};
|
||||
let symbol_id = builder.declare_symbol(
|
||||
self.id.span,
|
||||
&self.id.name,
|
||||
SymbolFlags::Interface,
|
||||
includes,
|
||||
SymbolFlags::InterfaceExcludes,
|
||||
);
|
||||
self.id.symbol_id.set(Some(symbol_id));
|
||||
@@ -361,11 +383,11 @@ impl<'a> Binder<'a> for TSInterfaceDeclaration<'a> {
|
||||
impl<'a> Binder<'a> for TSEnumDeclaration<'a> {
|
||||
fn bind(&self, builder: &mut SemanticBuilder) {
|
||||
let is_const = self.r#const;
|
||||
let includes = if is_const { SymbolFlags::ConstEnum } else { SymbolFlags::RegularEnum };
|
||||
let excludes = if is_const {
|
||||
SymbolFlags::ConstEnumExcludes
|
||||
let includes = if self.declare { SymbolFlags::Ambient } else { SymbolFlags::empty() };
|
||||
let (includes, excludes) = if is_const {
|
||||
(SymbolFlags::ConstEnum | includes, SymbolFlags::ConstEnumExcludes)
|
||||
} else {
|
||||
SymbolFlags::RegularEnumExcludes
|
||||
(SymbolFlags::RegularEnum | includes, SymbolFlags::RegularEnumExcludes)
|
||||
};
|
||||
let symbol_id = builder.declare_symbol(self.id.span, &self.id.name, includes, excludes);
|
||||
self.id.symbol_id.set(Some(symbol_id));
|
||||
@@ -392,16 +414,16 @@ impl<'a> Binder<'a> for TSModuleDeclaration<'a> {
|
||||
let TSModuleDeclarationName::Identifier(id) = &self.id else { return };
|
||||
let instantiated =
|
||||
get_module_instance_state(builder, self, builder.current_node_id).is_instantiated();
|
||||
let (includes, excludes) = if instantiated {
|
||||
let (mut includes, excludes) = if instantiated {
|
||||
(SymbolFlags::ValueModule, SymbolFlags::ValueModuleExcludes)
|
||||
} else {
|
||||
(SymbolFlags::NameSpaceModule, SymbolFlags::NamespaceModuleExcludes)
|
||||
};
|
||||
|
||||
// At declaration time a module has no value declaration it is only when a value declaration
|
||||
// is made inside a the scope of a module that the symbol is modified
|
||||
let ambient = if self.declare { SymbolFlags::Ambient } else { SymbolFlags::None };
|
||||
let symbol_id = builder.declare_symbol(id.span, &id.name, includes | ambient, excludes);
|
||||
if self.declare {
|
||||
includes |= SymbolFlags::Ambient;
|
||||
}
|
||||
let symbol_id = builder.declare_symbol(id.span, &id.name, includes, excludes);
|
||||
|
||||
id.set_symbol_id(symbol_id);
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -41,7 +41,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/decorators/clas
|
||||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flags": "SymbolFlags(Function)",
|
||||
"flags": "SymbolFlags(Function | Ambient)",
|
||||
"id": 0,
|
||||
"name": "deco",
|
||||
"node": "Function(deco)",
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/jsx/this-jsxide
|
||||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable | Ambient)",
|
||||
"id": 0,
|
||||
"name": "React",
|
||||
"node": "VariableDeclarator(React)",
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaratio
|
||||
]
|
||||
},
|
||||
{
|
||||
"flags": "SymbolFlags(Function)",
|
||||
"flags": "SymbolFlags(Function | Ambient)",
|
||||
"id": 2,
|
||||
"name": "setAlignment",
|
||||
"node": "Function(setAlignment)",
|
||||
|
||||
@@ -125,7 +125,12 @@ bitflags! {
|
||||
const TypeParameter = 1 << 13;
|
||||
const NameSpaceModule = 1 << 14;
|
||||
const ValueModule = 1 << 15;
|
||||
// In a dts file or there is a declare flag
|
||||
/// Declared with `declare` modifier, like `declare function x() {}`.
|
||||
//
|
||||
// This flag is not part of TypeScript's `SymbolFlags`, it comes from TypeScript's `NodeFlags`. We introduced it into
|
||||
// here because `NodeFlags` is incomplete and we only can access to `NodeFlags` in the Semantic, but we also need to
|
||||
// access it in the Transformer.
|
||||
// https://github.com/microsoft/TypeScript/blob/15392346d05045742e653eab5c87538ff2a3c863/src/compiler/types.ts#L819-L820
|
||||
const Ambient = 1 << 16;
|
||||
|
||||
const Enum = Self::ConstEnum.bits() | Self::RegularEnum.bits();
|
||||
@@ -245,6 +250,11 @@ impl SymbolFlags {
|
||||
self.contains(Self::TypeImport)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ambient(&self) -> bool {
|
||||
self.contains(Self::Ambient)
|
||||
}
|
||||
|
||||
/// If true, then the symbol can be referenced by a type reference
|
||||
#[inline]
|
||||
pub fn can_be_referenced_by_type(&self) -> bool {
|
||||
|
||||
@@ -1458,7 +1458,7 @@ semantic error: Scope children mismatch:
|
||||
after transform: ScopeId(0): [ScopeId(1), ScopeId(2)]
|
||||
rebuilt : ScopeId(0): [ScopeId(1)]
|
||||
Symbol flags mismatch for "C":
|
||||
after transform: SymbolId(0): SymbolFlags(Class | Function)
|
||||
after transform: SymbolId(0): SymbolFlags(Class | Function | Ambient)
|
||||
rebuilt : SymbolId(0): SymbolFlags(Function)
|
||||
Symbol span mismatch for "C":
|
||||
after transform: SymbolId(0): Span { start: 14, end: 15 }
|
||||
|
||||
@@ -379,7 +379,7 @@ Scope children mismatch:
|
||||
after transform: ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(3), ScopeId(4), ScopeId(5)]
|
||||
rebuilt : ScopeId(0): [ScopeId(1)]
|
||||
Symbol flags mismatch for "D":
|
||||
after transform: SymbolId(3): SymbolFlags(Class | ValueModule)
|
||||
after transform: SymbolId(3): SymbolFlags(Class | ValueModule | Ambient)
|
||||
rebuilt : SymbolId(0): SymbolFlags(BlockScopedVariable)
|
||||
Symbol span mismatch for "D":
|
||||
after transform: SymbolId(3): Span { start: 97, end: 98 }
|
||||
@@ -398,7 +398,7 @@ semantic error: Scope children mismatch:
|
||||
after transform: ScopeId(0): [ScopeId(1), ScopeId(2)]
|
||||
rebuilt : ScopeId(0): [ScopeId(1)]
|
||||
Symbol flags mismatch for "foo":
|
||||
after transform: SymbolId(0): SymbolFlags(Class | Function)
|
||||
after transform: SymbolId(0): SymbolFlags(Class | Function | Ambient)
|
||||
rebuilt : SymbolId(0): SymbolFlags(Function)
|
||||
Symbol span mismatch for "foo":
|
||||
after transform: SymbolId(0): Span { start: 14, end: 17 }
|
||||
@@ -46653,6 +46653,9 @@ tasks/coverage/typescript/tests/cases/conformance/jsx/jsxReactTestSuite.tsx
|
||||
semantic error: Bindings mismatch:
|
||||
after transform: ScopeId(0): ["Child", "Component", "Composite", "Composite2", "Namespace", "React", "_jsxFileName", "_objectSpread", "_reactJsxRuntime", "bar", "foo", "hasOwnProperty", "x", "y", "z"]
|
||||
rebuilt : ScopeId(0): ["_jsxFileName", "_objectSpread", "_reactJsxRuntime", "x"]
|
||||
Symbol flags mismatch for "x":
|
||||
after transform: SymbolId(9): SymbolFlags(FunctionScopedVariable | Ambient)
|
||||
rebuilt : SymbolId(3): SymbolFlags(FunctionScopedVariable)
|
||||
Symbol span mismatch for "x":
|
||||
after transform: SymbolId(9): Span { start: 231, end: 236 }
|
||||
rebuilt : SymbolId(3): Span { start: 537, end: 538 }
|
||||
|
||||
@@ -1705,7 +1705,7 @@ Scope children mismatch:
|
||||
after transform: ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(3), ScopeId(4)]
|
||||
rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)]
|
||||
Symbol flags mismatch for "Signal":
|
||||
after transform: SymbolId(0): SymbolFlags(Class | Function)
|
||||
after transform: SymbolId(0): SymbolFlags(Class | Function | Ambient)
|
||||
rebuilt : SymbolId(0): SymbolFlags(Function)
|
||||
Symbol span mismatch for "Signal":
|
||||
after transform: SymbolId(0): Span { start: 14, end: 20 }
|
||||
@@ -1717,7 +1717,7 @@ Symbol redeclarations mismatch for "Signal":
|
||||
after transform: SymbolId(0): [Span { start: 14, end: 20 }, Span { start: 54, end: 60 }]
|
||||
rebuilt : SymbolId(0): []
|
||||
Symbol flags mismatch for "Signal2":
|
||||
after transform: SymbolId(3): SymbolFlags(Class | Function)
|
||||
after transform: SymbolId(3): SymbolFlags(Class | Function | Ambient)
|
||||
rebuilt : SymbolId(2): SymbolFlags(Function)
|
||||
Symbol reference IDs mismatch for "Signal2":
|
||||
after transform: SymbolId(3): [ReferenceId(4), ReferenceId(7)]
|
||||
|
||||
Reference in new issue
Block a user