fix(mangler): no shorthand BindingProperty; handle var hoisting and export variables (#4319)

Trying to pass tests in https://github.com/oxc-project/monitor-oxc
This commit is contained in:
Boshen 2024-07-17 18:12:42 +08:00 committed by GitHub
parent a197e01b5c
commit 3df9e697cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 41 additions and 27 deletions

View file

@ -949,7 +949,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> 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<MINIFY> for ObjectPattern<'a> {
}
}
// NOTE: `shorthand` is not printed
impl<'a, const MINIFY: bool> Gen<MINIFY> 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<MINIFY> for TSTypeLiteral<'a> {
impl<'a, const MINIFY: bool> Gen<MINIFY> 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);

View file

@ -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<T>(p: T, rParam: T, r2: T): void;
export declare function fnDeclBad2<T>(p: T, r2: T): void;
export declare function fnDeclBad3<T>(p: T, rParam?: T, r2: T): void;

View file

@ -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(())

View file

@ -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::<Vec<_>>();
let unresolved_references =
scope_tree.root_unresolved_references().keys().collect::<Vec<_>>();
let mut names = Vec::with_capacity(total_number_of_slots);
@ -195,7 +209,9 @@ impl ManglerBuilder {
) -> Vec<SlotFrequency> {
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;