diff --git a/crates/oxc_ast/src/ast_builder_impl.rs b/crates/oxc_ast/src/ast_builder_impl.rs index cb1cb4dceb978a..3dc648715e040f 100644 --- a/crates/oxc_ast/src/ast_builder_impl.rs +++ b/crates/oxc_ast/src/ast_builder_impl.rs @@ -62,10 +62,10 @@ impl<'a> AstBuilder<'a> { /// This method is completely unsound and should not be used. /// We need to remove all uses of it. Please don't add any more! /// + #[allow(clippy::missing_safety_doc)] #[inline] - pub fn copy(self, src: &T) -> T { + pub unsafe fn copy(self, src: &T) -> T { // SAFETY: Not safe (see above) - unsafe { std::mem::transmute_copy(src) } } diff --git a/crates/oxc_isolated_declarations/src/class.rs b/crates/oxc_isolated_declarations/src/class.rs index 379c448c1ab757..90a90cfa7fd71b 100644 --- a/crates/oxc_isolated_declarations/src/class.rs +++ b/crates/oxc_isolated_declarations/src/class.rs @@ -59,7 +59,8 @@ impl<'a> IsolatedDeclarations<'a> { if property.accessibility.map_or(true, |a| !a.is_private()) { if property.type_annotation.is_some() { - type_annotations = self.ast.copy(&property.type_annotation); + // SAFETY: `ast.copy` is unsound! We need to fix. + type_annotations = unsafe { self.ast.copy(&property.type_annotation) }; } else if let Some(expr) = property.value.as_ref() { let ts_type = if property.readonly { // `field = 'string'` remain `field = 'string'` instead of `field: 'string'` @@ -71,7 +72,8 @@ impl<'a> IsolatedDeclarations<'a> { .transform_template_to_string(lit) .map(Expression::StringLiteral); } else { - value = Some(self.ast.copy(expr)); + // SAFETY: `ast.copy` is unsound! We need to fix. + value = Some(unsafe { self.ast.copy(expr) }); } None } @@ -91,7 +93,8 @@ impl<'a> IsolatedDeclarations<'a> { property.r#type, property.span, self.ast.vec(), - self.ast.copy(&property.key), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&property.key) }, value, property.computed, property.r#static, @@ -116,12 +119,15 @@ impl<'a> IsolatedDeclarations<'a> { let value = self.ast.alloc_function( FunctionType::TSEmptyBodyFunctionExpression, function.span, - self.ast.copy(&function.id), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&function.id) }, false, false, false, - self.ast.copy(&function.type_parameters), - self.ast.copy(&function.this_param), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&function.type_parameters) }, + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&function.this_param) }, params, return_type, Option::::None, @@ -131,7 +137,8 @@ impl<'a> IsolatedDeclarations<'a> { definition.r#type, definition.span, self.ast.vec(), - self.ast.copy(&definition.key), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&definition.key) }, value, definition.kind, definition.computed, @@ -209,7 +216,8 @@ impl<'a> IsolatedDeclarations<'a> { }; self.create_class_property( r#type, - self.ast.copy(&method.key), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&method.key) }, method.r#static, method.r#override, self.transform_accessibility(method.accessibility), @@ -247,7 +255,8 @@ impl<'a> IsolatedDeclarations<'a> { None } else { // transformed params will definitely have type annotation - self.ast.copy(¶ms.items[index].pattern.type_annotation) + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(¶ms.items[index].pattern.type_annotation) } }; if let Some(new_element) = self.transform_formal_parameter_to_class_property(param, type_annotation) @@ -289,7 +298,10 @@ impl<'a> IsolatedDeclarations<'a> { MethodDefinitionKind::Get => { let return_type = self.infer_function_return_type(function); if let Some(return_type) = return_type { - inferred_accessor_types.insert(name, self.ast.copy(&return_type)); + inferred_accessor_types.insert(name, { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&return_type) } + }); } } MethodDefinitionKind::Set => { @@ -300,7 +312,10 @@ impl<'a> IsolatedDeclarations<'a> { self.infer_type_from_formal_parameter(param) .map(|x| self.ast.alloc_ts_type_annotation(SPAN, x)) }, - |t| Some(self.ast.copy(t)), + |t| { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { Some(self.ast.copy(t)) } + }, ); if let Some(type_annotation) = type_annotation { inferred_accessor_types.insert(name, type_annotation); @@ -373,9 +388,10 @@ impl<'a> IsolatedDeclarations<'a> { |n| { self.transform_set_accessor_params( &function.params, - inferred_accessor_types - .get(&self.ast.atom(&n)) - .map(|t| self.ast.copy(t)), + inferred_accessor_types.get(&self.ast.atom(&n)).map(|t| { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(t) } + }), ) }, ) @@ -403,9 +419,10 @@ impl<'a> IsolatedDeclarations<'a> { } MethodDefinitionKind::Get => { let rt = method.key.static_name().and_then(|name| { - inferred_accessor_types - .get(&self.ast.atom(&name)) - .map(|t| self.ast.copy(t)) + inferred_accessor_types.get(&self.ast.atom(&name)).map(|t| { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(t) } + }) }); if rt.is_none() { self.error(accessor_must_have_explicit_return_type( @@ -446,14 +463,18 @@ impl<'a> IsolatedDeclarations<'a> { property.r#type, property.span, self.ast.vec(), - self.ast.copy(&property.key), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&property.key) }, None, property.computed, property.r#static, ); elements.push(new_element); } - ClassElement::TSIndexSignature(_) => elements.push(self.ast.copy(element)), + ClassElement::TSIndexSignature(_) => elements.push({ + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(element) } + }), } } @@ -490,11 +511,16 @@ impl<'a> IsolatedDeclarations<'a> { decl.r#type, decl.span, self.ast.vec(), - self.ast.copy(&decl.id), - self.ast.copy(&decl.type_parameters), - self.ast.copy(&decl.super_class), - self.ast.copy(&decl.super_type_parameters), - self.ast.copy(&decl.implements), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.id) }, + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.type_parameters) }, + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.super_class) }, + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.super_type_parameters) }, + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.implements) }, body, decl.r#abstract, declare.unwrap_or_else(|| self.is_declare()), @@ -510,7 +536,10 @@ impl<'a> IsolatedDeclarations<'a> { if items.first().map_or(true, |item| item.pattern.type_annotation.is_none()) { let kind = items.first().map_or_else( || self.ast.binding_pattern_kind_binding_identifier(SPAN, "value"), - |item| self.ast.copy(&item.pattern.kind), + |item| { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&item.pattern.kind) } + }, ); self.create_formal_parameters(kind, type_annotation) diff --git a/crates/oxc_isolated_declarations/src/declaration.rs b/crates/oxc_isolated_declarations/src/declaration.rs index 111f50cf6aa087..1a59a8010d11fc 100644 --- a/crates/oxc_isolated_declarations/src/declaration.rs +++ b/crates/oxc_isolated_declarations/src/declaration.rs @@ -77,7 +77,8 @@ impl<'a> IsolatedDeclarations<'a> { init = self.transform_template_to_string(lit).map(Expression::StringLiteral); } else { - init = Some(self.ast.copy(init_expr)); + // SAFETY: `ast.copy` is unsound! We need to fix. + init = Some(unsafe { self.ast.copy(init_expr) }); } } else if !decl.kind.is_const() || !matches!(init_expr, Expression::TemplateLiteral(_)) @@ -94,10 +95,14 @@ impl<'a> IsolatedDeclarations<'a> { } } let id = binding_type.map_or_else( - || self.ast.copy(&decl.id), + || { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.id) } + }, |ts_type| { self.ast.binding_pattern( - self.ast.copy(&decl.id.kind), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.id.kind) }, Some(self.ast.ts_type_annotation(SPAN, ts_type)), decl.id.optional, ) @@ -149,11 +154,13 @@ impl<'a> IsolatedDeclarations<'a> { decl: &Box<'a, TSModuleDeclaration<'a>>, ) -> Box<'a, TSModuleDeclaration<'a>> { if decl.declare { - return self.ast.copy(decl); + // SAFETY: `ast.copy` is unsound! We need to fix. + return unsafe { self.ast.copy(decl) }; } let Some(body) = &decl.body else { - return self.ast.copy(decl); + // SAFETY: `ast.copy` is unsound! We need to fix. + return unsafe { self.ast.copy(decl) }; }; match body { @@ -161,7 +168,8 @@ impl<'a> IsolatedDeclarations<'a> { let inner = self.transform_ts_module_declaration(decl); self.ast.alloc_ts_module_declaration( decl.span, - self.ast.copy(&decl.id), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.id) }, Some(TSModuleDeclarationBody::TSModuleDeclaration(inner)), decl.kind, self.is_declare(), @@ -171,7 +179,8 @@ impl<'a> IsolatedDeclarations<'a> { let body = self.transform_ts_module_block(block); self.ast.alloc_ts_module_declaration( decl.span, - self.ast.copy(&decl.id), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.id) }, Some(TSModuleDeclarationBody::TSModuleBlock(body)), decl.kind, self.is_declare(), @@ -213,7 +222,8 @@ impl<'a> IsolatedDeclarations<'a> { Declaration::TSTypeAliasDeclaration(alias_decl) => { self.visit_ts_type_alias_declaration(alias_decl); if !check_binding || self.scope.has_reference(&alias_decl.id.name) { - Some(self.ast.copy(decl)) + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(unsafe { self.ast.copy(decl) }) } else { None } @@ -221,7 +231,8 @@ impl<'a> IsolatedDeclarations<'a> { Declaration::TSInterfaceDeclaration(interface_decl) => { self.visit_ts_interface_declaration(interface_decl); if !check_binding || self.scope.has_reference(&interface_decl.id.name) { - Some(self.ast.copy(decl)) + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(unsafe { self.ast.copy(decl) }) } else { None } @@ -250,7 +261,8 @@ impl<'a> IsolatedDeclarations<'a> { } Declaration::TSImportEqualsDeclaration(decl) => { if !check_binding || self.scope.has_reference(&decl.id.name) { - Some(Declaration::TSImportEqualsDeclaration(self.ast.copy(decl))) + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(Declaration::TSImportEqualsDeclaration(unsafe { self.ast.copy(decl) })) } else { None } diff --git a/crates/oxc_isolated_declarations/src/enum.rs b/crates/oxc_isolated_declarations/src/enum.rs index 1f077200a21fc6..0e9150b12d02b8 100644 --- a/crates/oxc_isolated_declarations/src/enum.rs +++ b/crates/oxc_isolated_declarations/src/enum.rs @@ -61,7 +61,8 @@ impl<'a> IsolatedDeclarations<'a> { let member = self.ast.ts_enum_member( member.span, - self.ast.copy(&member.id), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&member.id) }, value.map(|v| match v { ConstantValue::Number(v) => { let is_negative = v < 0.0; @@ -94,7 +95,8 @@ impl<'a> IsolatedDeclarations<'a> { Some(self.ast.declaration_ts_enum( decl.span, - self.ast.copy(&decl.id), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.id) }, members, decl.r#const, self.is_declare(), diff --git a/crates/oxc_isolated_declarations/src/formal_parameter_binding_pattern.rs b/crates/oxc_isolated_declarations/src/formal_parameter_binding_pattern.rs index fb1372175af578..0e64905631782b 100644 --- a/crates/oxc_isolated_declarations/src/formal_parameter_binding_pattern.rs +++ b/crates/oxc_isolated_declarations/src/formal_parameter_binding_pattern.rs @@ -9,7 +9,8 @@ pub struct FormalParameterBindingPattern<'a> { impl<'a> VisitMut<'a> for FormalParameterBindingPattern<'a> { fn visit_binding_pattern_kind(&mut self, kind: &mut BindingPatternKind<'a>) { if let BindingPatternKind::AssignmentPattern(assignment) = kind { - *kind = self.ast.copy(&assignment.left.kind); + // SAFETY: `ast.copy` is unsound! We need to fix. + *kind = unsafe { self.ast.copy(&assignment.left.kind) }; } walk_binding_pattern_kind(self, kind); diff --git a/crates/oxc_isolated_declarations/src/function.rs b/crates/oxc_isolated_declarations/src/function.rs index 4f8956e1edb583..ef61db1ad2b6ca 100644 --- a/crates/oxc_isolated_declarations/src/function.rs +++ b/crates/oxc_isolated_declarations/src/function.rs @@ -30,12 +30,15 @@ impl<'a> IsolatedDeclarations<'a> { Some(self.ast.alloc_function( func.r#type, func.span, - self.ast.copy(&func.id), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&func.id) }, false, false, declare.unwrap_or_else(|| self.is_declare()), - self.ast.copy(&func.type_parameters), - self.ast.copy(&func.this_param), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&func.type_parameters) }, + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&func.this_param) }, params, return_type, Option::::None, @@ -61,9 +64,11 @@ impl<'a> IsolatedDeclarations<'a> { let is_assignment_pattern = pattern.kind.is_assignment_pattern(); let mut pattern = if let BindingPatternKind::AssignmentPattern(pattern) = ¶m.pattern.kind { - self.ast.copy(&pattern.left) + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&pattern.left) } } else { - self.ast.copy(¶m.pattern) + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(¶m.pattern) } }; FormalParameterBindingPattern::remove_assignments_from_kind(self.ast, &mut pattern.kind); @@ -72,7 +77,10 @@ impl<'a> IsolatedDeclarations<'a> { let type_annotation = pattern .type_annotation .as_ref() - .map(|type_annotation| self.ast.copy(&type_annotation.type_annotation)) + .map(|type_annotation| { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&type_annotation.type_annotation) } + }) .or_else(|| { // report error for has no type annotation let new_type = self.infer_type_from_formal_parameter(param); @@ -106,7 +114,8 @@ impl<'a> IsolatedDeclarations<'a> { }); pattern = self.ast.binding_pattern( - self.ast.copy(&pattern.kind), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&pattern.kind) }, type_annotation, // if it's assignment pattern, it's optional pattern.optional || (!is_remaining_params_have_required && is_assignment_pattern), @@ -121,7 +130,8 @@ impl<'a> IsolatedDeclarations<'a> { params: &FormalParameters<'a>, ) -> Box<'a, FormalParameters<'a>> { if params.kind.is_signature() || (params.rest.is_none() && params.items.is_empty()) { - return self.ast.alloc(self.ast.copy(params)); + // SAFETY: `ast.copy` is unsound! We need to fix. + return self.ast.alloc(unsafe { self.ast.copy(params) }); } let items = @@ -143,7 +153,8 @@ impl<'a> IsolatedDeclarations<'a> { params.span, FormalParameterKind::Signature, items, - self.ast.copy(¶ms.rest), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(¶ms.rest) }, ) } } diff --git a/crates/oxc_isolated_declarations/src/inferrer.rs b/crates/oxc_isolated_declarations/src/inferrer.rs index 09270b3568ecee..faa3827085b4f8 100644 --- a/crates/oxc_isolated_declarations/src/inferrer.rs +++ b/crates/oxc_isolated_declarations/src/inferrer.rs @@ -32,10 +32,16 @@ impl<'a> IsolatedDeclarations<'a> { _ => None, }, Expression::FunctionExpression(func) => { - self.transform_function_to_ts_type(func).map(|x| self.ast.copy(&x)) + self.transform_function_to_ts_type(func).map(|x| { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&x) } + }) } Expression::ArrowFunctionExpression(func) => { - self.transform_arrow_function_to_ts_type(func).map(|x| self.ast.copy(&x)) + self.transform_arrow_function_to_ts_type(func).map(|x| { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&x) } + }) } Expression::ObjectExpression(expr) => { Some(self.transform_object_expression_to_ts_type(expr, false)) @@ -48,7 +54,8 @@ impl<'a> IsolatedDeclarations<'a> { if expr.type_annotation.is_const_type_reference() { self.transform_expression_to_ts_type(&expr.expression) } else { - Some(self.ast.copy(&expr.type_annotation)) + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(unsafe { self.ast.copy(&expr.type_annotation) }) } } Expression::ClassExpression(expr) => { @@ -64,7 +71,10 @@ impl<'a> IsolatedDeclarations<'a> { Expression::TSSatisfiesExpression(expr) => { self.infer_type_from_expression(&expr.expression) } - Expression::TSTypeAssertion(expr) => Some(self.ast.copy(&expr.type_annotation)), + Expression::TSTypeAssertion(expr) => { + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(unsafe { self.ast.copy(&expr.type_annotation) }) + } Expression::UnaryExpression(expr) => { if Self::can_infer_unary_expression(expr) { self.infer_type_from_expression(&expr.argument) @@ -81,11 +91,15 @@ impl<'a> IsolatedDeclarations<'a> { param: &FormalParameter<'a>, ) -> Option> { if param.pattern.type_annotation.is_some() { - param.pattern.type_annotation.as_ref().map(|x| self.ast.copy(&x.type_annotation)); + param.pattern.type_annotation.as_ref().map(|x| { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&x.type_annotation) } + }); } if let BindingPatternKind::AssignmentPattern(pattern) = ¶m.pattern.kind { if let Some(annotation) = pattern.left.type_annotation.as_ref() { - Some(self.ast.copy(&annotation.type_annotation)) + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(unsafe { self.ast.copy(&annotation.type_annotation) }) } else { if let Expression::TSAsExpression(expr) = &pattern.right { if !expr.type_annotation.is_keyword_or_literal() { @@ -105,7 +119,8 @@ impl<'a> IsolatedDeclarations<'a> { function: &Function<'a>, ) -> Option>> { if function.return_type.is_some() { - return self.ast.copy(&function.return_type); + // SAFETY: `ast.copy` is unsound! We need to fix. + return unsafe { self.ast.copy(&function.return_type) }; } if function.r#async || function.generator { @@ -123,7 +138,8 @@ impl<'a> IsolatedDeclarations<'a> { function: &ArrowFunctionExpression<'a>, ) -> Option>> { if function.return_type.is_some() { - return self.ast.copy(&function.return_type); + // SAFETY: `ast.copy` is unsound! We need to fix. + return unsafe { self.ast.copy(&function.return_type) }; } if function.r#async { diff --git a/crates/oxc_isolated_declarations/src/lib.rs b/crates/oxc_isolated_declarations/src/lib.rs index 8485e01d03833b..db67332a52e694 100644 --- a/crates/oxc_isolated_declarations/src/lib.rs +++ b/crates/oxc_isolated_declarations/src/lib.rs @@ -99,12 +99,15 @@ impl<'a> IsolatedDeclarations<'a> { stmts: &oxc_allocator::Vec<'a, Statement<'a>>, ) -> oxc_allocator::Vec<'a, Statement<'a>> { let mut new_ast_stmts = self.ast.vec::>(); - for stmt in Self::remove_function_overloads_implementation(self.ast.copy(stmts)) { + // SAFETY: `ast.copy` is unsound! We need to fix. + for stmt in Self::remove_function_overloads_implementation(unsafe { self.ast.copy(stmts) }) + { if let Some(decl) = stmt.as_declaration() { if let Some(decl) = self.transform_declaration(decl, false) { new_ast_stmts.push(Statement::from(decl)); } else { - new_ast_stmts.push(Statement::from(self.ast.copy(decl))); + // SAFETY: `ast.copy` is unsound! We need to fix. + new_ast_stmts.push(Statement::from(unsafe { self.ast.copy(decl) })); } } } @@ -127,19 +130,27 @@ impl<'a> IsolatedDeclarations<'a> { // 2. Transform export declarations // 3. Collect all bindings / reference from module declarations // 4. Collect transformed indexes - for stmt in Self::remove_function_overloads_implementation(self.ast.copy(stmts)) { + // SAFETY: `ast.copy` is unsound! We need to fix. + for stmt in Self::remove_function_overloads_implementation(unsafe { self.ast.copy(stmts) }) + { match stmt { match_declaration!(Statement) => { match stmt.to_declaration() { Declaration::VariableDeclaration(decl) => { variables_declarations.push_back( - self.ast.copy(&decl.declarations).into_iter().collect::>(), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.declarations) } + .into_iter() + .collect::>(), ); variable_transformed_indexes.push_back(FxHashSet::default()); } Declaration::UsingDeclaration(decl) => { variables_declarations.push_back( - self.ast.copy(&decl.declarations).into_iter().collect::>(), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.declarations) } + .into_iter() + .collect::>(), ); variable_transformed_indexes.push_back(FxHashSet::default()); } diff --git a/crates/oxc_isolated_declarations/src/module.rs b/crates/oxc_isolated_declarations/src/module.rs index 7abf046faa735b..de6fff1b5b8b79 100644 --- a/crates/oxc_isolated_declarations/src/module.rs +++ b/crates/oxc_isolated_declarations/src/module.rs @@ -44,7 +44,8 @@ impl<'a> IsolatedDeclarations<'a> { .transform_class(decl, Some(false)) .map(|d| (None, ExportDefaultDeclarationKind::ClassDeclaration(d))), ExportDefaultDeclarationKind::TSInterfaceDeclaration(_) => { - Some((None, self.ast.copy(&decl.declaration))) + // SAFETY: `ast.copy` is unsound! We need to fix. + Some((None, unsafe { self.ast.copy(&decl.declaration) })) } expr @ match_expression!(ExportDefaultDeclarationKind) => { let expr = expr.to_expression(); @@ -95,7 +96,8 @@ impl<'a> IsolatedDeclarations<'a> { ) -> Option>> { let specifiers = decl.specifiers.as_ref()?; - let mut specifiers = self.ast.copy(specifiers); + // SAFETY: `ast.copy` is unsound! We need to fix. + let mut specifiers = unsafe { self.ast.copy(specifiers) }; specifiers.retain(|specifier| match specifier { ImportDeclarationSpecifier::ImportSpecifier(specifier) => { self.scope.has_reference(&specifier.local.name) @@ -114,8 +116,10 @@ impl<'a> IsolatedDeclarations<'a> { Some(self.ast.alloc_import_declaration( decl.span, Some(specifiers), - self.ast.copy(&decl.source), - self.ast.copy(&decl.with_clause), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.source) }, + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&decl.with_clause) }, decl.import_kind, )) } diff --git a/crates/oxc_isolated_declarations/src/return_type.rs b/crates/oxc_isolated_declarations/src/return_type.rs index 8702fffe7e4b57..9af88c9f5b30f6 100644 --- a/crates/oxc_isolated_declarations/src/return_type.rs +++ b/crates/oxc_isolated_declarations/src/return_type.rs @@ -157,6 +157,7 @@ impl<'a> Visit<'a> for FunctionReturnType<'a> { return; } } - self.return_expression = Some(self.ast.copy(&stmt.argument)); + // SAFETY: `ast.copy` is unsound! We need to fix. + self.return_expression = Some(unsafe { self.ast.copy(&stmt.argument) }); } } diff --git a/crates/oxc_isolated_declarations/src/types.rs b/crates/oxc_isolated_declarations/src/types.rs index 5647c743907ad8..54a647b9e136f3 100644 --- a/crates/oxc_isolated_declarations/src/types.rs +++ b/crates/oxc_isolated_declarations/src/types.rs @@ -26,10 +26,12 @@ impl<'a> IsolatedDeclarations<'a> { return_type.map(|return_type| { self.ast.ts_type_function_type( func.span, - self.ast.copy(&func.this_param), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&func.this_param) }, params, return_type, - self.ast.copy(&func.type_parameters), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&func.type_parameters) }, ) }) } @@ -55,7 +57,8 @@ impl<'a> IsolatedDeclarations<'a> { None, params, return_type, - self.ast.copy(&func.type_parameters), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&func.type_parameters) }, ) }) } @@ -95,14 +98,17 @@ impl<'a> IsolatedDeclarations<'a> { let params = self.transform_formal_parameters(&function.params); return Some(self.ast.ts_signature_method_signature( object.span, - self.ast.copy(&object.key), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&object.key) }, object.computed, false, TSMethodSignatureKind::Method, - self.ast.copy(&function.this_param), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&function.this_param) }, params, return_type, - self.ast.copy(&function.type_parameters), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&function.type_parameters) }, )); } } @@ -123,7 +129,8 @@ impl<'a> IsolatedDeclarations<'a> { false, false, is_const, - self.ast.copy(&object.key), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(&object.key) }, type_annotation.map(|type_annotation| { self.ast.ts_type_annotation(SPAN, type_annotation) }), @@ -169,18 +176,34 @@ impl<'a> IsolatedDeclarations<'a> { // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions pub fn transform_expression_to_ts_type(&self, expr: &Expression<'a>) -> Option> { match expr { - Expression::BooleanLiteral(lit) => Some( - self.ast.ts_type_literal_type(SPAN, TSLiteral::BooleanLiteral(self.ast.copy(lit))), - ), - Expression::NumericLiteral(lit) => Some( - self.ast.ts_type_literal_type(SPAN, TSLiteral::NumericLiteral(self.ast.copy(lit))), - ), - Expression::BigIntLiteral(lit) => Some( - self.ast.ts_type_literal_type(SPAN, TSLiteral::BigIntLiteral(self.ast.copy(lit))), - ), - Expression::StringLiteral(lit) => Some( - self.ast.ts_type_literal_type(SPAN, TSLiteral::StringLiteral(self.ast.copy(lit))), - ), + Expression::BooleanLiteral(lit) => Some(self.ast.ts_type_literal_type( + SPAN, + TSLiteral::BooleanLiteral({ + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(lit) } + }), + )), + Expression::NumericLiteral(lit) => Some(self.ast.ts_type_literal_type( + SPAN, + TSLiteral::NumericLiteral({ + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(lit) } + }), + )), + Expression::BigIntLiteral(lit) => Some(self.ast.ts_type_literal_type( + SPAN, + TSLiteral::BigIntLiteral({ + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(lit) } + }), + )), + Expression::StringLiteral(lit) => Some(self.ast.ts_type_literal_type( + SPAN, + TSLiteral::StringLiteral({ + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast.copy(lit) } + }), + )), Expression::NullLiteral(lit) => Some(self.ast.ts_type_null_keyword(lit.span)), Expression::Identifier(ident) => match ident.name.as_str() { "undefined" => Some(self.ast.ts_type_undefined_keyword(ident.span)), @@ -195,7 +218,8 @@ impl<'a> IsolatedDeclarations<'a> { if Self::can_infer_unary_expression(expr) { Some(self.ast.ts_type_literal_type( SPAN, - TSLiteral::UnaryExpression(self.ast.copy(expr)), + // SAFETY: `ast.copy` is unsound! We need to fix. + TSLiteral::UnaryExpression(unsafe { self.ast.copy(expr) }), )) } else { None @@ -215,7 +239,8 @@ impl<'a> IsolatedDeclarations<'a> { if expr.type_annotation.is_const_type_reference() { self.transform_expression_to_ts_type(&expr.expression) } else { - Some(self.ast.copy(&expr.type_annotation)) + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(unsafe { self.ast.copy(&expr.type_annotation) }) } } _ => None, diff --git a/crates/oxc_transformer/src/es2015/arrow_functions.rs b/crates/oxc_transformer/src/es2015/arrow_functions.rs index 1aea03547cd860..43fb3cec5fb706 100644 --- a/crates/oxc_transformer/src/es2015/arrow_functions.rs +++ b/crates/oxc_transformer/src/es2015/arrow_functions.rs @@ -184,15 +184,17 @@ impl<'a> ArrowFunctions<'a> { arrow_function_expr: &mut ArrowFunctionExpression<'a>, ctx: &mut TraverseCtx<'a>, ) -> Expression<'a> { - let mut body = self.ctx.ast.copy(&arrow_function_expr.body); + // SAFETY: `ast.copy` is unsound! We need to fix. + let mut body = unsafe { self.ctx.ast.copy(&arrow_function_expr.body) }; if arrow_function_expr.expression { let first_stmt = body.statements.remove(0); if let Statement::ExpressionStatement(stmt) = first_stmt { - let return_statement = self - .ctx - .ast - .statement_return(stmt.span, Some(self.ctx.ast.copy(&stmt.expression))); + let return_statement = self.ctx.ast.statement_return( + stmt.span, + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(unsafe { self.ctx.ast.copy(&stmt.expression) }), + ); body.statements.push(return_statement); } } @@ -222,10 +224,13 @@ impl<'a> ArrowFunctions<'a> { r#async: arrow_function_expr.r#async, declare: false, this_param: None, - params: self.ctx.ast.copy(&arrow_function_expr.params), + // SAFETY: `ast.copy` is unsound! We need to fix. + params: unsafe { self.ctx.ast.copy(&arrow_function_expr.params) }, body: Some(body), - type_parameters: self.ctx.ast.copy(&arrow_function_expr.type_parameters), - return_type: self.ctx.ast.copy(&arrow_function_expr.return_type), + // SAFETY: `ast.copy` is unsound! We need to fix. + type_parameters: unsafe { self.ctx.ast.copy(&arrow_function_expr.type_parameters) }, + // SAFETY: `ast.copy` is unsound! We need to fix. + return_type: unsafe { self.ctx.ast.copy(&arrow_function_expr.return_type) }, scope_id: Cell::new(scope_id), }; diff --git a/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs b/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs index e93ad852b6ae90..0603a734488b32 100644 --- a/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs +++ b/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs @@ -138,7 +138,13 @@ impl<'a> NullishCoalescingOperator<'a> { let op = BinaryOperator::StrictInequality; let null = ctx.ast.expression_null_literal(SPAN); let left = ctx.ast.expression_binary(SPAN, assignment, op, null); - let right = ctx.ast.expression_binary(SPAN, ctx.ast.copy(&reference), op, ctx.ast.void_0()); + let right = ctx.ast.expression_binary( + SPAN, + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { ctx.ast.copy(&reference) }, + op, + ctx.ast.void_0(), + ); let test = ctx.ast.expression_logical(SPAN, left, LogicalOperator::And, right); *expr = ctx.ast.expression_conditional(SPAN, test, reference, logical_expr.right); diff --git a/crates/oxc_transformer/src/react/jsx.rs b/crates/oxc_transformer/src/react/jsx.rs index 8741cddb75cf3e..f4d9c1d502b89b 100644 --- a/crates/oxc_transformer/src/react/jsx.rs +++ b/crates/oxc_transformer/src/react/jsx.rs @@ -523,7 +523,10 @@ impl<'a> ReactJsx<'a> { // deopt if spreading an object with `__proto__` key if !matches!(&spread.argument, Expression::ObjectExpression(o) if o.has_proto()) { - arguments.push(Argument::from(self.ast().copy(&spread.argument))); + arguments.push(Argument::from({ + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast().copy(&spread.argument) } + })); continue; } } @@ -813,10 +816,12 @@ impl<'a> ReactJsx<'a> { } JSXAttributeItem::SpreadAttribute(attr) => match &attr.argument { Expression::ObjectExpression(expr) if !expr.has_proto() => { - properties.extend(self.ast().copy(&expr.properties)); + // SAFETY: `ast.copy` is unsound! We need to fix. + properties.extend(unsafe { self.ast().copy(&expr.properties) }); } expr => { - let argument = self.ast().copy(expr); + // SAFETY: `ast.copy` is unsound! We need to fix. + let argument = unsafe { self.ast().copy(expr) }; let object_property = self.ast().object_property_kind_spread_element(attr.span, argument); properties.push(object_property); @@ -842,7 +847,10 @@ impl<'a> ReactJsx<'a> { self.transform_jsx(&JSXElementOrFragment::Fragment(e), ctx) } Some(JSXAttributeValue::ExpressionContainer(c)) => match &c.expression { - e @ match_expression!(JSXExpression) => self.ast().copy(e.to_expression()), + e @ match_expression!(JSXExpression) => { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ast().copy(e.to_expression()) } + } JSXExpression::EmptyExpression(e) => { self.ast().expression_boolean_literal(e.span, true) } @@ -859,7 +867,10 @@ impl<'a> ReactJsx<'a> { match child { JSXChild::Text(text) => self.transform_jsx_text(text), JSXChild::ExpressionContainer(e) => match &e.expression { - e @ match_expression!(JSXExpression) => Some(self.ast().copy(e.to_expression())), + e @ match_expression!(JSXExpression) => { + // SAFETY: `ast.copy` is unsound! We need to fix. + Some(unsafe { self.ast().copy(e.to_expression()) }) + } JSXExpression::EmptyExpression(_) => None, }, JSXChild::Element(e) => { diff --git a/crates/oxc_transformer/src/typescript/annotations.rs b/crates/oxc_transformer/src/typescript/annotations.rs index 10732afbf50b95..3a98884a4cbd0d 100644 --- a/crates/oxc_transformer/src/typescript/annotations.rs +++ b/crates/oxc_transformer/src/typescript/annotations.rs @@ -216,14 +216,16 @@ impl<'a> TypeScriptAnnotations<'a> { pub fn transform_expression(&mut self, expr: &mut Expression<'a>) { if expr.is_typescript_syntax() { - *expr = self.ctx.ast.copy(expr.get_inner_expression()); + // SAFETY: `ast.copy` is unsound! We need to fix. + *expr = unsafe { self.ctx.ast.copy(expr.get_inner_expression()) }; } } pub fn transform_simple_assignment_target(&mut self, target: &mut SimpleAssignmentTarget<'a>) { if let Some(expr) = target.get_expression() { if let Expression::Identifier(ident) = expr.get_inner_expression() { - let ident = self.ctx.ast.copy(ident); + // SAFETY: `ast.copy` is unsound! We need to fix. + let ident = unsafe { self.ctx.ast.copy(ident) }; *target = SimpleAssignmentTarget::AssignmentTargetIdentifier(ident); } } @@ -232,7 +234,8 @@ impl<'a> TypeScriptAnnotations<'a> { pub fn transform_assignment_target(&mut self, target: &mut AssignmentTarget<'a>) { if let Some(expr) = target.get_expression() { if let Some(member_expr) = expr.get_inner_expression().as_member_expression() { - *target = AssignmentTarget::from(self.ctx.ast.copy(member_expr)); + // SAFETY: `ast.copy` is unsound! We need to fix. + *target = AssignmentTarget::from(unsafe { self.ctx.ast.copy(member_expr) }); } } } diff --git a/crates/oxc_transformer/src/typescript/enum.rs b/crates/oxc_transformer/src/typescript/enum.rs index 66c1ad021de535..08f0821eb579d2 100644 --- a/crates/oxc_transformer/src/typescript/enum.rs +++ b/crates/oxc_transformer/src/typescript/enum.rs @@ -238,7 +238,8 @@ impl<'a> TypeScriptEnum<'a> { let init = match constant_value { None => { prev_constant_value = None; - let mut new_initializer = ast.copy(initializer); + // SAFETY: `ast.copy` is unsound! We need to fix. + let mut new_initializer = unsafe { ast.copy(initializer) }; // If the initializer is a binding identifier, // and it is not a binding in the current scope and parent scopes, diff --git a/crates/oxc_transformer/src/typescript/module.rs b/crates/oxc_transformer/src/typescript/module.rs index 968e476bf8605e..faa3fb511ed82a 100644 --- a/crates/oxc_transformer/src/typescript/module.rs +++ b/crates/oxc_transformer/src/typescript/module.rs @@ -92,7 +92,8 @@ impl<'a> TypeScript<'a> { } else { unreachable!() } - self.ctx.ast.expression_from_identifier_reference(ctx.ast.copy(ident)) + // SAFETY: `ast.copy` is unsound! We need to fix. + self.ctx.ast.expression_from_identifier_reference(unsafe { ctx.ast.copy(ident) }) } TSTypeName::QualifiedName(qualified_name) => self .ctx diff --git a/crates/oxc_transformer/src/typescript/namespace.rs b/crates/oxc_transformer/src/typescript/namespace.rs index e1b4ae0819d019..bb60be96bf8ed7 100644 --- a/crates/oxc_transformer/src/typescript/namespace.rs +++ b/crates/oxc_transformer/src/typescript/namespace.rs @@ -45,9 +45,14 @@ impl<'a> TypeScript<'a> { self.ctx.error(namespace_not_supported(decl.span)); } - if let Some(transformed_stmt) = - self.handle_nested(self.ctx.ast.copy(&decl).unbox(), None, ctx) - { + if let Some(transformed_stmt) = self.handle_nested( + { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ctx.ast.copy(&decl) }.unbox() + }, + None, + ctx, + ) { let name = decl.id.name(); if names.insert(name.clone()) { new_stmts @@ -68,9 +73,14 @@ impl<'a> TypeScript<'a> { self.ctx.error(namespace_not_supported(decl.span)); } - if let Some(transformed_stmt) = - self.handle_nested(self.ctx.ast.copy(decl), None, ctx) - { + if let Some(transformed_stmt) = self.handle_nested( + { + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ctx.ast.copy(decl) } + }, + None, + ctx, + ) { let name = decl.id.name(); if names.insert(name.clone()) { let declaration = self.create_variable_declaration(name); @@ -339,7 +349,9 @@ impl<'a> TypeScript<'a> { // (_N.M = {}) or (N = {}) let mut logical_right = { // _N.M - let assign_left = if let Some(parent_export) = self.ctx.ast.copy(&parent_export) { + // SAFETY: `ast.copy` is unsound! We need to fix. + let parent_export = unsafe { self.ctx.ast.copy(&parent_export) }; + let assign_left = if let Some(parent_export) = parent_export { self.ctx.ast.simple_assignment_target_member_expression( self.ctx.ast.member_expression_static( SPAN, @@ -464,7 +476,8 @@ impl<'a> TypeScript<'a> { ), ) .into(), - self.ctx.ast.copy(init), + // SAFETY: `ast.copy` is unsound! We need to fix. + unsafe { self.ctx.ast.copy(init) }, ), ); }