diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 64e7ca0a8164a..7b5bbd228f55e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -49373,11 +49373,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); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 38146135ae715..927d9032d62c1 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3550,6 +3550,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; diff --git a/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.js b/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.js new file mode 100644 index 0000000000000..14b8387479794 --- /dev/null +++ b/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.js @@ -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); diff --git a/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.symbols b/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.symbols new file mode 100644 index 0000000000000..0955090e6712f --- /dev/null +++ b/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.symbols @@ -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)) + diff --git a/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.types b/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.types new file mode 100644 index 0000000000000..ff153e104aa65 --- /dev/null +++ b/tests/baselines/reference/capturedShorthandPropertyAssignmentNoCheck.types @@ -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 : (callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>fns : any[] +> : ^^^^^ +>map : (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[] +> : ^^^^^ + diff --git a/tests/cases/compiler/capturedShorthandPropertyAssignmentNoCheck.ts b/tests/cases/compiler/capturedShorthandPropertyAssignmentNoCheck.ts new file mode 100644 index 0000000000000..6046c379844de --- /dev/null +++ b/tests/cases/compiler/capturedShorthandPropertyAssignmentNoCheck.ts @@ -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)