Skip to content

Commit d6ea754

Browse files
committed
feat(transformer/optional-chaining): change parent scope for expression when it wrapped with an arrow function
1 parent f60110a commit d6ea754

3 files changed

Lines changed: 16 additions & 325 deletions

File tree

crates/oxc_transformer/src/es2020/optional_chaining.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use std::mem;
5151

5252
use oxc_allocator::CloneIn;
5353
use oxc_ast::{ast::*, NONE};
54+
use oxc_semantic::ScopeFlags;
5455
use oxc_span::SPAN;
5556
use oxc_traverse::{Ancestor, BoundIdentifier, MaybeBoundIdentifier, Traverse, TraverseCtx};
5657

@@ -244,14 +245,20 @@ impl<'a> OptionalChaining<'a, '_> {
244245

245246
/// Wrap the expression with an arrow function
246247
///
247-
/// `expr` -> `() => { return expr; }`
248-
fn wrap_arrow_function(expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
248+
/// `expr` -> `(() => { return expr; })()`
249+
fn wrap_arrow_function_iife(
250+
expr: &mut Expression<'a>,
251+
ctx: &mut TraverseCtx<'a>,
252+
) -> Expression<'a> {
253+
// Create a child scope for the outside arrow function and change the parent scope for the expression
254+
let scope_id = ctx.create_child_scope_of_current(ScopeFlags::Arrow | ScopeFlags::Function);
255+
ctx.change_parent_scope_for_expression(scope_id, expr);
256+
249257
let kind = FormalParameterKind::ArrowFormalParameters;
250258
let params = ctx.ast.formal_parameters(SPAN, kind, ctx.ast.vec(), NONE);
251259
let statements =
252260
ctx.ast.vec1(ctx.ast.statement_return(SPAN, Some(ctx.ast.move_expression(expr))));
253261
let body = ctx.ast.function_body(SPAN, ctx.ast.vec(), statements);
254-
let scope_id = ctx.current_scope_id();
255262
let arrow = ctx.ast.alloc_arrow_function_expression_with_scope_id(
256263
SPAN, false, false, NONE, params, NONE, body, scope_id,
257264
);
@@ -306,7 +313,7 @@ impl<'a> OptionalChaining<'a, '_> {
306313
// To insert the temp binding in the correct scope, we wrap the expression with
307314
// an arrow function. During the chain expression transformation, the temp binding
308315
// will be inserted into the arrow function's body.
309-
Self::wrap_arrow_function(expr, ctx)
316+
Self::wrap_arrow_function_iife(expr, ctx)
310317
} else {
311318
self.transform_chain_expression_impl(false, expr, ctx)
312319
}
@@ -320,7 +327,7 @@ impl<'a> OptionalChaining<'a, '_> {
320327
) {
321328
*expr = if self.is_inside_function_parameter {
322329
// Same as the above `transform_chain_expression` explanation
323-
Self::wrap_arrow_function(expr, ctx)
330+
Self::wrap_arrow_function_iife(expr, ctx)
324331
} else {
325332
// Unfortunately no way to get compiler to see that this branch is provably unreachable.
326333
// We don't want to inline this function, to keep `enter_expression` as small as possible.
@@ -659,7 +666,6 @@ impl<'a> OptionalChaining<'a, '_> {
659666
let assignment_expression =
660667
Self::create_assignment_expression(temp_binding.create_write_target(ctx), expr, ctx);
661668

662-
let reference = temp_binding.create_read_expression(ctx);
663669
// `left || (binding = expr) === null`
664670
let left = Self::create_logical_expression(
665671
left,
@@ -670,6 +676,7 @@ impl<'a> OptionalChaining<'a, '_> {
670676
if self.ctx.assumptions.no_document_all {
671677
left
672678
} else {
679+
let reference = temp_binding.create_read_expression(ctx);
673680
// `left || (binding = expr) === null || binding === void 0`
674681
Self::create_logical_expression(left, Self::wrap_void0_check(reference, ctx), ctx)
675682
}

tasks/coverage/snapshots/semantic_typescript.snap

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ commit: d85767ab
22

33
semantic_typescript Summary:
44
AST Parsed : 6503/6503 (100.00%)
5-
Positive Passed: 2923/6503 (44.95%)
5+
Positive Passed: 2925/6503 (44.98%)
66
tasks/coverage/typescript/tests/cases/compiler/2dArrays.ts
77
semantic error: Symbol reference IDs mismatch for "Cell":
88
after transform: SymbolId(0): [ReferenceId(1)]
@@ -36429,34 +36429,6 @@ Unresolved references mismatch:
3642936429
after transform: []
3643036430
rebuilt : ["o1", "o2", "o3", "o4", "o5", "o6"]
3643136431

36432-
tasks/coverage/typescript/tests/cases/conformance/expressions/optionalChaining/optionalChainingInParameterBindingPattern.ts
36433-
semantic error: Scope children mismatch:
36434-
after transform: ScopeId(0): [ScopeId(1), ScopeId(2)]
36435-
rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)]
36436-
Bindings mismatch:
36437-
after transform: ScopeId(2): ["_a", "c"]
36438-
rebuilt : ScopeId(3): ["_a"]
36439-
Scope parent mismatch:
36440-
after transform: ScopeId(2): Some(ScopeId(0))
36441-
rebuilt : ScopeId(3): Some(ScopeId(2))
36442-
Symbol scope ID mismatch for "c":
36443-
after transform: SymbolId(1): ScopeId(2)
36444-
rebuilt : SymbolId(1): ScopeId(2)
36445-
36446-
tasks/coverage/typescript/tests/cases/conformance/expressions/optionalChaining/optionalChainingInParameterInitializer.ts
36447-
semantic error: Scope children mismatch:
36448-
after transform: ScopeId(0): [ScopeId(1), ScopeId(2)]
36449-
rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)]
36450-
Bindings mismatch:
36451-
after transform: ScopeId(2): ["_a", "b"]
36452-
rebuilt : ScopeId(3): ["_a"]
36453-
Scope parent mismatch:
36454-
after transform: ScopeId(2): Some(ScopeId(0))
36455-
rebuilt : ScopeId(3): Some(ScopeId(2))
36456-
Symbol scope ID mismatch for "b":
36457-
after transform: SymbolId(1): ScopeId(2)
36458-
rebuilt : SymbolId(1): ScopeId(2)
36459-
3646036432
tasks/coverage/typescript/tests/cases/conformance/expressions/optionalChaining/optionalChainingInference.ts
3646136433
semantic error: Bindings mismatch:
3646236434
after transform: ScopeId(0): ["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "fnu", "ofnu", "osu", "su", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"]

0 commit comments

Comments
 (0)