Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decorators normative updates #55276

Merged
merged 1 commit into from Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -32894,7 +32894,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
*/
function getThisArgumentOfCall(node: CallLikeExpression): LeftHandSideExpression | undefined {
const expression = node.kind === SyntaxKind.CallExpression ? node.expression :
node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag : undefined;
node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag :
node.kind === SyntaxKind.Decorator && !legacyDecorators ? node.expression :
undefined;
if (expression) {
const callee = skipOuterExpressions(expression);
if (isAccessExpression(callee)) {
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/factory/utilities.ts
Expand Up @@ -1645,7 +1645,7 @@ export function createAccessorPropertyBackingField(factory: NodeFactory, node: P
*
* @internal
*/
export function createAccessorPropertyGetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: ModifiersArray | undefined, name: PropertyName): GetAccessorDeclaration {
export function createAccessorPropertyGetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: readonly Modifier[] | undefined, name: PropertyName, receiver: Expression = factory.createThis()): GetAccessorDeclaration {
return factory.createGetAccessorDeclaration(
modifiers,
name,
Expand All @@ -1654,7 +1654,7 @@ export function createAccessorPropertyGetRedirector(factory: NodeFactory, node:
factory.createBlock([
factory.createReturnStatement(
factory.createPropertyAccessExpression(
factory.createThis(),
receiver,
factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage")
)
)
Expand All @@ -1667,7 +1667,7 @@ export function createAccessorPropertyGetRedirector(factory: NodeFactory, node:
*
* @internal
*/
export function createAccessorPropertySetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: ModifiersArray | undefined, name: PropertyName) {
export function createAccessorPropertySetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: readonly Modifier[] | undefined, name: PropertyName, receiver: Expression = factory.createThis()) {
return factory.createSetAccessorDeclaration(
modifiers,
name,
Expand All @@ -1680,7 +1680,7 @@ export function createAccessorPropertySetRedirector(factory: NodeFactory, node:
factory.createExpressionStatement(
factory.createAssignment(
factory.createPropertyAccessExpression(
factory.createThis(),
receiver,
factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage")
),
factory.createIdentifier("value")
Expand Down
26 changes: 19 additions & 7 deletions src/compiler/transformers/classFields.ts
Expand Up @@ -154,6 +154,7 @@ import {
Modifier,
ModifierFlags,
ModifierLike,
modifiersToFlags,
moveRangePastModifiers,
moveRangePos,
newPrivateEnvironment,
Expand Down Expand Up @@ -896,6 +897,12 @@ export function transformClassFields(context: TransformationContext): (x: Source
}
}

function getClassThis() {
const lex = getClassLexicalEnvironment();
const classThis = lex.classThis ?? lex.classConstructor ?? currentClassContainer?.name;
return Debug.checkDefined(classThis);
}

function transformAutoAccessor(node: AutoAccessorPropertyDeclaration): VisitResult<Node> {
// transforms:
// accessor x = 1;
Expand Down Expand Up @@ -935,12 +942,15 @@ export function transformClassFields(context: TransformationContext): (x: Source
setEmitFlags(backingField, EmitFlags.NoComments);
setSourceMapRange(backingField, sourceMapRange);

const getter = createAccessorPropertyGetRedirector(factory, node, modifiers, getterName);
const receiver = isStatic(node) ? getClassThis() : factory.createThis();
const getter = createAccessorPropertyGetRedirector(factory, node, modifiers, getterName, receiver);
setOriginalNode(getter, node);
setCommentRange(getter, commentRange);
setSourceMapRange(getter, sourceMapRange);

const setter = createAccessorPropertySetRedirector(factory, node, modifiers, setterName);
// create a fresh copy of the modifiers so that we don't duplicate comments
const setterModifiers = factory.createModifiersFromModifierFlags(modifiersToFlags(modifiers));
const setter = createAccessorPropertySetRedirector(factory, node, setterModifiers, setterName, receiver);
setOriginalNode(setter, node);
setEmitFlags(setter, EmitFlags.NoComments);
setSourceMapRange(setter, sourceMapRange);
Expand Down Expand Up @@ -1692,11 +1702,13 @@ export function transformClassFields(context: TransformationContext): (x: Source
let containsInstanceAutoAccessors = false;
for (const member of node.members) {
if (isStatic(member)) {
if (member.name &&
(isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) &&
if (member.name && (isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) &&
shouldTransformPrivateElementsOrClassStaticBlocks) {
facts |= ClassFacts.NeedsClassConstructorReference;
}
else if (isAutoAccessorPropertyDeclaration(member) && shouldTransformAutoAccessors === Ternary.True && !node.name && !node.emitNode?.classThis) {
facts |= ClassFacts.NeedsClassConstructorReference;
}
if (isPropertyDeclaration(member) || isClassStaticBlockDeclaration(member)) {
if (shouldTransformThisInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalThis) {
facts |= ClassFacts.NeedsSubstitutionForThisInClassStaticField;
Expand Down Expand Up @@ -1843,10 +1855,10 @@ export function transformClassFields(context: TransformationContext): (x: Source
getClassLexicalEnvironment().classConstructor = factory.cloneNode(temp);
pendingClassReferenceAssignment = factory.createAssignment(temp, factory.getInternalName(node));
}
}

if (node.emitNode?.classThis) {
getClassLexicalEnvironment().classThis = node.emitNode.classThis;
}
if (node.emitNode?.classThis) {
getClassLexicalEnvironment().classThis = node.emitNode.classThis;
}

const isExport = hasSyntacticModifier(node, ModifierFlags.Export);
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/transformers/esDecorators.ts
Expand Up @@ -47,6 +47,7 @@ import {
getAllDecoratorsOfClassElement,
getCommentRange,
getEffectiveBaseTypeNode,
getEmitScriptTarget,
getFirstConstructorWithBody,
getHeritageClause,
getNonAssignmentOperatorForCompoundAssignment,
Expand All @@ -62,6 +63,7 @@ import {
injectClassNamedEvaluationHelperBlockIfMissing,
injectClassThisAssignmentIfMissing,
InternalEmitFlags,
isAccessExpression,
isAmbientPropertyDeclaration,
isArrayBindingOrAssignmentElement,
isArrayLiteralExpression,
Expand Down Expand Up @@ -289,6 +291,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
hoistVariableDeclaration,
} = context;

const languageVersion = getEmitScriptTarget(context.getCompilerOptions());
let top: LexicalEnvironmentStackEntry | undefined;
let classInfo: ClassInfo | undefined;
let classThis: Identifier | undefined;
Expand Down Expand Up @@ -2147,6 +2150,13 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
function transformDecorator(decorator: Decorator) {
const expression = visitNode(decorator.expression, visitor, isExpression);
setEmitFlags(expression, EmitFlags.NoComments);

// preserve the 'this' binding for an access expression
const innerExpression = skipOuterExpressions(expression);
if (isAccessExpression(innerExpression)) {
const { target, thisArg } = factory.createCallBinding(expression, hoistVariableDeclaration, languageVersion, /*cacheIdentifiers*/ true);
return factory.restoreOuterExpressions(expression, factory.createFunctionBindCall(target, thisArg, []));
}
return expression;
}

Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor1(target=es2015).js
Expand Up @@ -31,10 +31,10 @@ class C1 {
set a(value) { __classPrivateFieldSet(this, _C1_a_accessor_storage, value, "f"); }
get b() { return __classPrivateFieldGet(this, _C1_b_accessor_storage, "f"); }
set b(value) { __classPrivateFieldSet(this, _C1_b_accessor_storage, value, "f"); }
static get c() { return __classPrivateFieldGet(this, _a, "f", _C1_c_accessor_storage); }
static set c(value) { __classPrivateFieldSet(this, _a, value, "f", _C1_c_accessor_storage); }
static get d() { return __classPrivateFieldGet(this, _a, "f", _C1_d_accessor_storage); }
static set d(value) { __classPrivateFieldSet(this, _a, value, "f", _C1_d_accessor_storage); }
static get c() { return __classPrivateFieldGet(_a, _a, "f", _C1_c_accessor_storage); }
static set c(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1_c_accessor_storage); }
static get d() { return __classPrivateFieldGet(_a, _a, "f", _C1_d_accessor_storage); }
static set d(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1_d_accessor_storage); }
}
_a = C1, _C1_a_accessor_storage = new WeakMap(), _C1_b_accessor_storage = new WeakMap();
_C1_c_accessor_storage = { value: void 0 };
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor1(target=es2022).js
Expand Up @@ -18,9 +18,9 @@ class C1 {
get b() { return this.#b_accessor_storage; }
set b(value) { this.#b_accessor_storage = value; }
static #c_accessor_storage;
static get c() { return this.#c_accessor_storage; }
static set c(value) { this.#c_accessor_storage = value; }
static get c() { return C1.#c_accessor_storage; }
static set c(value) { C1.#c_accessor_storage = value; }
static #d_accessor_storage = 2;
static get d() { return this.#d_accessor_storage; }
static set d(value) { this.#d_accessor_storage = value; }
static get d() { return C1.#d_accessor_storage; }
static set d(value) { C1.#d_accessor_storage = value; }
}
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor10.js
Expand Up @@ -57,11 +57,11 @@ class C3 {
}
class C4_1 {
static #a3_accessor_storage = 1;
static get a3() { return this.#a3_accessor_storage; }
static set a3(value) { this.#a3_accessor_storage = value; }
static get a3() { return C4_1.#a3_accessor_storage; }
static set a3(value) { C4_1.#a3_accessor_storage = value; }
}
class C4_2 {
static #a3_accessor_storage = 1;
static get a3() { return this.#a3_accessor_storage; }
static set a3(value) { this.#a3_accessor_storage = value; }
static get a3() { return C4_2.#a3_accessor_storage; }
static set a3(value) { C4_2.#a3_accessor_storage = value; }
}
2 changes: 1 addition & 1 deletion tests/baselines/reference/autoAccessor2(target=es2015).js
Expand Up @@ -41,7 +41,7 @@ class C1 {
__classPrivateFieldSet(this, _C1_instances, 4, "a", _C1_b_set);
}
}
_a = C1, _C1_instances = new WeakSet(), _C1_a_accessor_storage = new WeakMap(), _C1_b_accessor_storage = new WeakMap(), _C1_a_get = function _C1_a_get() { return __classPrivateFieldGet(this, _C1_a_accessor_storage, "f"); }, _C1_a_set = function _C1_a_set(value) { __classPrivateFieldSet(this, _C1_a_accessor_storage, value, "f"); }, _C1_b_get = function _C1_b_get() { return __classPrivateFieldGet(this, _C1_b_accessor_storage, "f"); }, _C1_b_set = function _C1_b_set(value) { __classPrivateFieldSet(this, _C1_b_accessor_storage, value, "f"); }, _C1_c_get = function _C1_c_get() { return __classPrivateFieldGet(this, _a, "f", _C1_c_accessor_storage); }, _C1_c_set = function _C1_c_set(value) { __classPrivateFieldSet(this, _a, value, "f", _C1_c_accessor_storage); }, _C1_d_get = function _C1_d_get() { return __classPrivateFieldGet(this, _a, "f", _C1_d_accessor_storage); }, _C1_d_set = function _C1_d_set(value) { __classPrivateFieldSet(this, _a, value, "f", _C1_d_accessor_storage); };
_a = C1, _C1_instances = new WeakSet(), _C1_a_accessor_storage = new WeakMap(), _C1_b_accessor_storage = new WeakMap(), _C1_a_get = function _C1_a_get() { return __classPrivateFieldGet(this, _C1_a_accessor_storage, "f"); }, _C1_a_set = function _C1_a_set(value) { __classPrivateFieldSet(this, _C1_a_accessor_storage, value, "f"); }, _C1_b_get = function _C1_b_get() { return __classPrivateFieldGet(this, _C1_b_accessor_storage, "f"); }, _C1_b_set = function _C1_b_set(value) { __classPrivateFieldSet(this, _C1_b_accessor_storage, value, "f"); }, _C1_c_get = function _C1_c_get() { return __classPrivateFieldGet(_a, _a, "f", _C1_c_accessor_storage); }, _C1_c_set = function _C1_c_set(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1_c_accessor_storage); }, _C1_d_get = function _C1_d_get() { return __classPrivateFieldGet(_a, _a, "f", _C1_d_accessor_storage); }, _C1_d_set = function _C1_d_set(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1_d_accessor_storage); };
_C1_c_accessor_storage = { value: void 0 };
_C1_d_accessor_storage = { value: 2 };
(() => {
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor2(target=es2022).js
Expand Up @@ -28,11 +28,11 @@ class C1 {
get #b() { return this.#b_accessor_storage; }
set #b(value) { this.#b_accessor_storage = value; }
static #c_accessor_storage;
static get #c() { return this.#c_accessor_storage; }
static set #c(value) { this.#c_accessor_storage = value; }
static get #c() { return C1.#c_accessor_storage; }
static set #c(value) { C1.#c_accessor_storage = value; }
static #d_accessor_storage = 2;
static get #d() { return this.#d_accessor_storage; }
static set #d(value) { this.#d_accessor_storage = value; }
static get #d() { return C1.#d_accessor_storage; }
static set #d(value) { C1.#d_accessor_storage = value; }
constructor() {
this.#a = 3;
this.#b = 4;
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor3(target=es2015).js
Expand Up @@ -31,10 +31,10 @@ class C1 {
set "w"(value) { __classPrivateFieldSet(this, _C1__a_accessor_storage, value, "f"); }
get "x"() { return __classPrivateFieldGet(this, _C1__b_accessor_storage, "f"); }
set "x"(value) { __classPrivateFieldSet(this, _C1__b_accessor_storage, value, "f"); }
static get "y"() { return __classPrivateFieldGet(this, _a, "f", _C1__c_accessor_storage); }
static set "y"(value) { __classPrivateFieldSet(this, _a, value, "f", _C1__c_accessor_storage); }
static get "z"() { return __classPrivateFieldGet(this, _a, "f", _C1__d_accessor_storage); }
static set "z"(value) { __classPrivateFieldSet(this, _a, value, "f", _C1__d_accessor_storage); }
static get "y"() { return __classPrivateFieldGet(_a, _a, "f", _C1__c_accessor_storage); }
static set "y"(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__c_accessor_storage); }
static get "z"() { return __classPrivateFieldGet(_a, _a, "f", _C1__d_accessor_storage); }
static set "z"(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__d_accessor_storage); }
}
_a = C1, _C1__a_accessor_storage = new WeakMap(), _C1__b_accessor_storage = new WeakMap();
_C1__c_accessor_storage = { value: void 0 };
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor3(target=es2022).js
Expand Up @@ -18,9 +18,9 @@ class C1 {
get "x"() { return this.#_b_accessor_storage; }
set "x"(value) { this.#_b_accessor_storage = value; }
static #_c_accessor_storage;
static get "y"() { return this.#_c_accessor_storage; }
static set "y"(value) { this.#_c_accessor_storage = value; }
static get "y"() { return C1.#_c_accessor_storage; }
static set "y"(value) { C1.#_c_accessor_storage = value; }
static #_d_accessor_storage = 2;
static get "z"() { return this.#_d_accessor_storage; }
static set "z"(value) { this.#_d_accessor_storage = value; }
static get "z"() { return C1.#_d_accessor_storage; }
static set "z"(value) { C1.#_d_accessor_storage = value; }
}
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor4(target=es2015).js
Expand Up @@ -31,10 +31,10 @@ class C1 {
set 0(value) { __classPrivateFieldSet(this, _C1__a_accessor_storage, value, "f"); }
get 1() { return __classPrivateFieldGet(this, _C1__b_accessor_storage, "f"); }
set 1(value) { __classPrivateFieldSet(this, _C1__b_accessor_storage, value, "f"); }
static get 2() { return __classPrivateFieldGet(this, _a, "f", _C1__c_accessor_storage); }
static set 2(value) { __classPrivateFieldSet(this, _a, value, "f", _C1__c_accessor_storage); }
static get 3() { return __classPrivateFieldGet(this, _a, "f", _C1__d_accessor_storage); }
static set 3(value) { __classPrivateFieldSet(this, _a, value, "f", _C1__d_accessor_storage); }
static get 2() { return __classPrivateFieldGet(_a, _a, "f", _C1__c_accessor_storage); }
static set 2(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__c_accessor_storage); }
static get 3() { return __classPrivateFieldGet(_a, _a, "f", _C1__d_accessor_storage); }
static set 3(value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__d_accessor_storage); }
}
_a = C1, _C1__a_accessor_storage = new WeakMap(), _C1__b_accessor_storage = new WeakMap();
_C1__c_accessor_storage = { value: void 0 };
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor4(target=es2022).js
Expand Up @@ -18,9 +18,9 @@ class C1 {
get 1() { return this.#_b_accessor_storage; }
set 1(value) { this.#_b_accessor_storage = value; }
static #_c_accessor_storage;
static get 2() { return this.#_c_accessor_storage; }
static set 2(value) { this.#_c_accessor_storage = value; }
static get 2() { return C1.#_c_accessor_storage; }
static set 2(value) { C1.#_c_accessor_storage = value; }
static #_d_accessor_storage = 2;
static get 3() { return this.#_d_accessor_storage; }
static set 3(value) { this.#_d_accessor_storage = value; }
static get 3() { return C1.#_d_accessor_storage; }
static set 3(value) { C1.#_d_accessor_storage = value; }
}
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor5(target=es2015).js
Expand Up @@ -35,10 +35,10 @@ class C1 {
set ["w"](value) { __classPrivateFieldSet(this, _C1__a_accessor_storage, value, "f"); }
get ["x"]() { return __classPrivateFieldGet(this, _C1__b_accessor_storage, "f"); }
set ["x"](value) { __classPrivateFieldSet(this, _C1__b_accessor_storage, value, "f"); }
static get ["y"]() { return __classPrivateFieldGet(this, _a, "f", _C1__c_accessor_storage); }
static set ["y"](value) { __classPrivateFieldSet(this, _a, value, "f", _C1__c_accessor_storage); }
static get ["z"]() { return __classPrivateFieldGet(this, _a, "f", _C1__d_accessor_storage); }
static set ["z"](value) { __classPrivateFieldSet(this, _a, value, "f", _C1__d_accessor_storage); }
static get ["y"]() { return __classPrivateFieldGet(_a, _a, "f", _C1__c_accessor_storage); }
static set ["y"](value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__c_accessor_storage); }
static get ["z"]() { return __classPrivateFieldGet(_a, _a, "f", _C1__d_accessor_storage); }
static set ["z"](value) { __classPrivateFieldSet(_a, _a, value, "f", _C1__d_accessor_storage); }
}
_a = C1;
_C1__c_accessor_storage = { value: void 0 };
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/autoAccessor5(target=es2022).js
Expand Up @@ -23,11 +23,11 @@ class C1 {
get ["x"]() { return this.#_b_accessor_storage; }
set ["x"](value) { this.#_b_accessor_storage = value; }
static #_c_accessor_storage;
static get ["y"]() { return this.#_c_accessor_storage; }
static set ["y"](value) { this.#_c_accessor_storage = value; }
static get ["y"]() { return C1.#_c_accessor_storage; }
static set ["y"](value) { C1.#_c_accessor_storage = value; }
static #_d_accessor_storage = 2;
static get ["z"]() { return this.#_d_accessor_storage; }
static set ["z"](value) { this.#_d_accessor_storage = value; }
static get ["z"]() { return C1.#_d_accessor_storage; }
static set ["z"](value) { C1.#_d_accessor_storage = value; }
}
class C2 {
#_e_accessor_storage = 1;
Expand Down