Fix unintended 'as const' name lookup error (#44311) (#44370)

* Fix logic for methods in isTypeParameterPossiblyReferenced

* Add regression tests

Co-authored-by: Anders Hejlsberg <andersh@microsoft.com>
This commit is contained in:
Daniel Rosenwasser 2021-06-01 14:55:21 -07:00 committed by GitHub
parent 28e3e6ff2f
commit e425f573aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 271 additions and 3 deletions

View File

@ -15941,8 +15941,7 @@ namespace ts {
}
function maybeTypeParameterReference(node: Node) {
return !(node.kind === SyntaxKind.QualifiedName ||
node.parent.kind === SyntaxKind.TypeReference && (<TypeReferenceNode>node.parent).typeArguments && node === (<TypeReferenceNode>node.parent).typeName ||
return !(node.parent.kind === SyntaxKind.TypeReference && (node.parent as TypeReferenceNode).typeArguments && node === (node.parent as TypeReferenceNode).typeName ||
node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments && node === (node.parent as ImportTypeNode).qualifier);
}
@ -15971,7 +15970,10 @@ namespace ts {
return true;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
return (!(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body) || !!forEachChild(node, containsReference);
return !(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body ||
some((node as FunctionLikeDeclaration).typeParameters, containsReference) ||
some((node as FunctionLikeDeclaration).parameters, containsReference) ||
!!(node as FunctionLikeDeclaration).type && containsReference((node as FunctionLikeDeclaration).type!);
}
return !!forEachChild(node, containsReference);
}

View File

@ -0,0 +1,70 @@
//// [noAsConstNameLookup.ts]
// Repros from #44292
type Store = { a: 123 }
export type Cleaner = <W extends Store>(runner: FeatureRunner<W>) => Promise<any>
export class FeatureRunner<W extends Store> {
private readonly cleaners: Cleaner[] = []
async runFeature(): Promise<any> {
const objectWhichShouldBeConst = {
flags: {},
settings: {},
} as const;
return objectWhichShouldBeConst
}
async run(): Promise<any> {
const result = {}
this.cleaners.forEach(c => c(this))
return result
}
}
export class C<T> {
f(): void {
let one = 1 as const;
}
}
new C<string>().f();
//// [noAsConstNameLookup.js]
// Repros from #44292
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
export class FeatureRunner {
constructor() {
this.cleaners = [];
}
runFeature() {
return __awaiter(this, void 0, void 0, function* () {
const objectWhichShouldBeConst = {
flags: {},
settings: {},
};
return objectWhichShouldBeConst;
});
}
run() {
return __awaiter(this, void 0, void 0, function* () {
const result = {};
this.cleaners.forEach(c => c(this));
return result;
});
}
}
export class C {
f() {
let one = 1;
}
}
new C().f();

View File

@ -0,0 +1,81 @@
=== tests/cases/compiler/noAsConstNameLookup.ts ===
// Repros from #44292
type Store = { a: 123 }
>Store : Symbol(Store, Decl(noAsConstNameLookup.ts, 0, 0))
>a : Symbol(a, Decl(noAsConstNameLookup.ts, 2, 14))
export type Cleaner = <W extends Store>(runner: FeatureRunner<W>) => Promise<any>
>Cleaner : Symbol(Cleaner, Decl(noAsConstNameLookup.ts, 2, 23))
>W : Symbol(W, Decl(noAsConstNameLookup.ts, 3, 23))
>Store : Symbol(Store, Decl(noAsConstNameLookup.ts, 0, 0))
>runner : Symbol(runner, Decl(noAsConstNameLookup.ts, 3, 40))
>FeatureRunner : Symbol(FeatureRunner, Decl(noAsConstNameLookup.ts, 3, 81))
>W : Symbol(W, Decl(noAsConstNameLookup.ts, 3, 23))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
export class FeatureRunner<W extends Store> {
>FeatureRunner : Symbol(FeatureRunner, Decl(noAsConstNameLookup.ts, 3, 81))
>W : Symbol(W, Decl(noAsConstNameLookup.ts, 5, 27))
>Store : Symbol(Store, Decl(noAsConstNameLookup.ts, 0, 0))
private readonly cleaners: Cleaner[] = []
>cleaners : Symbol(FeatureRunner.cleaners, Decl(noAsConstNameLookup.ts, 5, 45))
>Cleaner : Symbol(Cleaner, Decl(noAsConstNameLookup.ts, 2, 23))
async runFeature(): Promise<any> {
>runFeature : Symbol(FeatureRunner.runFeature, Decl(noAsConstNameLookup.ts, 6, 45))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
const objectWhichShouldBeConst = {
>objectWhichShouldBeConst : Symbol(objectWhichShouldBeConst, Decl(noAsConstNameLookup.ts, 9, 13))
flags: {},
>flags : Symbol(flags, Decl(noAsConstNameLookup.ts, 9, 42))
settings: {},
>settings : Symbol(settings, Decl(noAsConstNameLookup.ts, 10, 22))
} as const;
return objectWhichShouldBeConst
>objectWhichShouldBeConst : Symbol(objectWhichShouldBeConst, Decl(noAsConstNameLookup.ts, 9, 13))
}
async run(): Promise<any> {
>run : Symbol(FeatureRunner.run, Decl(noAsConstNameLookup.ts, 14, 5))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
const result = {}
>result : Symbol(result, Decl(noAsConstNameLookup.ts, 17, 13))
this.cleaners.forEach(c => c(this))
>this.cleaners.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>this.cleaners : Symbol(FeatureRunner.cleaners, Decl(noAsConstNameLookup.ts, 5, 45))
>this : Symbol(FeatureRunner, Decl(noAsConstNameLookup.ts, 3, 81))
>cleaners : Symbol(FeatureRunner.cleaners, Decl(noAsConstNameLookup.ts, 5, 45))
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
>c : Symbol(c, Decl(noAsConstNameLookup.ts, 18, 30))
>c : Symbol(c, Decl(noAsConstNameLookup.ts, 18, 30))
>this : Symbol(FeatureRunner, Decl(noAsConstNameLookup.ts, 3, 81))
return result
>result : Symbol(result, Decl(noAsConstNameLookup.ts, 17, 13))
}
}
export class C<T> {
>C : Symbol(C, Decl(noAsConstNameLookup.ts, 21, 1))
>T : Symbol(T, Decl(noAsConstNameLookup.ts, 23, 15))
f(): void {
>f : Symbol(C.f, Decl(noAsConstNameLookup.ts, 23, 19))
let one = 1 as const;
>one : Symbol(one, Decl(noAsConstNameLookup.ts, 25, 11))
}
}
new C<string>().f();
>new C<string>().f : Symbol(C.f, Decl(noAsConstNameLookup.ts, 23, 19))
>C : Symbol(C, Decl(noAsConstNameLookup.ts, 21, 1))
>f : Symbol(C.f, Decl(noAsConstNameLookup.ts, 23, 19))

View File

@ -0,0 +1,83 @@
=== tests/cases/compiler/noAsConstNameLookup.ts ===
// Repros from #44292
type Store = { a: 123 }
>Store : Store
>a : 123
export type Cleaner = <W extends Store>(runner: FeatureRunner<W>) => Promise<any>
>Cleaner : Cleaner
>runner : FeatureRunner<W>
export class FeatureRunner<W extends Store> {
>FeatureRunner : FeatureRunner<W>
private readonly cleaners: Cleaner[] = []
>cleaners : Cleaner[]
>[] : never[]
async runFeature(): Promise<any> {
>runFeature : () => Promise<any>
const objectWhichShouldBeConst = {
>objectWhichShouldBeConst : { readonly flags: {}; readonly settings: {}; }
>{ flags: {}, settings: {}, } as const : { readonly flags: {}; readonly settings: {}; }
>{ flags: {}, settings: {}, } : { readonly flags: {}; readonly settings: {}; }
flags: {},
>flags : {}
>{} : {}
settings: {},
>settings : {}
>{} : {}
} as const;
return objectWhichShouldBeConst
>objectWhichShouldBeConst : { readonly flags: {}; readonly settings: {}; }
}
async run(): Promise<any> {
>run : () => Promise<any>
const result = {}
>result : {}
>{} : {}
this.cleaners.forEach(c => c(this))
>this.cleaners.forEach(c => c(this)) : void
>this.cleaners.forEach : (callbackfn: (value: Cleaner, index: number, array: Cleaner[]) => void, thisArg?: any) => void
>this.cleaners : Cleaner[]
>this : this
>cleaners : Cleaner[]
>forEach : (callbackfn: (value: Cleaner, index: number, array: Cleaner[]) => void, thisArg?: any) => void
>c => c(this) : (c: Cleaner) => Promise<any>
>c : Cleaner
>c(this) : Promise<any>
>c : Cleaner
>this : this
return result
>result : {}
}
}
export class C<T> {
>C : C<T>
f(): void {
>f : () => void
let one = 1 as const;
>one : 1
>1 as const : 1
>1 : 1
}
}
new C<string>().f();
>new C<string>().f() : void
>new C<string>().f : () => void
>new C<string>() : C<string>
>C : typeof C
>f : () => void

View File

@ -0,0 +1,32 @@
// @strict: true
// @target: es2015
// Repros from #44292
type Store = { a: 123 }
export type Cleaner = <W extends Store>(runner: FeatureRunner<W>) => Promise<any>
export class FeatureRunner<W extends Store> {
private readonly cleaners: Cleaner[] = []
async runFeature(): Promise<any> {
const objectWhichShouldBeConst = {
flags: {},
settings: {},
} as const;
return objectWhichShouldBeConst
}
async run(): Promise<any> {
const result = {}
this.cleaners.forEach(c => c(this))
return result
}
}
export class C<T> {
f(): void {
let one = 1 as const;
}
}
new C<string>().f();