From 68b84f0bad36bd62ca225ac82c6f1ed008f21314 Mon Sep 17 00:00:00 2001 From: TypeScript Bot <23042052+typescript-bot@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:21:10 -0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Pick=20PR=20#60683=20(Cache=20st?= =?UTF-8?q?arted=20nonexistent=20property=20...)=20into=20release-5.7=20(#?= =?UTF-8?q?60686)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wesley Wigham --- src/compiler/checker.ts | 7 +++++ src/compiler/types.ts | 1 + ...ctWithThisInNamePositionNoCrash.errors.txt | 16 ++++++++++ ...kingObjectWithThisInNamePositionNoCrash.js | 31 +++++++++++++++++++ ...bjectWithThisInNamePositionNoCrash.symbols | 16 ++++++++++ ...gObjectWithThisInNamePositionNoCrash.types | 31 +++++++++++++++++++ ...kingObjectWithThisInNamePositionNoCrash.ts | 9 ++++++ 7 files changed, 111 insertions(+) create mode 100644 tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.errors.txt create mode 100644 tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.js create mode 100644 tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.symbols create mode 100644 tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.types create mode 100644 tests/cases/compiler/checkingObjectWithThisInNamePositionNoCrash.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f817b9b16e8dc..6ffb0fb010714 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34315,6 +34315,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function reportNonexistentProperty(propNode: Identifier | PrivateIdentifier, containingType: Type, isUncheckedJS: boolean) { + const links = getNodeLinks(propNode); + const cache = (links.nonExistentPropCheckCache ||= new Set()); + const key = `${getTypeId(containingType)}|${isUncheckedJS}`; + if (cache.has(key)) { + return; + } + cache.add(key); let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: Diagnostic | undefined; if (!isPrivateIdentifier(propNode) && containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9b5908d71d9bc..92af593d2651c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6243,6 +6243,7 @@ export interface NodeLinks { potentialUnusedRenamedBindingElementsInTypes?: BindingElement[]; externalHelpersModule?: Symbol; // Resolved symbol for the external helpers module instantiationExpressionTypes?: Map; // Cache of instantiation expression types for the node + nonExistentPropCheckCache?: Set; } /** @internal */ diff --git a/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.errors.txt b/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.errors.txt new file mode 100644 index 0000000000000..e59c81e953e16 --- /dev/null +++ b/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.errors.txt @@ -0,0 +1,16 @@ +checkingObjectWithThisInNamePositionNoCrash.ts(2,5): error TS7023: 'doit' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. +checkingObjectWithThisInNamePositionNoCrash.ts(4,19): error TS2339: Property 'a' does not exist on type '{ doit(): { [x: number]: string; }; }'. + + +==== checkingObjectWithThisInNamePositionNoCrash.ts (2 errors) ==== + export const thing = { + doit() { + ~~~~ +!!! error TS7023: 'doit' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. + return { + [this.a]: "", // should refer to the outer object with the doit method, notably not present + ~ +!!! error TS2339: Property 'a' does not exist on type '{ doit(): { [x: number]: string; }; }'. + } + } + } \ No newline at end of file diff --git a/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.js b/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.js new file mode 100644 index 0000000000000..462afe05d5fda --- /dev/null +++ b/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.js @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/checkingObjectWithThisInNamePositionNoCrash.ts] //// + +//// [checkingObjectWithThisInNamePositionNoCrash.ts] +export const thing = { + doit() { + return { + [this.a]: "", // should refer to the outer object with the doit method, notably not present + } + } +} + +//// [checkingObjectWithThisInNamePositionNoCrash.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.thing = void 0; +exports.thing = { + doit: function () { + var _a; + return _a = {}, + _a[this.a] = "", + _a; + } +}; + + +//// [checkingObjectWithThisInNamePositionNoCrash.d.ts] +export declare const thing: { + doit(): { + [x: number]: string; + }; +}; diff --git a/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.symbols b/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.symbols new file mode 100644 index 0000000000000..6622b9f23682e --- /dev/null +++ b/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.symbols @@ -0,0 +1,16 @@ +//// [tests/cases/compiler/checkingObjectWithThisInNamePositionNoCrash.ts] //// + +=== checkingObjectWithThisInNamePositionNoCrash.ts === +export const thing = { +>thing : Symbol(thing, Decl(checkingObjectWithThisInNamePositionNoCrash.ts, 0, 12)) + + doit() { +>doit : Symbol(doit, Decl(checkingObjectWithThisInNamePositionNoCrash.ts, 0, 22)) + + return { + [this.a]: "", // should refer to the outer object with the doit method, notably not present +>[this.a] : Symbol([this.a], Decl(checkingObjectWithThisInNamePositionNoCrash.ts, 2, 16)) +>this : Symbol(thing, Decl(checkingObjectWithThisInNamePositionNoCrash.ts, 0, 20)) + } + } +} diff --git a/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.types b/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.types new file mode 100644 index 0000000000000..cf00ba84fd1f2 --- /dev/null +++ b/tests/baselines/reference/checkingObjectWithThisInNamePositionNoCrash.types @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/checkingObjectWithThisInNamePositionNoCrash.ts] //// + +=== checkingObjectWithThisInNamePositionNoCrash.ts === +export const thing = { +>thing : { doit(): { [x: number]: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ doit() { return { [this.a]: "", // should refer to the outer object with the doit method, notably not present } }} : { doit(): { [x: number]: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + doit() { +>doit : () => { [x: number]: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return { +>{ [this.a]: "", // should refer to the outer object with the doit method, notably not present } : { [x: number]: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + [this.a]: "", // should refer to the outer object with the doit method, notably not present +>[this.a] : string +> : ^^^^^^ +>this.a : any +> : ^^^ +>this : { doit(): { [x: number]: string; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>a : any +> : ^^^ +>"" : "" +> : ^^ + } + } +} diff --git a/tests/cases/compiler/checkingObjectWithThisInNamePositionNoCrash.ts b/tests/cases/compiler/checkingObjectWithThisInNamePositionNoCrash.ts new file mode 100644 index 0000000000000..db6a56d346fbb --- /dev/null +++ b/tests/cases/compiler/checkingObjectWithThisInNamePositionNoCrash.ts @@ -0,0 +1,9 @@ +// @strict: true +// @declaration: true +export const thing = { + doit() { + return { + [this.a]: "", // should refer to the outer object with the doit method, notably not present + } + } +} \ No newline at end of file