Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 49 additions & 10 deletions src/js_parser/lower/lower_decorators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ struct SuperLowering<'r> {
is_static: bool,
}

/// Static code emitted after the class. Every relocation site uses `rewrite_relocated_static_*`.
#[derive(Clone, Copy)]
struct RelocatedStatic<'r> {
home: &'r Cell<Option<Ref>>,
class_ref: Ref,
class_loc: bun_ast::Loc,
}

impl<'r> RelocatedStatic<'r> {
/// `LowerSuper` first, so the `this` receivers it emits are replaced along with the user's own.
fn kinds(self) -> [RewriteKind<'r>; 2] {
[
RewriteKind::LowerSuper(SuperLowering {
class_ref: self.home,
is_static: true,
}),
RewriteKind::ReplaceThis {
ref_: self.class_ref,
loc: self.class_loc,
},
]
}
}

// ── Shallow-copy helpers (Property / Class are not `Clone` because they hold
// raw arena pointers; copying the raw pointers is intentional). ──

Expand Down Expand Up @@ -623,6 +647,18 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
self.rewrite_stmts(func.func.body.stmts.slice_mut(), kind);
}

fn rewrite_relocated_static_expr(&mut self, expr: &mut Expr, ctx: RelocatedStatic<'_>) {
for kind in ctx.kinds() {
self.rewrite_expr(expr, kind);
}
}

fn rewrite_relocated_static_stmts(&mut self, stmts: &mut [Stmt], ctx: RelocatedStatic<'_>) {
for kind in ctx.kinds() {
self.rewrite_stmts(stmts, kind);
}
}

/// The key of `super.name` / `super[expr]`; `None` for any other expression.
fn super_member_key(&mut self, expr: Expr, ctx: SuperLowering<'_>) -> Option<Expr> {
match expr.data {
Expand Down Expand Up @@ -1772,6 +1808,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
let mut emitted_private_adds: HashMap<u32, ()> = HashMap::default();
let mut static_private_add_blocks = BumpVec::<Property>::new_in(bump);
let super_home_ref: Cell<Option<Ref>> = Cell::new(None);
let relocated_static = RelocatedStatic {
home: &super_home_ref,
class_ref: class_name_ref,
class_loc: class_name_loc,
};

// Pre-scan: determine if all private members need lowering
let mut lower_all_private = false;
Expand Down Expand Up @@ -2012,7 +2053,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
..Default::default()
});

let init_val = prop
let mut init_val = prop
.initializer
.unwrap_or_else(|| p.new_expr(E::Undefined {}, loc));
if !prop.flags.contains(Flags::Property::IsStatic) {
Expand All @@ -2027,6 +2068,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
loc,
));
} else {
p.rewrite_relocated_static_expr(&mut init_val, relocated_static);
let cn_e = p.use_ref(class_name_ref, class_name_loc);
let wm_e3 = p.use_ref(wm_ref, loc);
suffix_exprs.push(p.call_rt(
Expand All @@ -2039,7 +2081,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
}
// Static blocks → extract to suffix
if prop.kind == PropertyKind::ClassStaticBlock {
if let Some(sb) = prop.class_static_block {
if let Some(mut sb) = prop.class_static_block {
p.rewrite_relocated_static_stmts(sb.stmts.slice_mut(), relocated_static);
static_element_order.push(StaticElement {
kind: StaticElementKind::Block,
index: extracted_static_blocks.len(),
Expand Down Expand Up @@ -2305,13 +2348,16 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
}

let is_accessor = k == 4;
let init_entry = FieldInitEntry {
let mut init_entry = FieldInitEntry {
prop: prop_shallow,
is_private,
is_accessor,
};

if prop.flags.contains(Flags::Property::IsStatic) {
if let Some(init) = &mut init_entry.prop.initializer {
p.rewrite_relocated_static_expr(init, relocated_static);
}
if is_accessor {
static_non_field_elements.push(element);
static_accessor_count += 1;
Expand Down Expand Up @@ -2509,13 +2555,6 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
// `StoreRef::DerefMut` — arena-owned, safe under the StoreRef invariant.
let sb = &mut *extracted_static_blocks[elem.index];
let stmts_slice = sb.stmts.slice_mut();
p.rewrite_stmts(
stmts_slice,
RewriteKind::ReplaceThis {
ref_: class_name_ref,
loc: class_name_loc,
},
);

let all_exprs = stmts_slice
.iter()
Expand Down
Loading