Skip to content

Commit

Permalink
perf(semantic): do not need to handle type resolving when it is not a…
Browse files Browse the repository at this point in the history
… typescript code
  • Loading branch information
Dunqing committed Jan 20, 2025
1 parent d9f5e7f commit 2f386ae
Showing 1 changed file with 50 additions and 37 deletions.
87 changes: 50 additions & 37 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,47 +488,56 @@ impl<'a> SemanticBuilder<'a> {
// If unresolved, transfer it to parent scope's unresolved references.
let bindings = self.scope.get_bindings(self.current_scope_id);
if let Some(symbol_id) = bindings.get(name.as_str()).copied() {
let symbol_flags = self.symbols.get_flags(symbol_id);
references.retain(|&reference_id| {
let reference = &mut self.symbols.references[reference_id];
if self.source_type.is_typescript() {
let symbol_flags = self.symbols.get_flags(symbol_id);
references.retain(|&reference_id| {
let reference = &mut self.symbols.references[reference_id];

let flags = reference.flags_mut();

// Determine the symbol whether can be referenced by this reference.
let resolved = (flags.is_value()
&& symbol_flags.can_be_referenced_by_value())
|| (flags.is_type() && symbol_flags.can_be_referenced_by_type())
|| (flags.is_value_as_type()
&& symbol_flags.can_be_referenced_by_value_as_type());

if !resolved {
return true;
}

let flags = reference.flags_mut();
if symbol_flags.is_value() && flags.is_value() {
// The non type-only ExportSpecifier can reference both type/value symbols,
// if the symbol is a value symbol and reference flag is not type-only,
// remove the type flag. For example: `const B = 1; export { B };`
*flags -= ReferenceFlags::Type;
} else {
// 1. ReferenceFlags::ValueAsType -> ReferenceFlags::Type
// `const ident = 0; typeof ident`
// ^^^^^ -> The ident is a value symbols,
// but it used as a type.
// 2. ReferenceFlags::Value | ReferenceFlags::Type -> ReferenceFlags::Type
// `type ident = string; export default ident;
// ^^^^^ We have confirmed the symbol is
// not a value symbol, so we need to
// make sure the reference is a type only.
*flags = ReferenceFlags::Type;
}
reference.set_symbol_id(symbol_id);
self.symbols.add_resolved_reference(symbol_id, reference_id);

// Determine the symbol whether can be referenced by this reference.
let resolved = (flags.is_value() && symbol_flags.can_be_referenced_by_value())
|| (flags.is_type() && symbol_flags.can_be_referenced_by_type())
|| (flags.is_value_as_type()
&& symbol_flags.can_be_referenced_by_value_as_type());
false
});

if !resolved {
return true;
if references.is_empty() {
continue;
}

if symbol_flags.is_value() && flags.is_value() {
// The non type-only ExportSpecifier can reference both type/value symbols,
// if the symbol is a value symbol and reference flag is not type-only,
// remove the type flag. For example: `const B = 1; export { B };`
*flags -= ReferenceFlags::Type;
} else {
// 1. ReferenceFlags::ValueAsType -> ReferenceFlags::Type
// `const ident = 0; typeof ident`
// ^^^^^ -> The ident is a value symbols,
// but it used as a type.
// 2. ReferenceFlags::Value | ReferenceFlags::Type -> ReferenceFlags::Type
// `type ident = string; export default ident;
// ^^^^^ We have confirmed the symbol is
// not a value symbol, so we need to
// make sure the reference is a type only.
*flags = ReferenceFlags::Type;
} else {
for reference_id in references.drain(..) {
let reference = &mut self.symbols.references[reference_id];
reference.set_symbol_id(symbol_id);
self.symbols.add_resolved_reference(symbol_id, reference_id);
}
reference.set_symbol_id(symbol_id);
self.symbols.add_resolved_reference(symbol_id, reference_id);

false
});

if references.is_empty() {
continue;
}
}

Expand Down Expand Up @@ -1843,7 +1852,9 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
ExportDefaultDeclarationKind::Identifier(it) => {
// `export default ident`
// ^^^^^ -> can reference both type/value symbols
self.current_reference_flags = ReferenceFlags::Read | ReferenceFlags::Type;
if self.source_type.is_typescript() {
self.current_reference_flags = ReferenceFlags::Read | ReferenceFlags::Type;
}
self.visit_identifier_reference(it);
}
match_expression!(ExportDefaultDeclarationKind) => {
Expand All @@ -1863,6 +1874,8 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
if let Some(source) = &it.source {
self.visit_string_literal(source);
self.visit_export_specifiers(&it.specifiers);
} else if !self.source_type.is_typescript() {
self.visit_export_specifiers(&it.specifiers);
} else {
for specifier in &it.specifiers {
// `export type { a }` or `export { type a }` -> `a` is a type reference
Expand Down

0 comments on commit 2f386ae

Please sign in to comment.