diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index cf29fac9de542..af3403baa37a6 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -861,7 +861,7 @@ pub struct ArrayAssignmentTarget<'a> { pub span: Span, pub elements: Vec<'a, Option>>, #[estree(append_to = elements)] - pub rest: Option>, + pub rest: Option>>, } /// `{ foo }` in `({ foo } = obj);` @@ -879,7 +879,7 @@ pub struct ObjectAssignmentTarget<'a> { pub span: Span, pub properties: Vec<'a, AssignmentTargetProperty<'a>>, #[estree(append_to = properties)] - pub rest: Option>, + pub rest: Option>>, } /// `rest` in `[foo, ...rest] = arr;` or `({foo, ...rest} = obj);`. diff --git a/crates/oxc_ast/src/generated/assert_layouts.rs b/crates/oxc_ast/src/generated/assert_layouts.rs index 79b6794bc9af5..437e0e79a9138 100644 --- a/crates/oxc_ast/src/generated/assert_layouts.rs +++ b/crates/oxc_ast/src/generated/assert_layouts.rs @@ -250,14 +250,14 @@ const _: () = { assert!(align_of::() == 8); // Padding: 0 bytes - assert!(size_of::() == 56); + assert!(size_of::() == 40); assert!(align_of::() == 8); assert!(offset_of!(ArrayAssignmentTarget, span) == 0); assert!(offset_of!(ArrayAssignmentTarget, elements) == 8); assert!(offset_of!(ArrayAssignmentTarget, rest) == 32); // Padding: 0 bytes - assert!(size_of::() == 56); + assert!(size_of::() == 40); assert!(align_of::() == 8); assert!(offset_of!(ObjectAssignmentTarget, span) == 0); assert!(offset_of!(ObjectAssignmentTarget, properties) == 8); @@ -1842,14 +1842,14 @@ const _: () = { assert!(align_of::() == 4); // Padding: 0 bytes - assert!(size_of::() == 40); + assert!(size_of::() == 28); assert!(align_of::() == 4); assert!(offset_of!(ArrayAssignmentTarget, span) == 0); assert!(offset_of!(ArrayAssignmentTarget, elements) == 8); assert!(offset_of!(ArrayAssignmentTarget, rest) == 24); // Padding: 0 bytes - assert!(size_of::() == 40); + assert!(size_of::() == 28); assert!(align_of::() == 4); assert!(offset_of!(ObjectAssignmentTarget, span) == 0); assert!(offset_of!(ObjectAssignmentTarget, properties) == 8); diff --git a/crates/oxc_ast/src/generated/ast_builder.rs b/crates/oxc_ast/src/generated/ast_builder.rs index f67c45ab88402..6f2855d2c9da6 100644 --- a/crates/oxc_ast/src/generated/ast_builder.rs +++ b/crates/oxc_ast/src/generated/ast_builder.rs @@ -2751,12 +2751,15 @@ impl<'a> AstBuilder<'a> { /// * `elements` /// * `rest` #[inline] - pub fn assignment_target_pattern_array_assignment_target( + pub fn assignment_target_pattern_array_assignment_target( self, span: Span, elements: Vec<'a, Option>>, - rest: Option>, - ) -> AssignmentTargetPattern<'a> { + rest: T1, + ) -> AssignmentTargetPattern<'a> + where + T1: IntoIn<'a, Option>>>, + { AssignmentTargetPattern::ArrayAssignmentTarget( self.alloc_array_assignment_target(span, elements, rest), ) @@ -2771,12 +2774,15 @@ impl<'a> AstBuilder<'a> { /// * `properties` /// * `rest` #[inline] - pub fn assignment_target_pattern_object_assignment_target( + pub fn assignment_target_pattern_object_assignment_target( self, span: Span, properties: Vec<'a, AssignmentTargetProperty<'a>>, - rest: Option>, - ) -> AssignmentTargetPattern<'a> { + rest: T1, + ) -> AssignmentTargetPattern<'a> + where + T1: IntoIn<'a, Option>>>, + { AssignmentTargetPattern::ObjectAssignmentTarget( self.alloc_object_assignment_target(span, properties, rest), ) @@ -2792,13 +2798,16 @@ impl<'a> AstBuilder<'a> { /// * `elements` /// * `rest` #[inline] - pub fn array_assignment_target( + pub fn array_assignment_target( self, span: Span, elements: Vec<'a, Option>>, - rest: Option>, - ) -> ArrayAssignmentTarget<'a> { - ArrayAssignmentTarget { span, elements, rest } + rest: T1, + ) -> ArrayAssignmentTarget<'a> + where + T1: IntoIn<'a, Option>>>, + { + ArrayAssignmentTarget { span, elements, rest: rest.into_in(self.allocator) } } /// Build an [`ArrayAssignmentTarget`], and store it in the memory arena. @@ -2811,12 +2820,15 @@ impl<'a> AstBuilder<'a> { /// * `elements` /// * `rest` #[inline] - pub fn alloc_array_assignment_target( + pub fn alloc_array_assignment_target( self, span: Span, elements: Vec<'a, Option>>, - rest: Option>, - ) -> Box<'a, ArrayAssignmentTarget<'a>> { + rest: T1, + ) -> Box<'a, ArrayAssignmentTarget<'a>> + where + T1: IntoIn<'a, Option>>>, + { Box::new_in(self.array_assignment_target(span, elements, rest), self.allocator) } @@ -2830,13 +2842,16 @@ impl<'a> AstBuilder<'a> { /// * `properties` /// * `rest` #[inline] - pub fn object_assignment_target( + pub fn object_assignment_target( self, span: Span, properties: Vec<'a, AssignmentTargetProperty<'a>>, - rest: Option>, - ) -> ObjectAssignmentTarget<'a> { - ObjectAssignmentTarget { span, properties, rest } + rest: T1, + ) -> ObjectAssignmentTarget<'a> + where + T1: IntoIn<'a, Option>>>, + { + ObjectAssignmentTarget { span, properties, rest: rest.into_in(self.allocator) } } /// Build an [`ObjectAssignmentTarget`], and store it in the memory arena. @@ -2849,17 +2864,23 @@ impl<'a> AstBuilder<'a> { /// * `properties` /// * `rest` #[inline] - pub fn alloc_object_assignment_target( + pub fn alloc_object_assignment_target( self, span: Span, properties: Vec<'a, AssignmentTargetProperty<'a>>, - rest: Option>, - ) -> Box<'a, ObjectAssignmentTarget<'a>> { + rest: T1, + ) -> Box<'a, ObjectAssignmentTarget<'a>> + where + T1: IntoIn<'a, Option>>>, + { Box::new_in(self.object_assignment_target(span, properties, rest), self.allocator) } /// Build an [`AssignmentTargetRest`]. /// + /// If you want the built node to be allocated in the memory arena, + /// use [`AstBuilder::alloc_assignment_target_rest`] instead. + /// /// ## Parameters /// * `span`: The [`Span`] covering this node /// * `target` @@ -2872,6 +2893,23 @@ impl<'a> AstBuilder<'a> { AssignmentTargetRest { span, target } } + /// Build an [`AssignmentTargetRest`], and store it in the memory arena. + /// + /// Returns a [`Box`] containing the newly-allocated node. + /// If you want a stack-allocated node, use [`AstBuilder::assignment_target_rest`] instead. + /// + /// ## Parameters + /// * `span`: The [`Span`] covering this node + /// * `target` + #[inline] + pub fn alloc_assignment_target_rest( + self, + span: Span, + target: AssignmentTarget<'a>, + ) -> Box<'a, AssignmentTargetRest<'a>> { + Box::new_in(self.assignment_target_rest(span, target), self.allocator) + } + /// Build an [`AssignmentTargetMaybeDefault::AssignmentTargetWithDefault`]. /// /// This node contains an [`AssignmentTargetWithDefault`] that will be stored in the memory arena. diff --git a/crates/oxc_ast/src/generated/derive_dummy.rs b/crates/oxc_ast/src/generated/derive_dummy.rs index 595f8c776377e..db1e6b0ca2a6e 100644 --- a/crates/oxc_ast/src/generated/derive_dummy.rs +++ b/crates/oxc_ast/src/generated/derive_dummy.rs @@ -451,7 +451,7 @@ impl<'a> Dummy<'a> for SimpleAssignmentTarget<'a> { impl<'a> Dummy<'a> for AssignmentTargetPattern<'a> { /// Create a dummy [`AssignmentTargetPattern`]. /// - /// Has cost of making 1 allocation (56 bytes). + /// Has cost of making 1 allocation (40 bytes). fn dummy(allocator: &'a Allocator) -> Self { Self::ArrayAssignmentTarget(Dummy::dummy(allocator)) } diff --git a/crates/oxc_formatter/src/generated/ast_nodes.rs b/crates/oxc_formatter/src/generated/ast_nodes.rs index 3283ca5eec856..9380717f611cf 100644 --- a/crates/oxc_formatter/src/generated/ast_nodes.rs +++ b/crates/oxc_formatter/src/generated/ast_nodes.rs @@ -5030,7 +5030,7 @@ impl<'a> AstNode<'a, ArrayAssignmentTarget<'a>> { #[inline] pub fn elements(&self) -> &AstNode<'a, Vec<'a, Option>>> { let following_node = - self.inner.rest.as_ref().map(SiblingNode::from).or(self.following_node); + self.inner.rest.as_deref().map(SiblingNode::from).or(self.following_node); self.allocator.alloc(AstNode { inner: &self.inner.elements, allocator: self.allocator, @@ -5044,7 +5044,7 @@ impl<'a> AstNode<'a, ArrayAssignmentTarget<'a>> { let following_node = self.following_node; self.allocator .alloc(self.inner.rest.as_ref().map(|inner| AstNode { - inner, + inner: inner.as_ref(), allocator: self.allocator, parent: self.allocator.alloc(AstNodes::ArrayAssignmentTarget(transmute_self(self))), following_node, @@ -5077,7 +5077,7 @@ impl<'a> AstNode<'a, ObjectAssignmentTarget<'a>> { #[inline] pub fn properties(&self) -> &AstNode<'a, Vec<'a, AssignmentTargetProperty<'a>>> { let following_node = - self.inner.rest.as_ref().map(SiblingNode::from).or(self.following_node); + self.inner.rest.as_deref().map(SiblingNode::from).or(self.following_node); self.allocator.alloc(AstNode { inner: &self.inner.properties, allocator: self.allocator, @@ -5091,7 +5091,7 @@ impl<'a> AstNode<'a, ObjectAssignmentTarget<'a>> { let following_node = self.following_node; self.allocator .alloc(self.inner.rest.as_ref().map(|inner| AstNode { - inner, + inner: inner.as_ref(), allocator: self.allocator, parent: self.allocator.alloc(AstNodes::ObjectAssignmentTarget(transmute_self(self))), diff --git a/crates/oxc_parser/src/js/grammar.rs b/crates/oxc_parser/src/js/grammar.rs index a3aadb6117b5c..d60525719fbe2 100644 --- a/crates/oxc_parser/src/js/grammar.rs +++ b/crates/oxc_parser/src/js/grammar.rs @@ -89,7 +89,7 @@ impl<'a> CoverGrammar<'a, ArrayExpression<'a>> for ArrayAssignmentTarget<'a> { p.error(diagnostics::invalid_rest_assignment_target(argument.span())); } let target = AssignmentTarget::cover(argument, p); - rest = Some(p.ast.assignment_target_rest(span, target)); + rest = Some(p.ast.alloc(p.ast.assignment_target_rest(span, target))); if let Some(span) = p.state.trailing_commas.get(&expr.span.start) { p.error(diagnostics::rest_element_trailing_comma(*span)); } @@ -153,7 +153,7 @@ impl<'a> CoverGrammar<'a, ObjectExpression<'a>> for ObjectAssignmentTarget<'a> { p.error(diagnostics::invalid_rest_assignment_target(argument.span())); } let target = AssignmentTarget::cover(argument, p); - rest = Some(p.ast.assignment_target_rest(span, target)); + rest = Some(p.ast.alloc(p.ast.assignment_target_rest(span, target))); } else { return p.fatal_error(diagnostics::spread_last_element(spread.span)); } diff --git a/crates/oxc_transformer/src/es2018/object_rest_spread.rs b/crates/oxc_transformer/src/es2018/object_rest_spread.rs index ce93354ce32b1..261634729af2c 100644 --- a/crates/oxc_transformer/src/es2018/object_rest_spread.rs +++ b/crates/oxc_transformer/src/es2018/object_rest_spread.rs @@ -326,6 +326,7 @@ impl<'a> ObjectRestSpread<'a, '_> { ctx: &mut TraverseCtx<'a>, ) -> Option> { let rest = object_assignment_target.rest.take()?; + let rest_target = rest.unbox(); let mut all_primitives = true; let keys = ctx.ast.vec_from_iter(object_assignment_target.properties.iter_mut().filter_map(|e| { @@ -347,7 +348,7 @@ impl<'a> ObjectRestSpread<'a, '_> { } })); Some(SpreadPair { - lhs: BindingPatternOrAssignmentTarget::AssignmentTarget(rest.target), + lhs: BindingPatternOrAssignmentTarget::AssignmentTarget(rest_target.target), keys, has_no_properties: object_assignment_target.is_empty(), all_primitives, diff --git a/crates/oxc_traverse/src/generated/ancestor.rs b/crates/oxc_traverse/src/generated/ancestor.rs index 057a0fb7a2a8a..7a5b778e47063 100644 --- a/crates/oxc_traverse/src/generated/ancestor.rs +++ b/crates/oxc_traverse/src/generated/ancestor.rs @@ -4150,10 +4150,10 @@ impl<'a, 't> ArrayAssignmentTargetWithoutElements<'a, 't> { } #[inline] - pub fn rest(self) -> &'t Option> { + pub fn rest(self) -> &'t Option>> { unsafe { &*((self.0 as *const u8).add(OFFSET_ARRAY_ASSIGNMENT_TARGET_REST) - as *const Option>) + as *const Option>>) } } } @@ -4217,10 +4217,10 @@ impl<'a, 't> ObjectAssignmentTargetWithoutProperties<'a, 't> { } #[inline] - pub fn rest(self) -> &'t Option> { + pub fn rest(self) -> &'t Option>> { unsafe { &*((self.0 as *const u8).add(OFFSET_OBJECT_ASSIGNMENT_TARGET_REST) - as *const Option>) + as *const Option>>) } } } diff --git a/crates/oxc_traverse/src/generated/walk.rs b/crates/oxc_traverse/src/generated/walk.rs index 39eb371f02dce..f9ae9e7e0ec30 100644 --- a/crates/oxc_traverse/src/generated/walk.rs +++ b/crates/oxc_traverse/src/generated/walk.rs @@ -1035,10 +1035,10 @@ unsafe fn walk_array_assignment_target<'a, State, Tr: Traverse<'a, State>>( walk_assignment_target_maybe_default(traverser, item as *mut _, ctx); } if let Some(field) = &mut *((node as *mut u8).add(ancestor::OFFSET_ARRAY_ASSIGNMENT_TARGET_REST) - as *mut Option) + as *mut Option>) { ctx.retag_stack(AncestorType::ArrayAssignmentTargetRest); - walk_assignment_target_rest(traverser, field as *mut _, ctx); + walk_assignment_target_rest(traverser, (&mut **field) as *mut _, ctx); } ctx.pop_stack(pop_token); traverser.exit_array_assignment_target(&mut *node, ctx); @@ -1060,10 +1060,10 @@ unsafe fn walk_object_assignment_target<'a, State, Tr: Traverse<'a, State>>( } if let Some(field) = &mut *((node as *mut u8) .add(ancestor::OFFSET_OBJECT_ASSIGNMENT_TARGET_REST) - as *mut Option) + as *mut Option>) { ctx.retag_stack(AncestorType::ObjectAssignmentTargetRest); - walk_assignment_target_rest(traverser, field as *mut _, ctx); + walk_assignment_target_rest(traverser, (&mut **field) as *mut _, ctx); } ctx.pop_stack(pop_token); traverser.exit_object_assignment_target(&mut *node, ctx); diff --git a/napi/parser/generated/deserialize/js.js b/napi/parser/generated/deserialize/js.js index f5b9ed3fec96e..76b0f1309fb58 100644 --- a/napi/parser/generated/deserialize/js.js +++ b/napi/parser/generated/deserialize/js.js @@ -323,7 +323,7 @@ function deserializeAssignmentExpression(pos) { function deserializeArrayAssignmentTarget(pos) { const elements = deserializeVecOptionAssignmentTargetMaybeDefault(pos + 8); - const rest = deserializeOptionAssignmentTargetRest(pos + 32); + const rest = deserializeOptionBoxAssignmentTargetRest(pos + 32); if (rest !== null) elements.push(rest); return { type: 'ArrayPattern', @@ -335,7 +335,7 @@ function deserializeArrayAssignmentTarget(pos) { function deserializeObjectAssignmentTarget(pos) { const properties = deserializeVecAssignmentTargetProperty(pos + 8); - const rest = deserializeOptionAssignmentTargetRest(pos + 32); + const rest = deserializeOptionBoxAssignmentTargetRest(pos + 32); if (rest !== null) properties.push(rest); return { type: 'ObjectPattern', @@ -4389,9 +4389,13 @@ function deserializeVecOptionAssignmentTargetMaybeDefault(pos) { return arr; } -function deserializeOptionAssignmentTargetRest(pos) { - if (uint8[pos + 8] === 51) return null; - return deserializeAssignmentTargetRest(pos); +function deserializeBoxAssignmentTargetRest(pos) { + return deserializeAssignmentTargetRest(uint32[pos >> 2]); +} + +function deserializeOptionBoxAssignmentTargetRest(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxAssignmentTargetRest(pos); } function deserializeVecAssignmentTargetProperty(pos) { diff --git a/napi/parser/generated/deserialize/ts.js b/napi/parser/generated/deserialize/ts.js index 63081411a7019..c988af2da35e7 100644 --- a/napi/parser/generated/deserialize/ts.js +++ b/napi/parser/generated/deserialize/ts.js @@ -355,7 +355,7 @@ function deserializeAssignmentExpression(pos) { function deserializeArrayAssignmentTarget(pos) { const elements = deserializeVecOptionAssignmentTargetMaybeDefault(pos + 8); - const rest = deserializeOptionAssignmentTargetRest(pos + 32); + const rest = deserializeOptionBoxAssignmentTargetRest(pos + 32); if (rest !== null) elements.push(rest); return { type: 'ArrayPattern', @@ -370,7 +370,7 @@ function deserializeArrayAssignmentTarget(pos) { function deserializeObjectAssignmentTarget(pos) { const properties = deserializeVecAssignmentTargetProperty(pos + 8); - const rest = deserializeOptionAssignmentTargetRest(pos + 32); + const rest = deserializeOptionBoxAssignmentTargetRest(pos + 32); if (rest !== null) properties.push(rest); return { type: 'ObjectPattern', @@ -4520,9 +4520,13 @@ function deserializeVecOptionAssignmentTargetMaybeDefault(pos) { return arr; } -function deserializeOptionAssignmentTargetRest(pos) { - if (uint8[pos + 8] === 51) return null; - return deserializeAssignmentTargetRest(pos); +function deserializeBoxAssignmentTargetRest(pos) { + return deserializeAssignmentTargetRest(uint32[pos >> 2]); +} + +function deserializeOptionBoxAssignmentTargetRest(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxAssignmentTargetRest(pos); } function deserializeVecAssignmentTargetProperty(pos) { diff --git a/napi/parser/generated/lazy/constructors.js b/napi/parser/generated/lazy/constructors.js index 193dc87dc223b..8edc9711ce705 100644 --- a/napi/parser/generated/lazy/constructors.js +++ b/napi/parser/generated/lazy/constructors.js @@ -12855,9 +12855,13 @@ function constructVecOptionAssignmentTargetMaybeDefault(pos, ast) { ); } -function constructOptionAssignmentTargetRest(pos, ast) { - if (ast.buffer[pos + 8] === 51) return null; - return new AssignmentTargetRest(pos, ast); +function constructBoxAssignmentTargetRest(pos, ast) { + return new AssignmentTargetRest(ast.buffer.uint32[pos >> 2], ast); +} + +function constructOptionBoxAssignmentTargetRest(pos, ast) { + if (ast.buffer.uint32[pos >> 2] === 0 && ast.buffer.uint32[(pos + 4) >> 2] === 0) return null; + return constructBoxAssignmentTargetRest(pos, ast); } function constructVecAssignmentTargetProperty(pos, ast) {