From 2869f9cb0535c2984e18de1fa9a4645f3582a256 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Fri, 28 Oct 2016 16:38:53 -0700 Subject: [PATCH 1/4] Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters --- src/compiler/checker.ts | 103 ++++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 14c05d93246..4f0c732c4b9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2180,54 +2180,105 @@ namespace ts { writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && isTypeAny(type) ? "any" : (type).intrinsicName); + return; } - else if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { + + if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { if (inObjectTypeLiteral) { writer.reportInaccessibleThisError(); } writer.writeKeyword("this"); + return; } - else if (getObjectFlags(type) & ObjectFlags.Reference) { + + if (getObjectFlags(type) & ObjectFlags.Reference) { writeTypeReference(type, nextFlags); + return; } - else if (type.flags & TypeFlags.EnumLiteral) { + + if (type.flags & TypeFlags.EnumLiteral) { buildSymbolDisplay(getParentOfSymbol(type.symbol), writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); writePunctuation(writer, SyntaxKind.DotToken); appendSymbolNameOnly(type.symbol, writer); + return; } - else if (getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.Enum | TypeFlags.TypeParameter)) { + if (getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.Enum | TypeFlags.TypeParameter)) { // The specified symbol flags need to be reinterpreted as type flags buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); + return; } - else if (!(flags & TypeFormatFlags.InTypeAlias) && ((getObjectFlags(type) & ObjectFlags.Anonymous && !(type).target) || type.flags & TypeFlags.UnionOrIntersection) && type.aliasSymbol && + + if (!(flags & TypeFormatFlags.InTypeAlias) && + (getObjectFlags(type) & ObjectFlags.Anonymous || type.flags & TypeFlags.UnionOrIntersection) && + type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { - // We emit inferred type as type-alias at the current localtion if all the following is true - // the input type is has alias symbol that is accessible - // the input type is a union, intersection or anonymous type that is fully instantiated (if not we want to keep dive into) - // e.g.: export type Bar = () => [X, Y]; - // export type Foo = Bar; - // export const y = (x: Foo) => 1 // we want to emit as ...x: () => [any, string]) + // We emit inferred type as type-alias if type is not in type-alias declaration, existed accessible alias-symbol, type is anonymous or union or intersection. + // However, if the type is an anonymous type with type arguments, we need to perform additional check. + + // 1) No type arguments, just emit type-alias as is + // 2) Existed type arguments, check if the type arguments full fill all type parameters of the alias-symbol by + // checking whether the target's aliasTypeArguments has the same size as type's aliasTypeArguments: + // i.e + // type Foo = { + // foo(): Foo + // }; + // function foo() { + // return {} as Foo; + // } + // Should be emitted as + // declare type Foo = { + // foo(): Foo; + // }; + // declare function foo(): Foo; + const typeArguments = type.aliasTypeArguments; - writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags); + if (!(type).target) { + // The given type has no target type then just write out its alias and tyep argument. + writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags); + return; + + } + else { + // The given type has target type. Then check hat the type contains same number of type arguments as its target type indicating that + // the given type has instantiate all type parameter. Then just emit type-alias using the current type argument. + // i.e + // type Foo = { foo(): Foo } + // function bar() { return {} as Foo; + // should be emitted as + // declare type Foo = { foo(): Foo; } + // declare function bar(): Foo + if (typeArguments && typeArguments.length === (type).target.aliasTypeArguments.length) { + writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments.length, nextFlags); + return; + } + // Otherwise type-alias only partially full fill type parameter (as below example), we will want to serialize the type-alias + // export type Bar = () => [X, Y]; + // export type Foo = Bar; + // export const y = (x: Foo) => 1 // this should be emit as "export declare const y: (x: () => [any, string]) => number;" + } } - else if (type.flags & TypeFlags.UnionOrIntersection) { + + if (type.flags & TypeFlags.UnionOrIntersection) { writeUnionOrIntersectionType(type, nextFlags); + return; } - else if (getObjectFlags(type) & ObjectFlags.Anonymous) { + if (getObjectFlags(type) & ObjectFlags.Anonymous) { writeAnonymousType(type, nextFlags); + return; } - else if (type.flags & TypeFlags.StringOrNumberLiteral) { + + if (type.flags & TypeFlags.StringOrNumberLiteral) { writer.writeStringLiteral(literalTypeToString(type)); + return; } - else { - // Should never get here - // { ... } - writePunctuation(writer, SyntaxKind.OpenBraceToken); - writeSpace(writer); - writePunctuation(writer, SyntaxKind.DotDotDotToken); - writeSpace(writer); - writePunctuation(writer, SyntaxKind.CloseBraceToken); - } + + // Should never get here + // { ... } + writePunctuation(writer, SyntaxKind.OpenBraceToken); + writeSpace(writer); + writePunctuation(writer, SyntaxKind.DotDotDotToken); + writeSpace(writer); + writePunctuation(writer, SyntaxKind.CloseBraceToken); } function writeTypeList(types: Type[], delimiter: SyntaxKind) { @@ -2330,7 +2381,9 @@ namespace ts { else if (contains(symbolStack, symbol)) { // If type is an anonymous type literal in a type alias declaration, use type alias name const typeAlias = getTypeAliasForTypeLiteral(type); - if (typeAlias) { + // We only want to use type-alias here if the typeAlias is not a generic one. (i.e it doesn't have a target type) + // If it is a generic type-alias just write out "any" + if (typeAlias && !(type).target) { // The specified symbol flags need to be reinterpreted as type flags buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags); } From 01e06f9295b2cd26aea734431c9840222dae8ff5 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Fri, 28 Oct 2016 16:39:05 -0700 Subject: [PATCH 2/4] Add tests and baselines --- ...tionEmitTypeAliasWithTypeParameters1.types | 4 +-- ...arationEmitTypeAliasWithTypeParameters2.js | 17 ++++++++++ ...onEmitTypeAliasWithTypeParameters2.symbols | 30 +++++++++++++++++ ...tionEmitTypeAliasWithTypeParameters2.types | 32 ++++++++++++++++++ ...arationEmitTypeAliasWithTypeParameters3.js | 21 ++++++++++++ ...onEmitTypeAliasWithTypeParameters3.symbols | 20 +++++++++++ ...tionEmitTypeAliasWithTypeParameters3.types | 22 +++++++++++++ ...arationEmitTypeAliasWithTypeParameters4.js | 26 +++++++++++++++ ...onEmitTypeAliasWithTypeParameters4.symbols | 29 ++++++++++++++++ ...tionEmitTypeAliasWithTypeParameters4.types | 31 +++++++++++++++++ ...mitTypeAliasWithTypeParameters5.errors.txt | 16 +++++++++ ...arationEmitTypeAliasWithTypeParameters5.js | 17 ++++++++++ ...arationEmitTypeAliasWithTypeParameters6.js | 24 ++++++++++++++ ...onEmitTypeAliasWithTypeParameters6.symbols | 31 +++++++++++++++++ ...tionEmitTypeAliasWithTypeParameters6.types | 33 +++++++++++++++++++ ...arationEmitTypeAliasWithTypeParameters2.ts | 6 ++++ ...arationEmitTypeAliasWithTypeParameters3.ts | 8 +++++ ...arationEmitTypeAliasWithTypeParameters4.ts | 10 ++++++ ...arationEmitTypeAliasWithTypeParameters5.ts | 10 ++++++ ...arationEmitTypeAliasWithTypeParameters6.ts | 10 ++++++ 20 files changed, 395 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.js create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.symbols create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.types create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.js create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.symbols create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.types create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.js create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.symbols create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.types create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters5.errors.txt create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters5.js create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.js create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.symbols create mode 100644 tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.types create mode 100644 tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters2.ts create mode 100644 tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters3.ts create mode 100644 tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters4.ts create mode 100644 tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters5.ts create mode 100644 tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters6.ts diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters1.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters1.types index 3ff9f9bde1d..ee6dbab804d 100644 --- a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters1.types +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters1.types @@ -8,7 +8,7 @@ export type Bar = () => [X, Y]; >Y : Y export type Foo = Bar; ->Foo : () => [any, Y] +>Foo : Bar >Y : Y >Bar : Bar >Y : Y @@ -17,6 +17,6 @@ export const y = (x: Foo) => 1 >y : (x: () => [any, string]) => number >(x: Foo) => 1 : (x: () => [any, string]) => number >x : () => [any, string] ->Foo : () => [any, Y] +>Foo : Bar >1 : 1 diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.js b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.js new file mode 100644 index 00000000000..aabeccffbc0 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.js @@ -0,0 +1,17 @@ +//// [declarationEmitTypeAliasWithTypeParameters2.ts] + +export type Bar = () => [X, Y, Z]; +export type Baz = Bar; +export type Baa = Baz; +export const y = (x: Baa) => 1 + +//// [declarationEmitTypeAliasWithTypeParameters2.js] +"use strict"; +exports.y = function (x) { return 1; }; + + +//// [declarationEmitTypeAliasWithTypeParameters2.d.ts] +export declare type Bar = () => [X, Y, Z]; +export declare type Baz = Bar; +export declare type Baa = Baz; +export declare const y: (x: () => [boolean, string, number]) => number; diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.symbols b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.symbols new file mode 100644 index 00000000000..cc13e9fd30b --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.symbols @@ -0,0 +1,30 @@ +=== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters2.ts === + +export type Bar = () => [X, Y, Z]; +>Bar : Symbol(Bar, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 0, 0)) +>X : Symbol(X, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 1, 16)) +>Y : Symbol(Y, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 1, 18)) +>Z : Symbol(Z, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 1, 21)) +>X : Symbol(X, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 1, 16)) +>Y : Symbol(Y, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 1, 18)) +>Z : Symbol(Z, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 1, 21)) + +export type Baz = Bar; +>Baz : Symbol(Baz, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 1, 43)) +>M : Symbol(M, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 2, 16)) +>N : Symbol(N, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 2, 18)) +>Bar : Symbol(Bar, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 0, 0)) +>M : Symbol(M, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 2, 16)) +>N : Symbol(N, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 2, 18)) + +export type Baa = Baz; +>Baa : Symbol(Baa, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 2, 42)) +>Y : Symbol(Y, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 3, 16)) +>Baz : Symbol(Baz, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 1, 43)) +>Y : Symbol(Y, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 3, 16)) + +export const y = (x: Baa) => 1 +>y : Symbol(y, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 4, 12)) +>x : Symbol(x, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 4, 18)) +>Baa : Symbol(Baa, Decl(declarationEmitTypeAliasWithTypeParameters2.ts, 2, 42)) + diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.types new file mode 100644 index 00000000000..4c88e88469a --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.types @@ -0,0 +1,32 @@ +=== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters2.ts === + +export type Bar = () => [X, Y, Z]; +>Bar : Bar +>X : X +>Y : Y +>Z : Z +>X : X +>Y : Y +>Z : Z + +export type Baz = Bar; +>Baz : Bar +>M : M +>N : N +>Bar : Bar +>M : M +>N : N + +export type Baa = Baz; +>Baa : () => [boolean, string, Y] +>Y : Y +>Baz : Bar +>Y : Y + +export const y = (x: Baa) => 1 +>y : (x: () => [boolean, string, number]) => number +>(x: Baa) => 1 : (x: () => [boolean, string, number]) => number +>x : () => [boolean, string, number] +>Baa : () => [boolean, string, Y] +>1 : 1 + diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.js b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.js new file mode 100644 index 00000000000..9e2a366a685 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.js @@ -0,0 +1,21 @@ +//// [declarationEmitTypeAliasWithTypeParameters3.ts] + +type Foo = { + foo(): Foo +}; +function bar() { + return {} as Foo; +} + + +//// [declarationEmitTypeAliasWithTypeParameters3.js] +function bar() { + return {}; +} + + +//// [declarationEmitTypeAliasWithTypeParameters3.d.ts] +declare type Foo = { + foo(): Foo; +}; +declare function bar(): Foo; diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.symbols b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.symbols new file mode 100644 index 00000000000..a18b1372cf1 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.symbols @@ -0,0 +1,20 @@ +=== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters3.ts === + +type Foo = { +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters3.ts, 0, 0)) +>T : Symbol(T, Decl(declarationEmitTypeAliasWithTypeParameters3.ts, 1, 9)) + + foo(): Foo +>foo : Symbol(foo, Decl(declarationEmitTypeAliasWithTypeParameters3.ts, 1, 15)) +>U : Symbol(U, Decl(declarationEmitTypeAliasWithTypeParameters3.ts, 2, 8)) +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters3.ts, 0, 0)) +>U : Symbol(U, Decl(declarationEmitTypeAliasWithTypeParameters3.ts, 2, 8)) + +}; +function bar() { +>bar : Symbol(bar, Decl(declarationEmitTypeAliasWithTypeParameters3.ts, 3, 2)) + + return {} as Foo; +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters3.ts, 0, 0)) +} + diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.types new file mode 100644 index 00000000000..1b2ff140178 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.types @@ -0,0 +1,22 @@ +=== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters3.ts === + +type Foo = { +>Foo : Foo +>T : T + + foo(): Foo +>foo : () => Foo +>U : U +>Foo : Foo +>U : U + +}; +function bar() { +>bar : () => Foo + + return {} as Foo; +>{} as Foo : Foo +>{} : {} +>Foo : Foo +} + diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.js b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.js new file mode 100644 index 00000000000..7f8a8ddbf9d --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.js @@ -0,0 +1,26 @@ +//// [declarationEmitTypeAliasWithTypeParameters4.ts] + +type Foo = { + foo(): Foo +}; +type SubFoo = Foo; + +function foo() { + return {} as SubFoo; +} + + +//// [declarationEmitTypeAliasWithTypeParameters4.js] +function foo() { + return {}; +} + + +//// [declarationEmitTypeAliasWithTypeParameters4.d.ts] +declare type Foo = { + foo(): Foo; +}; +declare type SubFoo = Foo; +declare function foo(): { + foo(): any; +}; diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.symbols b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.symbols new file mode 100644 index 00000000000..de73f544645 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.symbols @@ -0,0 +1,29 @@ +=== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters4.ts === + +type Foo = { +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 0, 0)) +>T : Symbol(T, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 1, 9)) +>Y : Symbol(Y, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 1, 11)) + + foo(): Foo +>foo : Symbol(foo, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 1, 18)) +>U : Symbol(U, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 2, 8)) +>J : Symbol(J, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 2, 10)) +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 0, 0)) +>U : Symbol(U, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 2, 8)) +>J : Symbol(J, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 2, 10)) + +}; +type SubFoo = Foo; +>SubFoo : Symbol(SubFoo, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 3, 2)) +>R : Symbol(R, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 4, 12)) +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 0, 0)) +>R : Symbol(R, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 4, 12)) + +function foo() { +>foo : Symbol(foo, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 4, 32)) + + return {} as SubFoo; +>SubFoo : Symbol(SubFoo, Decl(declarationEmitTypeAliasWithTypeParameters4.ts, 3, 2)) +} + diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.types new file mode 100644 index 00000000000..d77100c993d --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.types @@ -0,0 +1,31 @@ +=== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters4.ts === + +type Foo = { +>Foo : Foo +>T : T +>Y : Y + + foo(): Foo +>foo : () => Foo +>U : U +>J : J +>Foo : Foo +>U : U +>J : J + +}; +type SubFoo = Foo; +>SubFoo : Foo +>R : R +>Foo : Foo +>R : R + +function foo() { +>foo : () => { foo(): any; } + + return {} as SubFoo; +>{} as SubFoo : { foo(): any; } +>{} : {} +>SubFoo : Foo +} + diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters5.errors.txt b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters5.errors.txt new file mode 100644 index 00000000000..7f683dcc7b7 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters5.errors.txt @@ -0,0 +1,16 @@ +tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters5.ts(5,25): error TS4081: Exported type alias 'SubFoo' has or is using private name 'Foo'. + + +==== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters5.ts (1 errors) ==== + + type Foo = { + foo(): Foo + }; + export type SubFoo = Foo; + ~~~ +!!! error TS4081: Exported type alias 'SubFoo' has or is using private name 'Foo'. + + function foo() { + return {} as SubFoo; + } + \ No newline at end of file diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters5.js b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters5.js new file mode 100644 index 00000000000..2f4fff7d72c --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters5.js @@ -0,0 +1,17 @@ +//// [declarationEmitTypeAliasWithTypeParameters5.ts] + +type Foo = { + foo(): Foo +}; +export type SubFoo = Foo; + +function foo() { + return {} as SubFoo; +} + + +//// [declarationEmitTypeAliasWithTypeParameters5.js] +"use strict"; +function foo() { + return {}; +} diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.js b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.js new file mode 100644 index 00000000000..0e34bd44d40 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.js @@ -0,0 +1,24 @@ +//// [declarationEmitTypeAliasWithTypeParameters6.ts] + +type Foo = { + foo(): Foo +}; +type SubFoo = Foo; + +function foo() { + return {} as SubFoo; +} + + +//// [declarationEmitTypeAliasWithTypeParameters6.js] +function foo() { + return {}; +} + + +//// [declarationEmitTypeAliasWithTypeParameters6.d.ts] +declare type Foo = { + foo(): Foo; +}; +declare type SubFoo = Foo; +declare function foo(): Foo; diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.symbols b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.symbols new file mode 100644 index 00000000000..ec29989f078 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.symbols @@ -0,0 +1,31 @@ +=== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters6.ts === + +type Foo = { +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 0, 0)) +>T : Symbol(T, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 1, 9)) +>Y : Symbol(Y, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 1, 11)) + + foo(): Foo +>foo : Symbol(foo, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 1, 18)) +>U : Symbol(U, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 2, 8)) +>J : Symbol(J, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 2, 10)) +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 0, 0)) +>U : Symbol(U, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 2, 8)) +>J : Symbol(J, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 2, 10)) + +}; +type SubFoo = Foo; +>SubFoo : Symbol(SubFoo, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 3, 2)) +>R : Symbol(R, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 4, 12)) +>S : Symbol(S, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 4, 14)) +>Foo : Symbol(Foo, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 0, 0)) +>S : Symbol(S, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 4, 14)) +>R : Symbol(R, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 4, 12)) + +function foo() { +>foo : Symbol(foo, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 4, 30)) + + return {} as SubFoo; +>SubFoo : Symbol(SubFoo, Decl(declarationEmitTypeAliasWithTypeParameters6.ts, 3, 2)) +} + diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.types new file mode 100644 index 00000000000..ffa53c701fc --- /dev/null +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.types @@ -0,0 +1,33 @@ +=== tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters6.ts === + +type Foo = { +>Foo : Foo +>T : T +>Y : Y + + foo(): Foo +>foo : () => Foo +>U : U +>J : J +>Foo : Foo +>U : U +>J : J + +}; +type SubFoo = Foo; +>SubFoo : Foo +>R : R +>S : S +>Foo : Foo +>S : S +>R : R + +function foo() { +>foo : () => Foo + + return {} as SubFoo; +>{} as SubFoo : Foo +>{} : {} +>SubFoo : Foo +} + diff --git a/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters2.ts b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters2.ts new file mode 100644 index 00000000000..de94ad4998d --- /dev/null +++ b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters2.ts @@ -0,0 +1,6 @@ +// @declaration: true + +export type Bar = () => [X, Y, Z]; +export type Baz = Bar; +export type Baa = Baz; +export const y = (x: Baa) => 1 \ No newline at end of file diff --git a/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters3.ts b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters3.ts new file mode 100644 index 00000000000..6c7d4799abc --- /dev/null +++ b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters3.ts @@ -0,0 +1,8 @@ +// @declaration: true + +type Foo = { + foo(): Foo +}; +function bar() { + return {} as Foo; +} diff --git a/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters4.ts b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters4.ts new file mode 100644 index 00000000000..42bb8097997 --- /dev/null +++ b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters4.ts @@ -0,0 +1,10 @@ +// @declaration: true + +type Foo = { + foo(): Foo +}; +type SubFoo = Foo; + +function foo() { + return {} as SubFoo; +} diff --git a/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters5.ts b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters5.ts new file mode 100644 index 00000000000..b6334e76337 --- /dev/null +++ b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters5.ts @@ -0,0 +1,10 @@ +// @declaration: true + +type Foo = { + foo(): Foo +}; +export type SubFoo = Foo; + +function foo() { + return {} as SubFoo; +} diff --git a/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters6.ts b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters6.ts new file mode 100644 index 00000000000..9b313027021 --- /dev/null +++ b/tests/cases/compiler/declarationEmitTypeAliasWithTypeParameters6.ts @@ -0,0 +1,10 @@ +// @declaration: true + +type Foo = { + foo(): Foo +}; +type SubFoo = Foo; + +function foo() { + return {} as SubFoo; +} From f2e343903c739a22e792b8b9cedf762fd8193c39 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Fri, 28 Oct 2016 18:16:14 -0700 Subject: [PATCH 3/4] Skip trying to use alias if there is target type --- src/compiler/checker.ts | 82 ++++++++++++----------------------------- 1 file changed, 24 insertions(+), 58 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4f0c732c4b9..ba5b6a3690b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2180,41 +2180,31 @@ namespace ts { writer.writeKeyword(!(globalFlags & TypeFormatFlags.WriteOwnNameForAnyLike) && isTypeAny(type) ? "any" : (type).intrinsicName); - return; } - - if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { + else if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { if (inObjectTypeLiteral) { writer.reportInaccessibleThisError(); } writer.writeKeyword("this"); - return; } - - if (getObjectFlags(type) & ObjectFlags.Reference) { + else if (getObjectFlags(type) & ObjectFlags.Reference) { writeTypeReference(type, nextFlags); - return; } - - if (type.flags & TypeFlags.EnumLiteral) { + else if (type.flags & TypeFlags.EnumLiteral) { buildSymbolDisplay(getParentOfSymbol(type.symbol), writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); writePunctuation(writer, SyntaxKind.DotToken); appendSymbolNameOnly(type.symbol, writer); - return; } - if (getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.Enum | TypeFlags.TypeParameter)) { + else if (getObjectFlags(type) & ObjectFlags.ClassOrInterface || type.flags & (TypeFlags.Enum | TypeFlags.TypeParameter)) { // The specified symbol flags need to be reinterpreted as type flags buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); - return; } - - if (!(flags & TypeFormatFlags.InTypeAlias) && - (getObjectFlags(type) & ObjectFlags.Anonymous || type.flags & TypeFlags.UnionOrIntersection) && + else if (!(flags & TypeFormatFlags.InTypeAlias) && + (getObjectFlags(type) & ObjectFlags.Anonymous && !(type).target || type.flags & TypeFlags.UnionOrIntersection) && type.aliasSymbol && isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { // We emit inferred type as type-alias if type is not in type-alias declaration, existed accessible alias-symbol, type is anonymous or union or intersection. // However, if the type is an anonymous type with type arguments, we need to perform additional check. - // 1) No type arguments, just emit type-alias as is // 2) Existed type arguments, check if the type arguments full fill all type parameters of the alias-symbol by // checking whether the target's aliasTypeArguments has the same size as type's aliasTypeArguments: @@ -2230,55 +2220,31 @@ namespace ts { // foo(): Foo; // }; // declare function foo(): Foo; - - const typeArguments = type.aliasTypeArguments; - if (!(type).target) { - // The given type has no target type then just write out its alias and tyep argument. - writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags); - return; - - } - else { - // The given type has target type. Then check hat the type contains same number of type arguments as its target type indicating that - // the given type has instantiate all type parameter. Then just emit type-alias using the current type argument. - // i.e - // type Foo = { foo(): Foo } - // function bar() { return {} as Foo; - // should be emitted as - // declare type Foo = { foo(): Foo; } - // declare function bar(): Foo - if (typeArguments && typeArguments.length === (type).target.aliasTypeArguments.length) { - writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments.length, nextFlags); - return; - } - // Otherwise type-alias only partially full fill type parameter (as below example), we will want to serialize the type-alias - // export type Bar = () => [X, Y]; - // export type Foo = Bar; - // export const y = (x: Foo) => 1 // this should be emit as "export declare const y: (x: () => [any, string]) => number;" - } + // Otherwise type-alias is point to another generic type-alias then don't write it using alias symbol + // export type Bar = () => [X, Y]; + // export type Foo = Bar; + // export const y = (x: Foo) => 1 // this should be emit as "export declare const y: (x: () => [any, string]) => number;" + const typeArguments = (type).aliasTypeArguments; + writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags); } - - if (type.flags & TypeFlags.UnionOrIntersection) { + else if (type.flags & TypeFlags.UnionOrIntersection) { writeUnionOrIntersectionType(type, nextFlags); - return; } - if (getObjectFlags(type) & ObjectFlags.Anonymous) { + else if (getObjectFlags(type) & ObjectFlags.Anonymous) { writeAnonymousType(type, nextFlags); - return; } - - if (type.flags & TypeFlags.StringOrNumberLiteral) { + else if (type.flags & TypeFlags.StringOrNumberLiteral) { writer.writeStringLiteral(literalTypeToString(type)); - return; } - - // Should never get here - // { ... } - writePunctuation(writer, SyntaxKind.OpenBraceToken); - writeSpace(writer); - writePunctuation(writer, SyntaxKind.DotDotDotToken); - writeSpace(writer); - writePunctuation(writer, SyntaxKind.CloseBraceToken); + else { + // Should never get here + // { ... } + writePunctuation(writer, SyntaxKind.OpenBraceToken); + writeSpace(writer); + writePunctuation(writer, SyntaxKind.DotDotDotToken); + writeSpace(writer); + writePunctuation(writer, SyntaxKind.CloseBraceToken); + } } function writeTypeList(types: Type[], delimiter: SyntaxKind) { From f9a317ec97d864baaeb2125ebd8b0b0e090cd0f1 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Fri, 28 Oct 2016 18:16:33 -0700 Subject: [PATCH 4/4] Update baselines --- .../declarationEmitTypeAliasWithTypeParameters1.types | 4 ++-- .../declarationEmitTypeAliasWithTypeParameters2.types | 4 ++-- .../declarationEmitTypeAliasWithTypeParameters3.js | 4 +++- .../declarationEmitTypeAliasWithTypeParameters3.types | 6 +++--- .../declarationEmitTypeAliasWithTypeParameters4.types | 6 +++--- .../declarationEmitTypeAliasWithTypeParameters6.js | 4 +++- .../declarationEmitTypeAliasWithTypeParameters6.types | 10 +++++----- 7 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters1.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters1.types index ee6dbab804d..3ff9f9bde1d 100644 --- a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters1.types +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters1.types @@ -8,7 +8,7 @@ export type Bar = () => [X, Y]; >Y : Y export type Foo = Bar; ->Foo : Bar +>Foo : () => [any, Y] >Y : Y >Bar : Bar >Y : Y @@ -17,6 +17,6 @@ export const y = (x: Foo) => 1 >y : (x: () => [any, string]) => number >(x: Foo) => 1 : (x: () => [any, string]) => number >x : () => [any, string] ->Foo : Bar +>Foo : () => [any, Y] >1 : 1 diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.types index 4c88e88469a..8a16a05f32c 100644 --- a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.types +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters2.types @@ -10,7 +10,7 @@ export type Bar = () => [X, Y, Z]; >Z : Z export type Baz = Bar; ->Baz : Bar +>Baz : () => [M, string, N] >M : M >N : N >Bar : Bar @@ -20,7 +20,7 @@ export type Baz = Bar; export type Baa = Baz; >Baa : () => [boolean, string, Y] >Y : Y ->Baz : Bar +>Baz : () => [M, string, N] >Y : Y export const y = (x: Baa) => 1 diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.js b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.js index 9e2a366a685..8ab4c98c668 100644 --- a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.js +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.js @@ -18,4 +18,6 @@ function bar() { declare type Foo = { foo(): Foo; }; -declare function bar(): Foo; +declare function bar(): { + foo(): any; +}; diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.types index 1b2ff140178..f7ae5bd9cf6 100644 --- a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.types +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters3.types @@ -5,17 +5,17 @@ type Foo = { >T : T foo(): Foo ->foo : () => Foo +>foo : () => { foo(): any; } >U : U >Foo : Foo >U : U }; function bar() { ->bar : () => Foo +>bar : () => { foo(): any; } return {} as Foo; ->{} as Foo : Foo +>{} as Foo : { foo(): any; } >{} : {} >Foo : Foo } diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.types index d77100c993d..874d5247901 100644 --- a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.types +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters4.types @@ -6,7 +6,7 @@ type Foo = { >Y : Y foo(): Foo ->foo : () => Foo +>foo : () => { foo(): any; } >U : U >J : J >Foo : Foo @@ -15,7 +15,7 @@ type Foo = { }; type SubFoo = Foo; ->SubFoo : Foo +>SubFoo : { foo(): any; } >R : R >Foo : Foo >R : R @@ -26,6 +26,6 @@ function foo() { return {} as SubFoo; >{} as SubFoo : { foo(): any; } >{} : {} ->SubFoo : Foo +>SubFoo : { foo(): any; } } diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.js b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.js index 0e34bd44d40..d06d4c955bc 100644 --- a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.js +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.js @@ -21,4 +21,6 @@ declare type Foo = { foo(): Foo; }; declare type SubFoo = Foo; -declare function foo(): Foo; +declare function foo(): { + foo(): any; +}; diff --git a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.types b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.types index ffa53c701fc..40f25c88462 100644 --- a/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.types +++ b/tests/baselines/reference/declarationEmitTypeAliasWithTypeParameters6.types @@ -6,7 +6,7 @@ type Foo = { >Y : Y foo(): Foo ->foo : () => Foo +>foo : () => { foo(): any; } >U : U >J : J >Foo : Foo @@ -15,7 +15,7 @@ type Foo = { }; type SubFoo = Foo; ->SubFoo : Foo +>SubFoo : { foo(): any; } >R : R >S : S >Foo : Foo @@ -23,11 +23,11 @@ type SubFoo = Foo; >R : R function foo() { ->foo : () => Foo +>foo : () => { foo(): any; } return {} as SubFoo; ->{} as SubFoo : Foo +>{} as SubFoo : { foo(): any; } >{} : {} ->SubFoo : Foo +>SubFoo : { foo(): any; } }