Skip to content

Commit

Permalink
fix(semantic): incorrect resolve references for ExportSpecifier (#4320
Browse files Browse the repository at this point in the history
)

```ts
type A = any;
const B = 0;
export { A, B }
       ^^^^^^^^ ExportSpecifiers

export { A }
       ^^^^^ type-only ExportSpecifiers

```

non-type-only `ExportSpecifier` can reference value and type symbols. but currently, `IdentifierReference` in ExportSpecifier only has a `ReferenceFlags::Read`
  • Loading branch information
Dunqing committed Jul 17, 2024
1 parent a88d588 commit 95e15b6
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 23 deletions.
38 changes: 19 additions & 19 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,9 +399,15 @@ impl<'a> SemanticBuilder<'a> {
resolved_references.reserve(references.len());

references.retain(|(id, flag)| {
if flag.is_type() && symbol_flag.is_type()
if flag.is_type() && symbol_flag.is_can_be_referenced_by_type()
|| flag.is_value() && symbol_flag.is_value()
{
// The non type-only ExportSpecifier can reference a type,
// If the reference is not a type, remove the type flag from the reference
if !symbol_flag.is_type() && !flag.is_type_only() {
*self.symbols.references[*id].flag_mut() -= ReferenceFlag::Type;
}

self.symbols.references[*id].set_symbol_id(symbol_id);
resolved_references.push(*id);
false
Expand Down Expand Up @@ -1619,11 +1625,12 @@ impl<'a> SemanticBuilder<'a> {
self.current_reference_flag = ReferenceFlag::Type;
}
}
AstKind::ExportAllDeclaration(s) if s.export_kind.is_type() => {
self.current_reference_flag = ReferenceFlag::Type;
}
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
self.current_reference_flag = ReferenceFlag::Type;
AstKind::ExportSpecifier(s) => {
if self.current_reference_flag.is_type() || s.export_kind.is_type() {
self.current_reference_flag = ReferenceFlag::Type;
} else {
self.current_reference_flag = ReferenceFlag::Read | ReferenceFlag::Type;
}
}
AstKind::ImportSpecifier(specifier) => {
specifier.bind(self);
Expand Down Expand Up @@ -1709,9 +1716,6 @@ impl<'a> SemanticBuilder<'a> {
AstKind::TSTypeParameter(type_parameter) => {
type_parameter.bind(self);
}
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
self.current_reference_flag = ReferenceFlag::Type;
}
AstKind::TSInterfaceHeritage(_) => {
self.current_reference_flag = ReferenceFlag::Type;
}
Expand Down Expand Up @@ -1798,17 +1802,11 @@ impl<'a> SemanticBuilder<'a> {
AstKind::BindingIdentifier(_) => {
self.current_symbol_flags -= SymbolFlags::Export;
}
AstKind::ExportNamedDeclaration(decl) => {
if decl.export_kind.is_type() {
self.current_reference_flag -= ReferenceFlag::Type;
AstKind::ExportSpecifier(_) => {
if !self.current_reference_flag.is_type_only() {
self.current_reference_flag = ReferenceFlag::empty();
}
}
AstKind::ExportAllDeclaration(s) if s.export_kind.is_type() => {
self.current_reference_flag -= ReferenceFlag::Type;
}
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
self.current_reference_flag -= ReferenceFlag::Type;
}
AstKind::LabeledStatement(_) => self.label_builder.leave(),
AstKind::StaticBlock(_) => {
self.label_builder.leave_function_or_static_block();
Expand Down Expand Up @@ -1851,7 +1849,9 @@ impl<'a> SemanticBuilder<'a> {
self.current_reference_flag -= ReferenceFlag::Read;
}
}
AstKind::MemberExpression(_) | AstKind::TSTypeQuery(_) => {
AstKind::MemberExpression(_)
| AstKind::TSTypeQuery(_)
| AstKind::ExportNamedDeclaration(_) => {
self.current_reference_flag = ReferenceFlag::empty();
}
AstKind::AssignmentTarget(_) => self.current_reference_flag -= ReferenceFlag::Write,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named-du
"node": "VariableDeclarator",
"references": [
{
"flag": "ReferenceFlag(Read)",
"flag": "ReferenceFlag(Read | Type)",
"id": 0,
"name": "T",
"node_id": 12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named2-t
"id": 0,
"name": "A",
"node": "TSTypeAliasDeclaration",
"references": []
"references": [
{
"flag": "ReferenceFlag(Read | Type)",
"id": 0,
"name": "A",
"node_id": 8
}
]
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named3-t
"id": 0,
"name": "V",
"node": "TSTypeAliasDeclaration",
"references": []
"references": [
{
"flag": "ReferenceFlag(Read | Type)",
"id": 0,
"name": "V",
"node_id": 8
}
]
}
]
}
Expand Down
4 changes: 4 additions & 0 deletions crates/oxc_syntax/src/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ impl ReferenceFlag {
self.contains(Self::Type)
}

pub const fn is_type_only(self) -> bool {
matches!(self, Self::Type)
}

pub const fn is_value(&self) -> bool {
self.intersects(Self::Value)
}
Expand Down
6 changes: 5 additions & 1 deletion crates/oxc_syntax/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ impl SymbolFlags {
}

pub fn is_type(&self) -> bool {
self.intersects(Self::Type | Self::TypeImport | Self::Import)
self.intersects(Self::Type | Self::TypeImport)
}

pub fn is_can_be_referenced_by_type(&self) -> bool {
self.is_type() || self.contains(Self::Import)
}

pub fn is_value(&self) -> bool {
Expand Down

0 comments on commit 95e15b6

Please sign in to comment.