Merge pull request #19091 from Microsoft/fixAnonymousTypeInstantiation

Fix anonymous type instantiation
This commit is contained in:
Anders Hejlsberg
2017-10-12 00:54:14 +01:00
committed by GitHub
5 changed files with 297 additions and 8 deletions
+22 -8
View File
@@ -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;