Fix captured shorthand properties in ES2015 loops (#59285)

This commit is contained in:
Jake Bailey 2024-07-16 13:30:50 -07:00 committed by GitHub
parent 5e105ea71a
commit 003221becb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 136 additions and 2 deletions

View File

@ -49341,11 +49341,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
forEachNodeRecursively(node, checkIdentifiers);
}
function isExpressionNodeOrShorthandPropertyAssignmentName(node: Identifier) {
// TODO(jakebailey): Just use isExpressionNode once that considers these identifiers to be expressions.
return isExpressionNode(node)
|| isShorthandPropertyAssignment(node.parent) && (node.parent.objectAssignmentInitializer ?? node.parent.name) === node;
}
function checkSingleIdentifier(node: Node) {
const nodeLinks = getNodeLinks(node);
nodeLinks.calculatedFlags |= NodeCheckFlags.ConstructorReference | NodeCheckFlags.CapturedBlockScopedBinding | NodeCheckFlags.BlockScopedBindingInLoop;
if (isIdentifier(node) && isExpressionNode(node) && !(isPropertyAccessExpression(node.parent) && node.parent.name === node)) {
const s = getSymbolAtLocation(node, /*ignoreErrors*/ true);
if (isIdentifier(node) && isExpressionNodeOrShorthandPropertyAssignmentName(node) && !(isPropertyAccessExpression(node.parent) && node.parent.name === node)) {
const s = getResolvedSymbol(node);
if (s && s !== unknownSymbol) {
checkIdentifierCalculateNodeCheckFlags(node, s);
}

View File

@ -3582,6 +3582,7 @@ export function isInExpressionContext(node: Node): boolean {
case SyntaxKind.ExpressionWithTypeArguments:
return (parent as ExpressionWithTypeArguments).expression === node && !isPartOfTypeNode(parent);
case SyntaxKind.ShorthandPropertyAssignment:
// TODO(jakebailey): it's possible that node could be the name, too
return (parent as ShorthandPropertyAssignment).objectAssignmentInitializer === node;
case SyntaxKind.SatisfiesExpression:
return node === (parent as SatisfiesExpression).expression;

View File

@ -0,0 +1,22 @@
//// [tests/cases/compiler/capturedShorthandPropertyAssignmentNoCheck.ts] ////
//// [capturedShorthandPropertyAssignmentNoCheck.ts]
const fns = [];
for (const value of [1, 2, 3]) {
fns.push(() => ({ value }));
}
const result = fns.map(fn => fn());
console.log(result)
//// [capturedShorthandPropertyAssignmentNoCheck.js]
var fns = [];
var _loop_1 = function (value) {
fns.push(function () { return ({ value: value }); });
};
for (var _i = 0, _a = [1, 2, 3]; _i < _a.length; _i++) {
var value = _a[_i];
_loop_1(value);
}
var result = fns.map(function (fn) { return fn(); });
console.log(result);

View File

@ -0,0 +1,29 @@
//// [tests/cases/compiler/capturedShorthandPropertyAssignmentNoCheck.ts] ////
=== capturedShorthandPropertyAssignmentNoCheck.ts ===
const fns = [];
>fns : Symbol(fns, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 0, 5))
for (const value of [1, 2, 3]) {
>value : Symbol(value, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 1, 10))
fns.push(() => ({ value }));
>fns.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>fns : Symbol(fns, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 0, 5))
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>value : Symbol(value, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 2, 21))
}
const result = fns.map(fn => fn());
>result : Symbol(result, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 4, 5))
>fns.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
>fns : Symbol(fns, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 0, 5))
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
>fn : Symbol(fn, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 4, 23))
>fn : Symbol(fn, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 4, 23))
console.log(result)
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>result : Symbol(result, Decl(capturedShorthandPropertyAssignmentNoCheck.ts, 4, 5))

View File

@ -0,0 +1,68 @@
//// [tests/cases/compiler/capturedShorthandPropertyAssignmentNoCheck.ts] ////
=== capturedShorthandPropertyAssignmentNoCheck.ts ===
const fns = [];
>fns : any[]
> : ^^^^^
>[] : undefined[]
> : ^^^^^^^^^^^
for (const value of [1, 2, 3]) {
>value : number
> : ^^^^^^
>[1, 2, 3] : number[]
> : ^^^^^^^^
>1 : 1
> : ^
>2 : 2
> : ^
>3 : 3
> : ^
fns.push(() => ({ value }));
>fns.push(() => ({ value })) : number
> : ^^^^^^
>fns.push : (...items: any[]) => number
> : ^^^^ ^^^^^^^^^^^^
>fns : any[]
> : ^^^^^
>push : (...items: any[]) => number
> : ^^^^ ^^^^^^^^^^^^
>() => ({ value }) : () => { value: number; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^
>({ value }) : { value: number; }
> : ^^^^^^^^^^^^^^^^^^
>{ value } : { value: number; }
> : ^^^^^^^^^^^^^^^^^^
>value : number
> : ^^^^^^
}
const result = fns.map(fn => fn());
>result : any[]
> : ^^^^^
>fns.map(fn => fn()) : any[]
> : ^^^^^
>fns.map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
> : ^ ^^ ^^^ ^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^
>fns : any[]
> : ^^^^^
>map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
> : ^ ^^ ^^^ ^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^
>fn => fn() : (fn: any) => any
> : ^ ^^^^^^^^^^^^^
>fn : any
>fn() : any
>fn : any
console.log(result)
>console.log(result) : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>result : any[]
> : ^^^^^

View File

@ -0,0 +1,8 @@
// @target: es5
const fns = [];
for (const value of [1, 2, 3]) {
fns.push(() => ({ value }));
}
const result = fns.map(fn => fn());
console.log(result)