Track type recusion and symbol instantiation depth seperately in createAnonymousTypeNode (#28490)

This commit is contained in:
Wesley Wigham 2018-11-12 15:45:36 -08:00 committed by GitHub
parent 830be0651c
commit 2b345cc8f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 114 additions and 77 deletions

View File

@ -3201,7 +3201,8 @@ namespace ts {
getCurrentDirectory: host.getCurrentDirectory && (() => host.getCurrentDirectory!())
} : undefined },
encounteredError: false,
visitedSymbols: undefined,
visitedTypes: undefined,
symbolDepth: undefined,
inferTypeParameters: undefined,
approximateLength: 0
};
@ -3432,6 +3433,7 @@ namespace ts {
}
function createAnonymousTypeNode(type: ObjectType): TypeNode {
const typeId = "" + type.id;
const symbol = type.symbol;
let id: string;
if (symbol) {
@ -3448,7 +3450,7 @@ namespace ts {
shouldWriteTypeOfFunctionSymbol()) {
return symbolToTypeNode(symbol, context, SymbolFlags.Value);
}
else if (context.visitedSymbols && context.visitedSymbols.has(id)) {
else if (context.visitedTypes && context.visitedTypes.has(typeId)) {
// If type is an anonymous type literal in a type alias declaration, use type alias name
const typeAlias = getTypeAliasForTypeLiteral(type);
if (typeAlias) {
@ -3457,19 +3459,35 @@ namespace ts {
}
else {
context.approximateLength += 3;
if (!(context.flags & NodeBuilderFlags.NoTruncation)) {
return createTypeReferenceNode(createIdentifier("..."), /*typeArguments*/ undefined);
}
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
}
else {
// Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
// of types allows us to catch circular references to instantiations of the same anonymous type
if (!context.visitedSymbols) {
context.visitedSymbols = createMap<true>();
if (!context.visitedTypes) {
context.visitedTypes = createMap<true>();
}
if (!context.symbolDepth) {
context.symbolDepth = createMap<number>();
}
context.visitedSymbols.set(id, true);
const depth = context.symbolDepth.get(id) || 0;
if (depth > 10) {
context.approximateLength += 3;
if (!(context.flags & NodeBuilderFlags.NoTruncation)) {
return createTypeReferenceNode(createIdentifier("..."), /*typeArguments*/ undefined);
}
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
context.symbolDepth.set(id, depth + 1);
context.visitedTypes.set(typeId, true);
const result = createTypeNodeFromObjectType(type);
context.visitedSymbols.delete(id);
context.visitedTypes.delete(typeId);
context.symbolDepth.set(id, depth);
return result;
}
}
@ -3486,7 +3504,7 @@ namespace ts {
declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
// typeof is allowed only for static/non local functions
return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) || (context.visitedSymbols && context.visitedSymbols.has(id))) && // it is type of the symbol uses itself recursively
return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) || (context.visitedTypes && context.visitedTypes.has(typeId))) && // it is type of the symbol uses itself recursively
(!(context.flags & NodeBuilderFlags.UseStructuralFallback) || isValueSymbolAccessible(symbol, context.enclosingDeclaration!)); // TODO: GH#18217 // And the build is going to succeed without visibility error or there is no structural fallback allowed
}
}
@ -4310,7 +4328,8 @@ namespace ts {
// State
encounteredError: boolean;
visitedSymbols: Map<true> | undefined;
visitedTypes: Map<true> | undefined;
symbolDepth: Map<number> | undefined;
inferTypeParameters: TypeParameter[] | undefined;
approximateLength: number;
truncating?: boolean;

View File

@ -1,58 +1,58 @@
=== tests/cases/compiler/cyclicGenericTypeInstantiation.ts ===
function foo<T>() {
>foo : <T>() => { y2: any; }
>foo : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var z = foo<typeof y>();
>z : { y2: any; }
>foo<typeof y>() : { y2: any; }
>foo : <T>() => { y2: any; }
>y : { y2: any; }
>z : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>foo<typeof y>() : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>foo : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var y: {
>y : { y2: any; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
y2: typeof z
>y2 : { y2: any; }
>z : { y2: any; }
>y2 : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>z : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
};
return y;
>y : { y2: any; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
}
function bar<T>() {
>bar : <T>() => { y2: any; }
>bar : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var z = bar<typeof y>();
>z : { y2: any; }
>bar<typeof y>() : { y2: any; }
>bar : <T>() => { y2: any; }
>y : { y2: any; }
>z : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>bar<typeof y>() : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>bar : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var y: {
>y : { y2: any; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
y2: typeof z;
>y2 : { y2: any; }
>z : { y2: any; }
>y2 : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>z : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
}
return y;
>y : { y2: any; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
}
var a = foo<number>();
>a : { y2: any; }
>foo<number>() : { y2: any; }
>foo : <T>() => { y2: any; }
>a : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>foo<number>() : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>foo : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var b = bar<number>();
>b : { y2: any; }
>bar<number>() : { y2: any; }
>bar : <T>() => { y2: any; }
>b : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>bar<number>() : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>bar : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
a = b;
>a = b : { y2: any; }
>a : { y2: any; }
>b : { y2: any; }
>a = b : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>a : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>b : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }

View File

@ -1,63 +1,63 @@
=== tests/cases/compiler/cyclicGenericTypeInstantiationInference.ts ===
function foo<T>() {
>foo : <T>() => { y2: any; }
>foo : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var z = foo<typeof y>();
>z : { y2: any; }
>foo<typeof y>() : { y2: any; }
>foo : <T>() => { y2: any; }
>y : { y2: any; }
>z : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>foo<typeof y>() : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>foo : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var y: {
>y : { y2: any; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
y2: typeof z
>y2 : { y2: any; }
>z : { y2: any; }
>y2 : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>z : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
};
return y;
>y : { y2: any; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
}
function bar<T>() {
>bar : <T>() => { y2: any; }
>bar : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var z = bar<typeof y>();
>z : { y2: any; }
>bar<typeof y>() : { y2: any; }
>bar : <T>() => { y2: any; }
>y : { y2: any; }
>z : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>bar<typeof y>() : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>bar : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var y: {
>y : { y2: any; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
y2: typeof z;
>y2 : { y2: any; }
>z : { y2: any; }
>y2 : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>z : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
}
return y;
>y : { y2: any; }
>y : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
}
var a = foo<number>();
>a : { y2: any; }
>foo<number>() : { y2: any; }
>foo : <T>() => { y2: any; }
>a : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>foo<number>() : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>foo : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
var b = bar<number>();
>b : { y2: any; }
>bar<number>() : { y2: any; }
>bar : <T>() => { y2: any; }
>b : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>bar<number>() : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>bar : <T>() => { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
function test<T>(x: typeof a): void { }
>test : <T>(x: { y2: any; }) => void
>x : { y2: any; }
>a : { y2: any; }
>test : <T>(x: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }) => void
>x : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
>a : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }
test(b);
>test(b) : void
>test : <T>(x: { y2: any; }) => void
>b : { y2: any; }
>test : <T>(x: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }) => void
>b : { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: { y2: any; }; }; }; }; }; }; }; }; }; }; }

View File

@ -30,8 +30,8 @@ var r2 = foo({ bar: 1, baz: 1 }); // T = number
>1 : 1
var r3 = foo({ bar: foo, baz: foo }); // T = typeof foo
>r3 : { bar: <T>(x: any) => any; baz: <T>(x: any) => any; }
>foo({ bar: foo, baz: foo }) : { bar: <T>(x: any) => any; baz: <T>(x: any) => any; }
>r3 : { bar: <T>(x: { bar: T; baz: T; }) => { bar: T; baz: T; }; baz: <T>(x: { bar: T; baz: T; }) => { bar: T; baz: T; }; }
>foo({ bar: foo, baz: foo }) : { bar: <T>(x: { bar: T; baz: T; }) => { bar: T; baz: T; }; baz: <T>(x: { bar: T; baz: T; }) => { bar: T; baz: T; }; }
>foo : <T>(x: { bar: T; baz: T; }) => { bar: T; baz: T; }
>{ bar: foo, baz: foo } : { bar: <T>(x: { bar: T; baz: T; }) => { bar: T; baz: T; }; baz: <T>(x: { bar: T; baz: T; }) => { bar: T; baz: T; }; }
>bar : <T>(x: { bar: T; baz: T; }) => { bar: T; baz: T; }

View File

@ -2,8 +2,8 @@
// Repro from #14837
type Foo<T extends "true", B> = { "true": Foo<T, Foo<T, B>> }[T];
>Foo : { "true": any[T]; }[T]
>"true" : { "true": any[T]; }[T]
>Foo : { "true": { "true": { "true": { "true": { "true": { "true": { "true": { "true": { "true": { "true": { "true": any[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]
>"true" : { "true": { "true": { "true": { "true": { "true": { "true": { "true": { "true": { "true": { "true": { "true": any[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]; }[T]
let f1: Foo<"true", {}>;
>f1 : any

View File

@ -4,18 +4,18 @@ var axios = {}
>{} : {}
module.exports = axios // both assignments should be ok
>module.exports = axios : { default: any; }
>module.exports : { default: any; }
>module : { "tests/cases/conformance/salsa/axios": { default: any; }; }
>exports : { default: any; }
>module.exports = axios : { default: { default: any; }; }
>module.exports : { default: { default: any; }; }
>module : { "tests/cases/conformance/salsa/axios": { default: { default: any; }; }; }
>exports : { default: { default: any; }; }
>axios : { default: { default: any; }; }
module.exports.default = axios
>module.exports.default = axios : { default: { default: any; }; }
>module.exports.default : { default: any; }
>module.exports : { default: any; }
>module : { "tests/cases/conformance/salsa/axios": { default: any; }; }
>exports : { default: any; }
>module.exports : { default: { default: any; }; }
>module : { "tests/cases/conformance/salsa/axios": { default: { default: any; }; }; }
>exports : { default: { default: any; }; }
>default : { default: any; }
>axios : { default: { default: any; }; }

View File

@ -63,7 +63,7 @@ let z1 = function () { return z1; }
let z2 = { f() { return z2;}}
>z2 : { f(): any; }
>{ f() { return z2;}} : { f(): any; }
>{ f() { return z2;}} : { f(): { f(): any; }; }
>f : () => { f(): any; }
>z2 : { f(): any; }

View File

@ -9,4 +9,4 @@
/////// <reference path="file1.ts" />
////foo();
verify.singleReferenceGroup("(local function) foo(a?: void, b?: () => (a?: void, b?: any) => void): void");
verify.singleReferenceGroup("(local function) foo(a?: void, b?: () => (a?: void, b?: ...) => void): void");

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////declare function schema<T> (value : T) : {field : T};
////
////declare const b: boolean;
////const obj/*1*/ = schema(b);
////const actualTypeOfNested/*2*/ = schema(obj);
verify.quickInfos({
1: `const obj: {
field: boolean;
}`,
2: `const actualTypeOfNested: {
field: {
field: boolean;
};
}`
});