Parenthesize the fn or constructor type with type parameter when writing it in type argument

Fixes #8105
This commit is contained in:
Sheetal Nandi
2016-04-18 15:44:40 -07:00
parent 87b64c5b28
commit dc4871a12a
5 changed files with 24 additions and 66 deletions

View File

@@ -1990,7 +1990,7 @@ namespace ts {
}
if (pos < end) {
writePunctuation(writer, SyntaxKind.LessThanToken);
writeType(typeArguments[pos], TypeFormatFlags.None);
writeType(typeArguments[pos], TypeFormatFlags.InFirstTypeArgument);
pos++;
while (pos < end) {
writePunctuation(writer, SyntaxKind.CommaToken);
@@ -2143,6 +2143,19 @@ namespace ts {
}
}
function shouldAddParenthesisAroundFunctionType(callSignature: Signature, flags: TypeFormatFlags) {
if (flags & TypeFormatFlags.InElementType) {
return true;
}
else if (flags & TypeFormatFlags.InFirstTypeArgument) {
// Add parenthesis around function type for the first type argument to avoid ambiguity
const typeParameters = callSignature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) ?
callSignature.target.typeParameters : callSignature.typeParameters;
return typeParameters && typeParameters.length !== 0;
}
return false;
}
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
const resolved = resolveStructuredTypeMembers(type);
if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
@@ -2153,11 +2166,12 @@ namespace ts {
}
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
if (flags & TypeFormatFlags.InElementType) {
const parenthesizeSignature = shouldAddParenthesisAroundFunctionType(resolved.callSignatures[0], flags);
if (parenthesizeSignature) {
writePunctuation(writer, SyntaxKind.OpenParenToken);
}
buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
if (flags & TypeFormatFlags.InElementType) {
if (parenthesizeSignature) {
writePunctuation(writer, SyntaxKind.CloseParenToken);
}
return;
@@ -2317,12 +2331,14 @@ namespace ts {
function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
if (typeParameters && typeParameters.length) {
writePunctuation(writer, SyntaxKind.LessThanToken);
let flags = TypeFormatFlags.InFirstTypeArgument;
for (let i = 0; i < typeParameters.length; i++) {
if (i > 0) {
writePunctuation(writer, SyntaxKind.CommaToken);
writeSpace(writer);
flags = TypeFormatFlags.None;
}
buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, TypeFormatFlags.None);
buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, flags);
}
writePunctuation(writer, SyntaxKind.GreaterThanToken);
}

View File

@@ -1820,6 +1820,7 @@ namespace ts {
WriteTypeArgumentsOfSignature = 0x00000020, // Write the type arguments instead of type parameters of the signature
InElementType = 0x00000040, // Writing an array or union element type
UseFullyQualifiedType = 0x00000080, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
}
export const enum SymbolFormatFlags {

View File

@@ -60,63 +60,4 @@ export declare class bluebird<T> {
static all: Array<bluebird<any>>;
}
export declare function runSampleWorks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>;
export declare function runSampleBreaks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>;
//// [DtsFileErrors]
tests/cases/compiler/declarationEmitPromise.d.ts(5,141): error TS2314: Generic type 'Promise<T>' requires 1 type argument(s).
tests/cases/compiler/declarationEmitPromise.d.ts(5,148): error TS1144: '{' or ';' expected.
tests/cases/compiler/declarationEmitPromise.d.ts(5,150): error TS2304: Cannot find name 'T'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,153): error TS2304: Cannot find name 'f'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,154): error TS1005: ')' expected.
tests/cases/compiler/declarationEmitPromise.d.ts(5,160): error TS2304: Cannot find name 'A'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,167): error TS2304: Cannot find name 'B'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,174): error TS2304: Cannot find name 'C'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,181): error TS2304: Cannot find name 'D'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,188): error TS2304: Cannot find name 'E'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,194): error TS2304: Cannot find name 'T'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,195): error TS1005: ';' expected.
tests/cases/compiler/declarationEmitPromise.d.ts(5,197): error TS1128: Declaration or statement expected.
tests/cases/compiler/declarationEmitPromise.d.ts(5,200): error TS2304: Cannot find name 'T'.
tests/cases/compiler/declarationEmitPromise.d.ts(5,202): error TS1109: Expression expected.
==== tests/cases/compiler/declarationEmitPromise.d.ts (15 errors) ====
export declare class bluebird<T> {
static all: Array<bluebird<any>>;
}
export declare function runSampleWorks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>;
export declare function runSampleBreaks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>;
~~~~~~~
!!! error TS2314: Generic type 'Promise<T>' requires 1 type argument(s).
~~
!!! error TS1144: '{' or ';' expected.
~
!!! error TS2304: Cannot find name 'T'.
~
!!! error TS2304: Cannot find name 'f'.
~
!!! error TS1005: ')' expected.
~
!!! error TS2304: Cannot find name 'A'.
~
!!! error TS2304: Cannot find name 'B'.
~
!!! error TS2304: Cannot find name 'C'.
~
!!! error TS2304: Cannot find name 'D'.
~
!!! error TS2304: Cannot find name 'E'.
~
!!! error TS2304: Cannot find name 'T'.
~
!!! error TS1005: ';' expected.
~~
!!! error TS1128: Declaration or statement expected.
~
!!! error TS2304: Cannot find name 'T'.
~
!!! error TS1109: Expression expected.
export declare function runSampleBreaks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)>;

View File

@@ -96,7 +96,7 @@ export async function runSampleWorks<A, B, C, D, E>(
}
export async function runSampleBreaks<A, B, C, D, E>(
>runSampleBreaks : <A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>) => Promise<<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>
>runSampleBreaks : <A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>) => Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)>
>A : A
>B : B
>C : C

View File

@@ -4,7 +4,7 @@ class X<A> {
>A : A
prop: X< <Tany>() => Tany >;
>prop : X<<Tany>() => Tany>
>prop : X<(<Tany>() => Tany)>
>X : X<A>
>Tany : Tany
>Tany : Tany