From f413bb5c64827400da03246be168f15ac6bfaaf5 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Thu, 16 Jan 2025 12:21:44 +0000 Subject: [PATCH] feat(transformer/optional-chaining): change parent scope for expression when it wrapped with an arrow function (#8511) --- .../src/es2020/optional_chaining.rs | 18 +- .../snapshots/semantic_typescript.snap | 30 +- .../snapshots/babel.snap.md | 292 +----------------- 3 files changed, 15 insertions(+), 325 deletions(-) diff --git a/crates/oxc_transformer/src/es2020/optional_chaining.rs b/crates/oxc_transformer/src/es2020/optional_chaining.rs index 4da11a82d7600..8b44f45837c97 100644 --- a/crates/oxc_transformer/src/es2020/optional_chaining.rs +++ b/crates/oxc_transformer/src/es2020/optional_chaining.rs @@ -51,6 +51,7 @@ use std::mem; use oxc_allocator::CloneIn; use oxc_ast::{ast::*, NONE}; +use oxc_semantic::ScopeFlags; use oxc_span::SPAN; use oxc_traverse::{Ancestor, BoundIdentifier, MaybeBoundIdentifier, Traverse, TraverseCtx}; @@ -244,14 +245,19 @@ impl<'a> OptionalChaining<'a, '_> { /// Wrap the expression with an arrow function /// - /// `expr` -> `() => { return expr; }` - fn wrap_arrow_function(expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) -> Expression<'a> { + /// `expr` -> `(() => { return expr; })()` + fn wrap_arrow_function_iife( + expr: &mut Expression<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let scope_id = + ctx.insert_scope_below_expression(expr, ScopeFlags::Arrow | ScopeFlags::Function); + let kind = FormalParameterKind::ArrowFormalParameters; let params = ctx.ast.formal_parameters(SPAN, kind, ctx.ast.vec(), NONE); let statements = ctx.ast.vec1(ctx.ast.statement_return(SPAN, Some(ctx.ast.move_expression(expr)))); let body = ctx.ast.function_body(SPAN, ctx.ast.vec(), statements); - let scope_id = ctx.current_scope_id(); let arrow = ctx.ast.alloc_arrow_function_expression_with_scope_id( SPAN, false, false, NONE, params, NONE, body, scope_id, ); @@ -306,7 +312,7 @@ impl<'a> OptionalChaining<'a, '_> { // To insert the temp binding in the correct scope, we wrap the expression with // an arrow function. During the chain expression transformation, the temp binding // will be inserted into the arrow function's body. - Self::wrap_arrow_function(expr, ctx) + Self::wrap_arrow_function_iife(expr, ctx) } else { self.transform_chain_expression_impl(false, expr, ctx) } @@ -320,7 +326,7 @@ impl<'a> OptionalChaining<'a, '_> { ) { *expr = if self.is_inside_function_parameter { // Same as the above `transform_chain_expression` explanation - Self::wrap_arrow_function(expr, ctx) + Self::wrap_arrow_function_iife(expr, ctx) } else { // Unfortunately no way to get compiler to see that this branch is provably unreachable. // We don't want to inline this function, to keep `enter_expression` as small as possible. @@ -659,7 +665,6 @@ impl<'a> OptionalChaining<'a, '_> { let assignment_expression = Self::create_assignment_expression(temp_binding.create_write_target(ctx), expr, ctx); - let reference = temp_binding.create_read_expression(ctx); // `left || (binding = expr) === null` let left = Self::create_logical_expression( left, @@ -670,6 +675,7 @@ impl<'a> OptionalChaining<'a, '_> { if self.ctx.assumptions.no_document_all { left } else { + let reference = temp_binding.create_read_expression(ctx); // `left || (binding = expr) === null || binding === void 0` Self::create_logical_expression(left, Self::wrap_void0_check(reference, ctx), ctx) } diff --git a/tasks/coverage/snapshots/semantic_typescript.snap b/tasks/coverage/snapshots/semantic_typescript.snap index cc1e5d5f91b35..f0d5169f6a6ca 100644 --- a/tasks/coverage/snapshots/semantic_typescript.snap +++ b/tasks/coverage/snapshots/semantic_typescript.snap @@ -2,7 +2,7 @@ commit: d85767ab semantic_typescript Summary: AST Parsed : 6503/6503 (100.00%) -Positive Passed: 2923/6503 (44.95%) +Positive Passed: 2925/6503 (44.98%) tasks/coverage/typescript/tests/cases/compiler/2dArrays.ts semantic error: Symbol reference IDs mismatch for "Cell": after transform: SymbolId(0): [ReferenceId(1)] @@ -36429,34 +36429,6 @@ Unresolved references mismatch: after transform: [] rebuilt : ["o1", "o2", "o3", "o4", "o5", "o6"] -tasks/coverage/typescript/tests/cases/conformance/expressions/optionalChaining/optionalChainingInParameterBindingPattern.ts -semantic error: Scope children mismatch: -after transform: ScopeId(0): [ScopeId(1), ScopeId(2)] -rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)] -Bindings mismatch: -after transform: ScopeId(2): ["_a", "c"] -rebuilt : ScopeId(3): ["_a"] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(0)) -rebuilt : ScopeId(3): Some(ScopeId(2)) -Symbol scope ID mismatch for "c": -after transform: SymbolId(1): ScopeId(2) -rebuilt : SymbolId(1): ScopeId(2) - -tasks/coverage/typescript/tests/cases/conformance/expressions/optionalChaining/optionalChainingInParameterInitializer.ts -semantic error: Scope children mismatch: -after transform: ScopeId(0): [ScopeId(1), ScopeId(2)] -rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)] -Bindings mismatch: -after transform: ScopeId(2): ["_a", "b"] -rebuilt : ScopeId(3): ["_a"] -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(0)) -rebuilt : ScopeId(3): Some(ScopeId(2)) -Symbol scope ID mismatch for "b": -after transform: SymbolId(1): ScopeId(2) -rebuilt : SymbolId(1): ScopeId(2) - tasks/coverage/typescript/tests/cases/conformance/expressions/optionalChaining/optionalChainingInference.ts semantic error: Bindings mismatch: after transform: ScopeId(0): ["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "fnu", "ofnu", "osu", "su", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"] diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md index a666f7758fcf3..7c218b0c8881e 100644 --- a/tasks/transform_conformance/snapshots/babel.snap.md +++ b/tasks/transform_conformance/snapshots/babel.snap.md @@ -1,6 +1,6 @@ commit: acbc09a8 -Passed: 692/1168 +Passed: 698/1168 # All Passed: * babel-plugin-transform-logical-assignment-operators @@ -962,295 +962,7 @@ x Output mismatch x Output mismatch -# babel-plugin-transform-optional-chaining (36/45) -* assumption-noDocumentAll/assignment/input.js -Symbol reference IDs mismatch for "_obj$a": -after transform: SymbolId(5): [ReferenceId(7), ReferenceId(8), ReferenceId(9)] -rebuilt : SymbolId(0): [ReferenceId(3), ReferenceId(5)] -Symbol reference IDs mismatch for "_obj$b": -after transform: SymbolId(6): [ReferenceId(11), ReferenceId(12), ReferenceId(13)] -rebuilt : SymbolId(1): [ReferenceId(7), ReferenceId(9)] -Symbol reference IDs mismatch for "_obj$a2": -after transform: SymbolId(7): [ReferenceId(15), ReferenceId(16), ReferenceId(17)] -rebuilt : SymbolId(2): [ReferenceId(12), ReferenceId(14)] - -* assumption-noDocumentAll/in-function-params/input.js -Scope children mismatch: -after transform: ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(3), ScopeId(4), ScopeId(5)] -rebuilt : ScopeId(0): [ScopeId(1), ScopeId(3), ScopeId(5), ScopeId(7), ScopeId(9)] -Bindings mismatch: -after transform: ScopeId(1): ["_x", "a"] -rebuilt : ScopeId(2): ["_x"] -Scope flags mismatch: -after transform: ScopeId(1): ScopeFlags(Function) -rebuilt : ScopeId(2): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(1): Some(ScopeId(0)) -rebuilt : ScopeId(2): Some(ScopeId(1)) -Bindings mismatch: -after transform: ScopeId(2): ["a", "b"] -rebuilt : ScopeId(4): [] -Scope flags mismatch: -after transform: ScopeId(2): ScopeFlags(Function) -rebuilt : ScopeId(4): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(0)) -rebuilt : ScopeId(4): Some(ScopeId(3)) -Bindings mismatch: -after transform: ScopeId(3): ["_a$b", "a", "b"] -rebuilt : ScopeId(6): ["_a$b"] -Scope flags mismatch: -after transform: ScopeId(3): ScopeFlags(Function) -rebuilt : ScopeId(6): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(3): Some(ScopeId(0)) -rebuilt : ScopeId(6): Some(ScopeId(5)) -Bindings mismatch: -after transform: ScopeId(4): ["_a$b2", "a", "b"] -rebuilt : ScopeId(8): ["_a$b2"] -Scope flags mismatch: -after transform: ScopeId(4): ScopeFlags(Function) -rebuilt : ScopeId(8): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(0)) -rebuilt : ScopeId(8): Some(ScopeId(7)) -Bindings mismatch: -after transform: ScopeId(5): ["_a$b3", "a", "b"] -rebuilt : ScopeId(10): ["_a$b3"] -Scope flags mismatch: -after transform: ScopeId(5): ScopeFlags(Function) -rebuilt : ScopeId(10): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(5): Some(ScopeId(0)) -rebuilt : ScopeId(10): Some(ScopeId(9)) -Symbol scope ID mismatch for "a": -after transform: SymbolId(1): ScopeId(1) -rebuilt : SymbolId(1): ScopeId(1) -Symbol scope ID mismatch for "a": -after transform: SymbolId(3): ScopeId(2) -rebuilt : SymbolId(4): ScopeId(3) -Symbol scope ID mismatch for "b": -after transform: SymbolId(4): ScopeId(2) -rebuilt : SymbolId(5): ScopeId(3) -Symbol scope ID mismatch for "a": -after transform: SymbolId(6): ScopeId(3) -rebuilt : SymbolId(7): ScopeId(5) -Symbol scope ID mismatch for "b": -after transform: SymbolId(7): ScopeId(3) -rebuilt : SymbolId(8): ScopeId(5) -Symbol reference IDs mismatch for "_a$b": -after transform: SymbolId(15): [ReferenceId(8), ReferenceId(9), ReferenceId(10), ReferenceId(11), ReferenceId(12)] -rebuilt : SymbolId(9): [ReferenceId(5), ReferenceId(7), ReferenceId(8), ReferenceId(9)] -Symbol scope ID mismatch for "a": -after transform: SymbolId(9): ScopeId(4) -rebuilt : SymbolId(11): ScopeId(7) -Symbol scope ID mismatch for "b": -after transform: SymbolId(10): ScopeId(4) -rebuilt : SymbolId(12): ScopeId(7) -Symbol reference IDs mismatch for "_a$b2": -after transform: SymbolId(16): [ReferenceId(13), ReferenceId(14), ReferenceId(15), ReferenceId(16), ReferenceId(17)] -rebuilt : SymbolId(13): [ReferenceId(10), ReferenceId(12), ReferenceId(13), ReferenceId(14)] -Symbol scope ID mismatch for "a": -after transform: SymbolId(12): ScopeId(5) -rebuilt : SymbolId(15): ScopeId(9) -Symbol scope ID mismatch for "b": -after transform: SymbolId(13): ScopeId(5) -rebuilt : SymbolId(16): ScopeId(9) -Symbol reference IDs mismatch for "_a$b3": -after transform: SymbolId(17): [ReferenceId(19), ReferenceId(20), ReferenceId(21)] -rebuilt : SymbolId(17): [ReferenceId(16), ReferenceId(18)] - -* assumption-noDocumentAll/memoize/input.js -Symbol reference IDs mismatch for "_foo$bar": -after transform: SymbolId(2): [ReferenceId(27), ReferenceId(28), ReferenceId(29)] -rebuilt : SymbolId(2): [ReferenceId(3), ReferenceId(5)] -Symbol reference IDs mismatch for "_foo$bar5": -after transform: SymbolId(9): [ReferenceId(46), ReferenceId(47), ReferenceId(48)] -rebuilt : SymbolId(9): [ReferenceId(35), ReferenceId(37)] -Symbol reference IDs mismatch for "_foo$bar7": -after transform: SymbolId(11): [ReferenceId(53), ReferenceId(54), ReferenceId(55)] -rebuilt : SymbolId(11): [ReferenceId(45), ReferenceId(47)] -Symbol reference IDs mismatch for "_foo$bar8$baz": -after transform: SymbolId(13): [ReferenceId(58), ReferenceId(59), ReferenceId(60)] -rebuilt : SymbolId(13): [ReferenceId(51), ReferenceId(53)] -Symbol reference IDs mismatch for "_foo$bar9": -after transform: SymbolId(14): [ReferenceId(63), ReferenceId(64), ReferenceId(65), ReferenceId(69)] -rebuilt : SymbolId(14): [ReferenceId(57), ReferenceId(60), ReferenceId(62)] -Symbol reference IDs mismatch for "_foo$bar9$baz": -after transform: SymbolId(15): [ReferenceId(66), ReferenceId(67), ReferenceId(68)] -rebuilt : SymbolId(15): [ReferenceId(59), ReferenceId(61)] - -* general/delete-in-function-params/input.js -Scope children mismatch: -after transform: ScopeId(0): [ScopeId(1)] -rebuilt : ScopeId(0): [ScopeId(1)] -Bindings mismatch: -after transform: ScopeId(1): ["_a", "x"] -rebuilt : ScopeId(2): ["_a"] -Scope flags mismatch: -after transform: ScopeId(1): ScopeFlags(Function) -rebuilt : ScopeId(2): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(1): Some(ScopeId(0)) -rebuilt : ScopeId(2): Some(ScopeId(1)) -Symbol scope ID mismatch for "x": -after transform: SymbolId(1): ScopeId(1) -rebuilt : SymbolId(1): ScopeId(1) - -* general/in-function-params/input.js -Scope children mismatch: -after transform: ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(3), ScopeId(4), ScopeId(5)] -rebuilt : ScopeId(0): [ScopeId(1), ScopeId(3), ScopeId(5), ScopeId(7), ScopeId(9)] -Bindings mismatch: -after transform: ScopeId(1): ["_x", "a"] -rebuilt : ScopeId(2): ["_x"] -Scope flags mismatch: -after transform: ScopeId(1): ScopeFlags(Function) -rebuilt : ScopeId(2): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(1): Some(ScopeId(0)) -rebuilt : ScopeId(2): Some(ScopeId(1)) -Bindings mismatch: -after transform: ScopeId(2): ["a", "b"] -rebuilt : ScopeId(4): [] -Scope flags mismatch: -after transform: ScopeId(2): ScopeFlags(Function) -rebuilt : ScopeId(4): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(0)) -rebuilt : ScopeId(4): Some(ScopeId(3)) -Bindings mismatch: -after transform: ScopeId(3): ["_a$b", "a", "b"] -rebuilt : ScopeId(6): ["_a$b"] -Scope flags mismatch: -after transform: ScopeId(3): ScopeFlags(Function) -rebuilt : ScopeId(6): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(3): Some(ScopeId(0)) -rebuilt : ScopeId(6): Some(ScopeId(5)) -Bindings mismatch: -after transform: ScopeId(4): ["_a$b2", "a", "b"] -rebuilt : ScopeId(8): ["_a$b2"] -Scope flags mismatch: -after transform: ScopeId(4): ScopeFlags(Function) -rebuilt : ScopeId(8): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(0)) -rebuilt : ScopeId(8): Some(ScopeId(7)) -Bindings mismatch: -after transform: ScopeId(5): ["_a$b3", "a", "b"] -rebuilt : ScopeId(10): ["_a$b3"] -Scope flags mismatch: -after transform: ScopeId(5): ScopeFlags(Function) -rebuilt : ScopeId(10): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(5): Some(ScopeId(0)) -rebuilt : ScopeId(10): Some(ScopeId(9)) -Symbol scope ID mismatch for "a": -after transform: SymbolId(1): ScopeId(1) -rebuilt : SymbolId(1): ScopeId(1) -Symbol scope ID mismatch for "a": -after transform: SymbolId(3): ScopeId(2) -rebuilt : SymbolId(4): ScopeId(3) -Symbol scope ID mismatch for "b": -after transform: SymbolId(4): ScopeId(2) -rebuilt : SymbolId(5): ScopeId(3) -Symbol scope ID mismatch for "a": -after transform: SymbolId(6): ScopeId(3) -rebuilt : SymbolId(7): ScopeId(5) -Symbol scope ID mismatch for "b": -after transform: SymbolId(7): ScopeId(3) -rebuilt : SymbolId(8): ScopeId(5) -Symbol scope ID mismatch for "a": -after transform: SymbolId(9): ScopeId(4) -rebuilt : SymbolId(11): ScopeId(7) -Symbol scope ID mismatch for "b": -after transform: SymbolId(10): ScopeId(4) -rebuilt : SymbolId(12): ScopeId(7) -Symbol scope ID mismatch for "a": -after transform: SymbolId(12): ScopeId(5) -rebuilt : SymbolId(15): ScopeId(9) -Symbol scope ID mismatch for "b": -after transform: SymbolId(13): ScopeId(5) -rebuilt : SymbolId(16): ScopeId(9) - -* general/in-function-params-loose/input.js -Scope children mismatch: -after transform: ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(3), ScopeId(4), ScopeId(5)] -rebuilt : ScopeId(0): [ScopeId(1), ScopeId(3), ScopeId(5), ScopeId(7), ScopeId(9)] -Bindings mismatch: -after transform: ScopeId(1): ["_x", "a"] -rebuilt : ScopeId(2): ["_x"] -Scope flags mismatch: -after transform: ScopeId(1): ScopeFlags(Function) -rebuilt : ScopeId(2): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(1): Some(ScopeId(0)) -rebuilt : ScopeId(2): Some(ScopeId(1)) -Bindings mismatch: -after transform: ScopeId(2): ["a", "b"] -rebuilt : ScopeId(4): [] -Scope flags mismatch: -after transform: ScopeId(2): ScopeFlags(Function) -rebuilt : ScopeId(4): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(2): Some(ScopeId(0)) -rebuilt : ScopeId(4): Some(ScopeId(3)) -Bindings mismatch: -after transform: ScopeId(3): ["_a$b", "a", "b"] -rebuilt : ScopeId(6): ["_a$b"] -Scope flags mismatch: -after transform: ScopeId(3): ScopeFlags(Function) -rebuilt : ScopeId(6): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(3): Some(ScopeId(0)) -rebuilt : ScopeId(6): Some(ScopeId(5)) -Bindings mismatch: -after transform: ScopeId(4): ["_a$b2", "a", "b"] -rebuilt : ScopeId(8): ["_a$b2"] -Scope flags mismatch: -after transform: ScopeId(4): ScopeFlags(Function) -rebuilt : ScopeId(8): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(4): Some(ScopeId(0)) -rebuilt : ScopeId(8): Some(ScopeId(7)) -Bindings mismatch: -after transform: ScopeId(5): ["_a$b3", "a", "b"] -rebuilt : ScopeId(10): ["_a$b3"] -Scope flags mismatch: -after transform: ScopeId(5): ScopeFlags(Function) -rebuilt : ScopeId(10): ScopeFlags(Function | Arrow) -Scope parent mismatch: -after transform: ScopeId(5): Some(ScopeId(0)) -rebuilt : ScopeId(10): Some(ScopeId(9)) -Symbol scope ID mismatch for "a": -after transform: SymbolId(1): ScopeId(1) -rebuilt : SymbolId(1): ScopeId(1) -Symbol scope ID mismatch for "a": -after transform: SymbolId(3): ScopeId(2) -rebuilt : SymbolId(4): ScopeId(3) -Symbol scope ID mismatch for "b": -after transform: SymbolId(4): ScopeId(2) -rebuilt : SymbolId(5): ScopeId(3) -Symbol scope ID mismatch for "a": -after transform: SymbolId(6): ScopeId(3) -rebuilt : SymbolId(7): ScopeId(5) -Symbol scope ID mismatch for "b": -after transform: SymbolId(7): ScopeId(3) -rebuilt : SymbolId(8): ScopeId(5) -Symbol scope ID mismatch for "a": -after transform: SymbolId(9): ScopeId(4) -rebuilt : SymbolId(11): ScopeId(7) -Symbol scope ID mismatch for "b": -after transform: SymbolId(10): ScopeId(4) -rebuilt : SymbolId(12): ScopeId(7) -Symbol scope ID mismatch for "a": -after transform: SymbolId(12): ScopeId(5) -rebuilt : SymbolId(15): ScopeId(9) -Symbol scope ID mismatch for "b": -after transform: SymbolId(13): ScopeId(5) -rebuilt : SymbolId(16): ScopeId(9) - +# babel-plugin-transform-optional-chaining (42/45) * transparent-expr-wrappers/ts-as-function-call-loose/input.ts Unresolved references mismatch: after transform: ["A", "B", "foo"]