Skip to content

Commit edd7359

Browse files
committed
Transform private-named methods
Signed-off-by: Max Heiber <max.heiber@gmail.com>
1 parent a7303e1 commit edd7359

37 files changed

+563
-224
lines changed

src/compiler/transformers/esnext.ts

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -383,20 +383,18 @@ namespace ts {
383383

384384
pendingExpressions = pendingExpressions || [];
385385
last(privateNameEnvironmentStack).forEach(entry => {
386-
const { placement } = entry;
387-
switch (placement) {
386+
switch (entry.placement) {
388387
case PrivateNamePlacement.InstanceField:
389388
break;
390389
case PrivateNamePlacement.InstanceMethod:
391-
entry = entry as PrivateNamedInstanceMethod;
392-
const func = privateNamedMethodToFunction(entry.origFunc, entry.funcName, entry.accumulator);
390+
const func = privateNamedMethodToFunction(entry.origFunc, entry.funcName);
393391
(pendingExpressions = pendingExpressions || []).push(createAssignment(
394392
entry.funcName,
395393
func
396394
));
397395
break;
398396
default:
399-
Debug.assertNever(placement, "unexpected Private Name Placement");
397+
Debug.assertNever(entry, "unexpected private name placement");
400398
}
401399
});
402400
const members: ClassElement[] = [];
@@ -616,29 +614,16 @@ namespace ts {
616614
privateNameEnvironmentStack.pop();
617615
}
618616

619-
function privateNamedMethodToFunction (declaration: MethodDeclaration, funcName: Identifier, accumulator: Identifier): FunctionExpression {
617+
function privateNamedMethodToFunction (declaration: MethodDeclaration, funcName: Identifier): FunctionExpression {
620618
const params = declaration.parameters;
621-
let body = getMutableClone(declaration.body || createBlock([], true));
622-
body = visitEachChild(body, visitor, context);
623-
const toPrepend = startOnNewLine(
624-
createStatement(
625-
createClassPrivateNamedCallCheckHelper(context, accumulator)
626-
)
627-
);
628-
body.statements = setTextRange(
629-
createNodeArray([
630-
toPrepend,
631-
...body.statements
632-
]),
633-
body.statements
634-
);
619+
const body = visitEachChild(declaration.body, visitor, context) || createBlock([], /* multiLine */ true);
635620
const func = createFunctionExpression(
636-
/* modifiers */ undefined,
637-
/* asteriskToken */ undefined,
638-
funcName,
639-
/* typeParameters */ undefined,
640-
params,
641-
/* type */ undefined,
621+
/* modifiers */ undefined,
622+
/* asteriskToken */ undefined,
623+
funcName,
624+
/* typeParameters*/ undefined,
625+
params,
626+
/* type */ undefined,
642627
body);
643628
return func;
644629
}
@@ -647,21 +632,22 @@ namespace ts {
647632
function addPrivateName(element: ClassElement & { name: PrivateName }) {
648633
const env = last(privateNameEnvironmentStack);
649634
const text = getTextOfPropertyName(element.name) as string;
650-
const accumulator = createUniqueName(`_${text.substring(1)}`);
651635
const { escapedText } = element.name;
652-
hoistVariableDeclaration(accumulator);
653636

654637
let identifierName: string;
638+
let accumulator: Identifier;
655639
if (hasModifier(element, ModifierFlags.Static)) {
656640
// statics not supported yet
657641
return;
658642
}
659643
if (isPropertyDeclaration(element)) {
660644
identifierName = "WeakMap";
645+
accumulator = createUniqueName(`_${text.slice(1)}WeakMap`);
661646
env.set(escapedText, { placement: PrivateNamePlacement.InstanceField, accumulator });
662647
}
663648
else if (isMethodDeclaration(element)) {
664649
identifierName = "WeakSet";
650+
accumulator = createUniqueName(`_${text.slice(1)}WeakSet`);
665651
const escapedText = element.name.escapedText;
666652
const escapedTextNoHash = `_${`${escapedText}`.slice(1)}`;
667653
const funcName: Identifier = createUniqueName(escapedTextNoHash);
@@ -671,6 +657,7 @@ namespace ts {
671657
else {
672658
return;
673659
}
660+
hoistVariableDeclaration(accumulator);
674661
(pendingExpressions = pendingExpressions || []).push(
675662
createAssignment(
676663
accumulator,
@@ -696,18 +683,36 @@ namespace ts {
696683
function visitPropertyAccessExpression(node: PropertyAccessExpression) {
697684
if (isPrivateName(node.name)) {
698685
const privateNameInfo = accessPrivateName(node.name);
699-
if (privateNameInfo && privateNameInfo.placement === PrivateNamePlacement.InstanceField) {
700-
return setOriginalNode(
701-
setTextRange(
702-
createClassPrivateFieldGetHelper(
703-
context,
704-
visitNode(node.expression, visitor, isExpression),
705-
privateNameInfo.accumulator
686+
if (!privateNameInfo) {
687+
return visitEachChild(node, visitor, context);
688+
}
689+
switch (privateNameInfo.placement) {
690+
case PrivateNamePlacement.InstanceField:
691+
return setOriginalNode(
692+
setTextRange(
693+
createClassPrivateFieldGetHelper(
694+
context,
695+
visitNode(node.expression, visitor, isExpression),
696+
privateNameInfo.accumulator
697+
),
698+
node
706699
),
707700
node
708-
),
709-
node
710-
);
701+
);
702+
case PrivateNamePlacement.InstanceMethod:
703+
return setOriginalNode(
704+
setTextRange(
705+
createClassPrivateNamedMethodGetHelper(
706+
context,
707+
privateNameInfo.accumulator,
708+
privateNameInfo.funcName
709+
),
710+
node
711+
),
712+
node
713+
);
714+
default:
715+
Debug.assertNever(privateNameInfo, "Unexpected private name placement");
711716
}
712717
}
713718
return visitEachChild(node, visitor, context);
@@ -804,13 +809,18 @@ namespace ts {
804809
setTextRange(
805810
createCall(
806811
createPropertyAccess(
807-
privateNameEntry.funcName,
812+
createClassPrivateNamedMethodGetHelper(
813+
context,
814+
privateNameEntry.accumulator,
815+
privateNameEntry.funcName
816+
),
808817
"call"
809818
),
810-
/*typeArguments*/ undefined,
811-
[createThis(), ...node.arguments]
819+
/* typeArguments */ undefined,
820+
// node.arguments
821+
concatenate([createThis()], node.arguments)
812822
),
813-
/* location */ node
823+
/* location */ node
814824
),
815825
node
816826
);
@@ -1985,15 +1995,18 @@ namespace ts {
19851995
context.requestEmitHelper(classPrivateFieldSetHelper);
19861996
return createCall(getHelperName("_classPrivateFieldSet"), /* typeArguments */ undefined, [receiver, privateField, value]);
19871997
}
1988-
const classPrivateNamedCallCheckHelper: EmitHelper = {
1989-
name: "typescript:classPrivateNamedCallCheck",
1998+
1999+
const classPrivateNamedMethodGet: EmitHelper = {
2000+
name: "typescript:classPrivateNamedMethodGet",
19902001
scoped: false,
1991-
text: `var _classPrivateNamedCallCheck = function (receiver, privateSet) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get weak field on non-instance"); }};`
2002+
text: `function _classPrivateNamedMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }`
19922003
};
19932004

1994-
function createClassPrivateNamedCallCheckHelper(context: TransformationContext, weakSet: Identifier) {
1995-
context.requestEmitHelper(classPrivateNamedCallCheckHelper);
1996-
return createCall(getHelperName("_classPrivateNamedCallCheck"), /* typeArguments */ undefined, [ createThis(), weakSet ]);
2005+
function createClassPrivateNamedMethodGetHelper(context: TransformationContext, weakSet: Identifier, name: Identifier) {
2006+
2007+
context.requestEmitHelper(classPrivateNamedMethodGet);
2008+
return createCall(getHelperName("_classPrivateNamedMethodGet"), /* typeArguments */ undefined,
2009+
[ createThis(), weakSet, name ]);
19972010
}
19982011

19992012
}

tests/baselines/reference/classConstructorParametersCommentPlacement.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ class A {
1010

1111
//// [classConstructorParametersCommentPlacement.js]
1212
var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };
13-
var _a, _b;
13+
var _aWeakMap_1, _bWeakMap_1;
1414
// some comment
1515
var A = /** @class */ (function () {
1616
function A(b) {
1717
if (b === void 0) { b = "something"; }
18-
_a.set(this, void 0);
19-
_b.set(this, void 0);
18+
_aWeakMap_1.set(this, void 0);
19+
_bWeakMap_1.set(this, void 0);
2020
this.b = b;
21-
_classPrivateFieldSet(this, _a, "private hello");
22-
_classPrivateFieldSet(this, _b, "another private name");
21+
_classPrivateFieldSet(this, _aWeakMap_1, "private hello");
22+
_classPrivateFieldSet(this, _bWeakMap_1, "another private name");
2323
this.a = "public property";
2424
}
2525
return A;
2626
}());
27-
_a = new WeakMap(), _b = new WeakMap();
27+
_aWeakMap_1 = new WeakMap(), _bWeakMap_1 = new WeakMap();

tests/baselines/reference/privateNameConstructorReserved.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ class A {
88

99
//// [privateNameConstructorReserved.js]
1010
// @target es6
11+
var _constructor_1, _constructorWeakSet_1;
1112
var A = /** @class */ (function () {
1213
function A() {
14+
_constructorWeakSet_1.add(this);
1315
}
14-
A.prototype.#constructor = function () { }; // Error: `#constructor` is a reserved word.
1516
return A;
1617
}());
18+
_constructorWeakSet_1 = new WeakSet(), _constructor_1 = function _constructor_1() { };

tests/baselines/reference/privateNameDuplicateField.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ class A {
99

1010
//// [privateNameDuplicateField.js]
1111
// @target es6
12-
var _foo, _foo_1;
12+
var _fooWeakMap_1, _fooWeakMap_2;
1313
"use strict";
1414
var A = /** @class */ (function () {
1515
function A() {
16-
_foo_1.set(this, "foo");
17-
_foo_1.set(this, "foo");
16+
_fooWeakMap_2.set(this, "foo");
17+
_fooWeakMap_2.set(this, "foo");
1818
}
1919
return A;
2020
}());
21-
_foo = new WeakMap(), _foo_1 = new WeakMap();
21+
_fooWeakMap_1 = new WeakMap(), _fooWeakMap_2 = new WeakMap();

tests/baselines/reference/privateNameField.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,13 @@ class A {
1111
//// [privateNameField.js]
1212
// @target es6
1313
var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };
14-
<<<<<<< HEAD
15-
var _namePrivate;
14+
var _nameWeakMap_1;
1615
"use strict";
17-
=======
18-
var _name_1;
19-
>>>>>>> simplify and fixes for private methods emit
2016
var A = /** @class */ (function () {
2117
function A(name) {
22-
_name_1.set(this, void 0);
23-
_classPrivateFieldSet(this, _name_1, name);
18+
_nameWeakMap_1.set(this, void 0);
19+
_classPrivateFieldSet(this, _nameWeakMap_1, name);
2420
}
2521
return A;
2622
}());
27-
_name_1 = new WeakMap();
23+
_nameWeakMap_1 = new WeakMap();

tests/baselines/reference/privateNameFieldAccess.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ class A {
99

1010
//// [privateNameFieldAccess.js]
1111
var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };
12-
var _myField_1;
12+
var _myFieldWeakMap_1;
1313
var A = /** @class */ (function () {
1414
function A() {
15-
_myField_1.set(this, "hello world");
16-
console.log(_classPrivateFieldGet(this, _myField_1));
15+
_myFieldWeakMap_1.set(this, "hello world");
16+
console.log(_classPrivateFieldGet(this, _myFieldWeakMap_1));
1717
}
1818
return A;
1919
}());
20-
_myField_1 = new WeakMap();
20+
_myFieldWeakMap_1 = new WeakMap();

tests/baselines/reference/privateNameFieldAssignment.js

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,41 +38,41 @@ class A {
3838
//// [privateNameFieldAssignment.js]
3939
var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };
4040
var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };
41-
var _field_1;
41+
var _fieldWeakMap_1;
4242
var A = /** @class */ (function () {
4343
function A() {
44-
_field_1.set(this, 0);
44+
_fieldWeakMap_1.set(this, 0);
4545
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
46-
_classPrivateFieldSet(this, _field_1, 1);
47-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) + 2);
48-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) - 3);
49-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) / 4);
50-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) * 5);
51-
_classPrivateFieldSet(this, _field_1, Math.pow(_classPrivateFieldGet(this, _field_1), 6));
52-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) % 7);
53-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) << 8);
54-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) >> 9);
55-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) >>> 10);
56-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) & 11);
57-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) | 12);
58-
_classPrivateFieldSet(this, _field_1, _classPrivateFieldGet(this, _field_1) ^ 13);
59-
_classPrivateFieldSet(A.getInstance(), _field_1, 1);
60-
_classPrivateFieldSet(_a = A.getInstance(), _field_1, _classPrivateFieldGet(_a, _field_1) + 2);
61-
_classPrivateFieldSet(_b = A.getInstance(), _field_1, _classPrivateFieldGet(_b, _field_1) - 3);
62-
_classPrivateFieldSet(_c = A.getInstance(), _field_1, _classPrivateFieldGet(_c, _field_1) / 4);
63-
_classPrivateFieldSet(_d = A.getInstance(), _field_1, _classPrivateFieldGet(_d, _field_1) * 5);
64-
_classPrivateFieldSet(_e = A.getInstance(), _field_1, Math.pow(_classPrivateFieldGet(_e, _field_1), 6));
65-
_classPrivateFieldSet(_f = A.getInstance(), _field_1, _classPrivateFieldGet(_f, _field_1) % 7);
66-
_classPrivateFieldSet(_g = A.getInstance(), _field_1, _classPrivateFieldGet(_g, _field_1) << 8);
67-
_classPrivateFieldSet(_h = A.getInstance(), _field_1, _classPrivateFieldGet(_h, _field_1) >> 9);
68-
_classPrivateFieldSet(_j = A.getInstance(), _field_1, _classPrivateFieldGet(_j, _field_1) >>> 10);
69-
_classPrivateFieldSet(_k = A.getInstance(), _field_1, _classPrivateFieldGet(_k, _field_1) & 11);
70-
_classPrivateFieldSet(_l = A.getInstance(), _field_1, _classPrivateFieldGet(_l, _field_1) | 12);
71-
_classPrivateFieldSet(_m = A.getInstance(), _field_1, _classPrivateFieldGet(_m, _field_1) ^ 13);
46+
_classPrivateFieldSet(this, _fieldWeakMap_1, 1);
47+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) + 2);
48+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) - 3);
49+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) / 4);
50+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) * 5);
51+
_classPrivateFieldSet(this, _fieldWeakMap_1, Math.pow(_classPrivateFieldGet(this, _fieldWeakMap_1), 6));
52+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) % 7);
53+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) << 8);
54+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) >> 9);
55+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) >>> 10);
56+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) & 11);
57+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) | 12);
58+
_classPrivateFieldSet(this, _fieldWeakMap_1, _classPrivateFieldGet(this, _fieldWeakMap_1) ^ 13);
59+
_classPrivateFieldSet(A.getInstance(), _fieldWeakMap_1, 1);
60+
_classPrivateFieldSet(_a = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_a, _fieldWeakMap_1) + 2);
61+
_classPrivateFieldSet(_b = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_b, _fieldWeakMap_1) - 3);
62+
_classPrivateFieldSet(_c = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_c, _fieldWeakMap_1) / 4);
63+
_classPrivateFieldSet(_d = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_d, _fieldWeakMap_1) * 5);
64+
_classPrivateFieldSet(_e = A.getInstance(), _fieldWeakMap_1, Math.pow(_classPrivateFieldGet(_e, _fieldWeakMap_1), 6));
65+
_classPrivateFieldSet(_f = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_f, _fieldWeakMap_1) % 7);
66+
_classPrivateFieldSet(_g = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_g, _fieldWeakMap_1) << 8);
67+
_classPrivateFieldSet(_h = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_h, _fieldWeakMap_1) >> 9);
68+
_classPrivateFieldSet(_j = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_j, _fieldWeakMap_1) >>> 10);
69+
_classPrivateFieldSet(_k = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_k, _fieldWeakMap_1) & 11);
70+
_classPrivateFieldSet(_l = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_l, _fieldWeakMap_1) | 12);
71+
_classPrivateFieldSet(_m = A.getInstance(), _fieldWeakMap_1, _classPrivateFieldGet(_m, _fieldWeakMap_1) ^ 13);
7272
}
7373
A.getInstance = function () {
7474
return new A();
7575
};
7676
return A;
7777
}());
78-
_field_1 = new WeakMap();
78+
_fieldWeakMap_1 = new WeakMap();

0 commit comments

Comments
 (0)