Skip to content

Commit 4a1851c

Browse files
committed
Merge pull request microsoft#1562 from csnover/fix-1133
Ensure specialized signatures are always at the top when performing call candidate resolution
2 parents 87bcdff + 4aef3d6 commit 4a1851c

5 files changed

Lines changed: 145 additions & 50 deletions

File tree

src/compiler/checker.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6130,34 +6130,47 @@ module ts {
61306130
var result = candidates;
61316131
var lastParent: Node;
61326132
var lastSymbol: Symbol;
6133-
var cutoffPos: number = 0;
6134-
var pos: number;
6133+
var cutoffIndex: number = 0;
6134+
var index: number;
6135+
var specializedIndex: number = -1;
6136+
var spliceIndex: number;
61356137
Debug.assert(!result.length);
61366138
for (var i = 0; i < signatures.length; i++) {
61376139
var signature = signatures[i];
61386140
var symbol = signature.declaration && getSymbolOfNode(signature.declaration);
61396141
var parent = signature.declaration && signature.declaration.parent;
61406142
if (!lastSymbol || symbol === lastSymbol) {
61416143
if (lastParent && parent === lastParent) {
6142-
pos++;
6144+
index++;
61436145
}
61446146
else {
61456147
lastParent = parent;
6146-
pos = cutoffPos;
6148+
index = cutoffIndex;
61476149
}
61486150
}
61496151
else {
61506152
// current declaration belongs to a different symbol
6151-
// set cutoffPos so re-orderings in the future won't change result set from 0 to cutoffPos
6152-
pos = cutoffPos = result.length;
6153+
// set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex
6154+
index = cutoffIndex = result.length;
61536155
lastParent = parent;
61546156
}
61556157
lastSymbol = symbol;
61566158

6157-
for (var j = result.length; j > pos; j--) {
6158-
result[j] = result[j - 1];
6159+
// specialized signatures always need to be placed before non-specialized signatures regardless
6160+
// of the cutoff position; see GH#1133
6161+
if (signature.hasStringLiterals) {
6162+
specializedIndex++;
6163+
spliceIndex = specializedIndex;
6164+
// The cutoff index always needs to be greater than or equal to the specialized signature index
6165+
// in order to prevent non-specialized signatures from being added before a specialized
6166+
// signature.
6167+
cutoffIndex++;
61596168
}
6160-
result[pos] = signature;
6169+
else {
6170+
spliceIndex = index;
6171+
}
6172+
6173+
result.splice(spliceIndex, 0, signature);
61616174
}
61626175
}
61636176
}

tests/baselines/reference/inheritedOverloadedSpecializedSignatures.js

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,43 @@ interface B {
2828
(x: 'B2'): string[];
2929
}
3030

31-
var b: B;
32-
// non of these lines should error
33-
var x1: string[] = b('B2');
34-
var x2: number = b('B1');
35-
var x3: boolean = b('A2');
36-
var x4: string = b('A1');
37-
var x5: void = b('A0');
31+
interface C1 extends B {
32+
(x: 'C1'): number[];
33+
}
34+
35+
interface C2 extends B {
36+
(x: 'C2'): boolean[];
37+
}
38+
39+
interface C extends C1, C2 {
40+
(x: 'C'): string;
41+
}
42+
43+
var c: C;
44+
// none of these lines should error
45+
var x1: string[] = c('B2');
46+
var x2: number = c('B1');
47+
var x3: boolean = c('A2');
48+
var x4: string = c('A1');
49+
var x5: void = c('A0');
50+
var x6: number[] = c('C1');
51+
var x7: boolean[] = c('C2');
52+
var x8: string = c('C');
53+
var x9: void = c('generic');
54+
3855

3956
//// [inheritedOverloadedSpecializedSignatures.js]
4057
var b;
4158
// Should not error
4259
b('foo').charAt(0);
43-
var b;
44-
// non of these lines should error
45-
var x1 = b('B2');
46-
var x2 = b('B1');
47-
var x3 = b('A2');
48-
var x4 = b('A1');
49-
var x5 = b('A0');
60+
var c;
61+
// none of these lines should error
62+
var x1 = c('B2');
63+
var x2 = c('B1');
64+
var x3 = c('A2');
65+
var x4 = c('A1');
66+
var x5 = c('A0');
67+
var x6 = c('C1');
68+
var x7 = c('C2');
69+
var x8 = c('C');
70+
var x9 = c('generic');

tests/baselines/reference/inheritedOverloadedSpecializedSignatures.types

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,33 +58,78 @@ interface B {
5858
>x : 'B2'
5959
}
6060

61-
var b: B;
62-
>b : B
61+
interface C1 extends B {
62+
>C1 : C1
63+
>B : B
64+
65+
(x: 'C1'): number[];
66+
>x : 'C1'
67+
}
68+
69+
interface C2 extends B {
70+
>C2 : C2
6371
>B : B
6472

65-
// non of these lines should error
66-
var x1: string[] = b('B2');
73+
(x: 'C2'): boolean[];
74+
>x : 'C2'
75+
}
76+
77+
interface C extends C1, C2 {
78+
>C : C
79+
>C1 : C1
80+
>C2 : C2
81+
82+
(x: 'C'): string;
83+
>x : 'C'
84+
}
85+
86+
var c: C;
87+
>c : C
88+
>C : C
89+
90+
// none of these lines should error
91+
var x1: string[] = c('B2');
6792
>x1 : string[]
68-
>b('B2') : string[]
69-
>b : B
93+
>c('B2') : string[]
94+
>c : C
7095

71-
var x2: number = b('B1');
96+
var x2: number = c('B1');
7297
>x2 : number
73-
>b('B1') : number
74-
>b : B
98+
>c('B1') : number
99+
>c : C
75100

76-
var x3: boolean = b('A2');
101+
var x3: boolean = c('A2');
77102
>x3 : boolean
78-
>b('A2') : boolean
79-
>b : B
103+
>c('A2') : boolean
104+
>c : C
80105

81-
var x4: string = b('A1');
106+
var x4: string = c('A1');
82107
>x4 : string
83-
>b('A1') : string
84-
>b : B
108+
>c('A1') : string
109+
>c : C
85110

86-
var x5: void = b('A0');
111+
var x5: void = c('A0');
87112
>x5 : void
88-
>b('A0') : void
89-
>b : B
113+
>c('A0') : void
114+
>c : C
115+
116+
var x6: number[] = c('C1');
117+
>x6 : number[]
118+
>c('C1') : number[]
119+
>c : C
120+
121+
var x7: boolean[] = c('C2');
122+
>x7 : boolean[]
123+
>c('C2') : boolean[]
124+
>c : C
125+
126+
var x8: string = c('C');
127+
>x8 : string
128+
>c('C') : string
129+
>c : C
130+
131+
var x9: void = c('generic');
132+
>x9 : void
133+
>c('generic') : void
134+
>c : C
90135

tests/cases/compiler/inheritedOverloadedSpecializedSignatures.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,26 @@ interface B {
2727
(x: 'B2'): string[];
2828
}
2929

30-
var b: B;
31-
// non of these lines should error
32-
var x1: string[] = b('B2');
33-
var x2: number = b('B1');
34-
var x3: boolean = b('A2');
35-
var x4: string = b('A1');
36-
var x5: void = b('A0');
30+
interface C1 extends B {
31+
(x: 'C1'): number[];
32+
}
33+
34+
interface C2 extends B {
35+
(x: 'C2'): boolean[];
36+
}
37+
38+
interface C extends C1, C2 {
39+
(x: 'C'): string;
40+
}
41+
42+
var c: C;
43+
// none of these lines should error
44+
var x1: string[] = c('B2');
45+
var x2: number = c('B1');
46+
var x3: boolean = c('A2');
47+
var x4: string = c('A1');
48+
var x5: void = c('A0');
49+
var x6: number[] = c('C1');
50+
var x7: boolean[] = c('C2');
51+
var x8: string = c('C');
52+
var x9: void = c('generic');

tests/cases/fourslash/overloadOnConstCallSignature.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
goTo.marker('1');
1313
verify.signatureHelpCountIs(4);
14-
verify.currentSignatureHelpIs('foo(name: string): string');
14+
verify.currentSignatureHelpIs('foo(name: \'order\'): string');
1515
edit.insert('"hi"');
1616

1717
goTo.marker('2');
18-
verify.quickInfoIs('(var) x: string');
18+
verify.quickInfoIs('(var) x: string');

0 commit comments

Comments
 (0)