Summary
#6470 (be2e23f86, "per-evaluation captures for class declarations in function bodies") regressed class .name for a captured-param class-declaration factory. A named class declared inside a factory function that captures an outer parameter now reports .name === undefined instead of its declared name.
Repro
function makeTagged(tag: string) {
class Inner {
readonly _tag = tag; // captures the outer `tag` param
who() { return "tagged:" + this._tag; }
}
return Inner;
}
const T = makeTagged("S");
console.log(JSON.stringify(T.name)); // node: "Inner" perry(main): undefined
console.log(new T().who()); // node: "tagged:S" perry: "tagged:S" (construction is fine)
Construction, the captured field, and method dispatch all work — only .name is lost. Covered by the existing gap test test_gap_5952_mixin_factory_binding (case 7), which now fails on main.
Bisect
Mechanism
For a capturing class declaration with no static state, #6470 sets fresh_binding = true and binds the name to a ClassExprFresh per-evaluation object (lower_decl/body_stmt.rs). The fresh object gets the right class_id (so methods/construction work), but its class_id is never entered into the CLASS_NAMES registry: name registration (codegen/string_pool.rs → js_register_class_name) only fires for class_ids collected into named_classes, and this fresh-factory template ends up excluded (classified anon / name-mismatched). .name then resolves via class_name_for_id(class_id) → None → undefined. Named class expressions through the same ClassExprFresh machinery keep their name, so the gap is specific to the declaration route + the specialize_captured_class_factories interaction.
Impact
Blocks conformance-smoke (shard containing test_gap_5952) on every PR branched off current main — surfaced while merging #6476 (unrelated streams PR). Mixin/class-factory patterns that read .name (incl. effect-style tagged classes) are affected.
Summary
#6470(be2e23f86, "per-evaluation captures for class declarations in function bodies") regressed class.namefor a captured-param class-declaration factory. A namedclassdeclared inside a factory function that captures an outer parameter now reports.name === undefinedinstead of its declared name.Repro
Construction, the captured field, and method dispatch all work — only
.nameis lost. Covered by the existing gap testtest_gap_5952_mixin_factory_binding(case 7), which now fails onmain.Bisect
b4b47ba34(parent of fix(hir): per-evaluation captures for class declarations in function bodies (#6465) #6470)be2e23f86(fix(hir): per-evaluation captures for class declarations in function bodies (#6465) #6470) and every commit since (confirmed on currentmain)Mechanism
For a capturing class declaration with no static state, #6470 sets
fresh_binding = trueand binds the name to aClassExprFreshper-evaluation object (lower_decl/body_stmt.rs). The fresh object gets the rightclass_id(so methods/construction work), but itsclass_idis never entered into theCLASS_NAMESregistry: name registration (codegen/string_pool.rs→js_register_class_name) only fires for class_ids collected intonamed_classes, and this fresh-factory template ends up excluded (classified anon / name-mismatched)..namethen resolves viaclass_name_for_id(class_id)→None→undefined. Named class expressions through the sameClassExprFreshmachinery keep their name, so the gap is specific to the declaration route + thespecialize_captured_class_factoriesinteraction.Impact
Blocks conformance-smoke (shard containing
test_gap_5952) on every PR branched off current main — surfaced while merging #6476 (unrelated streams PR). Mixin/class-factory patterns that read.name(incl. effect-style tagged classes) are affected.