mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #19091 from Microsoft/fixAnonymousTypeInstantiation
Fix anonymous type instantiation
This commit is contained in:
+22
-8
@@ -8289,11 +8289,11 @@ namespace ts {
|
||||
// The first time an anonymous type is instantiated we compute and store a list of the type
|
||||
// parameters that are in scope (and therefore potentially referenced). For type literals that
|
||||
// aren't the right hand side of a generic type alias declaration we optimize by reducing the
|
||||
// set of type parameters to those that are actually referenced somewhere in the literal.
|
||||
// set of type parameters to those that are possibly referenced in the literal.
|
||||
const declaration = symbol.declarations[0];
|
||||
const outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true) || emptyArray;
|
||||
typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ?
|
||||
filter(outerTypeParameters, tp => isTypeParameterReferencedWithin(tp, declaration)) :
|
||||
filter(outerTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) :
|
||||
outerTypeParameters;
|
||||
links.typeParameters = typeParameters;
|
||||
if (typeParameters.length) {
|
||||
@@ -8319,13 +8319,27 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function isTypeParameterReferencedWithin(tp: TypeParameter, node: Node) {
|
||||
return tp.isThisType ? forEachChild(node, checkThis) : forEachChild(node, checkIdentifier);
|
||||
function checkThis(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.ThisType || forEachChild(node, checkThis);
|
||||
function isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node) {
|
||||
// If the type parameter doesn't have exactly one declaration, if there are invening statement blocks
|
||||
// between the node and the type parameter declaration, if the node contains actual references to the
|
||||
// type parameter, or if the node contains type queries, we consider the type parameter possibly referenced.
|
||||
if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1) {
|
||||
const container = tp.symbol.declarations[0].parent;
|
||||
if (findAncestor(node, n => n.kind === SyntaxKind.Block ? "quit" : n === container)) {
|
||||
return forEachChild(node, containsReference);
|
||||
}
|
||||
}
|
||||
function checkIdentifier(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.Identifier && isPartOfTypeNode(node) && getTypeFromTypeNode(<TypeNode>node) === tp || forEachChild(node, checkIdentifier);
|
||||
return true;
|
||||
function containsReference(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ThisType:
|
||||
return tp.isThisType;
|
||||
case SyntaxKind.Identifier:
|
||||
return !tp.isThisType && isPartOfTypeNode(node) && getTypeFromTypeNode(<TypeNode>node) === tp;
|
||||
case SyntaxKind.TypeQuery:
|
||||
return true;
|
||||
}
|
||||
return forEachChild(node, containsReference);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//// [indirectTypeParameterReferences.ts]
|
||||
// Repro from #19043
|
||||
|
||||
type B = {b: string}
|
||||
|
||||
const flowtypes = <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}
|
||||
}
|
||||
|
||||
const {combined, literal} = flowtypes<{a: string}>({b: 'b-value'})
|
||||
|
||||
literal(aPlusB => {
|
||||
aPlusB.b
|
||||
aPlusB.a
|
||||
})
|
||||
|
||||
combined(comb => {
|
||||
comb.b
|
||||
comb.a
|
||||
})
|
||||
|
||||
// Repro from #19091
|
||||
|
||||
declare function f<T>(a: T): { a: typeof a };
|
||||
let n: number = f(2).a;
|
||||
|
||||
|
||||
//// [indirectTypeParameterReferences.js]
|
||||
// Repro from #19043
|
||||
var flowtypes = function (b) {
|
||||
var combined = function (fn) { return null; };
|
||||
var literal = function (fn) { return null; };
|
||||
return { combined: combined, literal: literal };
|
||||
};
|
||||
var _a = flowtypes({ b: 'b-value' }), combined = _a.combined, literal = _a.literal;
|
||||
literal(function (aPlusB) {
|
||||
aPlusB.b;
|
||||
aPlusB.a;
|
||||
});
|
||||
combined(function (comb) {
|
||||
comb.b;
|
||||
comb.a;
|
||||
});
|
||||
var n = f(2).a;
|
||||
@@ -0,0 +1,91 @@
|
||||
=== tests/cases/compiler/indirectTypeParameterReferences.ts ===
|
||||
// Repro from #19043
|
||||
|
||||
type B = {b: string}
|
||||
>B : Symbol(B, Decl(indirectTypeParameterReferences.ts, 0, 0))
|
||||
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
|
||||
|
||||
const flowtypes = <A>(b: B) => {
|
||||
>flowtypes : Symbol(flowtypes, Decl(indirectTypeParameterReferences.ts, 4, 5))
|
||||
>A : Symbol(A, Decl(indirectTypeParameterReferences.ts, 4, 19))
|
||||
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 4, 22))
|
||||
>B : Symbol(B, Decl(indirectTypeParameterReferences.ts, 0, 0))
|
||||
|
||||
type Combined = A & B
|
||||
>Combined : Symbol(Combined, Decl(indirectTypeParameterReferences.ts, 4, 32))
|
||||
>A : Symbol(A, Decl(indirectTypeParameterReferences.ts, 4, 19))
|
||||
>B : Symbol(B, Decl(indirectTypeParameterReferences.ts, 0, 0))
|
||||
|
||||
const combined = (fn: (combined: Combined) => void) => null
|
||||
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 7, 7))
|
||||
>fn : Symbol(fn, Decl(indirectTypeParameterReferences.ts, 7, 20))
|
||||
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 7, 25))
|
||||
>Combined : Symbol(Combined, Decl(indirectTypeParameterReferences.ts, 4, 32))
|
||||
|
||||
const literal = (fn: (aPlusB: A & B) => void) => null
|
||||
>literal : Symbol(literal, Decl(indirectTypeParameterReferences.ts, 8, 7))
|
||||
>fn : Symbol(fn, Decl(indirectTypeParameterReferences.ts, 8, 19))
|
||||
>aPlusB : Symbol(aPlusB, Decl(indirectTypeParameterReferences.ts, 8, 24))
|
||||
>A : Symbol(A, Decl(indirectTypeParameterReferences.ts, 4, 19))
|
||||
>B : Symbol(B, Decl(indirectTypeParameterReferences.ts, 0, 0))
|
||||
|
||||
return {combined, literal}
|
||||
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 10, 10))
|
||||
>literal : Symbol(literal, Decl(indirectTypeParameterReferences.ts, 10, 19))
|
||||
}
|
||||
|
||||
const {combined, literal} = flowtypes<{a: string}>({b: 'b-value'})
|
||||
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 13, 7))
|
||||
>literal : Symbol(literal, Decl(indirectTypeParameterReferences.ts, 13, 16))
|
||||
>flowtypes : Symbol(flowtypes, Decl(indirectTypeParameterReferences.ts, 4, 5))
|
||||
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
|
||||
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 13, 52))
|
||||
|
||||
literal(aPlusB => {
|
||||
>literal : Symbol(literal, Decl(indirectTypeParameterReferences.ts, 13, 16))
|
||||
>aPlusB : Symbol(aPlusB, Decl(indirectTypeParameterReferences.ts, 15, 8))
|
||||
|
||||
aPlusB.b
|
||||
>aPlusB.b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
|
||||
>aPlusB : Symbol(aPlusB, Decl(indirectTypeParameterReferences.ts, 15, 8))
|
||||
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
|
||||
|
||||
aPlusB.a
|
||||
>aPlusB.a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
|
||||
>aPlusB : Symbol(aPlusB, Decl(indirectTypeParameterReferences.ts, 15, 8))
|
||||
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
|
||||
|
||||
})
|
||||
|
||||
combined(comb => {
|
||||
>combined : Symbol(combined, Decl(indirectTypeParameterReferences.ts, 13, 7))
|
||||
>comb : Symbol(comb, Decl(indirectTypeParameterReferences.ts, 20, 9))
|
||||
|
||||
comb.b
|
||||
>comb.b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
|
||||
>comb : Symbol(comb, Decl(indirectTypeParameterReferences.ts, 20, 9))
|
||||
>b : Symbol(b, Decl(indirectTypeParameterReferences.ts, 2, 10))
|
||||
|
||||
comb.a
|
||||
>comb.a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
|
||||
>comb : Symbol(comb, Decl(indirectTypeParameterReferences.ts, 20, 9))
|
||||
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 13, 39))
|
||||
|
||||
})
|
||||
|
||||
// Repro from #19091
|
||||
|
||||
declare function f<T>(a: T): { a: typeof a };
|
||||
>f : Symbol(f, Decl(indirectTypeParameterReferences.ts, 23, 2))
|
||||
>T : Symbol(T, Decl(indirectTypeParameterReferences.ts, 27, 19))
|
||||
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 22))
|
||||
>T : Symbol(T, Decl(indirectTypeParameterReferences.ts, 27, 19))
|
||||
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 30))
|
||||
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 22))
|
||||
|
||||
let n: number = f(2).a;
|
||||
>n : Symbol(n, Decl(indirectTypeParameterReferences.ts, 28, 3))
|
||||
>f(2).a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 30))
|
||||
>f : Symbol(f, Decl(indirectTypeParameterReferences.ts, 23, 2))
|
||||
>a : Symbol(a, Decl(indirectTypeParameterReferences.ts, 27, 30))
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
=== tests/cases/compiler/indirectTypeParameterReferences.ts ===
|
||||
// Repro from #19043
|
||||
|
||||
type B = {b: string}
|
||||
>B : B
|
||||
>b : string
|
||||
|
||||
const flowtypes = <A>(b: B) => {
|
||||
>flowtypes : <A>(b: B) => { combined: (fn: (combined: A & B) => void) => any; literal: (fn: (aPlusB: A & B) => void) => any; }
|
||||
><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; }
|
||||
>A : A
|
||||
>b : B
|
||||
>B : B
|
||||
|
||||
type Combined = A & B
|
||||
>Combined : A & B
|
||||
>A : A
|
||||
>B : B
|
||||
|
||||
const combined = (fn: (combined: Combined) => void) => null
|
||||
>combined : (fn: (combined: A & B) => void) => any
|
||||
>(fn: (combined: Combined) => void) => null : (fn: (combined: A & B) => void) => any
|
||||
>fn : (combined: A & B) => void
|
||||
>combined : A & B
|
||||
>Combined : A & B
|
||||
>null : null
|
||||
|
||||
const literal = (fn: (aPlusB: A & B) => void) => null
|
||||
>literal : (fn: (aPlusB: A & B) => void) => any
|
||||
>(fn: (aPlusB: A & B) => void) => null : (fn: (aPlusB: A & B) => void) => any
|
||||
>fn : (aPlusB: A & B) => void
|
||||
>aPlusB : A & B
|
||||
>A : A
|
||||
>B : B
|
||||
>null : null
|
||||
|
||||
return {combined, literal}
|
||||
>{combined, literal} : { combined: (fn: (combined: A & B) => void) => any; literal: (fn: (aPlusB: A & B) => void) => any; }
|
||||
>combined : (fn: (combined: A & B) => void) => any
|
||||
>literal : (fn: (aPlusB: A & B) => void) => any
|
||||
}
|
||||
|
||||
const {combined, literal} = flowtypes<{a: string}>({b: 'b-value'})
|
||||
>combined : (fn: (combined: { a: string; } & B) => void) => any
|
||||
>literal : (fn: (aPlusB: { a: string; } & B) => void) => any
|
||||
>flowtypes<{a: string}>({b: 'b-value'}) : { combined: (fn: (combined: { a: string; } & B) => void) => any; literal: (fn: (aPlusB: { a: string; } & B) => void) => any; }
|
||||
>flowtypes : <A>(b: B) => { combined: (fn: (combined: A & B) => void) => any; literal: (fn: (aPlusB: A & B) => void) => any; }
|
||||
>a : string
|
||||
>{b: 'b-value'} : { b: string; }
|
||||
>b : string
|
||||
>'b-value' : "b-value"
|
||||
|
||||
literal(aPlusB => {
|
||||
>literal(aPlusB => { aPlusB.b aPlusB.a}) : any
|
||||
>literal : (fn: (aPlusB: { a: string; } & B) => void) => any
|
||||
>aPlusB => { aPlusB.b aPlusB.a} : (aPlusB: { a: string; } & B) => void
|
||||
>aPlusB : { a: string; } & B
|
||||
|
||||
aPlusB.b
|
||||
>aPlusB.b : string
|
||||
>aPlusB : { a: string; } & B
|
||||
>b : string
|
||||
|
||||
aPlusB.a
|
||||
>aPlusB.a : string
|
||||
>aPlusB : { a: string; } & B
|
||||
>a : string
|
||||
|
||||
})
|
||||
|
||||
combined(comb => {
|
||||
>combined(comb => { comb.b comb.a}) : any
|
||||
>combined : (fn: (combined: { a: string; } & B) => void) => any
|
||||
>comb => { comb.b comb.a} : (comb: { a: string; } & B) => void
|
||||
>comb : { a: string; } & B
|
||||
|
||||
comb.b
|
||||
>comb.b : string
|
||||
>comb : { a: string; } & B
|
||||
>b : string
|
||||
|
||||
comb.a
|
||||
>comb.a : string
|
||||
>comb : { a: string; } & B
|
||||
>a : string
|
||||
|
||||
})
|
||||
|
||||
// Repro from #19091
|
||||
|
||||
declare function f<T>(a: T): { a: typeof a };
|
||||
>f : <T>(a: T) => { a: T; }
|
||||
>T : T
|
||||
>a : T
|
||||
>T : T
|
||||
>a : T
|
||||
>a : T
|
||||
|
||||
let n: number = f(2).a;
|
||||
>n : number
|
||||
>f(2).a : number
|
||||
>f(2) : { a: number; }
|
||||
>f : <T>(a: T) => { a: T; }
|
||||
>2 : 2
|
||||
>a : number
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Repro from #19043
|
||||
|
||||
type B = {b: string}
|
||||
|
||||
const flowtypes = <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}
|
||||
}
|
||||
|
||||
const {combined, literal} = flowtypes<{a: string}>({b: 'b-value'})
|
||||
|
||||
literal(aPlusB => {
|
||||
aPlusB.b
|
||||
aPlusB.a
|
||||
})
|
||||
|
||||
combined(comb => {
|
||||
comb.b
|
||||
comb.a
|
||||
})
|
||||
|
||||
// Repro from #19091
|
||||
|
||||
declare function f<T>(a: T): { a: typeof a };
|
||||
let n: number = f(2).a;
|
||||
Reference in New Issue
Block a user