Skip to content

Commit 728d2a9

Browse files
authored
Merge pull request #19091 from Microsoft/fixAnonymousTypeInstantiation
Fix anonymous type instantiation
2 parents bada009 + 7ee9629 commit 728d2a9

File tree

5 files changed

+297
-8
lines changed

5 files changed

+297
-8
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8289,11 +8289,11 @@ namespace ts {
82898289
// The first time an anonymous type is instantiated we compute and store a list of the type
82908290
// parameters that are in scope (and therefore potentially referenced). For type literals that
82918291
// aren't the right hand side of a generic type alias declaration we optimize by reducing the
8292-
// set of type parameters to those that are actually referenced somewhere in the literal.
8292+
// set of type parameters to those that are possibly referenced in the literal.
82938293
const declaration = symbol.declarations[0];
82948294
const outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true) || emptyArray;
82958295
typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ?
8296-
filter(outerTypeParameters, tp => isTypeParameterReferencedWithin(tp, declaration)) :
8296+
filter(outerTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) :
82978297
outerTypeParameters;
82988298
links.typeParameters = typeParameters;
82998299
if (typeParameters.length) {
@@ -8319,13 +8319,27 @@ namespace ts {
83198319
return type;
83208320
}
83218321

8322-
function isTypeParameterReferencedWithin(tp: TypeParameter, node: Node) {
8323-
return tp.isThisType ? forEachChild(node, checkThis) : forEachChild(node, checkIdentifier);
8324-
function checkThis(node: Node): boolean {
8325-
return node.kind === SyntaxKind.ThisType || forEachChild(node, checkThis);
8322+
function isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node) {
8323+
// If the type parameter doesn't have exactly one declaration, if there are invening statement blocks
8324+
// between the node and the type parameter declaration, if the node contains actual references to the
8325+
// type parameter, or if the node contains type queries, we consider the type parameter possibly referenced.
8326+
if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1) {
8327+
const container = tp.symbol.declarations[0].parent;
8328+
if (findAncestor(node, n => n.kind === SyntaxKind.Block ? "quit" : n === container)) {
8329+
return forEachChild(node, containsReference);
8330+
}
83268331
}
8327-
function checkIdentifier(node: Node): boolean {
8328-
return node.kind === SyntaxKind.Identifier && isPartOfTypeNode(node) && getTypeFromTypeNode(<TypeNode>node) === tp || forEachChild(node, checkIdentifier);
8332+
return true;
8333+
function containsReference(node: Node): boolean {
8334+
switch (node.kind) {
8335+
case SyntaxKind.ThisType:
8336+
return tp.isThisType;
8337+
case SyntaxKind.Identifier:
8338+
return !tp.isThisType && isPartOfTypeNode(node) && getTypeFromTypeNode(<TypeNode>node) === tp;
8339+
case SyntaxKind.TypeQuery:
8340+
return true;
8341+
}
8342+
return forEachChild(node, containsReference);
83298343
}
83308344
}
83318345

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//// [indirectTypeParameterReferences.ts]
2+
// Repro from #19043
3+
4+
type B = {b: string}
5+
6+
const flowtypes = <A>(b: B) => {
7+
type Combined = A & B
8+
9+
const combined = (fn: (combined: Combined) => void) => null
10+
const literal = (fn: (aPlusB: A & B) => void) => null
11+
12+
return {combined, literal}
13+
}
14+
15+
const {combined, literal} = flowtypes<{a: string}>({b: 'b-value'})
16+
17+
literal(aPlusB => {
18+
aPlusB.b
19+
aPlusB.a
20+
})
21+
22+
combined(comb => {
23+
comb.b
24+
comb.a
25+
})
26+
27+
// Repro from #19091
28+
29+
declare function f<T>(a: T): { a: typeof a };
30+
let n: number = f(2).a;
31+
32+
33+
//// [indirectTypeParameterReferences.js]
34+
// Repro from #19043
35+
var flowtypes = function (b) {
36+
var combined = function (fn) { return null; };
37+
var literal = function (fn) { return null; };
38+
return { combined: combined, literal: literal };
39+
};
40+
var _a = flowtypes({ b: 'b-value' }), combined = _a.combined, literal = _a.literal;
41+
literal(function (aPlusB) {
42+
aPlusB.b;
43+
aPlusB.a;
44+
});
45+
combined(function (comb) {
46+
comb.b;
47+
comb.a;
48+
});
49+
var n = f(2).a;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
=== tests/cases/compiler/indirectTypeParameterReferences.ts ===
2+
// Repro from #19043
3+
4+
type B = {b: string}
5+
>B : Symbol(B, Decl(indirectTypeParameterReferences.ts, 0, 0))
6+
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
7+
8+
const flowtypes = <A>(b: B) => {
9+
>flowtypes : Symbol(flowtypes, Decl(indirectTypeParameterReferences.ts, 4, 5))
10+
>A : Symbol(A, Decl(indirectTypeParameterReferences.ts, 4, 19))
11+
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 4, 22))
12+
>B : Symbol(B, Decl(indirectTypeParameterReferences.ts, 0, 0))
13+
14+
type Combined = A & B
15+
>Combined : Symbol(Combined, Decl(indirectTypeParameterReferences.ts, 4, 32))
16+
>A : Symbol(A, Decl(indirectTypeParameterReferences.ts, 4, 19))
17+
>B : Symbol(B, Decl(indirectTypeParameterReferences.ts, 0, 0))
18+
19+
const combined = (fn: (combined: Combined) => void) => null
20+
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 7, 7))
21+
>fn : Symbol(fn, Decl(indirectTypeParameterReferences.ts, 7, 20))
22+
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 7, 25))
23+
>Combined : Symbol(Combined, Decl(indirectTypeParameterReferences.ts, 4, 32))
24+
25+
const literal = (fn: (aPlusB: A & B) => void) => null
26+
>literal : Symbol(literal, Decl(indirectTypeParameterReferences.ts, 8, 7))
27+
>fn : Symbol(fn, Decl(indirectTypeParameterReferences.ts, 8, 19))
28+
>aPlusB : Symbol(aPlusB, Decl(indirectTypeParameterReferences.ts, 8, 24))
29+
>A : Symbol(A, Decl(indirectTypeParameterReferences.ts, 4, 19))
30+
>B : Symbol(B, Decl(indirectTypeParameterReferences.ts, 0, 0))
31+
32+
return {combined, literal}
33+
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 10, 10))
34+
>literal : Symbol(literal, Decl(indirectTypeParameterReferences.ts, 10, 19))
35+
}
36+
37+
const {combined, literal} = flowtypes<{a: string}>({b: 'b-value'})
38+
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 13, 7))
39+
>literal : Symbol(literal, Decl(indirectTypeParameterReferences.ts, 13, 16))
40+
>flowtypes : Symbol(flowtypes, Decl(indirectTypeParameterReferences.ts, 4, 5))
41+
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
42+
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 13, 52))
43+
44+
literal(aPlusB => {
45+
>literal : Symbol(literal, Decl(indirectTypeParameterReferences.ts, 13, 16))
46+
>aPlusB : Symbol(aPlusB, Decl(indirectTypeParameterReferences.ts, 15, 8))
47+
48+
aPlusB.b
49+
>aPlusB.b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
50+
>aPlusB : Symbol(aPlusB, Decl(indirectTypeParameterReferences.ts, 15, 8))
51+
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
52+
53+
aPlusB.a
54+
>aPlusB.a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
55+
>aPlusB : Symbol(aPlusB, Decl(indirectTypeParameterReferences.ts, 15, 8))
56+
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
57+
58+
})
59+
60+
combined(comb => {
61+
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 13, 7))
62+
>comb : Symbol(comb, Decl(indirectTypeParameterReferences.ts, 20, 9))
63+
64+
comb.b
65+
>comb.b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
66+
>comb : Symbol(comb, Decl(indirectTypeParameterReferences.ts, 20, 9))
67+
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
68+
69+
comb.a
70+
>comb.a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
71+
>comb : Symbol(comb, Decl(indirectTypeParameterReferences.ts, 20, 9))
72+
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
73+
74+
})
75+
76+
// Repro from #19091
77+
78+
declare function f<T>(a: T): { a: typeof a };
79+
>f : Symbol(f, Decl(indirectTypeParameterReferences.ts, 23, 2))
80+
>T : Symbol(T, Decl(indirectTypeParameterReferences.ts, 27, 19))
81+
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 22))
82+
>T : Symbol(T, Decl(indirectTypeParameterReferences.ts, 27, 19))
83+
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 30))
84+
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 22))
85+
86+
let n: number = f(2).a;
87+
>n : Symbol(n, Decl(indirectTypeParameterReferences.ts, 28, 3))
88+
>f(2).a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 30))
89+
>f : Symbol(f, Decl(indirectTypeParameterReferences.ts, 23, 2))
90+
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 30))
91+
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
=== tests/cases/compiler/indirectTypeParameterReferences.ts ===
2+
// Repro from #19043
3+
4+
type B = {b: string}
5+
>B : B
6+
>b : string
7+
8+
const flowtypes = <A>(b: B) => {
9+
>flowtypes : <A>(b: B) => { combined: (fn: (combined: A & B) => void) => any; literal: (fn: (aPlusB: A & B) => void) => any; }
10+
><A>(b: B) => { type Combined = A & B const combined = (fn: (combined: Combined) => void) => null const literal = (fn: (aPlusB: A & B) => void) => null return {combined, literal}} : <A>(b: B) => { combined: (fn: (combined: A & B) => void) => any; literal: (fn: (aPlusB: A & B) => void) => any; }
11+
>A : A
12+
>b : B
13+
>B : B
14+
15+
type Combined = A & B
16+
>Combined : A & B
17+
>A : A
18+
>B : B
19+
20+
const combined = (fn: (combined: Combined) => void) => null
21+
>combined : (fn: (combined: A & B) => void) => any
22+
>(fn: (combined: Combined) => void) => null : (fn: (combined: A & B) => void) => any
23+
>fn : (combined: A & B) => void
24+
>combined : A & B
25+
>Combined : A & B
26+
>null : null
27+
28+
const literal = (fn: (aPlusB: A & B) => void) => null
29+
>literal : (fn: (aPlusB: A & B) => void) => any
30+
>(fn: (aPlusB: A & B) => void) => null : (fn: (aPlusB: A & B) => void) => any
31+
>fn : (aPlusB: A & B) => void
32+
>aPlusB : A & B
33+
>A : A
34+
>B : B
35+
>null : null
36+
37+
return {combined, literal}
38+
>{combined, literal} : { combined: (fn: (combined: A & B) => void) => any; literal: (fn: (aPlusB: A & B) => void) => any; }
39+
>combined : (fn: (combined: A & B) => void) => any
40+
>literal : (fn: (aPlusB: A & B) => void) => any
41+
}
42+
43+
const {combined, literal} = flowtypes<{a: string}>({b: 'b-value'})
44+
>combined : (fn: (combined: { a: string; } & B) => void) => any
45+
>literal : (fn: (aPlusB: { a: string; } & B) => void) => any
46+
>flowtypes<{a: string}>({b: 'b-value'}) : { combined: (fn: (combined: { a: string; } & B) => void) => any; literal: (fn: (aPlusB: { a: string; } & B) => void) => any; }
47+
>flowtypes : <A>(b: B) => { combined: (fn: (combined: A & B) => void) => any; literal: (fn: (aPlusB: A & B) => void) => any; }
48+
>a : string
49+
>{b: 'b-value'} : { b: string; }
50+
>b : string
51+
>'b-value' : "b-value"
52+
53+
literal(aPlusB => {
54+
>literal(aPlusB => { aPlusB.b aPlusB.a}) : any
55+
>literal : (fn: (aPlusB: { a: string; } & B) => void) => any
56+
>aPlusB => { aPlusB.b aPlusB.a} : (aPlusB: { a: string; } & B) => void
57+
>aPlusB : { a: string; } & B
58+
59+
aPlusB.b
60+
>aPlusB.b : string
61+
>aPlusB : { a: string; } & B
62+
>b : string
63+
64+
aPlusB.a
65+
>aPlusB.a : string
66+
>aPlusB : { a: string; } & B
67+
>a : string
68+
69+
})
70+
71+
combined(comb => {
72+
>combined(comb => { comb.b comb.a}) : any
73+
>combined : (fn: (combined: { a: string; } & B) => void) => any
74+
>comb => { comb.b comb.a} : (comb: { a: string; } & B) => void
75+
>comb : { a: string; } & B
76+
77+
comb.b
78+
>comb.b : string
79+
>comb : { a: string; } & B
80+
>b : string
81+
82+
comb.a
83+
>comb.a : string
84+
>comb : { a: string; } & B
85+
>a : string
86+
87+
})
88+
89+
// Repro from #19091
90+
91+
declare function f<T>(a: T): { a: typeof a };
92+
>f : <T>(a: T) => { a: T; }
93+
>T : T
94+
>a : T
95+
>T : T
96+
>a : T
97+
>a : T
98+
99+
let n: number = f(2).a;
100+
>n : number
101+
>f(2).a : number
102+
>f(2) : { a: number; }
103+
>f : <T>(a: T) => { a: T; }
104+
>2 : 2
105+
>a : number
106+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Repro from #19043
2+
3+
type B = {b: string}
4+
5+
const flowtypes = <A>(b: B) => {
6+
type Combined = A & B
7+
8+
const combined = (fn: (combined: Combined) => void) => null
9+
const literal = (fn: (aPlusB: A & B) => void) => null
10+
11+
return {combined, literal}
12+
}
13+
14+
const {combined, literal} = flowtypes<{a: string}>({b: 'b-value'})
15+
16+
literal(aPlusB => {
17+
aPlusB.b
18+
aPlusB.a
19+
})
20+
21+
combined(comb => {
22+
comb.b
23+
comb.a
24+
})
25+
26+
// Repro from #19091
27+
28+
declare function f<T>(a: T): { a: typeof a };
29+
let n: number = f(2).a;

0 commit comments

Comments
 (0)