From 3df9e697ccf1944359edf3b94fe569eb5a00b364 Mon Sep 17 00:00:00 2001 From: Boshen Date: Wed, 17 Jul 2024 18:12:42 +0800 Subject: [PATCH] fix(mangler): no shorthand `BindingProperty`; handle var hoisting and export variables (#4319) Trying to pass tests in https://github.com/oxc-project/monitor-oxc --- crates/oxc_codegen/src/gen.rs | 17 ++++---- .../tests/snapshots/function-parameters.snap | 4 +- crates/oxc_mangler/examples/mangler.rs | 5 ++- crates/oxc_mangler/src/lib.rs | 42 +++++++++++++------ 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 9b170ed688a78..0d56a6fa01300 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -949,7 +949,7 @@ impl<'a, const MINIFY: bool> Gen for ModuleExportName<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { Self::IdentifierName(identifier) => p.print_str(identifier.name.as_str()), - Self::IdentifierReference(identifier) => p.print_str(identifier.name.as_str()), + Self::IdentifierReference(identifier) => identifier.gen(p, ctx), Self::StringLiteral(literal) => literal.gen(p, ctx), }; } @@ -2538,22 +2538,19 @@ impl<'a, const MINIFY: bool> Gen for ObjectPattern<'a> { } } +// NOTE: `shorthand` is not printed impl<'a, const MINIFY: bool> Gen for BindingProperty<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.add_source_mapping(self.span.start); if self.computed { p.print_char(b'['); } - if !self.shorthand { - self.key.gen(p, ctx); - } + self.key.gen(p, ctx); if self.computed { p.print_char(b']'); } - if !self.shorthand { - p.print_colon(); - p.print_soft_space(); - } + p.print_colon(); + p.print_soft_space(); self.value.gen(p, ctx); } } @@ -2959,8 +2956,8 @@ impl<'a, const MINIFY: bool> Gen for TSTypeLiteral<'a> { impl<'a, const MINIFY: bool> Gen for TSTypeName<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { - Self::IdentifierReference(decl) => { - p.print_str(decl.name.as_str()); + Self::IdentifierReference(ident) => { + ident.gen(p, ctx); } Self::QualifiedName(decl) => { decl.left.gen(p, ctx); diff --git a/crates/oxc_isolated_declarations/tests/snapshots/function-parameters.snap b/crates/oxc_isolated_declarations/tests/snapshots/function-parameters.snap index c006d77d4c613..ab84d4ebf1128 100644 --- a/crates/oxc_isolated_declarations/tests/snapshots/function-parameters.snap +++ b/crates/oxc_isolated_declarations/tests/snapshots/function-parameters.snap @@ -7,8 +7,8 @@ input_file: crates/oxc_isolated_declarations/tests/fixtures/function-parameters. export declare function fnDeclGood(p?: T, rParam?: string): void; export declare function fnDeclGood2(p?: T, rParam?: number): void; export declare function fooGood([a, b]?: any[]): number; -export declare const fooGood2: ({ a, b }?: object) => number; -export declare function fooGood3({ a, b: [{ c }] }: object): void; +export declare const fooGood2: ({ a: a, b: b }?: object) => number; +export declare function fooGood3({ a: a, b: [{ c: c }] }: object): void; export declare function fnDeclBad(p: T, rParam: T, r2: T): void; export declare function fnDeclBad2(p: T, r2: T): void; export declare function fnDeclBad3(p: T, rParam?: T, r2: T): void; diff --git a/crates/oxc_mangler/examples/mangler.rs b/crates/oxc_mangler/examples/mangler.rs index 775636ef16f08..4b01f782e999a 100644 --- a/crates/oxc_mangler/examples/mangler.rs +++ b/crates/oxc_mangler/examples/mangler.rs @@ -27,8 +27,9 @@ fn main() -> std::io::Result<()> { println!("{printed}"); if twice { - let printed = mangler(&printed, source_type, debug); - println!("{printed}"); + let printed2 = mangler(&printed, source_type, debug); + println!("{printed2}"); + println!("same = {}", printed == printed2); } Ok(()) diff --git a/crates/oxc_mangler/src/lib.rs b/crates/oxc_mangler/src/lib.rs index 98e3ae1b3294e..2b5c23576023a 100644 --- a/crates/oxc_mangler/src/lib.rs +++ b/crates/oxc_mangler/src/lib.rs @@ -77,8 +77,7 @@ impl ManglerBuilder { #[must_use] pub fn build<'a>(self, program: &'a Program<'a>) -> Mangler { - let semantic_ret = SemanticBuilder::new("", program.source_type).build(program); - let semantic = semantic_ret.semantic; + let semantic = SemanticBuilder::new("", program.source_type).build(program).semantic; // Mangle the symbol table by computing slots from the scope tree. // A slot is the occurrence index of a binding identifier inside a scope. @@ -96,6 +95,7 @@ impl ManglerBuilder { // Walk the scope tree and compute the slot number for each scope for scope_id in scope_tree.descendants_from_root() { let bindings = scope_tree.get_bindings(scope_id); + // The current slot number is continued by the maximum slot from the parent scope let parent_max_slot = scope_tree .get_parent_id(scope_id) @@ -103,10 +103,28 @@ impl ManglerBuilder { let mut slot = parent_max_slot; - // `bindings` are stored in order, traverse and increment slot - for symbol_id in bindings.values() { - slots[*symbol_id] = slot; - slot += 1; + if !bindings.is_empty() { + let mut parent_bindings = None; + + // `bindings` are stored in order, traverse and increment slot + for symbol_id in bindings.values() { + // omit var hoisting because var symbols are added to every parent scope + if symbol_table.get_flag(*symbol_id).is_function_scoped_declaration() + && parent_bindings.is_none() + { + parent_bindings = scope_tree + .get_parent_id(scope_id) + .map(|parent_scope_id| scope_tree.get_bindings(parent_scope_id)); + } + if let Some(parent_bindings) = &parent_bindings { + if parent_bindings.values().contains(symbol_id) { + continue; + } + } + + slots[*symbol_id] = slot; + slot += 1; + } } max_slot_for_scope[scope_id.index()] = slot; @@ -119,12 +137,8 @@ impl ManglerBuilder { let frequencies = Self::tally_slot_frequencies(&symbol_table, total_number_of_slots, &slots); - let unresolved_references = scope_tree - .root_unresolved_references() - .keys() - // It is unlike to get a 5 letter mangled identifier, which is a lot of slots. - // .filter(|name| name.len() < 5) - .collect::>(); + let unresolved_references = + scope_tree.root_unresolved_references().keys().collect::>(); let mut names = Vec::with_capacity(total_number_of_slots); @@ -195,7 +209,9 @@ impl ManglerBuilder { ) -> Vec { let mut frequencies = vec![SlotFrequency::default(); total_number_of_slots]; for (symbol_id, slot) in slots.iter_enumerated() { - if !symbol_table.get_flag(symbol_id).is_variable() { + let symbol_flag = symbol_table.get_flag(symbol_id); + // omit renaming `export { x }` + if !symbol_flag.is_variable() || symbol_flag.is_export() { continue; } let index = *slot;