Skip to content

Commit

Permalink
lowering: always propagate class expression names
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed May 15, 2024
1 parent 90acd14 commit bd0b13b
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 152 deletions.
14 changes: 7 additions & 7 deletions internal/bundler_tests/snapshots/snapshots_lower.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2298,20 +2298,20 @@ _foo = new WeakMap();
================================================================================
TestLowerPrivateClassExpr2020NoBundle
---------- /out.js ----------
var _field, _instances, method_fn, _a, _staticField, _static, staticMethod_fn;
var _field, _Foo_instances, method_fn, _a, _staticField, _Foo_static, staticMethod_fn;
export let Foo = (_a = class {
constructor() {
__privateAdd(this, _instances);
__privateAdd(this, _Foo_instances);
__privateAdd(this, _field);
}
foo() {
var _a2;
__privateSet(this, _field, __privateMethod(this, _instances, method_fn).call(this));
__privateSet(Foo, _staticField, __privateMethod(_a2 = Foo, _static, staticMethod_fn).call(_a2));
__privateSet(this, _field, __privateMethod(this, _Foo_instances, method_fn).call(this));
__privateSet(Foo, _staticField, __privateMethod(_a2 = Foo, _Foo_static, staticMethod_fn).call(_a2));
}
}, _field = new WeakMap(), _instances = new WeakSet(), method_fn = function() {
}, _staticField = new WeakMap(), _static = new WeakSet(), staticMethod_fn = function() {
}, __privateAdd(_a, _static), __privateAdd(_a, _staticField), _a);
}, _field = new WeakMap(), _Foo_instances = new WeakSet(), method_fn = function() {
}, _staticField = new WeakMap(), _Foo_static = new WeakSet(), staticMethod_fn = function() {
}, __privateAdd(_a, _Foo_static), __privateAdd(_a, _staticField), _a);

================================================================================
TestLowerPrivateClassFieldOrder
Expand Down
6 changes: 3 additions & 3 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -10158,7 +10158,7 @@ func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_
result := p.visitClass(s.Value.Loc, &s2.Class, s.DefaultName.Ref, "default")

// Lower class field syntax for browsers that don't support it
classStmts, _ := p.lowerClass(stmt, js_ast.Expr{}, result)
classStmts, _ := p.lowerClass(stmt, js_ast.Expr{}, result, "")

// Remember if the class was side-effect free before lowering
if result.canBeRemovedIfUnused {
Expand Down Expand Up @@ -10856,7 +10856,7 @@ func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_
}

// Lower class field syntax for browsers that don't support it
classStmts, _ := p.lowerClass(stmt, js_ast.Expr{}, result)
classStmts, _ := p.lowerClass(stmt, js_ast.Expr{}, result, "")

// Remember if the class was side-effect free before lowering
if result.canBeRemovedIfUnused {
Expand Down Expand Up @@ -15099,7 +15099,7 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
result := p.visitClass(expr.Loc, &e.Class, ast.InvalidRef, nameToKeep)

// Lower class field syntax for browsers that don't support it
_, expr = p.lowerClass(js_ast.Stmt{}, expr, result)
_, expr = p.lowerClass(js_ast.Stmt{}, expr, result, nameToKeep)

// We may be able to determine that a class is side-effect before lowering
// but not after lowering (e.g. due to "--keep-names" mutating the object).
Expand Down
32 changes: 15 additions & 17 deletions internal/js_parser/js_parser_lower_class.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,12 +623,12 @@ const (
)

type lowerClassContext struct {
optionalNameHint string
kind classKind
class *js_ast.Class
classLoc logger.Loc
classExpr js_ast.Expr // Only for "kind == classKindExpr", may be replaced by "nameFunc()"
defaultName ast.LocRef
nameToKeep string
kind classKind
class *js_ast.Class
classLoc logger.Loc
classExpr js_ast.Expr // Only for "kind == classKindExpr", may be replaced by "nameFunc()"
defaultName ast.LocRef

ctor *js_ast.EFunction
parameterFields []js_ast.Stmt
Expand Down Expand Up @@ -679,8 +679,9 @@ type lowerClassContext struct {
// body (e.g. the contents of initializers, methods, and static blocks). Those
// have already been transformed by "visitClass" by this point. It's done that
// way for performance so that we don't need to do another AST pass.
func (p *parser) lowerClass(stmt js_ast.Stmt, expr js_ast.Expr, result visitClassResult) ([]js_ast.Stmt, js_ast.Expr) {
func (p *parser) lowerClass(stmt js_ast.Stmt, expr js_ast.Expr, result visitClassResult, nameToKeep string) ([]js_ast.Stmt, js_ast.Expr) {
ctx := lowerClassContext{
nameToKeep: nameToKeep,
decoratorContextRef: ast.InvalidRef,
privateInstanceMethodRef: ast.InvalidRef,
privateStaticMethodRef: ast.InvalidRef,
Expand All @@ -694,7 +695,7 @@ func (p *parser) lowerClass(stmt js_ast.Stmt, expr js_ast.Expr, result visitClas
ctx.kind = classKindExpr
if ctx.class.Name != nil {
symbol := &p.symbols[ctx.class.Name.Ref.InnerIndex]
ctx.optionalNameHint = symbol.OriginalName
ctx.nameToKeep = symbol.OriginalName

// The inner class name inside the class expression should be the same as
// the class expression name itself
Expand All @@ -708,13 +709,10 @@ func (p *parser) lowerClass(stmt js_ast.Stmt, expr js_ast.Expr, result visitClas
ctx.class.Name = nil
}
}
if p.nameToKeepIsFor == e {
ctx.optionalNameHint = p.nameToKeep
}
} else if s, ok := stmt.Data.(*js_ast.SClass); ok {
ctx.class = &s.Class
if ctx.class.Name != nil {
ctx.optionalNameHint = p.symbols[ctx.class.Name.Ref.InnerIndex].OriginalName
ctx.nameToKeep = p.symbols[ctx.class.Name.Ref.InnerIndex].OriginalName
}
if s.IsExport {
ctx.kind = classKindExportStmt
Expand All @@ -726,7 +724,7 @@ func (p *parser) lowerClass(stmt js_ast.Stmt, expr js_ast.Expr, result visitClas
s2, _ := s.Value.Data.(*js_ast.SClass)
ctx.class = &s2.Class
if ctx.class.Name != nil {
ctx.optionalNameHint = p.symbols[ctx.class.Name.Ref.InnerIndex].OriginalName
ctx.nameToKeep = p.symbols[ctx.class.Name.Ref.InnerIndex].OriginalName
}
ctx.defaultName = s.DefaultName
ctx.kind = classKindExportDefaultStmt
Expand Down Expand Up @@ -987,8 +985,8 @@ func (ctx *lowerClassContext) lowerPrivateMethod(p *parser, prop js_ast.Property
} else {
name = "_instances"
}
if ctx.optionalNameHint != "" {
name = fmt.Sprintf("_%s%s", ctx.optionalNameHint, name)
if ctx.nameToKeep != "" {
name = fmt.Sprintf("_%s%s", ctx.nameToKeep, name)
}
*ref = p.generateTempRef(tempRefNeedsDeclare, name)

Expand Down Expand Up @@ -1486,7 +1484,7 @@ func (ctx *lowerClassContext) processProperties(p *parser, classLoweringInfo cla
// Evaluate the decorator expressions inline
if p.options.unsupportedJSFeatures.Has(compat.Decorators) && len(ctx.class.Decorators) > 0 &&
(!p.options.ts.Parse || p.options.ts.Config.ExperimentalDecorators != config.True) {
name := ctx.optionalNameHint
name := ctx.nameToKeep
if name == "" {
name = "class"
}
Expand Down Expand Up @@ -2092,7 +2090,7 @@ func (ctx *lowerClassContext) finishAndGenerateCode(p *parser, result visitClass
decorateClassExpr = p.callRuntime(ctx.classLoc, "__decorateElement", []js_ast.Expr{
{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},
{Loc: ctx.classLoc, Data: &js_ast.ENumber{Value: 0}},
{Loc: ctx.classLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(ctx.optionalNameHint)}},
{Loc: ctx.classLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(ctx.nameToKeep)}},
classDecorators,
ctx.nameFunc(),
})
Expand Down
Loading

0 comments on commit bd0b13b

Please sign in to comment.