Skip to content

Commit e425f57

Browse files
Fix unintended 'as const' name lookup error (#44311) (#44370)
* Fix logic for methods in isTypeParameterPossiblyReferenced * Add regression tests Co-authored-by: Anders Hejlsberg <[email protected]>
1 parent 28e3e6f commit e425f57

File tree

5 files changed

+271
-3
lines changed

5 files changed

+271
-3
lines changed

src/compiler/checker.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -15941,8 +15941,7 @@ namespace ts {
1594115941
}
1594215942

1594315943
function maybeTypeParameterReference(node: Node) {
15944-
return !(node.kind === SyntaxKind.QualifiedName ||
15945-
node.parent.kind === SyntaxKind.TypeReference && (<TypeReferenceNode>node.parent).typeArguments && node === (<TypeReferenceNode>node.parent).typeName ||
15944+
return !(node.parent.kind === SyntaxKind.TypeReference && (node.parent as TypeReferenceNode).typeArguments && node === (node.parent as TypeReferenceNode).typeName ||
1594615945
node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments && node === (node.parent as ImportTypeNode).qualifier);
1594715946
}
1594815947

@@ -15971,7 +15970,10 @@ namespace ts {
1597115970
return true;
1597215971
case SyntaxKind.MethodDeclaration:
1597315972
case SyntaxKind.MethodSignature:
15974-
return (!(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body) || !!forEachChild(node, containsReference);
15973+
return !(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body ||
15974+
some((node as FunctionLikeDeclaration).typeParameters, containsReference) ||
15975+
some((node as FunctionLikeDeclaration).parameters, containsReference) ||
15976+
!!(node as FunctionLikeDeclaration).type && containsReference((node as FunctionLikeDeclaration).type!);
1597515977
}
1597615978
return !!forEachChild(node, containsReference);
1597715979
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//// [noAsConstNameLookup.ts]
2+
// Repros from #44292
3+
4+
type Store = { a: 123 }
5+
export type Cleaner = <W extends Store>(runner: FeatureRunner<W>) => Promise<any>
6+
7+
export class FeatureRunner<W extends Store> {
8+
private readonly cleaners: Cleaner[] = []
9+
10+
async runFeature(): Promise<any> {
11+
const objectWhichShouldBeConst = {
12+
flags: {},
13+
settings: {},
14+
} as const;
15+
return objectWhichShouldBeConst
16+
}
17+
18+
async run(): Promise<any> {
19+
const result = {}
20+
this.cleaners.forEach(c => c(this))
21+
return result
22+
}
23+
}
24+
25+
export class C<T> {
26+
f(): void {
27+
let one = 1 as const;
28+
}
29+
}
30+
new C<string>().f();
31+
32+
33+
//// [noAsConstNameLookup.js]
34+
// Repros from #44292
35+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37+
return new (P || (P = Promise))(function (resolve, reject) {
38+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41+
step((generator = generator.apply(thisArg, _arguments || [])).next());
42+
});
43+
};
44+
export class FeatureRunner {
45+
constructor() {
46+
this.cleaners = [];
47+
}
48+
runFeature() {
49+
return __awaiter(this, void 0, void 0, function* () {
50+
const objectWhichShouldBeConst = {
51+
flags: {},
52+
settings: {},
53+
};
54+
return objectWhichShouldBeConst;
55+
});
56+
}
57+
run() {
58+
return __awaiter(this, void 0, void 0, function* () {
59+
const result = {};
60+
this.cleaners.forEach(c => c(this));
61+
return result;
62+
});
63+
}
64+
}
65+
export class C {
66+
f() {
67+
let one = 1;
68+
}
69+
}
70+
new C().f();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
=== tests/cases/compiler/noAsConstNameLookup.ts ===
2+
// Repros from #44292
3+
4+
type Store = { a: 123 }
5+
>Store : Symbol(Store, Decl(noAsConstNameLookup.ts, 0, 0))
6+
>a : Symbol(a, Decl(noAsConstNameLookup.ts, 2, 14))
7+
8+
export type Cleaner = <W extends Store>(runner: FeatureRunner<W>) => Promise<any>
9+
>Cleaner : Symbol(Cleaner, Decl(noAsConstNameLookup.ts, 2, 23))
10+
>W : Symbol(W, Decl(noAsConstNameLookup.ts, 3, 23))
11+
>Store : Symbol(Store, Decl(noAsConstNameLookup.ts, 0, 0))
12+
>runner : Symbol(runner, Decl(noAsConstNameLookup.ts, 3, 40))
13+
>FeatureRunner : Symbol(FeatureRunner, Decl(noAsConstNameLookup.ts, 3, 81))
14+
>W : Symbol(W, Decl(noAsConstNameLookup.ts, 3, 23))
15+
>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, --, --))
16+
17+
export class FeatureRunner<W extends Store> {
18+
>FeatureRunner : Symbol(FeatureRunner, Decl(noAsConstNameLookup.ts, 3, 81))
19+
>W : Symbol(W, Decl(noAsConstNameLookup.ts, 5, 27))
20+
>Store : Symbol(Store, Decl(noAsConstNameLookup.ts, 0, 0))
21+
22+
private readonly cleaners: Cleaner[] = []
23+
>cleaners : Symbol(FeatureRunner.cleaners, Decl(noAsConstNameLookup.ts, 5, 45))
24+
>Cleaner : Symbol(Cleaner, Decl(noAsConstNameLookup.ts, 2, 23))
25+
26+
async runFeature(): Promise<any> {
27+
>runFeature : Symbol(FeatureRunner.runFeature, Decl(noAsConstNameLookup.ts, 6, 45))
28+
>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, --, --))
29+
30+
const objectWhichShouldBeConst = {
31+
>objectWhichShouldBeConst : Symbol(objectWhichShouldBeConst, Decl(noAsConstNameLookup.ts, 9, 13))
32+
33+
flags: {},
34+
>flags : Symbol(flags, Decl(noAsConstNameLookup.ts, 9, 42))
35+
36+
settings: {},
37+
>settings : Symbol(settings, Decl(noAsConstNameLookup.ts, 10, 22))
38+
39+
} as const;
40+
return objectWhichShouldBeConst
41+
>objectWhichShouldBeConst : Symbol(objectWhichShouldBeConst, Decl(noAsConstNameLookup.ts, 9, 13))
42+
}
43+
44+
async run(): Promise<any> {
45+
>run : Symbol(FeatureRunner.run, Decl(noAsConstNameLookup.ts, 14, 5))
46+
>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, --, --))
47+
48+
const result = {}
49+
>result : Symbol(result, Decl(noAsConstNameLookup.ts, 17, 13))
50+
51+
this.cleaners.forEach(c => c(this))
52+
>this.cleaners.forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
53+
>this.cleaners : Symbol(FeatureRunner.cleaners, Decl(noAsConstNameLookup.ts, 5, 45))
54+
>this : Symbol(FeatureRunner, Decl(noAsConstNameLookup.ts, 3, 81))
55+
>cleaners : Symbol(FeatureRunner.cleaners, Decl(noAsConstNameLookup.ts, 5, 45))
56+
>forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --))
57+
>c : Symbol(c, Decl(noAsConstNameLookup.ts, 18, 30))
58+
>c : Symbol(c, Decl(noAsConstNameLookup.ts, 18, 30))
59+
>this : Symbol(FeatureRunner, Decl(noAsConstNameLookup.ts, 3, 81))
60+
61+
return result
62+
>result : Symbol(result, Decl(noAsConstNameLookup.ts, 17, 13))
63+
}
64+
}
65+
66+
export class C<T> {
67+
>C : Symbol(C, Decl(noAsConstNameLookup.ts, 21, 1))
68+
>T : Symbol(T, Decl(noAsConstNameLookup.ts, 23, 15))
69+
70+
f(): void {
71+
>f : Symbol(C.f, Decl(noAsConstNameLookup.ts, 23, 19))
72+
73+
let one = 1 as const;
74+
>one : Symbol(one, Decl(noAsConstNameLookup.ts, 25, 11))
75+
}
76+
}
77+
new C<string>().f();
78+
>new C<string>().f : Symbol(C.f, Decl(noAsConstNameLookup.ts, 23, 19))
79+
>C : Symbol(C, Decl(noAsConstNameLookup.ts, 21, 1))
80+
>f : Symbol(C.f, Decl(noAsConstNameLookup.ts, 23, 19))
81+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
=== tests/cases/compiler/noAsConstNameLookup.ts ===
2+
// Repros from #44292
3+
4+
type Store = { a: 123 }
5+
>Store : Store
6+
>a : 123
7+
8+
export type Cleaner = <W extends Store>(runner: FeatureRunner<W>) => Promise<any>
9+
>Cleaner : Cleaner
10+
>runner : FeatureRunner<W>
11+
12+
export class FeatureRunner<W extends Store> {
13+
>FeatureRunner : FeatureRunner<W>
14+
15+
private readonly cleaners: Cleaner[] = []
16+
>cleaners : Cleaner[]
17+
>[] : never[]
18+
19+
async runFeature(): Promise<any> {
20+
>runFeature : () => Promise<any>
21+
22+
const objectWhichShouldBeConst = {
23+
>objectWhichShouldBeConst : { readonly flags: {}; readonly settings: {}; }
24+
>{ flags: {}, settings: {}, } as const : { readonly flags: {}; readonly settings: {}; }
25+
>{ flags: {}, settings: {}, } : { readonly flags: {}; readonly settings: {}; }
26+
27+
flags: {},
28+
>flags : {}
29+
>{} : {}
30+
31+
settings: {},
32+
>settings : {}
33+
>{} : {}
34+
35+
} as const;
36+
return objectWhichShouldBeConst
37+
>objectWhichShouldBeConst : { readonly flags: {}; readonly settings: {}; }
38+
}
39+
40+
async run(): Promise<any> {
41+
>run : () => Promise<any>
42+
43+
const result = {}
44+
>result : {}
45+
>{} : {}
46+
47+
this.cleaners.forEach(c => c(this))
48+
>this.cleaners.forEach(c => c(this)) : void
49+
>this.cleaners.forEach : (callbackfn: (value: Cleaner, index: number, array: Cleaner[]) => void, thisArg?: any) => void
50+
>this.cleaners : Cleaner[]
51+
>this : this
52+
>cleaners : Cleaner[]
53+
>forEach : (callbackfn: (value: Cleaner, index: number, array: Cleaner[]) => void, thisArg?: any) => void
54+
>c => c(this) : (c: Cleaner) => Promise<any>
55+
>c : Cleaner
56+
>c(this) : Promise<any>
57+
>c : Cleaner
58+
>this : this
59+
60+
return result
61+
>result : {}
62+
}
63+
}
64+
65+
export class C<T> {
66+
>C : C<T>
67+
68+
f(): void {
69+
>f : () => void
70+
71+
let one = 1 as const;
72+
>one : 1
73+
>1 as const : 1
74+
>1 : 1
75+
}
76+
}
77+
new C<string>().f();
78+
>new C<string>().f() : void
79+
>new C<string>().f : () => void
80+
>new C<string>() : C<string>
81+
>C : typeof C
82+
>f : () => void
83+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// @strict: true
2+
// @target: es2015
3+
4+
// Repros from #44292
5+
6+
type Store = { a: 123 }
7+
export type Cleaner = <W extends Store>(runner: FeatureRunner<W>) => Promise<any>
8+
9+
export class FeatureRunner<W extends Store> {
10+
private readonly cleaners: Cleaner[] = []
11+
12+
async runFeature(): Promise<any> {
13+
const objectWhichShouldBeConst = {
14+
flags: {},
15+
settings: {},
16+
} as const;
17+
return objectWhichShouldBeConst
18+
}
19+
20+
async run(): Promise<any> {
21+
const result = {}
22+
this.cleaners.forEach(c => c(this))
23+
return result
24+
}
25+
}
26+
27+
export class C<T> {
28+
f(): void {
29+
let one = 1 as const;
30+
}
31+
}
32+
new C<string>().f();

0 commit comments

Comments
 (0)