Skip to content

Commit b7dcb95

Browse files
committed
transform: reuse lowerField for auto-accessors
1 parent b24180e commit b7dcb95

File tree

1 file changed

+31
-97
lines changed

1 file changed

+31
-97
lines changed

internal/js_parser/js_parser_lower_class.go

Lines changed: 31 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,9 @@ func (ctx *lowerClassContext) lowerField(
823823
shouldOmitFieldInitializer bool,
824824
staticFieldToBlockAssign bool,
825825
initializerIndex int,
826-
) (js_ast.Property, bool) {
826+
) (js_ast.Property, ast.Ref, bool) {
827827
mustLowerPrivate := private != nil && p.privateSymbolNeedsToBeLowered(private)
828+
ref := ast.InvalidRef
828829

829830
// The TypeScript compiler doesn't follow the JavaScript spec for
830831
// uninitialized fields. They are supposed to be set to undefined but the
@@ -872,7 +873,7 @@ func (ctx *lowerClassContext) lowerField(
872873
var memberExpr js_ast.Expr
873874
if mustLowerPrivate {
874875
// Generate a new symbol for this private field
875-
ref := p.generateTempRef(tempRefNeedsDeclare, "_"+p.symbols[private.Ref.InnerIndex].OriginalName[1:])
876+
ref = p.generateTempRef(tempRefNeedsDeclare, "_"+p.symbols[private.Ref.InnerIndex].OriginalName[1:])
876877
p.symbols[private.Ref.InnerIndex].Link = ref
877878

878879
// Initialize the private field to a new WeakMap
@@ -949,7 +950,7 @@ func (ctx *lowerClassContext) lowerField(
949950
{Loc: loc, Data: &js_ast.SExpr{Value: memberExpr}}},
950951
},
951952
},
952-
}, true
953+
}, ref, true
953954
} else {
954955
// Move this property to an assignment after the class ends
955956
ctx.staticMembers = append(ctx.staticMembers, memberExpr)
@@ -962,12 +963,12 @@ func (ctx *lowerClassContext) lowerField(
962963

963964
if private == nil || mustLowerPrivate {
964965
// Remove the field from the class body
965-
return js_ast.Property{}, false
966+
return js_ast.Property{}, ref, false
966967
}
967968

968969
// Keep the private field but remove the initializer
969970
prop.InitializerOrNil = js_ast.Expr{}
970-
return prop, true
971+
return prop, ref, true
971972
}
972973

973974
func (ctx *lowerClassContext) lowerPrivateMethod(p *parser, prop js_ast.Property, private *js_ast.EPrivateIdentifier) {
@@ -1180,19 +1181,17 @@ func (ctx *lowerClassContext) analyzeProperty(p *parser, prop js_ast.Property, c
11801181
return
11811182
}
11821183

1183-
func (p *parser) propertyNameHint(key js_ast.Expr, suffix string) string {
1184-
var text string
1184+
func (p *parser) propertyNameHint(key js_ast.Expr) string {
11851185
switch k := key.Data.(type) {
11861186
case *js_ast.EString:
1187-
text = helpers.UTF16ToString(k.Value)
1187+
return helpers.UTF16ToString(k.Value)
11881188
case *js_ast.EIdentifier:
1189-
text = p.symbols[k.Ref.InnerIndex].OriginalName
1189+
return p.symbols[k.Ref.InnerIndex].OriginalName
11901190
case *js_ast.EPrivateIdentifier:
1191-
text = p.symbols[k.Ref.InnerIndex].OriginalName[1:]
1191+
return p.symbols[k.Ref.InnerIndex].OriginalName[1:]
11921192
default:
1193-
return suffix
1193+
return ""
11941194
}
1195-
return fmt.Sprintf("_%s%s", text, suffix)
11961195
}
11971196

11981197
func (ctx *lowerClassContext) hoistComputedProperties(p *parser, classLoweringInfo classLoweringInfo) (
@@ -1234,7 +1233,12 @@ func (ctx *lowerClassContext) hoistComputedProperties(p *parser, classLoweringIn
12341233
// Evaluate the decorator expressions inline before computed property keys
12351234
var decorators js_ast.Expr
12361235
if len(analysis.propDecorators) > 0 {
1237-
ref := p.generateTempRef(tempRefNeedsDeclare, p.propertyNameHint(prop.Key, "_dec"))
1236+
name := p.propertyNameHint(prop.Key)
1237+
if name != "" {
1238+
name = "_" + name
1239+
}
1240+
name += "_dec"
1241+
ref := p.generateTempRef(tempRefNeedsDeclare, name)
12381242
values := make([]js_ast.Expr, len(analysis.propDecorators))
12391243
for i, decorator := range analysis.propDecorators {
12401244
values[i] = decorator.Value
@@ -1676,16 +1680,20 @@ func (ctx *lowerClassContext) processProperties(p *parser, classLoweringInfo cla
16761680
args = append(args, ctx.nameFunc())
16771681
}
16781682

1679-
autoAccessorWeakMapRef := ast.InvalidRef
1683+
// Auto-accessors will generate a private field for storage. Lower this
1684+
// field, which will generate a WeakMap instance, and then pass the
1685+
// WeakMap instance into the decorator helper so the lowered getter and
1686+
// setter can use it.
16801687
if prop.Kind == js_ast.PropertyAutoAccessor {
1681-
// Initialize the private field to a new WeakMap
1682-
if p.weakMapRef == ast.InvalidRef {
1683-
p.weakMapRef = p.newSymbol(ast.SymbolUnbound, "WeakMap")
1684-
p.moduleScope.Generated = append(p.moduleScope.Generated, p.weakMapRef)
1688+
var kind ast.SymbolKind
1689+
if prop.Flags.Has(js_ast.PropertyIsStatic) {
1690+
kind = ast.SymbolPrivateStaticField
1691+
} else {
1692+
kind = ast.SymbolPrivateField
16851693
}
1686-
1687-
// Pass the WeakMap instance into the decorator helper
1688-
autoAccessorWeakMapRef = p.generateTempRef(tempRefNeedsDeclare, p.propertyNameHint(prop.Key, ""))
1694+
ref := p.newSymbol(kind, "#"+p.propertyNameHint(prop.Key))
1695+
p.symbols[ref.InnerIndex].Flags |= ast.PrivateSymbolMustBeLowered
1696+
_, autoAccessorWeakMapRef, _ := ctx.lowerField(p, prop, &js_ast.EPrivateIdentifier{Ref: ref}, false, false, initializerIndex)
16891697
args = append(args, js_ast.Expr{Loc: keyLoc, Data: &js_ast.EIdentifier{Ref: autoAccessorWeakMapRef}})
16901698
p.recordUsage(autoAccessorWeakMapRef)
16911699
}
@@ -1739,80 +1747,6 @@ func (ctx *lowerClassContext) processProperties(p *parser, classLoweringInfo cla
17391747

17401748
// Omit decorated auto-accessors as they will be now generated at run-time instead
17411749
if prop.Kind == js_ast.PropertyAutoAccessor {
1742-
// Determine where to store the field
1743-
var target js_ast.Expr
1744-
if prop.Flags.Has(js_ast.PropertyIsStatic) && !analysis.staticFieldToBlockAssign {
1745-
target = ctx.nameFunc()
1746-
} else {
1747-
target = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}
1748-
}
1749-
1750-
// Generate the assignment initializer
1751-
var init js_ast.Expr
1752-
if prop.InitializerOrNil.Data != nil {
1753-
init = prop.InitializerOrNil
1754-
} else {
1755-
init = js_ast.Expr{Loc: loc, Data: js_ast.EUndefinedShared}
1756-
}
1757-
1758-
// Optionally call registered decorator initializers
1759-
if initializerIndex != -1 {
1760-
var value js_ast.Expr
1761-
if prop.Flags.Has(js_ast.PropertyIsStatic) {
1762-
value = ctx.nameFunc()
1763-
} else {
1764-
value = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}
1765-
}
1766-
args := []js_ast.Expr{
1767-
{Loc: loc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},
1768-
{Loc: loc, Data: &js_ast.ENumber{Value: float64((3 + 2*initializerIndex) << 1)}},
1769-
value,
1770-
}
1771-
if _, ok := init.Data.(*js_ast.EUndefined); !ok {
1772-
args = append(args, init)
1773-
}
1774-
init = p.callRuntime(init.Loc, "__runInitializers", args)
1775-
p.recordUsage(ctx.decoratorContextRef)
1776-
}
1777-
1778-
// Initialize the private field to a new WeakMap
1779-
ctx.privateMembers = append(ctx.privateMembers, js_ast.Assign(
1780-
js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: autoAccessorWeakMapRef}},
1781-
js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.ENew{Target: js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: p.weakMapRef}}}},
1782-
))
1783-
p.recordUsage(autoAccessorWeakMapRef)
1784-
1785-
// Add every newly-constructed instance into this map
1786-
key := js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: autoAccessorWeakMapRef}}
1787-
args := []js_ast.Expr{target, key}
1788-
if _, ok := init.Data.(*js_ast.EUndefined); !ok {
1789-
args = append(args, init)
1790-
}
1791-
memberExpr := p.callRuntime(loc, "__privateAdd", args)
1792-
p.recordUsage(autoAccessorWeakMapRef)
1793-
1794-
// Run extra initializers
1795-
if initializerIndex != -1 {
1796-
var value js_ast.Expr
1797-
if prop.Flags.Has(js_ast.PropertyIsStatic) {
1798-
value = ctx.nameFunc()
1799-
} else {
1800-
value = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}
1801-
}
1802-
memberExpr = js_ast.JoinWithComma(memberExpr, p.callRuntime(loc, "__runInitializers", []js_ast.Expr{
1803-
{Loc: loc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},
1804-
{Loc: loc, Data: &js_ast.ENumber{Value: float64(((4 + 2*initializerIndex) << 1) | 1)}},
1805-
value,
1806-
}))
1807-
p.recordUsage(ctx.decoratorContextRef)
1808-
}
1809-
1810-
if prop.Flags.Has(js_ast.PropertyIsStatic) {
1811-
ctx.staticMembers = append(ctx.staticMembers, memberExpr)
1812-
} else {
1813-
ctx.instanceMembers = append(ctx.instanceMembers, js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: memberExpr}})
1814-
}
1815-
18161750
if analysis.private != nil {
18171751
ctx.lowerPrivateMethod(p, prop, analysis.private)
18181752
}
@@ -1829,7 +1763,7 @@ func (ctx *lowerClassContext) processProperties(p *parser, classLoweringInfo cla
18291763
// Lower fields
18301764
if (!prop.Kind.IsMethodDefinition() && analysis.mustLowerField) || analysis.staticFieldToBlockAssign {
18311765
var keep bool
1832-
prop, keep = ctx.lowerField(p, prop, analysis.private, analysis.shouldOmitFieldInitializer, analysis.staticFieldToBlockAssign, initializerIndex)
1766+
prop, _, keep = ctx.lowerField(p, prop, analysis.private, analysis.shouldOmitFieldInitializer, analysis.staticFieldToBlockAssign, initializerIndex)
18331767
if !keep {
18341768
continue
18351769
}
@@ -1936,7 +1870,7 @@ func (ctx *lowerClassContext) rewriteAutoAccessorToGetSet(
19361870
}
19371871
if !mustLowerField {
19381872
properties = append(properties, storageProp)
1939-
} else if prop, ok := ctx.lowerField(p, storageProp, storagePrivate, false, false, -1); ok {
1873+
} else if prop, _, ok := ctx.lowerField(p, storageProp, storagePrivate, false, false, -1); ok {
19401874
properties = append(properties, prop)
19411875
}
19421876

0 commit comments

Comments
 (0)