Skip to content

Commit e6808c4

Browse files
Instantiation expression can be followed by line break or binary operator (#49353)
* Allow instantiation expression to be followed by let or interface on new line * Add tests * Update src/compiler/parser.ts * Instantiation expressions followed by line breaks or binary operators * Add more tests * Accept new baselines * Fix lint error * Update fourslash test Co-authored-by: Daniel Rosenwasser <[email protected]>
1 parent b3a79db commit e6808c4

File tree

7 files changed

+653
-48
lines changed

7 files changed

+653
-48
lines changed

src/compiler/parser.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5783,9 +5783,18 @@ namespace ts {
57835783
case SyntaxKind.NoSubstitutionTemplateLiteral: // foo<T> `...`
57845784
case SyntaxKind.TemplateHead: // foo<T> `...${100}...`
57855785
return true;
5786+
// A type argument list followed by `<` never makes sense, and a type argument list followed
5787+
// by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in
5788+
// this context, `+` and `-` are unary operators, not binary operators.
5789+
case SyntaxKind.LessThanToken:
5790+
case SyntaxKind.GreaterThanToken:
5791+
case SyntaxKind.PlusToken:
5792+
case SyntaxKind.MinusToken:
5793+
return false;
57865794
}
5787-
// Consider something a type argument list only if the following token can't start an expression.
5788-
return !isStartOfExpression();
5795+
// We favor the type argument list interpretation when it is immediately followed by
5796+
// a line break, a binary operator, or something that can't start an expression.
5797+
return scanner.hasPrecedingLineBreak() || isBinaryOperator() || !isStartOfExpression();
57895798
}
57905799

57915800
function parsePrimaryExpression(): PrimaryExpression {

tests/baselines/reference/instantiationExpressionErrors.errors.txt

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@ tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpr
66
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(19,24): error TS2635: Type '{ (): number; g<U>(): U; }' has no signatures for which the type argument list is applicable.
77
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(23,23): error TS1005: '(' expected.
88
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(26,24): error TS2558: Expected 0 type arguments, but got 1.
9-
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(31,2): error TS2554: Expected 0 arguments, but got 1.
10-
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(35,12): error TS2365: Operator '<' cannot be applied to types '{ <T>(): T; g<U>(): U; }' and 'boolean'.
9+
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(39,2): error TS2554: Expected 0 arguments, but got 1.
10+
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(43,12): error TS2365: Operator '<' cannot be applied to types '{ <T>(): T; g<U>(): U; }' and 'boolean'.
11+
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(44,12): error TS2365: Operator '<' cannot be applied to types '{ <T>(): T; g<U>(): U; }' and 'boolean'.
12+
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(44,12): error TS2365: Operator '>' cannot be applied to types 'boolean' and 'number'.
13+
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(45,12): error TS2365: Operator '<' cannot be applied to types '{ <T>(): T; g<U>(): U; }' and 'boolean'.
14+
tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts(45,12): error TS2365: Operator '>' cannot be applied to types 'boolean' and 'number'.
1115

1216

13-
==== tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts (10 errors) ====
17+
==== tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpressionErrors.ts (14 errors) ====
1418
declare let f: { <T>(): T, g<U>(): U };
1519

1620
// Type arguments in member expressions
@@ -54,27 +58,86 @@ tests/cases/conformance/types/typeParameters/typeArgumentLists/instantiationExpr
5458
~~~~~~
5559
!!! error TS2558: Expected 0 type arguments, but got 1.
5660

61+
// Instantiation expression and binary operators
62+
63+
declare let g: (<T>(x: T) => T) | undefined;
64+
65+
const c1 = g<string> || ((x: string) => x);
66+
const c2 = g<string> ?? ((x: string) => x);
67+
const c3 = g<string> && ((x: string) => x);
68+
5769
// Parsed as function call, even though this differs from JavaScript
5870

5971
const x1 = f<true>
6072
(true);
6173
~~~~
6274
!!! error TS2554: Expected 0 arguments, but got 1.
6375

64-
// Parsed as relational expression
76+
// Parsed as relational expressions
6577

66-
const x2 = f<true>
67-
~~~~~~
78+
const r1 = f < true > true;
79+
~~~~~~~~
6880
!!! error TS2365: Operator '<' cannot be applied to types '{ <T>(): T; g<U>(): U; }' and 'boolean'.
69-
true;
81+
const r2 = f < true > +1;
82+
~~~~~~~~
83+
!!! error TS2365: Operator '<' cannot be applied to types '{ <T>(): T; g<U>(): U; }' and 'boolean'.
84+
~~~~~~~~~~~~~
85+
!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and 'number'.
86+
const r3 = f < true > -1;
87+
~~~~~~~~
88+
!!! error TS2365: Operator '<' cannot be applied to types '{ <T>(): T; g<U>(): U; }' and 'boolean'.
89+
~~~~~~~~~~~~~
90+
!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and 'number'.
7091

71-
// Parsed as instantiation expression
92+
// All of the following are parsed as instantiation expressions
7293

73-
const x3 = f<true>;
94+
const x2 = f<true>
7495
true;
7596

76-
// Parsed as instantiation expression
97+
const x3 = f<true>;
98+
true;
7799

78100
const x4 = f<true>
79101
if (true) {}
102+
103+
const x5 = f<true>
104+
let yy = 0;
105+
106+
const x6 = f<true>
107+
interface I {}
108+
109+
let x10 = f<true>
110+
this.bar()
111+
112+
let x11 = f<true>
113+
function bar() {}
114+
115+
let x12 = f<true>
116+
class C {}
117+
118+
let x13 = f<true>
119+
bar()
120+
121+
let x14 = f<true>
122+
void bar()
123+
124+
class C1 {
125+
static specialFoo = f<string>
126+
static bar = 123
127+
}
128+
129+
class C2 {
130+
public specialFoo = f<string>
131+
public bar = 123
132+
}
133+
134+
class C3 {
135+
private specialFoo = f<string>
136+
private bar = 123
137+
}
138+
139+
class C4 {
140+
protected specialFoo = f<string>
141+
protected bar = 123
142+
}
80143

tests/baselines/reference/instantiationExpressionErrors.js

Lines changed: 182 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,81 @@ const b2 = f?.<number>();
2626
const b3 = f<number>?.();
2727
const b4 = f<number>?.<number>(); // Error, expected no type arguments
2828

29+
// Instantiation expression and binary operators
30+
31+
declare let g: (<T>(x: T) => T) | undefined;
32+
33+
const c1 = g<string> || ((x: string) => x);
34+
const c2 = g<string> ?? ((x: string) => x);
35+
const c3 = g<string> && ((x: string) => x);
36+
2937
// Parsed as function call, even though this differs from JavaScript
3038

3139
const x1 = f<true>
3240
(true);
3341

34-
// Parsed as relational expression
42+
// Parsed as relational expressions
43+
44+
const r1 = f < true > true;
45+
const r2 = f < true > +1;
46+
const r3 = f < true > -1;
47+
48+
// All of the following are parsed as instantiation expressions
3549

3650
const x2 = f<true>
3751
true;
3852

39-
// Parsed as instantiation expression
40-
4153
const x3 = f<true>;
4254
true;
4355

44-
// Parsed as instantiation expression
45-
4656
const x4 = f<true>
4757
if (true) {}
58+
59+
const x5 = f<true>
60+
let yy = 0;
61+
62+
const x6 = f<true>
63+
interface I {}
64+
65+
let x10 = f<true>
66+
this.bar()
67+
68+
let x11 = f<true>
69+
function bar() {}
70+
71+
let x12 = f<true>
72+
class C {}
73+
74+
let x13 = f<true>
75+
bar()
76+
77+
let x14 = f<true>
78+
void bar()
79+
80+
class C1 {
81+
static specialFoo = f<string>
82+
static bar = 123
83+
}
84+
85+
class C2 {
86+
public specialFoo = f<string>
87+
public bar = 123
88+
}
89+
90+
class C3 {
91+
private specialFoo = f<string>
92+
private bar = 123
93+
}
94+
95+
class C4 {
96+
protected specialFoo = f<string>
97+
protected bar = 123
98+
}
4899

49100

50101
//// [instantiationExpressionErrors.js]
51102
"use strict";
52-
var _a, _b;
103+
var _a, _b, _c;
53104
// Type arguments in member expressions
54105
var a1 = (f); // { (): number; g<U>(): U; }
55106
var a2 = (f.g); // () => number
@@ -67,17 +118,67 @@ var b1 = f === null || f === void 0 ? void 0 : f(); // Error, `(` expected
67118
var b2 = f === null || f === void 0 ? void 0 : f();
68119
var b3 = (_a = (f)) === null || _a === void 0 ? void 0 : _a();
69120
var b4 = (_b = (f)) === null || _b === void 0 ? void 0 : _b(); // Error, expected no type arguments
121+
var c1 = (g) || (function (x) { return x; });
122+
var c2 = (_c = (g)) !== null && _c !== void 0 ? _c : (function (x) { return x; });
123+
var c3 = (g) && (function (x) { return x; });
70124
// Parsed as function call, even though this differs from JavaScript
71125
var x1 = f(true);
72-
// Parsed as relational expression
73-
var x2 = f < true >
74-
true;
75-
// Parsed as instantiation expression
126+
// Parsed as relational expressions
127+
var r1 = f < true > true;
128+
var r2 = f < true > +1;
129+
var r3 = f < true > -1;
130+
// All of the following are parsed as instantiation expressions
131+
var x2 = (f);
132+
true;
76133
var x3 = (f);
77134
true;
78-
// Parsed as instantiation expression
79135
var x4 = (f);
80136
if (true) { }
137+
var x5 = (f);
138+
var yy = 0;
139+
var x6 = (f);
140+
var x10 = (f);
141+
this.bar();
142+
var x11 = (f);
143+
function bar() { }
144+
var x12 = (f);
145+
var C = /** @class */ (function () {
146+
function C() {
147+
}
148+
return C;
149+
}());
150+
var x13 = (f);
151+
bar();
152+
var x14 = (f);
153+
void bar();
154+
var C1 = /** @class */ (function () {
155+
function C1() {
156+
}
157+
C1.specialFoo = (f);
158+
C1.bar = 123;
159+
return C1;
160+
}());
161+
var C2 = /** @class */ (function () {
162+
function C2() {
163+
this.specialFoo = (f);
164+
this.bar = 123;
165+
}
166+
return C2;
167+
}());
168+
var C3 = /** @class */ (function () {
169+
function C3() {
170+
this.specialFoo = (f);
171+
this.bar = 123;
172+
}
173+
return C3;
174+
}());
175+
var C4 = /** @class */ (function () {
176+
function C4() {
177+
this.specialFoo = (f);
178+
this.bar = 123;
179+
}
180+
return C4;
181+
}());
81182

82183

83184
//// [instantiationExpressionErrors.d.ts]
@@ -103,8 +204,18 @@ declare const b1: number;
103204
declare const b2: number;
104205
declare const b3: number;
105206
declare const b4: number;
207+
declare let g: (<T>(x: T) => T) | undefined;
208+
declare const c1: (x: string) => string;
209+
declare const c2: (x: string) => string;
210+
declare const c3: ((x: string) => string) | undefined;
106211
declare const x1: true;
107-
declare const x2: boolean;
212+
declare const r1: boolean;
213+
declare const r2: boolean;
214+
declare const r3: boolean;
215+
declare const x2: {
216+
(): true;
217+
g<U>(): U;
218+
};
108219
declare const x3: {
109220
(): true;
110221
g<U>(): U;
@@ -113,3 +224,62 @@ declare const x4: {
113224
(): true;
114225
g<U>(): U;
115226
};
227+
declare const x5: {
228+
(): true;
229+
g<U>(): U;
230+
};
231+
declare let yy: number;
232+
declare const x6: {
233+
(): true;
234+
g<U>(): U;
235+
};
236+
interface I {
237+
}
238+
declare let x10: {
239+
(): true;
240+
g<U>(): U;
241+
};
242+
declare let x11: {
243+
(): true;
244+
g<U>(): U;
245+
};
246+
declare function bar(): void;
247+
declare let x12: {
248+
(): true;
249+
g<U>(): U;
250+
};
251+
declare class C {
252+
}
253+
declare let x13: {
254+
(): true;
255+
g<U>(): U;
256+
};
257+
declare let x14: {
258+
(): true;
259+
g<U>(): U;
260+
};
261+
declare class C1 {
262+
static specialFoo: {
263+
(): string;
264+
g<U>(): U;
265+
};
266+
static bar: number;
267+
}
268+
declare class C2 {
269+
specialFoo: {
270+
(): string;
271+
g<U>(): U;
272+
};
273+
bar: number;
274+
}
275+
declare class C3 {
276+
private specialFoo;
277+
private bar;
278+
}
279+
declare class C4 {
280+
protected specialFoo: {
281+
(): string;
282+
g<U>(): U;
283+
};
284+
protected bar: number;
285+
}

0 commit comments

Comments
 (0)