fix(transformer): emit design:paramtypes when class has static anonymous class expression (#20382)

related https://github.com/rolldown/rolldown/discussions/8684

Fix `design:paramtypes` being silently dropped in release builds when a
decorated class has static properties with anonymous class expression
initializers (`static Foo = class extends Error
  {}`).

`pop_constructor_metadata()` was inside `debug_assert!`, which is a
no-op in release builds, causing stack imbalance and missing metadata.

---------

Co-authored-by: Dunqing <dengqing0821@gmail.com>
This commit is contained in:
babandDunqing authored and GitHub committed 2026-03-15 22:10:43 +08:00
1 parent fa70d5c283
commit 1f65c3f181
4 files changed
+48 -6

No files matched your search

@@ -507,10 +507,13 @@ impl<'a> LegacyDecorator<'a> {
);
}
debug_assert!(
!self.emit_decorator_metadata || self.metadata.pop_constructor_metadata().is_none(),
"`pop_constructor_metadata` should be `None` because there are no class decorators, so no metadata was generated."
);
if self.emit_decorator_metadata {
let metadata = self.metadata.pop_constructor_metadata();
debug_assert!(
metadata.is_none(),
"`pop_constructor_metadata` should be `None` because there are no class decorators, so no metadata was generated."
);
}
}
/// Transforms a decorated class declaration and appends the resulting statements. If
@@ -1,6 +1,6 @@
commit: 87a048db
Passed: 204/336
Passed: 204/337
# All Passed:
* babel-plugin-transform-class-static-block
@@ -555,7 +555,7 @@ x Output mismatch
x Output mismatch
# legacy-decorators (6/87)
# legacy-decorators (6/88)
* oxc/class-without-name-with-decorated_class/input.ts
Bindings mismatch:
after transform: ScopeId(0): ["dec"]
@@ -854,6 +854,26 @@ Unresolved reference IDs mismatch for "babelHelpers":
after transform: [ReferenceId(7), ReferenceId(8), ReferenceId(9), ReferenceId(11), ReferenceId(13), ReferenceId(17), ReferenceId(18), ReferenceId(19), ReferenceId(20), ReferenceId(22), ReferenceId(24)]
rebuilt : [ReferenceId(0), ReferenceId(3), ReferenceId(5), ReferenceId(6), ReferenceId(8), ReferenceId(9), ReferenceId(12), ReferenceId(14), ReferenceId(16)]
* oxc/metadata/static-anonymous-class-expression/input.ts
Bindings mismatch:
after transform: ScopeId(0): ["A", "Foo", "_ref", "dec"]
rebuilt : ScopeId(0): ["A", "Foo", "_ref"]
Symbol reference IDs mismatch for "A":
after transform: SymbolId(1): [ReferenceId(4), ReferenceId(5), ReferenceId(6)]
rebuilt : SymbolId(1): [ReferenceId(7), ReferenceId(8)]
Symbol span mismatch for "Foo":
after transform: SymbolId(2): Span { start: 72, end: 75 }
rebuilt : SymbolId(2): Span { start: 0, end: 0 }
Symbol span mismatch for "Foo":
after transform: SymbolId(5): Span { start: 0, end: 0 }
rebuilt : SymbolId(3): Span { start: 72, end: 75 }
Reference symbol mismatch for "dec":
after transform: SymbolId(0) "dec"
rebuilt : <None>
Unresolved references mismatch:
after transform: ["ClassDecorator", "Error", "Object", "babelHelpers"]
rebuilt : ["Error", "Object", "babelHelpers", "dec"]
* oxc/metadata/this/input.ts
Symbol span mismatch for "Example":
after transform: SymbolId(0): Span { start: 6, end: 13 }
@@ -0,0 +1,10 @@
declare function dec(): ClassDecorator;
class A {}
@dec()
export class Foo {
static Error1 = class extends Error {};
static Error2 = class extends Error {};
constructor(a: A) {}
}
@@ -0,0 +1,9 @@
var _ref;
class A {}
let Foo = class Foo {
static Error1 = class extends Error {};
static Error2 = class extends Error {};
constructor(a) {}
};
Foo = babelHelpers.decorate([dec(), babelHelpers.decorateMetadata("design:paramtypes", [typeof (_ref = typeof A !== "undefined" && A) === "function" ? _ref : Object])], Foo);
export { Foo };