diff --git a/crates/oxc_transformer/src/common/arrow_function_converter.rs b/crates/oxc_transformer/src/common/arrow_function_converter.rs index 2a65839ef3490..3228f8095e23b 100644 --- a/crates/oxc_transformer/src/common/arrow_function_converter.rs +++ b/crates/oxc_transformer/src/common/arrow_function_converter.rs @@ -87,8 +87,8 @@ //! The Implementation based on //! -use oxc_allocator::{Box as ArenaBox, Vec as ArenaVec}; -use oxc_ast::ast::*; +use oxc_allocator::{Box as ArenaBox, String as ArenaString, Vec as ArenaVec}; +use oxc_ast::{ast::*, AstBuilder, NONE}; use oxc_data_structures::stack::SparseStack; use oxc_span::SPAN; use oxc_syntax::{ @@ -96,6 +96,7 @@ use oxc_syntax::{ symbol::SymbolFlags, }; use oxc_traverse::{Ancestor, BoundIdentifier, Traverse, TraverseCtx}; +use rustc_hash::FxHashMap; use crate::TransformOptions; @@ -112,9 +113,19 @@ pub enum ArrowFunctionConverterMode { AsyncOnly, } +struct SuperMethodInfo<'a> { + binding: BoundIdentifier<'a>, + super_expr: Expression<'a>, + /// If it is true, the method should accept a prop parameter. + is_computed: bool, + /// If it is true, the method should accept a value parameter. + is_assignment: bool, +} + pub struct ArrowFunctionConverter<'a> { mode: ArrowFunctionConverterMode, this_var_stack: SparseStack>, + super_methods: Option, SuperMethodInfo<'a>>>, } impl<'a> ArrowFunctionConverter<'a> { @@ -129,7 +140,7 @@ impl<'a> ArrowFunctionConverter<'a> { ArrowFunctionConverterMode::Disabled }; // `SparseStack` is created with 1 empty entry, for `Program` - Self { mode, this_var_stack: SparseStack::new() } + Self { mode, this_var_stack: SparseStack::new(), super_methods: None } } } @@ -143,25 +154,27 @@ impl<'a> Traverse<'a> for ArrowFunctionConverter<'a> { return; } - if let Some(this_var) = self.this_var_stack.take_last() { - let target_scope_id = program.scope_id(); - Self::insert_this_var_statement_at_the_top_of_statements( - &mut program.body, - target_scope_id, - &this_var, - ctx, - ); - } + let this_var = self.this_var_stack.take_last(); + self.insert_variable_statement_at_the_top_of_statements( + program.scope_id(), + &mut program.body, + this_var, + ctx, + ); debug_assert!(self.this_var_stack.len() == 1); debug_assert!(self.this_var_stack.last().is_none()); } - fn enter_function(&mut self, _func: &mut Function<'a>, _ctx: &mut TraverseCtx<'a>) { - if self.is_disabled() { + fn enter_function(&mut self, func: &mut Function<'a>, ctx: &mut TraverseCtx<'a>) { + if self.is_disabled() || func.body.is_none() { return; } self.this_var_stack.push(None); + if self.is_async_only() && func.r#async && Self::is_class_method_like_ancestor(ctx.parent()) + { + self.super_methods = Some(FxHashMap::default()); + } } /// ```ts @@ -180,17 +193,17 @@ impl<'a> Traverse<'a> for ArrowFunctionConverter<'a> { return; } - if let Some(this_var) = self.this_var_stack.pop() { - let target_scope_id = func.scope_id(); - let Some(body) = &mut func.body else { unreachable!() }; - - Self::insert_this_var_statement_at_the_top_of_statements( - &mut body.statements, - target_scope_id, - &this_var, - ctx, - ); - } + let scope_id = func.scope_id(); + let Some(body) = &mut func.body else { + return; + }; + let this_var = self.this_var_stack.pop(); + self.insert_variable_statement_at_the_top_of_statements( + scope_id, + &mut body.statements, + this_var, + ctx, + ); } fn enter_static_block(&mut self, _block: &mut StaticBlock<'a>, _ctx: &mut TraverseCtx<'a>) { @@ -206,15 +219,13 @@ impl<'a> Traverse<'a> for ArrowFunctionConverter<'a> { return; } - if let Some(this_var) = self.this_var_stack.pop() { - let target_scope_id = block.scope_id(); - Self::insert_this_var_statement_at_the_top_of_statements( - &mut block.body, - target_scope_id, - &this_var, - ctx, - ); - } + let this_var = self.this_var_stack.pop(); + self.insert_variable_statement_at_the_top_of_statements( + block.scope_id(), + &mut block.body, + this_var, + ctx, + ); } fn enter_jsx_element_name( @@ -254,10 +265,22 @@ impl<'a> Traverse<'a> for ArrowFunctionConverter<'a> { return; } - if let Expression::ThisExpression(this) = expr { - if let Some(ident) = self.get_this_identifier(this.span, ctx) { - *expr = Expression::Identifier(ident); + let new_expr = match expr { + Expression::ThisExpression(this) => { + self.get_this_identifier(this.span, ctx).map(Expression::Identifier) + } + Expression::CallExpression(call) => self.transform_call_expression_for_super(call, ctx), + Expression::AssignmentExpression(assignment) => { + self.transform_assignment_expression_for_super(assignment, ctx) } + match_member_expression!(Expression) => { + self.transform_member_expression_for_super(expr, None, ctx) + } + _ => return, + }; + + if let Some(new_expr) = new_expr { + *expr = new_expr; } } @@ -383,14 +406,16 @@ impl<'a> ArrowFunctionConverter<'a> { // Arrow function Ancestor::ArrowFunctionExpressionParams(func) => { return if self.is_async_only() && !*func.r#async() { - None + // Continue checking the parent to see if it's inside an async function. + continue; } else { Some(func.scope_id().get().unwrap()) }; } Ancestor::ArrowFunctionExpressionBody(func) => { return if self.is_async_only() && !*func.r#async() { - None + // Continue checking the parent to see if it's inside an async function. + continue; } else { Some(func.scope_id().get().unwrap()) }; @@ -461,34 +486,348 @@ impl<'a> ArrowFunctionConverter<'a> { } } - /// Insert `var _this = this;` at the top of the statements. - fn insert_this_var_statement_at_the_top_of_statements( - statements: &mut ArenaVec<'a, Statement<'a>>, + /// Transforms a `MemberExpression` whose object is a `super` expression. + /// + /// In the [`AsyncToGenerator`](crate::es2017::async_to_generator::AsyncToGenerator) and + /// [`AsyncGeneratorFunctions`](crate::es2018::async_generator_functions::AsyncGeneratorFunctions) plugins, + /// we move the body of an async method to a new generator function. This can cause + /// `super` expressions to appear in unexpected places, leading to syntax errors. + /// + /// ## How it works + /// + /// To correctly handle `super` expressions, we need to ensure that they remain + /// within the async method's body. + /// + /// This function modifies the `super` expression to call a new arrow function + /// whose body includes the original `super` expression. The arrow function's name + /// is generated based on the property name, such as `_superprop_getProperty`. + /// + /// The `super` expressions are temporarily stored in [`Self::super_methods`] + /// and eventually inserted by [`Self::insert_variable_statement_at_the_top_of_statements`].` + /// + /// ## Example + /// + /// Before: + /// ```js + /// super.property; + /// super['property'] + /// ``` + /// + /// After: + /// ```js + /// var _superprop_getProperty = () => super.property, _superprop_get = (_prop) => super[_prop]; + /// _superprop_getProperty(); + /// _superprop_get('property') + /// ``` + fn transform_member_expression_for_super( + &mut self, + expr: &mut Expression<'a>, + assign_value: Option<&mut Expression<'a>>, + ctx: &mut TraverseCtx<'a>, + ) -> Option> { + let super_methods = self.super_methods.as_mut()?; + + let mut argument = None; + let mut property = Atom::empty(); + let init = match expr.to_member_expression_mut() { + MemberExpression::ComputedMemberExpression(computed_member) => { + if !matches!(computed_member.object, Expression::Super(_)) { + return None; + } + // The property will as a parameter to pass to the new arrow function. + // `super[property]` to `_superprop_get(property)` + argument = Some(ctx.ast.move_expression(&mut computed_member.expression)); + ctx.ast.move_expression(&mut computed_member.object) + } + MemberExpression::StaticMemberExpression(static_member) => { + if !matches!(static_member.object, Expression::Super(_)) { + return None; + } + + // Used to generate the name of the arrow function. + property = static_member.property.name.clone(); + ctx.ast.move_expression(expr) + } + MemberExpression::PrivateFieldExpression(_) => { + // Private fields can't be accessed by `super`. + return None; + } + }; + + let binding_name = + Self::generate_super_binding_name(assign_value.is_some(), &property, ctx.ast); + let super_info = super_methods.entry(binding_name.clone()).or_insert_with(|| { + let binding = ctx + .generate_uid_in_current_scope(&binding_name, SymbolFlags::FunctionScopedVariable); + SuperMethodInfo { + binding, + super_expr: init, + is_computed: argument.is_some(), + is_assignment: assign_value.is_some(), + } + }); + + let callee = super_info.binding.create_read_expression(ctx); + let mut arguments = ctx.ast.vec_with_capacity( + usize::from(assign_value.is_some()) + usize::from(argument.is_some()), + ); + // _prop + if let Some(argument) = argument { + arguments.push(Argument::from(argument)); + } + // _value + if let Some(assign_value) = assign_value { + arguments.push(Argument::from(ctx.ast.move_expression(assign_value))); + } + let call = ctx.ast.expression_call(SPAN, callee, NONE, arguments, false); + Some(call) + } + + /// Transform a `CallExpression` whose callee is a `super` member expression. + /// + /// This function modifies calls to `super` methods within arrow functions + /// to ensure the correct `this` context is maintained after transformation. + /// + /// ## Example + /// + /// Before: + /// ```js + /// super.method(a, b); + /// ``` + /// + /// After: + /// ```js + /// var _superprop_getMethod = () => super.method; + /// _superprop_getMethod.call(this, a, b); + /// ``` + #[inline] + fn transform_call_expression_for_super( + &mut self, + call: &mut CallExpression<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Option> { + if self.super_methods.is_none() || !call.callee.is_member_expression() { + return None; + } + + let object = self.transform_member_expression_for_super(&mut call.callee, None, ctx)?; + // Add `this` as the first argument and original arguments as the rest. + let mut arguments = ctx.ast.vec_with_capacity(call.arguments.len() + 1); + arguments.push(Argument::from(ctx.ast.expression_this(SPAN))); + arguments.extend(ctx.ast.move_vec(&mut call.arguments)); + + let property = ctx.ast.identifier_name(SPAN, "call"); + let callee = ctx.ast.member_expression_static(SPAN, object, property, false); + let callee = Expression::from(callee); + Some(ctx.ast.expression_call(SPAN, callee, NONE, arguments, false)) + } + + /// Transform an `AssignmentExpression` whose assignment target is a `super` member expression. + /// + /// In this function, we replace assignments to call a new arrow function whose body includes + /// [AssignmentExpression::left], and use [AssignmentExpression::right] as arguments for the call expression. + /// + /// ## Example + /// + /// Before: + /// ```js + /// super.value = true; + /// ``` + /// + /// After: + /// ```js + /// var _superprop_setValue = (_value) => super.value = _value; + /// _superprop_setValue(true); + /// ``` + fn transform_assignment_expression_for_super( + &mut self, + assignment: &mut AssignmentExpression<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Option> { + // Check if the left of the assignment is a `super` member expression. + if self.super_methods.is_none() + || !assignment + .left + .as_member_expression() + .is_some_and(|m| matches!(m.object(), Expression::Super(_))) + { + return None; + } + + let assignment_target = ctx.ast.move_assignment_target(&mut assignment.left); + let mut assignment_expr = Expression::from(assignment_target.into_member_expression()); + self.transform_member_expression_for_super( + &mut assignment_expr, + Some(&mut assignment.right), + ctx, + ) + } + + /// Adjust the scope of the binding. + /// + /// Since scope can be moved or deleted, we need to ensure the scope of the binding + /// same as the target scope, if it's mismatch, we need to move the binding to the target scope. + fn adjust_binding_scope( target_scope_id: ScopeId, - this_var: &BoundIdentifier<'a>, + binding: &BoundIdentifier<'a>, ctx: &mut TraverseCtx<'a>, ) { - let symbol_id = this_var.symbol_id; - let scope_id = ctx.symbols().get_scope_id(symbol_id); - // Because scope can be moved or deleted, we need to check the scope id again, - // if it's different, we need to move the binding to the target scope. - if target_scope_id != scope_id { - ctx.scopes_mut().move_binding(scope_id, target_scope_id, &this_var.name); - ctx.symbols_mut().set_scope_id(symbol_id, target_scope_id); + let original_scope_id = ctx.symbols().get_scope_id(binding.symbol_id); + if target_scope_id != original_scope_id { + ctx.symbols_mut().set_scope_id(binding.symbol_id, target_scope_id); + ctx.scopes_mut().move_binding(original_scope_id, target_scope_id, &binding.name); } + } + + /// Generate a variable declarator for the super method by the given [`SuperMethodInfo`]. + fn generate_super_method( + target_scope_id: ScopeId, + super_method: SuperMethodInfo<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> VariableDeclarator<'a> { + let SuperMethodInfo { binding, super_expr: mut init, is_computed, is_assignment } = + super_method; + + Self::adjust_binding_scope(target_scope_id, &binding, ctx); + let scope_id = + ctx.create_child_scope(target_scope_id, ScopeFlags::Arrow | ScopeFlags::Function); + + let mut items = ctx.ast.vec_with_capacity(2); + + // Create a parameter for the prop if it's a computed member expression. + if is_computed { + let param_binding = + ctx.generate_uid("prop", scope_id, SymbolFlags::FunctionScopedVariable); + let param = ctx.ast.formal_parameter( + SPAN, + ctx.ast.vec(), + param_binding.create_binding_pattern(ctx), + None, + false, + false, + ); + items.push(param); + + // `super` -> `super[prop]` + init = Expression::from(ctx.ast.member_expression_computed( + SPAN, + init, + param_binding.create_read_expression(ctx), + false, + )); + }; - let variable_declarator = ctx.ast.variable_declarator( + // Create a parameter for the value if it's an assignment. + if is_assignment { + let param_binding = + ctx.generate_uid("value", scope_id, SymbolFlags::FunctionScopedVariable); + let param = ctx.ast.formal_parameter( + SPAN, + ctx.ast.vec(), + param_binding.create_binding_pattern(ctx), + None, + false, + false, + ); + items.push(param); + + // `super[prop]` -> `super[prop] = value` + let left = SimpleAssignmentTarget::from(init.into_member_expression()); + let left = AssignmentTarget::from(left); + let right = param_binding.create_read_expression(ctx); + init = ctx.ast.expression_assignment(SPAN, AssignmentOperator::Assign, left, right); + } + + let params = ctx.ast.formal_parameters( + SPAN, + FormalParameterKind::ArrowFormalParameters, + items, + NONE, + ); + let statements = ctx.ast.vec1(ctx.ast.statement_expression(SPAN, init)); + let body = ctx.ast.function_body(SPAN, ctx.ast.vec(), statements); + let init = ctx.ast.alloc_arrow_function_expression_with_scope_id( + SPAN, true, false, NONE, params, NONE, body, scope_id, + ); + ctx.ast.variable_declarator( SPAN, VariableDeclarationKind::Var, - this_var.create_binding_pattern(ctx), - Some(ctx.ast.expression_this(SPAN)), + binding.create_binding_pattern(ctx), + Some(Expression::ArrowFunctionExpression(init)), false, - ); + ) + } + + /// Generate a binding name for the super method, like `_superprop_getXXX`. + fn generate_super_binding_name( + is_assignment: bool, + property: &Atom<'a>, + ast: AstBuilder<'a>, + ) -> Atom<'a> { + let mut name = ArenaString::new_in(ast.allocator); + + name.push_str("superprop_"); + if is_assignment { + name.push_str("set"); + } else { + name.push_str("get"); + } + + // Capitalize the first letter of the property name. + if let Some(first_byte) = property.as_bytes().first() { + name.push(first_byte.to_ascii_uppercase() as char); + } + if property.len() > 1 { + name.push_str(&property[1..]); + } + ast.atom(name.into_bump_str()) + } + + /// Insert variable statement at the top of the statements. + fn insert_variable_statement_at_the_top_of_statements( + &mut self, + target_scope_id: ScopeId, + statements: &mut ArenaVec<'a, Statement<'a>>, + this_var: Option>, + ctx: &mut TraverseCtx<'a>, + ) { + // `_superprop_getSomething = () => super.getSomething;` + let mut declarations = if Self::is_class_method_like_ancestor(ctx.parent()) { + if let Some(super_methods) = self.super_methods.as_mut() { + let mut declarations = ctx.ast.vec_with_capacity(super_methods.len() + 1); + declarations.extend(super_methods.drain().map(|(_, super_method)| { + Self::generate_super_method(target_scope_id, super_method, ctx) + })); + declarations + } else { + ctx.ast.vec_with_capacity(1) + } + } else { + ctx.ast.vec_with_capacity(1) + }; + + // `_this = this;` + if let Some(this_var) = this_var { + Self::adjust_binding_scope(target_scope_id, &this_var, ctx); + let variable_declarator = ctx.ast.variable_declarator( + SPAN, + VariableDeclarationKind::Var, + this_var.create_binding_pattern(ctx), + Some(ctx.ast.expression_this(SPAN)), + false, + ); + declarations.push(variable_declarator); + } + + // If there are no declarations, we don't need to insert a variable declaration. + if declarations.is_empty() { + return; + } let stmt = ctx.ast.alloc_variable_declaration( SPAN, VariableDeclarationKind::Var, - ctx.ast.vec1(variable_declarator), + declarations, false, ); diff --git a/crates/oxc_transformer/src/es2017/mod.rs b/crates/oxc_transformer/src/es2017/mod.rs index 562969ecea26d..105b6c325f6fd 100644 --- a/crates/oxc_transformer/src/es2017/mod.rs +++ b/crates/oxc_transformer/src/es2017/mod.rs @@ -1,4 +1,4 @@ -mod async_to_generator; +pub(crate) mod async_to_generator; mod options; use oxc_ast::ast::{Expression, Function, Statement}; diff --git a/crates/oxc_transformer/src/es2018/mod.rs b/crates/oxc_transformer/src/es2018/mod.rs index 9915639b6d3e5..caeaf33a29e20 100644 --- a/crates/oxc_transformer/src/es2018/mod.rs +++ b/crates/oxc_transformer/src/es2018/mod.rs @@ -1,4 +1,4 @@ -mod async_generator_functions; +pub(crate) mod async_generator_functions; mod object_rest_spread; mod options; diff --git a/tasks/coverage/snapshots/semantic_misc.snap b/tasks/coverage/snapshots/semantic_misc.snap index 06901e562c3dd..7bf0e30195567 100644 --- a/tasks/coverage/snapshots/semantic_misc.snap +++ b/tasks/coverage/snapshots/semantic_misc.snap @@ -57,19 +57,19 @@ after transform: ScopeId(0): ["BrowserWorkingCopyBackupTracker", "CancellationTo rebuilt : ScopeId(0): ["BrowserWorkingCopyBackupTracker", "DisposableStore", "EditorService", "IEditorGroupsService", "IEditorService", "IFilesConfigurationService", "ILifecycleService", "ILogService", "IWorkingCopyBackupService", "IWorkingCopyEditorService", "IWorkingCopyService", "InMemoryTestWorkingCopyBackupService", "LifecyclePhase", "Schemas", "TestServiceAccessor", "TestWorkingCopy", "URI", "UntitledTextEditorInput", "VSBuffer", "_asyncToGenerator", "assert", "bufferToReadable", "createEditorPart", "ensureNoDisposablesAreLeakedInTestSuite", "isWindows", "registerTestResourceEditor", "timeout", "toResource", "toTypedWorkingCopyId", "toUntypedWorkingCopyId", "workbenchInstantiationService", "workbenchTeardown"] Symbol reference IDs mismatch for "URI": after transform: SymbolId(1): [ReferenceId(109), ReferenceId(117), ReferenceId(156), ReferenceId(158), ReferenceId(160), ReferenceId(162)] -rebuilt : SymbolId(1): [ReferenceId(147), ReferenceId(149), ReferenceId(151), ReferenceId(153)] +rebuilt : SymbolId(1): [ReferenceId(150), ReferenceId(152), ReferenceId(154), ReferenceId(156)] Symbol reference IDs mismatch for "IEditorService": after transform: SymbolId(2): [ReferenceId(23), ReferenceId(24), ReferenceId(67), ReferenceId(184)] -rebuilt : SymbolId(2): [ReferenceId(17), ReferenceId(55), ReferenceId(174)] +rebuilt : SymbolId(2): [ReferenceId(17), ReferenceId(58), ReferenceId(177)] Symbol reference IDs mismatch for "IEditorGroupsService": after transform: SymbolId(4): [ReferenceId(25), ReferenceId(26), ReferenceId(57), ReferenceId(176)] -rebuilt : SymbolId(3): [ReferenceId(18), ReferenceId(46), ReferenceId(167)] +rebuilt : SymbolId(3): [ReferenceId(18), ReferenceId(49), ReferenceId(170)] Symbol reference IDs mismatch for "EditorService": after transform: SymbolId(5): [ReferenceId(61), ReferenceId(64), ReferenceId(178), ReferenceId(181)] -rebuilt : SymbolId(4): [ReferenceId(52), ReferenceId(171)] +rebuilt : SymbolId(4): [ReferenceId(55), ReferenceId(174)] Symbol reference IDs mismatch for "IWorkingCopyBackupService": after transform: SymbolId(7): [ReferenceId(11), ReferenceId(12), ReferenceId(51), ReferenceId(170)] -rebuilt : SymbolId(5): [ReferenceId(11), ReferenceId(40), ReferenceId(161)] +rebuilt : SymbolId(5): [ReferenceId(11), ReferenceId(43), ReferenceId(164)] Symbol reference IDs mismatch for "IFilesConfigurationService": after transform: SymbolId(10): [ReferenceId(13), ReferenceId(14)] rebuilt : SymbolId(8): [ReferenceId(12)] @@ -84,22 +84,22 @@ after transform: SymbolId(14): [ReferenceId(17), ReferenceId(18)] rebuilt : SymbolId(11): [ReferenceId(14)] Symbol reference IDs mismatch for "UntitledTextEditorInput": after transform: SymbolId(17): [ReferenceId(38), ReferenceId(87)] -rebuilt : SymbolId(13): [ReferenceId(29)] +rebuilt : SymbolId(13): [ReferenceId(31)] Symbol reference IDs mismatch for "InMemoryTestWorkingCopyBackupService": after transform: SymbolId(19): [ReferenceId(43), ReferenceId(46), ReferenceId(165)] -rebuilt : SymbolId(15): [ReferenceId(35), ReferenceId(156)] +rebuilt : SymbolId(15): [ReferenceId(38), ReferenceId(159)] Symbol reference IDs mismatch for "TestServiceAccessor": after transform: SymbolId(21): [ReferenceId(1), ReferenceId(40), ReferenceId(71), ReferenceId(155), ReferenceId(188)] -rebuilt : SymbolId(17): [ReferenceId(59), ReferenceId(178)] +rebuilt : SymbolId(17): [ReferenceId(62), ReferenceId(181)] Symbol reference IDs mismatch for "IWorkingCopyEditorService": after transform: SymbolId(32): [ReferenceId(21), ReferenceId(22)] rebuilt : SymbolId(26): [ReferenceId(16)] Symbol reference IDs mismatch for "TestWorkingCopyBackupTracker": after transform: SymbolId(39): [ReferenceId(42), ReferenceId(74), ReferenceId(154), ReferenceId(215)] -rebuilt : SymbolId(34): [ReferenceId(62), ReferenceId(205)] +rebuilt : SymbolId(34): [ReferenceId(65), ReferenceId(208)] Unresolved reference IDs mismatch for "Promise": after transform: [ReferenceId(36), ReferenceId(39), ReferenceId(82), ReferenceId(114), ReferenceId(153), ReferenceId(282)] -rebuilt : [ReferenceId(278)] +rebuilt : [ReferenceId(281)] tasks/coverage/misc/pass/oxc-4449.ts semantic error: Scope flags mismatch: diff --git a/tasks/coverage/snapshots/semantic_test262.snap b/tasks/coverage/snapshots/semantic_test262.snap index 4dd4ffccc246d..e1e4631d0778f 100644 --- a/tasks/coverage/snapshots/semantic_test262.snap +++ b/tasks/coverage/snapshots/semantic_test262.snap @@ -20458,13 +20458,22 @@ rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) tasks/coverage/test262/test/language/expressions/object/method-definition/async-super-call-body.js semantic error: Symbol flags mismatch for "_asyncToGenerator": -after transform: SymbolId(3): SymbolFlags(Import) +after transform: SymbolId(5): SymbolFlags(Import) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) tasks/coverage/test262/test/language/expressions/object/method-definition/async-super-call-param.js semantic error: Symbol flags mismatch for "_asyncToGenerator": -after transform: SymbolId(4): SymbolFlags(Import) +after transform: SymbolId(5): SymbolFlags(Import) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) +Symbol reference IDs mismatch for "_superprop_getMethod": +after transform: SymbolId(4): [ReferenceId(9)] +rebuilt : SymbolId(4): [] +Reference symbol mismatch for "_superprop_getMethod": +after transform: SymbolId(4) "_superprop_getMethod" +rebuilt : +Unresolved references mismatch: +after transform: ["$DONE", "Object", "assert", "require"] +rebuilt : ["$DONE", "Object", "_superprop_getMethod", "assert", "require"] tasks/coverage/test262/test/language/expressions/object/method-definition/forbidden-ext/b1/async-gen-meth-forbidden-ext-direct-access-prop-arguments.js semantic error: Symbol flags mismatch for "_wrapAsyncGenerator": @@ -24611,6 +24620,15 @@ tasks/coverage/test262/test/language/statements/class/definition/methods-async-s semantic error: Symbol flags mismatch for "_asyncToGenerator": after transform: SymbolId(4): SymbolFlags(Import) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) +Symbol reference IDs mismatch for "_superprop_getMethod": +after transform: SymbolId(5): [ReferenceId(8)] +rebuilt : SymbolId(4): [] +Reference symbol mismatch for "_superprop_getMethod": +after transform: SymbolId(5) "_superprop_getMethod" +rebuilt : +Unresolved references mismatch: +after transform: ["$DONE", "assert", "require"] +rebuilt : ["$DONE", "_superprop_getMethod", "assert", "require"] tasks/coverage/test262/test/language/statements/class/dstr/async-gen-meth-ary-init-iter-close.js semantic error: Symbol flags mismatch for "_wrapAsyncGenerator": diff --git a/tasks/coverage/snapshots/semantic_typescript.snap b/tasks/coverage/snapshots/semantic_typescript.snap index 075bdf2c94ba8..5c03464280af2 100644 --- a/tasks/coverage/snapshots/semantic_typescript.snap +++ b/tasks/coverage/snapshots/semantic_typescript.snap @@ -38180,12 +38180,12 @@ rebuilt : ["arguments", "mp", "p", "require"] tasks/coverage/typescript/tests/cases/conformance/async/es2017/asyncMethodWithSuperConflict_es6.ts semantic error: Symbol flags mismatch for "_asyncToGenerator": -after transform: SymbolId(11): SymbolFlags(Import) +after transform: SymbolId(15): SymbolFlags(Import) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) tasks/coverage/typescript/tests/cases/conformance/async/es2017/asyncMethodWithSuper_es2017.ts semantic error: Symbol flags mismatch for "_asyncToGenerator": -after transform: SymbolId(7): SymbolFlags(Import) +after transform: SymbolId(11): SymbolFlags(Import) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) tasks/coverage/typescript/tests/cases/conformance/async/es2017/asyncUseStrict_es2017.ts @@ -38566,8 +38566,8 @@ rebuilt : ["arguments", "require"] tasks/coverage/typescript/tests/cases/conformance/async/es5/asyncArrowFunction/asyncArrowFunction11_es5.ts semantic error: Symbol flags mismatch for "_asyncToGenerator": -after transform: SymbolId(3): SymbolFlags(Import) -rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) +after transform: SymbolId(4): SymbolFlags(Import) +rebuilt : SymbolId(1): SymbolFlags(FunctionScopedVariable) tasks/coverage/typescript/tests/cases/conformance/async/es5/asyncArrowFunction/asyncArrowFunction1_es5.ts semantic error: Symbol flags mismatch for "_asyncToGenerator": @@ -38658,7 +38658,7 @@ rebuilt : ScopeId(1): [] tasks/coverage/typescript/tests/cases/conformance/async/es5/asyncMethodWithSuper_es5.ts semantic error: Symbol flags mismatch for "_asyncToGenerator": -after transform: SymbolId(7): SymbolFlags(Import) +after transform: SymbolId(11): SymbolFlags(Import) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) tasks/coverage/typescript/tests/cases/conformance/async/es5/asyncMultiFile_es5.ts @@ -39173,10 +39173,10 @@ rebuilt : ["arguments", "mp", "p", "require"] tasks/coverage/typescript/tests/cases/conformance/async/es6/asyncMethodWithSuper_es6.ts semantic error: Symbol flags mismatch for "_asyncToGenerator": -after transform: SymbolId(21): SymbolFlags(Import) +after transform: SymbolId(25): SymbolFlags(Import) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) Symbol flags mismatch for "_wrapAsyncGenerator": -after transform: SymbolId(22): SymbolFlags(Import) +after transform: SymbolId(48): SymbolFlags(Import) rebuilt : SymbolId(1): SymbolFlags(FunctionScopedVariable) tasks/coverage/typescript/tests/cases/conformance/async/es6/asyncMultiFile_es6.ts @@ -47284,7 +47284,7 @@ rebuilt : ["o1", "o2", "o3", "o4"] tasks/coverage/typescript/tests/cases/conformance/expressions/optionalChaining/callChain/superMethodCall.ts semantic error: Symbol flags mismatch for "_asyncToGenerator": -after transform: SymbolId(2): SymbolFlags(Import) +after transform: SymbolId(3): SymbolFlags(Import) rebuilt : SymbolId(0): SymbolFlags(FunctionScopedVariable) tasks/coverage/typescript/tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.2.ts diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md index 9d061ee0710cb..2314b99edec26 100644 --- a/tasks/transform_conformance/snapshots/babel.snap.md +++ b/tasks/transform_conformance/snapshots/babel.snap.md @@ -1,6 +1,6 @@ commit: d20b314c -Passed: 314/626 +Passed: 316/626 # All Passed: * babel-plugin-transform-class-static-block @@ -13,7 +13,7 @@ Passed: 314/626 * babel-plugin-transform-react-jsx-source -# babel-preset-env (40/127) +# babel-preset-env (41/127) * dynamic-import/auto-esm-unsupported-import-unsupported/input.mjs x Output mismatch @@ -107,9 +107,6 @@ x Output mismatch * plugins-integration/issue-7527/input.mjs x Output mismatch -* plugins-integration/issue-9935/input.js -x Output mismatch - * plugins-integration/regression-2892/input.mjs x Output mismatch @@ -463,7 +460,7 @@ x Output mismatch x Output mismatch -# babel-plugin-transform-async-to-generator (10/24) +# babel-plugin-transform-async-to-generator (11/24) * assumption-ignoreFunctionLength-true/basic/input.mjs x Output mismatch @@ -476,9 +473,6 @@ x Output mismatch * async-to-generator/async-iife-with-regenerator-spec/input.js x Output mismatch -* async-to-generator/object-method-with-super/input.js -x Output mismatch - * bluebird-coroutines/arrow-function/input.js x Output mismatch diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 67c76d59bfc0f..6f697f3ec4214 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: d20b314c -Passed: 80/89 +Passed: 82/91 # All Passed: * babel-plugin-transform-class-static-block diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/assign/input.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/assign/input.js new file mode 100644 index 0000000000000..5b30dfa38e26c --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/assign/input.js @@ -0,0 +1,10 @@ +const Obj = { + value: 0, + async method() { + super.value = true; + () => { + super['value'] = true; + super.object.value = true; + } + } +} \ No newline at end of file diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/assign/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/assign/output.js new file mode 100644 index 0000000000000..1e69ce6904e0d --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/assign/output.js @@ -0,0 +1,15 @@ +const Obj = { + value: 0, + method() { + var _superprop_getObject = () => super.object, + _superprop_set = (_prop, _value) => super[_prop] = _value, + _superprop_setValue = _value2 => super.value = _value2; + return babelHelpers.asyncToGenerator(function* () { + _superprop_setValue(true); + () => { + _superprop_set('value', true); + _superprop_getObject().value = true; + }; + })(); + } +}; \ No newline at end of file diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/computed-member/input.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/computed-member/input.js new file mode 100644 index 0000000000000..46f3d22ed14b8 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/computed-member/input.js @@ -0,0 +1,9 @@ +class Foo extends class {} { + async method() { + super['name']; + { + super['name'](); + super['object']['name'](); + } + } +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/computed-member/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/computed-member/output.js new file mode 100644 index 0000000000000..280d5772224f4 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/computed-member/output.js @@ -0,0 +1,13 @@ +class Foo extends class {} { + method() { + var _superprop_get = _prop => super[_prop], + _this = this; + return babelHelpers.asyncToGenerator(function* () { + _superprop_get('name'); + { + _superprop_get('name').call(_this); + _superprop_get('object')['name'](); + } + })(); + } +} \ No newline at end of file