mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 20:28:58 +00:00
fix(semantic): reset references flags when resolved (#7923)
For this case, we set `current_reference_flags` to `ReferenceFlags::Type` for `TSInterfaceHeritage`, but never unset it, which causes resolving `fowardRef` identifier reuse `current_reference_flags` of `TSInterfaceHeritage`.
```ts
import { forwardRef } from "react";
export interface MenuTriggerProps extends Object {}
export const MenuTrigger = forwardRef();
```
In this PR, reset the `current_reference_flags` when resolved, so that we don't need to reset it in individual visit functions. This is a reasonable change because the `current_reference_flags` only applies to the next encountered identifier.
This commit is contained in:
parent
523d48ccb2
commit
596aead0e9
4 changed files with 60 additions and 20 deletions
|
|
@ -1,6 +1,9 @@
|
|||
//! Semantic Builder
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
mem,
|
||||
};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
|
|
@ -1789,7 +1792,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
fn visit_simple_assignment_target(&mut self, it: &SimpleAssignmentTarget<'a>) {
|
||||
let kind = AstKind::SimpleAssignmentTarget(self.alloc(it));
|
||||
self.enter_node(kind);
|
||||
let prev_reference_flags = self.current_reference_flags;
|
||||
// Except that the read-write flags has been set in visit_assignment_expression
|
||||
// and visit_update_expression, this is always a write-only reference here.
|
||||
if !self.current_reference_flags.is_write() {
|
||||
|
|
@ -1819,7 +1821,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
self.visit_member_expression(it.to_member_expression());
|
||||
}
|
||||
}
|
||||
self.current_reference_flags = prev_reference_flags;
|
||||
self.leave_node(kind);
|
||||
}
|
||||
|
||||
|
|
@ -1828,10 +1829,8 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
it: &AssignmentTargetPropertyIdentifier<'a>,
|
||||
) {
|
||||
// NOTE: AstKind doesn't exists!
|
||||
let prev_reference_flags = self.current_reference_flags;
|
||||
self.current_reference_flags = ReferenceFlags::Write;
|
||||
self.visit_identifier_reference(&it.binding);
|
||||
self.current_reference_flags = prev_reference_flags;
|
||||
if let Some(init) = &it.init {
|
||||
self.visit_expression(init);
|
||||
}
|
||||
|
|
@ -1850,10 +1849,8 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
ExportDefaultDeclarationKind::Identifier(it) => {
|
||||
// `export default ident`
|
||||
// ^^^^^ -> can reference both type/value symbols
|
||||
let prev_reference_flags = self.current_reference_flags;
|
||||
self.current_reference_flags = ReferenceFlags::Read | ReferenceFlags::Type;
|
||||
self.visit_identifier_reference(it);
|
||||
self.current_reference_flags = prev_reference_flags;
|
||||
}
|
||||
match_expression!(ExportDefaultDeclarationKind) => {
|
||||
self.visit_expression(it.to_expression());
|
||||
|
|
@ -1868,13 +1865,10 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
if let Some(declaration) = &it.declaration {
|
||||
self.visit_declaration(declaration);
|
||||
}
|
||||
// let prev_reference_flags = self.current_reference_flags;
|
||||
if it.export_kind.is_type() {
|
||||
self.current_reference_flags = ReferenceFlags::Type;
|
||||
}
|
||||
self.visit_export_specifiers(&it.specifiers);
|
||||
// self.current_reference_flags = prev_reference_flags;
|
||||
|
||||
if let Some(source) = &it.source {
|
||||
self.visit_string_literal(source);
|
||||
}
|
||||
|
|
@ -1914,14 +1908,12 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
let kind = AstKind::TSExportAssignment(self.alloc(it));
|
||||
self.enter_node(kind);
|
||||
self.visit_span(&it.span);
|
||||
let prev_reference_flags = self.current_reference_flags;
|
||||
// export = a;
|
||||
// ^ can reference type/value symbols
|
||||
if it.expression.is_identifier_reference() {
|
||||
self.current_reference_flags = ReferenceFlags::Read | ReferenceFlags::Type;
|
||||
}
|
||||
self.visit_expression(&it.expression);
|
||||
self.current_reference_flags = prev_reference_flags;
|
||||
self.leave_node(kind);
|
||||
}
|
||||
}
|
||||
|
|
@ -2140,11 +2132,12 @@ impl<'a> SemanticBuilder<'a> {
|
|||
|
||||
/// Resolve reference flags for the current ast node.
|
||||
#[inline]
|
||||
fn resolve_reference_usages(&self) -> ReferenceFlags {
|
||||
fn resolve_reference_usages(&mut self) -> ReferenceFlags {
|
||||
if self.current_reference_flags.is_empty() {
|
||||
ReferenceFlags::Read
|
||||
} else {
|
||||
self.current_reference_flags
|
||||
// Take the current reference flags so that we can reset it to empty
|
||||
mem::take(&mut self.current_reference_flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
50
crates/oxc_semantic/tests/fixtures/oxc/ts/exports/named/interface-heritage.snap
vendored
Normal file
50
crates/oxc_semantic/tests/fixtures/oxc/ts/exports/named/interface-heritage.snap
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
source: crates/oxc_semantic/tests/main.rs
|
||||
input_file: crates/oxc_semantic/tests/fixtures/oxc/ts/exports/named/interface-heritage.ts
|
||||
---
|
||||
[
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [],
|
||||
"flags": "ScopeFlags(StrictMode)",
|
||||
"id": 1,
|
||||
"node": "TSInterfaceDeclaration",
|
||||
"symbols": []
|
||||
}
|
||||
],
|
||||
"flags": "ScopeFlags(StrictMode | Top)",
|
||||
"id": 0,
|
||||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flags": "SymbolFlags(Import)",
|
||||
"id": 0,
|
||||
"name": "forwardRef",
|
||||
"node": "ImportSpecifier(forwardRef)",
|
||||
"references": [
|
||||
{
|
||||
"flags": "ReferenceFlags(Read)",
|
||||
"id": 1,
|
||||
"name": "forwardRef",
|
||||
"node_id": 19
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"flags": "SymbolFlags(Interface)",
|
||||
"id": 1,
|
||||
"name": "MenuTriggerProps",
|
||||
"node": "TSInterfaceDeclaration",
|
||||
"references": []
|
||||
},
|
||||
{
|
||||
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"id": 2,
|
||||
"name": "MenuTrigger",
|
||||
"node": "VariableDeclarator(MenuTrigger)",
|
||||
"references": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
3
crates/oxc_semantic/tests/fixtures/oxc/ts/exports/named/interface-heritage.ts
vendored
Normal file
3
crates/oxc_semantic/tests/fixtures/oxc/ts/exports/named/interface-heritage.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { forwardRef } from "react";
|
||||
export interface MenuTriggerProps extends Object {}
|
||||
export const MenuTrigger = forwardRef();
|
||||
|
|
@ -36818,9 +36818,6 @@ rebuilt : ScopeId(19): ["key", "obj"]
|
|||
Bindings mismatch:
|
||||
after transform: ScopeId(26): ["T", "a"]
|
||||
rebuilt : ScopeId(21): ["a"]
|
||||
Reference flags mismatch for "Monkey":
|
||||
after transform: ReferenceId(7): ReferenceFlags(Type)
|
||||
rebuilt : ReferenceId(2): ReferenceFlags(Read)
|
||||
Unresolved references mismatch:
|
||||
after transform: ["Partial", "Readonly"]
|
||||
rebuilt : []
|
||||
|
|
@ -40376,9 +40373,6 @@ rebuilt : SymbolId(0): Span { start: 62, end: 63 }
|
|||
Symbol redeclarations mismatch for "B":
|
||||
after transform: SymbolId(1): [Span { start: 62, end: 63 }]
|
||||
rebuilt : SymbolId(0): []
|
||||
Reference flags mismatch for "B":
|
||||
after transform: ReferenceId(1): ReferenceFlags(Type)
|
||||
rebuilt : ReferenceId(0): ReferenceFlags(Read)
|
||||
|
||||
tasks/coverage/typescript/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts
|
||||
semantic error: Bindings mismatch:
|
||||
|
|
|
|||
Loading…
Reference in a new issue