Merge pull request #3316 from Microsoft/circularInstantiatedTypes
Detect circular instantiated types
This commit is contained in:
commit
b55117792f
6 changed files with 244 additions and 78 deletions
|
@ -1485,7 +1485,7 @@ module ts {
|
|||
return appendParentTypeArgumentsAndSymbolName(symbol);
|
||||
}
|
||||
|
||||
function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, typeStack?: Type[]) {
|
||||
function buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
let globalFlagsToPass = globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike;
|
||||
return writeType(type, globalFlags);
|
||||
|
||||
|
@ -1608,49 +1608,54 @@ module ts {
|
|||
}
|
||||
|
||||
function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) {
|
||||
// Always use 'typeof T' for type of class, enum, and module objects
|
||||
if (type.symbol && type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
|
||||
writeTypeofSymbol(type, flags);
|
||||
}
|
||||
// Use 'typeof T' for types of functions and methods that circularly reference themselves
|
||||
else if (shouldWriteTypeOfFunctionSymbol()) {
|
||||
writeTypeofSymbol(type, flags);
|
||||
}
|
||||
else if (typeStack && contains(typeStack, type)) {
|
||||
// If type is an anonymous type literal in a type alias declaration, use type alias name
|
||||
let typeAlias = getTypeAliasForTypeLiteral(type);
|
||||
if (typeAlias) {
|
||||
// The specified symbol flags need to be reinterpreted as type flags
|
||||
buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
|
||||
let symbol = type.symbol;
|
||||
if (symbol) {
|
||||
// Always use 'typeof T' for type of class, enum, and module objects
|
||||
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
|
||||
writeTypeofSymbol(type, flags);
|
||||
}
|
||||
else if (shouldWriteTypeOfFunctionSymbol()) {
|
||||
writeTypeofSymbol(type, flags);
|
||||
}
|
||||
else if (contains(symbolStack, symbol)) {
|
||||
// If type is an anonymous type literal in a type alias declaration, use type alias name
|
||||
let typeAlias = getTypeAliasForTypeLiteral(type);
|
||||
if (typeAlias) {
|
||||
// The specified symbol flags need to be reinterpreted as type flags
|
||||
buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
|
||||
}
|
||||
else {
|
||||
// Recursive usage, use any
|
||||
writeKeyword(writer, SyntaxKind.AnyKeyword);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Recursive usage, use any
|
||||
writeKeyword(writer, SyntaxKind.AnyKeyword);
|
||||
// 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 (!symbolStack) {
|
||||
symbolStack = [];
|
||||
}
|
||||
symbolStack.push(symbol);
|
||||
writeLiteralType(type, flags);
|
||||
symbolStack.pop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!typeStack) {
|
||||
typeStack = [];
|
||||
}
|
||||
typeStack.push(type);
|
||||
// Anonymous types with no symbol are never circular
|
||||
writeLiteralType(type, flags);
|
||||
typeStack.pop();
|
||||
}
|
||||
|
||||
function shouldWriteTypeOfFunctionSymbol() {
|
||||
if (type.symbol) {
|
||||
let isStaticMethodSymbol = !!(type.symbol.flags & SymbolFlags.Method && // typeof static method
|
||||
ts.forEach(type.symbol.declarations, declaration => declaration.flags & NodeFlags.Static));
|
||||
let isNonLocalFunctionSymbol = !!(type.symbol.flags & SymbolFlags.Function) &&
|
||||
(type.symbol.parent || // is exported function symbol
|
||||
ts.forEach(type.symbol.declarations, declaration =>
|
||||
declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
|
||||
|
||||
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
|
||||
// typeof is allowed only for static/non local functions
|
||||
return !!(flags & TypeFormatFlags.UseTypeOfFunction) || // use typeof if format flags specify it
|
||||
(typeStack && contains(typeStack, type)); // it is type of the symbol uses itself recursively
|
||||
}
|
||||
let isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method && // typeof static method
|
||||
forEach(symbol.declarations, declaration => declaration.flags & NodeFlags.Static));
|
||||
let isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
|
||||
(symbol.parent || // is exported function symbol
|
||||
forEach(symbol.declarations, declaration =>
|
||||
declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
|
||||
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
|
||||
// typeof is allowed only for static/non local functions
|
||||
return !!(flags & TypeFormatFlags.UseTypeOfFunction) || // use typeof if format flags specify it
|
||||
(contains(symbolStack, symbol)); // it is type of the symbol uses itself recursively
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1685,7 +1690,7 @@ module ts {
|
|||
if (flags & TypeFormatFlags.InElementType) {
|
||||
writePunctuation(writer, SyntaxKind.OpenParenToken);
|
||||
}
|
||||
buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, typeStack);
|
||||
buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, symbolStack);
|
||||
if (flags & TypeFormatFlags.InElementType) {
|
||||
writePunctuation(writer, SyntaxKind.CloseParenToken);
|
||||
}
|
||||
|
@ -1697,7 +1702,7 @@ module ts {
|
|||
}
|
||||
writeKeyword(writer, SyntaxKind.NewKeyword);
|
||||
writeSpace(writer);
|
||||
buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, typeStack);
|
||||
buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, symbolStack);
|
||||
if (flags & TypeFormatFlags.InElementType) {
|
||||
writePunctuation(writer, SyntaxKind.CloseParenToken);
|
||||
}
|
||||
|
@ -1709,7 +1714,7 @@ module ts {
|
|||
writer.writeLine();
|
||||
writer.increaseIndent();
|
||||
for (let signature of resolved.callSignatures) {
|
||||
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack);
|
||||
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack);
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
|
@ -1717,7 +1722,7 @@ module ts {
|
|||
writeKeyword(writer, SyntaxKind.NewKeyword);
|
||||
writeSpace(writer);
|
||||
|
||||
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack);
|
||||
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack);
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
|
@ -1758,7 +1763,7 @@ module ts {
|
|||
if (p.flags & SymbolFlags.Optional) {
|
||||
writePunctuation(writer, SyntaxKind.QuestionToken);
|
||||
}
|
||||
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, typeStack);
|
||||
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack);
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
|
@ -1787,18 +1792,18 @@ module ts {
|
|||
}
|
||||
}
|
||||
|
||||
function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
|
||||
function buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
appendSymbolNameOnly(tp.symbol, writer);
|
||||
let constraint = getConstraintOfTypeParameter(tp);
|
||||
if (constraint) {
|
||||
writeSpace(writer);
|
||||
writeKeyword(writer, SyntaxKind.ExtendsKeyword);
|
||||
writeSpace(writer);
|
||||
buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, typeStack);
|
||||
buildTypeDisplay(constraint, writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
}
|
||||
|
||||
function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
|
||||
function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
let parameterNode = <ParameterDeclaration>p.valueDeclaration;
|
||||
if (isRestParameter(parameterNode)) {
|
||||
writePunctuation(writer, SyntaxKind.DotDotDotToken);
|
||||
|
@ -1810,10 +1815,10 @@ module ts {
|
|||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
|
||||
buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, typeStack);
|
||||
buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
|
||||
function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
|
||||
function buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
if (typeParameters && typeParameters.length) {
|
||||
writePunctuation(writer, SyntaxKind.LessThanToken);
|
||||
for (let i = 0; i < typeParameters.length; i++) {
|
||||
|
@ -1821,13 +1826,13 @@ module ts {
|
|||
writePunctuation(writer, SyntaxKind.CommaToken);
|
||||
writeSpace(writer);
|
||||
}
|
||||
buildTypeParameterDisplay(typeParameters[i], writer, enclosingDeclaration, flags, typeStack);
|
||||
buildTypeParameterDisplay(typeParameters[i], writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
writePunctuation(writer, SyntaxKind.GreaterThanToken);
|
||||
}
|
||||
}
|
||||
|
||||
function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
|
||||
function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
if (typeParameters && typeParameters.length) {
|
||||
writePunctuation(writer, SyntaxKind.LessThanToken);
|
||||
for (let i = 0; i < typeParameters.length; i++) {
|
||||
|
@ -1841,19 +1846,19 @@ module ts {
|
|||
}
|
||||
}
|
||||
|
||||
function buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
|
||||
function buildDisplayForParametersAndDelimiters(parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
writePunctuation(writer, SyntaxKind.OpenParenToken);
|
||||
for (let i = 0; i < parameters.length; i++) {
|
||||
if (i > 0) {
|
||||
writePunctuation(writer, SyntaxKind.CommaToken);
|
||||
writeSpace(writer);
|
||||
}
|
||||
buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, typeStack);
|
||||
buildParameterDisplay(parameters[i], writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
writePunctuation(writer, SyntaxKind.CloseParenToken);
|
||||
}
|
||||
|
||||
function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
|
||||
function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
if (flags & TypeFormatFlags.WriteArrowStyleSignature) {
|
||||
writeSpace(writer);
|
||||
writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken);
|
||||
|
@ -1862,21 +1867,21 @@ module ts {
|
|||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
}
|
||||
writeSpace(writer);
|
||||
buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, typeStack);
|
||||
buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
|
||||
function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) {
|
||||
function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) {
|
||||
// Instantiated signature, write type arguments instead
|
||||
// This is achieved by passing in the mapper separately
|
||||
buildDisplayForTypeArgumentsAndDelimiters(signature.target.typeParameters, signature.mapper, writer, enclosingDeclaration);
|
||||
}
|
||||
else {
|
||||
buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, typeStack);
|
||||
buildDisplayForTypeParametersAndDelimiters(signature.typeParameters, writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
|
||||
buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, typeStack);
|
||||
buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, typeStack);
|
||||
buildDisplayForParametersAndDelimiters(signature.parameters, writer, enclosingDeclaration, flags, symbolStack);
|
||||
buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
|
||||
return _displayBuilder || (_displayBuilder = {
|
||||
|
@ -3996,19 +4001,8 @@ module ts {
|
|||
}
|
||||
|
||||
function instantiateAnonymousType(type: ObjectType, mapper: TypeMapper): ObjectType {
|
||||
// If this type has already been instantiated using this mapper, returned the cached result. This guards against
|
||||
// infinite instantiations of cyclic types, e.g. "var x: { a: T, b: typeof x };"
|
||||
if (mapper.mappings) {
|
||||
let cached = <ObjectType>mapper.mappings[type.id];
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mapper.mappings = {};
|
||||
}
|
||||
// Instantiate the given type using the given mapper and cache the result
|
||||
let result = <ResolvedType>createObjectType(TypeFlags.Anonymous, type.symbol);
|
||||
// Mark the anonymous type as instantiated such that our infinite instantiation detection logic can recognize it
|
||||
let result = <ResolvedType>createObjectType(TypeFlags.Anonymous | TypeFlags.Instantiated, type.symbol);
|
||||
result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol);
|
||||
result.members = createSymbolTable(result.properties);
|
||||
result.callSignatures = instantiateList(getSignaturesOfType(type, SignatureKind.Call), mapper, instantiateSignature);
|
||||
|
@ -4017,7 +4011,6 @@ module ts {
|
|||
let numberIndexType = getIndexTypeOfType(type, IndexKind.Number);
|
||||
if (stringIndexType) result.stringIndexType = instantiateType(stringIndexType, mapper);
|
||||
if (numberIndexType) result.numberIndexType = instantiateType(numberIndexType, mapper);
|
||||
mapper.mappings[type.id] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4432,12 +4425,13 @@ module ts {
|
|||
// Effectively, we will generate a false positive when two types are structurally equal to at least 10 levels, but unequal at
|
||||
// some level beyond that.
|
||||
function isDeeplyNestedGeneric(type: ObjectType, stack: ObjectType[]): boolean {
|
||||
if (type.flags & TypeFlags.Reference && depth >= 10) {
|
||||
let target = (<TypeReference>type).target;
|
||||
// We track type references (created by createTypeReference) and instantiated types (created by instantiateType)
|
||||
if (type.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && depth >= 10) {
|
||||
let symbol = type.symbol;
|
||||
let count = 0;
|
||||
for (let i = 0; i < depth; i++) {
|
||||
let t = stack[i];
|
||||
if (t.flags & TypeFlags.Reference && (<TypeReference>t).target === target) {
|
||||
if (t.flags & (TypeFlags.Reference | TypeFlags.Instantiated) && t.symbol === symbol) {
|
||||
count++;
|
||||
if (count >= 10) return true;
|
||||
}
|
||||
|
|
|
@ -1582,14 +1582,15 @@ module ts {
|
|||
Tuple = 0x00002000, // Tuple
|
||||
Union = 0x00004000, // Union
|
||||
Anonymous = 0x00008000, // Anonymous
|
||||
Instantiated = 0x00010000, // Instantiated anonymous type
|
||||
/* @internal */
|
||||
FromSignature = 0x00010000, // Created for signature assignment check
|
||||
ObjectLiteral = 0x00020000, // Originates in an object literal
|
||||
FromSignature = 0x00020000, // Created for signature assignment check
|
||||
ObjectLiteral = 0x00040000, // Originates in an object literal
|
||||
/* @internal */
|
||||
ContainsUndefinedOrNull = 0x00040000, // Type is or contains Undefined or Null type
|
||||
ContainsUndefinedOrNull = 0x00080000, // Type is or contains Undefined or Null type
|
||||
/* @internal */
|
||||
ContainsObjectLiteral = 0x00080000, // Type is or contains object literal type
|
||||
ESSymbol = 0x00100000, // Type of symbol primitive introduced in ES6
|
||||
ContainsObjectLiteral = 0x00100000, // Type is or contains object literal type
|
||||
ESSymbol = 0x00200000, // Type of symbol primitive introduced in ES6
|
||||
|
||||
/* @internal */
|
||||
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
|
||||
|
@ -1731,7 +1732,6 @@ module ts {
|
|||
/* @internal */
|
||||
export interface TypeMapper {
|
||||
(t: TypeParameter): Type;
|
||||
mappings?: Map<Type>; // Type mapping cache
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
|
37
tests/baselines/reference/cyclicGenericTypeInstantiation.js
Normal file
37
tests/baselines/reference/cyclicGenericTypeInstantiation.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
//// [cyclicGenericTypeInstantiation.ts]
|
||||
function foo<T>() {
|
||||
var z = foo<typeof y>();
|
||||
var y: {
|
||||
y2: typeof z
|
||||
};
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
function bar<T>() {
|
||||
var z = bar<typeof y>();
|
||||
var y: {
|
||||
y2: typeof z;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
var a = foo<number>();
|
||||
var b = bar<number>();
|
||||
a = b;
|
||||
|
||||
|
||||
//// [cyclicGenericTypeInstantiation.js]
|
||||
function foo() {
|
||||
var z = foo();
|
||||
var y;
|
||||
return y;
|
||||
}
|
||||
function bar() {
|
||||
var z = bar();
|
||||
var y;
|
||||
return y;
|
||||
}
|
||||
var a = foo();
|
||||
var b = bar();
|
||||
a = b;
|
|
@ -0,0 +1,55 @@
|
|||
=== tests/cases/compiler/cyclicGenericTypeInstantiation.ts ===
|
||||
function foo<T>() {
|
||||
>foo : Symbol(foo, Decl(cyclicGenericTypeInstantiation.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(cyclicGenericTypeInstantiation.ts, 0, 13))
|
||||
|
||||
var z = foo<typeof y>();
|
||||
>z : Symbol(z, Decl(cyclicGenericTypeInstantiation.ts, 1, 7))
|
||||
>foo : Symbol(foo, Decl(cyclicGenericTypeInstantiation.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 2, 7))
|
||||
|
||||
var y: {
|
||||
>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 2, 7))
|
||||
|
||||
y2: typeof z
|
||||
>y2 : Symbol(y2, Decl(cyclicGenericTypeInstantiation.ts, 2, 12))
|
||||
>z : Symbol(z, Decl(cyclicGenericTypeInstantiation.ts, 1, 7))
|
||||
|
||||
};
|
||||
return y;
|
||||
>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 2, 7))
|
||||
}
|
||||
|
||||
|
||||
function bar<T>() {
|
||||
>bar : Symbol(bar, Decl(cyclicGenericTypeInstantiation.ts, 6, 1))
|
||||
>T : Symbol(T, Decl(cyclicGenericTypeInstantiation.ts, 9, 13))
|
||||
|
||||
var z = bar<typeof y>();
|
||||
>z : Symbol(z, Decl(cyclicGenericTypeInstantiation.ts, 10, 7))
|
||||
>bar : Symbol(bar, Decl(cyclicGenericTypeInstantiation.ts, 6, 1))
|
||||
>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 11, 7))
|
||||
|
||||
var y: {
|
||||
>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 11, 7))
|
||||
|
||||
y2: typeof z;
|
||||
>y2 : Symbol(y2, Decl(cyclicGenericTypeInstantiation.ts, 11, 12))
|
||||
>z : Symbol(z, Decl(cyclicGenericTypeInstantiation.ts, 10, 7))
|
||||
}
|
||||
return y;
|
||||
>y : Symbol(y, Decl(cyclicGenericTypeInstantiation.ts, 11, 7))
|
||||
}
|
||||
|
||||
var a = foo<number>();
|
||||
>a : Symbol(a, Decl(cyclicGenericTypeInstantiation.ts, 17, 3))
|
||||
>foo : Symbol(foo, Decl(cyclicGenericTypeInstantiation.ts, 0, 0))
|
||||
|
||||
var b = bar<number>();
|
||||
>b : Symbol(b, Decl(cyclicGenericTypeInstantiation.ts, 18, 3))
|
||||
>bar : Symbol(bar, Decl(cyclicGenericTypeInstantiation.ts, 6, 1))
|
||||
|
||||
a = b;
|
||||
>a : Symbol(a, Decl(cyclicGenericTypeInstantiation.ts, 17, 3))
|
||||
>b : Symbol(b, Decl(cyclicGenericTypeInstantiation.ts, 18, 3))
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
=== tests/cases/compiler/cyclicGenericTypeInstantiation.ts ===
|
||||
function foo<T>() {
|
||||
>foo : <T>() => { y2: any; }
|
||||
>T : T
|
||||
|
||||
var z = foo<typeof y>();
|
||||
>z : { y2: any; }
|
||||
>foo<typeof y>() : { y2: any; }
|
||||
>foo : <T>() => { y2: any; }
|
||||
>y : { y2: any; }
|
||||
|
||||
var y: {
|
||||
>y : { y2: any; }
|
||||
|
||||
y2: typeof z
|
||||
>y2 : { y2: any; }
|
||||
>z : { y2: any; }
|
||||
|
||||
};
|
||||
return y;
|
||||
>y : { y2: any; }
|
||||
}
|
||||
|
||||
|
||||
function bar<T>() {
|
||||
>bar : <T>() => { y2: any; }
|
||||
>T : T
|
||||
|
||||
var z = bar<typeof y>();
|
||||
>z : { y2: any; }
|
||||
>bar<typeof y>() : { y2: any; }
|
||||
>bar : <T>() => { y2: any; }
|
||||
>y : { y2: any; }
|
||||
|
||||
var y: {
|
||||
>y : { y2: any; }
|
||||
|
||||
y2: typeof z;
|
||||
>y2 : { y2: any; }
|
||||
>z : { y2: any; }
|
||||
}
|
||||
return y;
|
||||
>y : { y2: any; }
|
||||
}
|
||||
|
||||
var a = foo<number>();
|
||||
>a : { y2: any; }
|
||||
>foo<number>() : { y2: any; }
|
||||
>foo : <T>() => { y2: any; }
|
||||
|
||||
var b = bar<number>();
|
||||
>b : { y2: any; }
|
||||
>bar<number>() : { y2: any; }
|
||||
>bar : <T>() => { y2: any; }
|
||||
|
||||
a = b;
|
||||
>a = b : { y2: any; }
|
||||
>a : { y2: any; }
|
||||
>b : { y2: any; }
|
||||
|
20
tests/cases/compiler/cyclicGenericTypeInstantiation.ts
Normal file
20
tests/cases/compiler/cyclicGenericTypeInstantiation.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
function foo<T>() {
|
||||
var z = foo<typeof y>();
|
||||
var y: {
|
||||
y2: typeof z
|
||||
};
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
function bar<T>() {
|
||||
var z = bar<typeof y>();
|
||||
var y: {
|
||||
y2: typeof z;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
var a = foo<number>();
|
||||
var b = bar<number>();
|
||||
a = b;
|
Loading…
Reference in a new issue