Skip to content

Commit 78ba4b2

Browse files
committed
Merge pull request #5781 from Microsoft/fix4715
Fix completion and quick info crash in type parameter in function in type alias
2 parents 090eb20 + 2cc7a79 commit 78ba4b2

5 files changed

+100
-24
lines changed

src/services/services.ts

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,7 +1901,7 @@ namespace ts {
19011901
sourceMapText = text;
19021902
}
19031903
else {
1904-
Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name);
1904+
Debug.assert(outputText === undefined, `Unexpected multiple outputs for the file: '${name}'`);
19051905
outputText = text;
19061906
}
19071907
},
@@ -4248,28 +4248,31 @@ namespace ts {
42484248
}
42494249
else {
42504250
// Method/function type parameter
4251-
let container = getContainingFunction(location);
4252-
if (container) {
4253-
let signatureDeclaration = <SignatureDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent;
4254-
let signature = typeChecker.getSignatureFromDeclaration(signatureDeclaration);
4255-
if (signatureDeclaration.kind === SyntaxKind.ConstructSignature) {
4256-
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
4257-
displayParts.push(spacePart());
4251+
let declaration = <Node>getDeclarationOfKind(symbol, SyntaxKind.TypeParameter);
4252+
Debug.assert(declaration !== undefined);
4253+
declaration = declaration.parent;
4254+
4255+
if (declaration) {
4256+
if (isFunctionLikeKind(declaration.kind)) {
4257+
const signature = typeChecker.getSignatureFromDeclaration(<SignatureDeclaration>declaration);
4258+
if (declaration.kind === SyntaxKind.ConstructSignature) {
4259+
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
4260+
displayParts.push(spacePart());
4261+
}
4262+
else if (declaration.kind !== SyntaxKind.CallSignature && (<SignatureDeclaration>declaration).name) {
4263+
addFullSymbolName(declaration.symbol);
4264+
}
4265+
addRange(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature));
42584266
}
4259-
else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) {
4260-
addFullSymbolName(signatureDeclaration.symbol);
4267+
else {
4268+
// Type alias type parameter
4269+
// For example
4270+
// type list<T> = T[]; // Both T will go through same code path
4271+
displayParts.push(keywordPart(SyntaxKind.TypeKeyword));
4272+
displayParts.push(spacePart());
4273+
addFullSymbolName(declaration.symbol);
4274+
writeTypeParametersOfSymbol(declaration.symbol, sourceFile);
42614275
}
4262-
addRange(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature));
4263-
}
4264-
else {
4265-
// Type aliash type parameter
4266-
// For example
4267-
// type list<T> = T[]; // Both T will go through same code path
4268-
let declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent;
4269-
displayParts.push(keywordPart(SyntaxKind.TypeKeyword));
4270-
displayParts.push(spacePart());
4271-
addFullSymbolName(declaration.symbol);
4272-
writeTypeParametersOfSymbol(declaration.symbol, sourceFile);
42734276
}
42744277
}
42754278
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
//// type constructorType<T1, T2> = new <T/*1*/, /*2*/
4+
5+
goTo.marker("1");
6+
verify.memberListContains("T");
7+
verify.memberListContains("T1");
8+
verify.memberListContains("T2");
9+
10+
goTo.marker("2");
11+
verify.memberListContains("T");
12+
verify.memberListContains("T1");
13+
verify.memberListContains("T2");
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
//// type MixinCtor<A> = new () => /*0*/A & { constructor: MixinCtor</*1*/A> };
4+
//// type MixinCtor<A> = new () => A & { constructor: { constructor: MixinCtor</*2*/A> } };
5+
6+
let typeAliashDisplayParts = [{ text: "type", kind: "keyword" }, { text: " ", kind: "space" }, { text: "MixinCtor", kind: "aliasName" },
7+
{ text: "<", kind: "punctuation" }, { text: "A", kind: "typeParameterName" }, { text: ">", kind: "punctuation" }];
8+
9+
let typeParameterDisplayParts = [{ text: "(", kind: "punctuation" }, { text: "type parameter", kind: "text" }, { text: ")", kind: "punctuation" }, { text: " ", kind: "space" },
10+
{ text: "A", kind: "typeParameterName" }, { text: " ", kind: "space" }, { text: "in", kind: "keyword" }, { text: " ", kind: "space" }];
11+
12+
goTo.marker('0');
13+
verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("0").position, length: "A".length },
14+
typeParameterDisplayParts.concat(typeAliashDisplayParts), []);
15+
16+
goTo.marker('1');
17+
verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("1").position, length: "A".length },
18+
typeParameterDisplayParts.concat(typeAliashDisplayParts), []);;
19+
20+
goTo.marker('2');
21+
verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("2").position, length: "A".length },
22+
typeParameterDisplayParts.concat(typeAliashDisplayParts), []);

tests/cases/fourslash/quickInfoDisplayPartsTypeParameterInTypeAlias.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
////type /*0*/List</*1*/T> = /*2*/T[]
44
////type /*3*/List2</*4*/T extends string> = /*5*/T[];
55

6-
type List2<T extends string> = T[];
7-
8-
type L<T> = T[]
96
let typeAliashDisplayParts = [{ text: "type", kind: "keyword" }, { text: " ", kind: "space" }, { text: "List", kind: "aliasName" },
107
{ text: "<", kind: "punctuation" }, { text: "T", kind: "typeParameterName" }, { text: ">", kind: "punctuation" }];
118

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
//// type jamming<A> = new </*0*/A>() => jamming</*1*/A>;
4+
//// type jamming<A> = (new <A>() => jamming<A>) & { constructor: /*2*/A };
5+
//// type jamming<A> = new <A>() => jamming<A> & { constructor: /*3*/A };
6+
7+
let typeAliashDisplayParts = [{ text: "type", kind: "keyword" }, { text: " ", kind: "space" }, { text: "jamming", kind: "aliasName" },
8+
{ text: "<", kind: "punctuation" }, { text: "A", kind: "typeParameterName" }, { text: ">", kind: "punctuation" }];
9+
10+
let typeParameterDisplayParts = [{ text: "(", kind: "punctuation" }, { text: "type parameter", kind: "text" }, { text: ")", kind: "punctuation" }, { text: " ", kind: "space" },
11+
{ text: "A", kind: "typeParameterName" }, { text: " ", kind: "space" }, { text: "in", kind: "keyword" }, { text: " ", kind: "space" }];
12+
13+
let constructorTypeDisplayParts = [{ text: "<", kind: "punctuation" }, { text: "A", kind: "typeParameterName" }, { text: ">", kind: "punctuation" },
14+
{ text: "(", kind: "punctuation" }, { text: ")", kind: "punctuation" }, { text: ":", kind: "punctuation" }, { text: " ", kind: "space" },
15+
{ text: "new", kind: "keyword" }, { "text": " ", kind: "space" }, { text: "<", kind: "punctuation" }, { text: "A", kind: "typeParameterName" },
16+
{ text: ">", kind: "punctuation" }, { text: "(", kind: "punctuation" }, { text: ")", kind: "punctuation" }, {"text": " ", kind: "space" },
17+
{ text: "=>", kind: "punctuation" }, { "text": " ", kind: "space" }, { text: "jamming", kind: "aliasName" }];
18+
19+
let constructorTypeWithLongReturnTypeDisplayParts = [{ "text": "<", kind: "punctuation" }, { "text": "A", kind: "typeParameterName" }, { "text": ">", kind: "punctuation" },
20+
{ "text": "(", kind: "punctuation" }, { "text": ")", kind: "punctuation" }, { "text": ":", kind: "punctuation" }, { "text": " ", kind: "space" }, { "text": "(", kind: "punctuation" },
21+
{ "text": "new", kind: "keyword" }, { "text": " ", kind: "space" }, { "text": "<", kind: "punctuation" }, { "text": "A", kind: "typeParameterName" }, { "text": ">", kind: "punctuation" },
22+
{ "text": "(", kind: "punctuation" }, { "text": ")", kind: "punctuation" }, { "text": " ", kind: "space" }, { "text": "=>", kind: "punctuation" }, { "text": " ", kind: "space" },
23+
{ "text": "jamming", kind: "aliasName" }, { "text": ")", kind: "punctuation" }, { "text": " ", kind: "space" }, { "text": "&", kind: "punctuation" }, { "text": " ", kind: "space" },
24+
{ "text": "{", kind: "punctuation" }, { "text": "\n", kind: "lineBreak" }, { "text": " ", kind: "space" }, { "text": "constructor", kind: "propertyName" }, { "text": ":", kind: "punctuation" },
25+
{ "text": " ", kind: "space" }, { "text": "A", kind: "typeParameterName" }, {"text":";", kind: "punctuation" }, {"text":"\n", kind: "lineBreak" }, {"text":"}", kind: "punctuation" }];
26+
27+
goTo.marker('0');
28+
verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("0").position, length: "A".length },
29+
typeParameterDisplayParts.concat(constructorTypeDisplayParts), []);
30+
31+
goTo.marker('1');
32+
verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("1").position, length: "A".length },
33+
typeParameterDisplayParts.concat(constructorTypeDisplayParts), []);
34+
35+
goTo.marker('2');
36+
verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("2").position, length: "A".length },
37+
typeParameterDisplayParts.concat(typeAliashDisplayParts), []);
38+
39+
goTo.marker('3');
40+
verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("3").position, length: "A".length },
41+
typeParameterDisplayParts.concat(constructorTypeWithLongReturnTypeDisplayParts), []);

0 commit comments

Comments
 (0)