mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
fix(semantic): TSConditionalType scope enter/exit locations (#6351)
Fixes the same problem as #6270, but uses `#[scope(enter_before)]` and `#[scope(exit_after)]` to correct scope entry/exit locations.
This commit is contained in:
parent
d9718adc8d
commit
834ee2aa6c
7 changed files with 65 additions and 42 deletions
|
|
@ -347,10 +347,12 @@ pub struct TSConditionalType<'a> {
|
|||
/// The type before `extends` in the test expression.
|
||||
pub check_type: TSType<'a>,
|
||||
/// The type `check_type` is being tested against.
|
||||
#[scope(enter_before)]
|
||||
pub extends_type: TSType<'a>,
|
||||
/// The type evaluated to if the test is true.
|
||||
pub true_type: TSType<'a>,
|
||||
/// The type evaluated to if the test is false.
|
||||
#[scope(exit_before)]
|
||||
pub false_type: TSType<'a>,
|
||||
#[serde(skip)]
|
||||
#[clone_in(default)]
|
||||
|
|
|
|||
|
|
@ -1913,12 +1913,12 @@ pub mod walk {
|
|||
pub fn walk_ts_conditional_type<'a, V: Visit<'a>>(visitor: &mut V, it: &TSConditionalType<'a>) {
|
||||
let kind = AstKind::TSConditionalType(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
visitor.visit_ts_type(&it.check_type);
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
visitor.visit_ts_type(&it.extends_type);
|
||||
visitor.visit_ts_type(&it.true_type);
|
||||
visitor.visit_ts_type(&it.false_type);
|
||||
visitor.leave_scope();
|
||||
visitor.visit_ts_type(&it.false_type);
|
||||
visitor.leave_node(kind);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1956,12 +1956,12 @@ pub mod walk_mut {
|
|||
) {
|
||||
let kind = AstType::TSConditionalType;
|
||||
visitor.enter_node(kind);
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
visitor.visit_ts_type(&mut it.check_type);
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
visitor.visit_ts_type(&mut it.extends_type);
|
||||
visitor.visit_ts_type(&mut it.true_type);
|
||||
visitor.visit_ts_type(&mut it.false_type);
|
||||
visitor.leave_scope();
|
||||
visitor.visit_ts_type(&mut it.false_type);
|
||||
visitor.leave_node(kind);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,30 +12,7 @@ SCOPES
|
|||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"children": [],
|
||||
"flags": "ScopeFlags(StrictMode)",
|
||||
"id": 3,
|
||||
"node": "TSConditionalType",
|
||||
"symbols": [
|
||||
{
|
||||
"flags": "SymbolFlags(TypeParameter)",
|
||||
"id": 3,
|
||||
"name": "U",
|
||||
"node": "TSTypeParameter(U)",
|
||||
"references": [
|
||||
{
|
||||
"flags": "ReferenceFlags(Type)",
|
||||
"id": 5,
|
||||
"name": "U",
|
||||
"node_id": 33
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"children": [],
|
||||
"flags": "ScopeFlags(StrictMode)",
|
||||
"id": 2,
|
||||
"node": "TSConditionalType",
|
||||
|
|
@ -55,6 +32,28 @@ SCOPES
|
|||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"children": [],
|
||||
"flags": "ScopeFlags(StrictMode)",
|
||||
"id": 3,
|
||||
"node": "TSConditionalType",
|
||||
"symbols": [
|
||||
{
|
||||
"flags": "SymbolFlags(TypeParameter)",
|
||||
"id": 3,
|
||||
"name": "U",
|
||||
"node": "TSTypeParameter(U)",
|
||||
"references": [
|
||||
{
|
||||
"flags": "ReferenceFlags(Type)",
|
||||
"id": 5,
|
||||
"name": "U",
|
||||
"node_id": 33
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"flags": "ScopeFlags(StrictMode)",
|
||||
|
|
|
|||
|
|
@ -239,3 +239,25 @@ fn get_child_ids() {
|
|||
let child_scope_ids = scopes.get_child_ids(child_scope_ids[0]);
|
||||
assert!(child_scope_ids.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ts_conditional_types() {
|
||||
SemanticTester::ts("type A<T> = T extends string ? T : false;")
|
||||
.has_some_symbol("T")
|
||||
.has_number_of_references(2)
|
||||
.test();
|
||||
|
||||
// Conditional types create a new scope after check_type.
|
||||
SemanticTester::ts(
|
||||
"type S<A> = A extends (infer B extends number ? string : never) ? B : false;",
|
||||
)
|
||||
.has_some_symbol("B")
|
||||
.has_number_of_references(1)
|
||||
.test();
|
||||
|
||||
// Inferred type parameter is only available within true branch
|
||||
SemanticTester::ts("type S<A> = A extends infer R ? never : R")
|
||||
.has_some_symbol("R")
|
||||
.has_number_of_references(0)
|
||||
.test();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3964,13 +3964,6 @@ pub(crate) unsafe fn walk_ts_conditional_type<'a, Tr: Traverse<'a>>(
|
|||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
traverser.enter_ts_conditional_type(&mut *node, ctx);
|
||||
let previous_scope_id = ctx.current_scope_id();
|
||||
ctx.set_current_scope_id(
|
||||
(*((node as *mut u8).add(ancestor::OFFSET_TS_CONDITIONAL_TYPE_SCOPE_ID)
|
||||
as *mut Cell<Option<ScopeId>>))
|
||||
.get()
|
||||
.unwrap(),
|
||||
);
|
||||
let pop_token = ctx.push_stack(Ancestor::TSConditionalTypeCheckType(
|
||||
ancestor::TSConditionalTypeWithoutCheckType(node, PhantomData),
|
||||
));
|
||||
|
|
@ -3979,6 +3972,13 @@ pub(crate) unsafe fn walk_ts_conditional_type<'a, Tr: Traverse<'a>>(
|
|||
(node as *mut u8).add(ancestor::OFFSET_TS_CONDITIONAL_TYPE_CHECK_TYPE) as *mut TSType,
|
||||
ctx,
|
||||
);
|
||||
let previous_scope_id = ctx.current_scope_id();
|
||||
ctx.set_current_scope_id(
|
||||
(*((node as *mut u8).add(ancestor::OFFSET_TS_CONDITIONAL_TYPE_SCOPE_ID)
|
||||
as *mut Cell<Option<ScopeId>>))
|
||||
.get()
|
||||
.unwrap(),
|
||||
);
|
||||
ctx.retag_stack(AncestorType::TSConditionalTypeExtendsType);
|
||||
walk_ts_type(
|
||||
traverser,
|
||||
|
|
@ -3991,6 +3991,7 @@ pub(crate) unsafe fn walk_ts_conditional_type<'a, Tr: Traverse<'a>>(
|
|||
(node as *mut u8).add(ancestor::OFFSET_TS_CONDITIONAL_TYPE_TRUE_TYPE) as *mut TSType,
|
||||
ctx,
|
||||
);
|
||||
ctx.set_current_scope_id(previous_scope_id);
|
||||
ctx.retag_stack(AncestorType::TSConditionalTypeFalseType);
|
||||
walk_ts_type(
|
||||
traverser,
|
||||
|
|
@ -3998,7 +3999,6 @@ pub(crate) unsafe fn walk_ts_conditional_type<'a, Tr: Traverse<'a>>(
|
|||
ctx,
|
||||
);
|
||||
ctx.pop_stack(pop_token);
|
||||
ctx.set_current_scope_id(previous_scope_id);
|
||||
traverser.exit_ts_conditional_type(&mut *node, ctx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3897,13 +3897,13 @@ Bindings mismatch:
|
|||
after transform: ScopeId(2): ["P", "attrs"]
|
||||
rebuilt : ScopeId(1): ["attrs"]
|
||||
Scope children mismatch:
|
||||
after transform: ScopeId(2): [ScopeId(3)]
|
||||
after transform: ScopeId(2): [ScopeId(3), ScopeId(5)]
|
||||
rebuilt : ScopeId(1): []
|
||||
Bindings mismatch:
|
||||
after transform: ScopeId(6): ["P", "attrs"]
|
||||
rebuilt : ScopeId(2): ["attrs"]
|
||||
Scope children mismatch:
|
||||
after transform: ScopeId(6): [ScopeId(7)]
|
||||
after transform: ScopeId(6): [ScopeId(7), ScopeId(8)]
|
||||
rebuilt : ScopeId(2): []
|
||||
Bindings mismatch:
|
||||
after transform: ScopeId(9): ["P", "attrs"]
|
||||
|
|
@ -8852,7 +8852,7 @@ Bindings mismatch:
|
|||
after transform: ScopeId(3): ["D", "clientDef"]
|
||||
rebuilt : ScopeId(1): ["clientDef"]
|
||||
Scope children mismatch:
|
||||
after transform: ScopeId(3): [ScopeId(4)]
|
||||
after transform: ScopeId(3): [ScopeId(4), ScopeId(5)]
|
||||
rebuilt : ScopeId(1): []
|
||||
Unresolved references mismatch:
|
||||
after transform: ["Record"]
|
||||
|
|
@ -17164,7 +17164,7 @@ Scope children mismatch:
|
|||
after transform: ScopeId(8): [ScopeId(9), ScopeId(10)]
|
||||
rebuilt : ScopeId(2): []
|
||||
Symbol reference IDs mismatch for "state":
|
||||
after transform: SymbolId(8): [ReferenceId(11), ReferenceId(12), ReferenceId(13), ReferenceId(15)]
|
||||
after transform: SymbolId(9): [ReferenceId(11), ReferenceId(12), ReferenceId(13), ReferenceId(15)]
|
||||
rebuilt : SymbolId(1): [ReferenceId(0), ReferenceId(1), ReferenceId(2)]
|
||||
Unresolved references mismatch:
|
||||
after transform: ["State", "true"]
|
||||
|
|
@ -52205,10 +52205,10 @@ Scope children mismatch:
|
|||
after transform: ScopeId(0): [ScopeId(1), ScopeId(4), ScopeId(5), ScopeId(6), ScopeId(7), ScopeId(10), ScopeId(11), ScopeId(12), ScopeId(13), ScopeId(16), ScopeId(17), ScopeId(18), ScopeId(19), ScopeId(22), ScopeId(23), ScopeId(24), ScopeId(25), ScopeId(28), ScopeId(29), ScopeId(30), ScopeId(31), ScopeId(34), ScopeId(35), ScopeId(36), ScopeId(37), ScopeId(40), ScopeId(41), ScopeId(42), ScopeId(43), ScopeId(44), ScopeId(47), ScopeId(48), ScopeId(49), ScopeId(50), ScopeId(51), ScopeId(54), ScopeId(55), ScopeId(56), ScopeId(57), ScopeId(58), ScopeId(61), ScopeId(63), ScopeId(64), ScopeId(67), ScopeId(69), ScopeId(71), ScopeId(73), ScopeId(77), ScopeId(80), ScopeId(84), ScopeId(87), ScopeId(89), ScopeId(90), ScopeId(91), ScopeId(92), ScopeId(95), ScopeId(96), ScopeId(98), ScopeId(99), ScopeId(100), ScopeId(101), ScopeId(102), ScopeId(103), ScopeId(107), ScopeId(108), ScopeId(109), ScopeId(110), ScopeId(111)]
|
||||
rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)]
|
||||
Reference symbol mismatch for "x1":
|
||||
after transform: SymbolId(126) "x1"
|
||||
after transform: SymbolId(127) "x1"
|
||||
rebuilt : <None>
|
||||
Reference symbol mismatch for "x2":
|
||||
after transform: SymbolId(132) "x2"
|
||||
after transform: SymbolId(133) "x2"
|
||||
rebuilt : <None>
|
||||
Unresolved references mismatch:
|
||||
after transform: ["Promise"]
|
||||
|
|
|
|||
Loading…
Reference in a new issue