Skip to content

Commit dc237b3

Browse files
Kingwlrbuckton
andauthored
Change static fields emits (#43114)
* use emit into iife * Update emit * Revert un-related changes * Allow super in static context * Allow this and super in static property declaration * Add more tests * Avoid errors * Accept baseline * Accept baseline * Add decorated classes test * Add errors * Avoid this in emitter * make lint happy * Add class expression tests * Add computed name test * Avoid super if target below es6 * Adjust function boundary * Add internal * Fix minor CR issues * accept baseline * Update behavior * Avoid spaces * Make lint happy * Avoid function boundary utils * Update baseline * Avoid errors * Accept baseline * Accept baseline * Accept baseline * Accept baseline * Use substitutions * Full coverage for super, this, merge static and private context * Fix use-before-def in static fields Co-authored-by: Ron Buckton <ron.buckton@microsoft.com>
1 parent 328e888 commit dc237b3

File tree

215 files changed

+9184
-781
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

215 files changed

+9184
-781
lines changed

src/compiler/binder.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ namespace ts {
669669
}
670670
// We create a return control flow graph for IIFEs and constructors. For constructors
671671
// we use the return control flow graph in strict property initialization checks.
672-
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined;
672+
currentReturnTarget = isIIFE || node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined;
673673
currentExceptionTarget = undefined;
674674
currentBreakTarget = undefined;
675675
currentContinueTarget = undefined;
@@ -678,10 +678,10 @@ namespace ts {
678678
bindChildren(node);
679679
// Reset all reachability check related flags on node (for incremental scenarios)
680680
node.flags &= ~NodeFlags.ReachabilityAndEmitFlags;
681-
if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node as FunctionLikeDeclaration).body)) {
681+
if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).body)) {
682682
node.flags |= NodeFlags.HasImplicitReturn;
683683
if (hasExplicitReturn) node.flags |= NodeFlags.HasExplicitReturn;
684-
(node as FunctionLikeDeclaration).endFlowNode = currentFlow;
684+
(node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).endFlowNode = currentFlow;
685685
}
686686
if (node.kind === SyntaxKind.SourceFile) {
687687
node.flags |= emitFlags;
@@ -691,8 +691,8 @@ namespace ts {
691691
if (currentReturnTarget) {
692692
addAntecedent(currentReturnTarget, currentFlow);
693693
currentFlow = finishFlowLabel(currentReturnTarget);
694-
if (node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) {
695-
(node as FunctionLikeDeclaration).returnFlowNode = currentFlow;
694+
if (node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) {
695+
(node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).returnFlowNode = currentFlow;
696696
}
697697
}
698698
if (!isIIFE) {
@@ -1944,7 +1944,7 @@ namespace ts {
19441944
}
19451945

19461946
function declareClassMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
1947-
return hasSyntacticModifier(node, ModifierFlags.Static)
1947+
return isStatic(node)
19481948
? declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes)
19491949
: declareSymbol(container.symbol.members!, container.symbol, node, symbolFlags, symbolExcludes);
19501950
}
@@ -2950,7 +2950,7 @@ namespace ts {
29502950
// this.foo assignment in a JavaScript class
29512951
// Bind this property to the containing class
29522952
const containingClass = thisContainer.parent;
2953-
const symbolTable = hasSyntacticModifier(thisContainer, ModifierFlags.Static) ? containingClass.symbol.exports! : containingClass.symbol.members!;
2953+
const symbolTable = isStatic(thisContainer) ? containingClass.symbol.exports! : containingClass.symbol.members!;
29542954
if (hasDynamicName(node)) {
29552955
bindDynamicallyNamedThisPropertyAssignment(node, containingClass.symbol, symbolTable);
29562956
}

src/compiler/checker.ts

Lines changed: 136 additions & 75 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3344,6 +3344,14 @@
33443344
"category": "Error",
33453345
"code": 2815
33463346
},
3347+
"Cannot use 'this' in a static property initializer of a decorated class.": {
3348+
"category": "Error",
3349+
"code": 2816
3350+
},
3351+
"Property '{0}' has no initializer and is not definitely assigned in a class static block.": {
3352+
"category": "Error",
3353+
"code": 2817
3354+
},
33473355

33483356
"Import declaration '{0}' is using private name '{1}'.": {
33493357
"category": "Error",

src/compiler/factory/nodeFactory.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,11 @@ namespace ts {
496496
createArraySliceCall,
497497
createArrayConcatCall,
498498
createObjectDefinePropertyCall,
499+
createReflectGetCall,
500+
createReflectSetCall,
499501
createPropertyDescriptor,
500502
createCallBinding,
503+
createAssignmentTargetWrapper,
501504

502505
// Utilities
503506
inlineExpressions,
@@ -998,8 +1001,10 @@ namespace ts {
9981001
case SyntaxKind.UndefinedKeyword: // `undefined` is an Identifier in the expression case.
9991002
transformFlags = TransformFlags.ContainsTypeScript;
10001003
break;
1001-
case SyntaxKind.StaticKeyword:
10021004
case SyntaxKind.SuperKeyword:
1005+
transformFlags = TransformFlags.ContainsES2015 | TransformFlags.ContainsLexicalSuper;
1006+
break;
1007+
case SyntaxKind.StaticKeyword:
10031008
transformFlags = TransformFlags.ContainsES2015;
10041009
break;
10051010
case SyntaxKind.ThisKeyword:
@@ -2624,7 +2629,7 @@ namespace ts {
26242629
propagateChildFlags(node.equalsGreaterThanToken) |
26252630
TransformFlags.ContainsES2015;
26262631
if (modifiersToFlags(node.modifiers) & ModifierFlags.Async) {
2627-
node.transformFlags |= TransformFlags.ContainsES2017;
2632+
node.transformFlags |= TransformFlags.ContainsES2017 | TransformFlags.ContainsLexicalThis;
26282633
}
26292634
return node;
26302635
}
@@ -5435,6 +5440,15 @@ namespace ts {
54355440
}
54365441

54375442
function createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]) {
5443+
// Preserve the optionality of `object`.
5444+
if (isCallChain(object)) {
5445+
return createCallChain(
5446+
createPropertyAccessChain(object, /*questionDotToken*/ undefined, methodName),
5447+
/*questionDotToken*/ undefined,
5448+
/*typeArguments*/ undefined,
5449+
argumentsList
5450+
);
5451+
}
54385452
return createCallExpression(
54395453
createPropertyAccessExpression(object, methodName),
54405454
/*typeArguments*/ undefined,
@@ -5470,6 +5484,14 @@ namespace ts {
54705484
return createGlobalMethodCall("Object", "defineProperty", [target, asExpression(propertyName), attributes]);
54715485
}
54725486

5487+
function createReflectGetCall(target: Expression, propertyKey: Expression, receiver?: Expression): CallExpression {
5488+
return createGlobalMethodCall("Reflect", "get", receiver ? [target, propertyKey, receiver] : [target, propertyKey]);
5489+
}
5490+
5491+
function createReflectSetCall(target: Expression, propertyKey: Expression, value: Expression, receiver?: Expression): CallExpression {
5492+
return createGlobalMethodCall("Reflect", "set", receiver ? [target, propertyKey, value, receiver] : [target, propertyKey, value]);
5493+
}
5494+
54735495
function tryAddPropertyAssignment(properties: Push<PropertyAssignment>, propertyName: string, expression: Expression | undefined) {
54745496
if (expression) {
54755497
properties.push(createPropertyAssignment(propertyName, expression));
@@ -5645,6 +5667,34 @@ namespace ts {
56455667
return { target, thisArg };
56465668
}
56475669

5670+
function createAssignmentTargetWrapper(paramName: Identifier, expression: Expression): LeftHandSideExpression {
5671+
return createPropertyAccessExpression(
5672+
// Explicit parens required because of v8 regression (https://bugs.chromium.org/p/v8/issues/detail?id=9560)
5673+
createParenthesizedExpression(
5674+
createObjectLiteralExpression([
5675+
createSetAccessorDeclaration(
5676+
/*decorators*/ undefined,
5677+
/*modifiers*/ undefined,
5678+
"value",
5679+
[createParameterDeclaration(
5680+
/*decorators*/ undefined,
5681+
/*modifiers*/ undefined,
5682+
/*dotDotDotToken*/ undefined,
5683+
paramName,
5684+
/*questionToken*/ undefined,
5685+
/*type*/ undefined,
5686+
/*initializer*/ undefined
5687+
)],
5688+
createBlock([
5689+
createExpressionStatement(expression)
5690+
])
5691+
)
5692+
])
5693+
),
5694+
"value"
5695+
);
5696+
}
5697+
56485698
function inlineExpressions(expressions: readonly Expression[]) {
56495699
// Avoid deeply nested comma expressions as traversing them during emit can result in "Maximum call
56505700
// stack size exceeded" errors.

src/compiler/factory/utilities.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,67 @@ namespace ts {
303303
}
304304
}
305305

306+
/**
307+
* Expand the read and increment/decrement operations a pre- or post-increment or pre- or post-decrement expression.
308+
*
309+
* ```ts
310+
* // input
311+
* <expression>++
312+
* // output (if result is not discarded)
313+
* var <temp>;
314+
* (<temp> = <expression>, <resultVariable> = <temp>++, <temp>)
315+
* // output (if result is discarded)
316+
* var <temp>;
317+
* (<temp> = <expression>, <temp>++, <temp>)
318+
*
319+
* // input
320+
* ++<expression>
321+
* // output (if result is not discarded)
322+
* var <temp>;
323+
* (<temp> = <expression>, <resultVariable> = ++<temp>)
324+
* // output (if result is discarded)
325+
* var <temp>;
326+
* (<temp> = <expression>, ++<temp>)
327+
* ```
328+
*
329+
* It is up to the caller to supply a temporary variable for `<resultVariable>` if one is needed.
330+
* The temporary variable `<temp>` is injected so that `++` and `--` work uniformly with `number` and `bigint`.
331+
* The result of the expression is always the final result of incrementing or decrementing the expression, so that it can be used for storage.
332+
*
333+
* @param factory {@link NodeFactory} used to create the expanded representation.
334+
* @param node The original prefix or postfix unary node.
335+
* @param expression The expression to use as the value to increment or decrement
336+
* @param resultVariable A temporary variable in which to store the result. Pass `undefined` if the result is discarded, or if the value of `<temp>` is the expected result.
337+
*/
338+
export function expandPreOrPostfixIncrementOrDecrementExpression(factory: NodeFactory, node: PrefixUnaryExpression | PostfixUnaryExpression, expression: Expression, recordTempVariable: (node: Identifier) => void, resultVariable: Identifier | undefined) {
339+
const operator = node.operator;
340+
Debug.assert(operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken, "Expected 'node' to be a pre- or post-increment or pre- or post-decrement expression");
341+
342+
const temp = factory.createTempVariable(recordTempVariable);
343+
expression = factory.createAssignment(temp, expression);
344+
setTextRange(expression, node.operand);
345+
346+
let operation: Expression = isPrefixUnaryExpression(node) ?
347+
factory.createPrefixUnaryExpression(operator, temp) :
348+
factory.createPostfixUnaryExpression(temp, operator);
349+
setTextRange(operation, node);
350+
351+
if (resultVariable) {
352+
operation = factory.createAssignment(resultVariable, operation);
353+
setTextRange(operation, node);
354+
}
355+
356+
expression = factory.createComma(expression, operation);
357+
setTextRange(expression, node);
358+
359+
if (isPostfixUnaryExpression(node)) {
360+
expression = factory.createComma(expression, temp);
361+
setTextRange(expression, node);
362+
}
363+
364+
return expression;
365+
}
366+
306367
/**
307368
* Gets whether an identifier should only be referred to by its internal name.
308369
*/

0 commit comments

Comments
 (0)