Skip to content

Commit d7f03fb

Browse files
authored
Parse generic function types in import type argument lists (microsoft#31079)
* Parenthesize in import type node factory * And now parse unparenthesized generic functions so we can handle parsing the older output
1 parent 8fc6640 commit d7f03fb

11 files changed

+206
-2
lines changed

src/compiler/factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ namespace ts {
845845
const node = <ImportTypeNode>createSynthesizedNode(SyntaxKind.ImportType);
846846
node.argument = argument;
847847
node.qualifier = qualifier;
848-
node.typeArguments = asNodeArray(typeArguments);
848+
node.typeArguments = parenthesizeTypeParameters(typeArguments);
849849
node.isTypeOf = isTypeOf;
850850
return node;
851851
}

src/compiler/parser.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2922,7 +2922,9 @@ namespace ts {
29222922
if (parseOptional(SyntaxKind.DotToken)) {
29232923
node.qualifier = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);
29242924
}
2925-
node.typeArguments = tryParseTypeArguments();
2925+
if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) {
2926+
node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
2927+
}
29262928
return finishNode(node);
29272929
}
29282930

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//// [tests/cases/compiler/importTypeGenericArrowTypeParenthesized.ts] ////
2+
3+
//// [module.d.ts]
4+
declare module "module" {
5+
export interface Modifier<T> { }
6+
7+
export function fn<T>(x: T): Modifier<T>;
8+
}
9+
//// [index.ts]
10+
import { fn } from "module";
11+
12+
export const fail1 = fn(<T>(x: T): T => x);
13+
export const fail2 = fn(function<T>(x: T): T {
14+
return x;
15+
});
16+
17+
export const works1 = fn((x: number) => x);
18+
type MakeItWork = <T>(x: T) => T;
19+
export const works2 = fn<MakeItWork>(x => x);
20+
21+
22+
//// [index.js]
23+
"use strict";
24+
exports.__esModule = true;
25+
var module_1 = require("module");
26+
exports.fail1 = module_1.fn(function (x) { return x; });
27+
exports.fail2 = module_1.fn(function (x) {
28+
return x;
29+
});
30+
exports.works1 = module_1.fn(function (x) { return x; });
31+
exports.works2 = module_1.fn(function (x) { return x; });
32+
33+
34+
//// [index.d.ts]
35+
/// <reference path="module.d.ts" />
36+
export declare const fail1: import("module").Modifier<(<T>(x: T) => T)>;
37+
export declare const fail2: import("module").Modifier<(<T>(x: T) => T)>;
38+
export declare const works1: import("module").Modifier<(x: number) => number>;
39+
declare type MakeItWork = <T>(x: T) => T;
40+
export declare const works2: import("module").Modifier<MakeItWork>;
41+
export {};
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
=== tests/cases/compiler/module.d.ts ===
2+
declare module "module" {
3+
>"module" : Symbol("module", Decl(module.d.ts, 0, 0))
4+
5+
export interface Modifier<T> { }
6+
>Modifier : Symbol(Modifier, Decl(module.d.ts, 0, 25))
7+
>T : Symbol(T, Decl(module.d.ts, 1, 30))
8+
9+
export function fn<T>(x: T): Modifier<T>;
10+
>fn : Symbol(fn, Decl(module.d.ts, 1, 36))
11+
>T : Symbol(T, Decl(module.d.ts, 3, 23))
12+
>x : Symbol(x, Decl(module.d.ts, 3, 26))
13+
>T : Symbol(T, Decl(module.d.ts, 3, 23))
14+
>Modifier : Symbol(Modifier, Decl(module.d.ts, 0, 25))
15+
>T : Symbol(T, Decl(module.d.ts, 3, 23))
16+
}
17+
=== tests/cases/compiler/index.ts ===
18+
import { fn } from "module";
19+
>fn : Symbol(fn, Decl(index.ts, 0, 8))
20+
21+
export const fail1 = fn(<T>(x: T): T => x);
22+
>fail1 : Symbol(fail1, Decl(index.ts, 2, 12))
23+
>fn : Symbol(fn, Decl(index.ts, 0, 8))
24+
>T : Symbol(T, Decl(index.ts, 2, 25))
25+
>x : Symbol(x, Decl(index.ts, 2, 28))
26+
>T : Symbol(T, Decl(index.ts, 2, 25))
27+
>T : Symbol(T, Decl(index.ts, 2, 25))
28+
>x : Symbol(x, Decl(index.ts, 2, 28))
29+
30+
export const fail2 = fn(function<T>(x: T): T {
31+
>fail2 : Symbol(fail2, Decl(index.ts, 3, 12))
32+
>fn : Symbol(fn, Decl(index.ts, 0, 8))
33+
>T : Symbol(T, Decl(index.ts, 3, 33))
34+
>x : Symbol(x, Decl(index.ts, 3, 36))
35+
>T : Symbol(T, Decl(index.ts, 3, 33))
36+
>T : Symbol(T, Decl(index.ts, 3, 33))
37+
38+
return x;
39+
>x : Symbol(x, Decl(index.ts, 3, 36))
40+
41+
});
42+
43+
export const works1 = fn((x: number) => x);
44+
>works1 : Symbol(works1, Decl(index.ts, 7, 12))
45+
>fn : Symbol(fn, Decl(index.ts, 0, 8))
46+
>x : Symbol(x, Decl(index.ts, 7, 26))
47+
>x : Symbol(x, Decl(index.ts, 7, 26))
48+
49+
type MakeItWork = <T>(x: T) => T;
50+
>MakeItWork : Symbol(MakeItWork, Decl(index.ts, 7, 43))
51+
>T : Symbol(T, Decl(index.ts, 8, 19))
52+
>x : Symbol(x, Decl(index.ts, 8, 22))
53+
>T : Symbol(T, Decl(index.ts, 8, 19))
54+
>T : Symbol(T, Decl(index.ts, 8, 19))
55+
56+
export const works2 = fn<MakeItWork>(x => x);
57+
>works2 : Symbol(works2, Decl(index.ts, 9, 12))
58+
>fn : Symbol(fn, Decl(index.ts, 0, 8))
59+
>MakeItWork : Symbol(MakeItWork, Decl(index.ts, 7, 43))
60+
>x : Symbol(x, Decl(index.ts, 9, 37))
61+
>x : Symbol(x, Decl(index.ts, 9, 37))
62+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
=== tests/cases/compiler/module.d.ts ===
2+
declare module "module" {
3+
>"module" : typeof import("module")
4+
5+
export interface Modifier<T> { }
6+
7+
export function fn<T>(x: T): Modifier<T>;
8+
>fn : <T>(x: T) => Modifier<T>
9+
>x : T
10+
}
11+
=== tests/cases/compiler/index.ts ===
12+
import { fn } from "module";
13+
>fn : <T>(x: T) => import("module").Modifier<T>
14+
15+
export const fail1 = fn(<T>(x: T): T => x);
16+
>fail1 : import("module").Modifier<(<T>(x: T) => T)>
17+
>fn(<T>(x: T): T => x) : import("module").Modifier<(<T>(x: T) => T)>
18+
>fn : <T>(x: T) => import("module").Modifier<T>
19+
><T>(x: T): T => x : <T>(x: T) => T
20+
>x : T
21+
>x : T
22+
23+
export const fail2 = fn(function<T>(x: T): T {
24+
>fail2 : import("module").Modifier<(<T>(x: T) => T)>
25+
>fn(function<T>(x: T): T { return x;}) : import("module").Modifier<(<T>(x: T) => T)>
26+
>fn : <T>(x: T) => import("module").Modifier<T>
27+
>function<T>(x: T): T { return x;} : <T>(x: T) => T
28+
>x : T
29+
30+
return x;
31+
>x : T
32+
33+
});
34+
35+
export const works1 = fn((x: number) => x);
36+
>works1 : import("module").Modifier<(x: number) => number>
37+
>fn((x: number) => x) : import("module").Modifier<(x: number) => number>
38+
>fn : <T>(x: T) => import("module").Modifier<T>
39+
>(x: number) => x : (x: number) => number
40+
>x : number
41+
>x : number
42+
43+
type MakeItWork = <T>(x: T) => T;
44+
>MakeItWork : MakeItWork
45+
>x : T
46+
47+
export const works2 = fn<MakeItWork>(x => x);
48+
>works2 : import("module").Modifier<MakeItWork>
49+
>fn<MakeItWork>(x => x) : import("module").Modifier<MakeItWork>
50+
>fn : <T>(x: T) => import("module").Modifier<T>
51+
>x => x : <T>(x: T) => T
52+
>x : T
53+
>x : T
54+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts(1,36): error TS2307: Cannot find module 'module'.
2+
3+
4+
==== tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts (1 errors) ====
5+
export declare const fail1: import("module").Modifier<<T>(x: T) => T>; // shouldn't be a parse error
6+
~~~~~~~~
7+
!!! error TS2307: Cannot find module 'module'.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//// [importTypeWithUnparenthesizedGenericFunctionParsed.ts]
2+
export declare const fail1: import("module").Modifier<<T>(x: T) => T>; // shouldn't be a parse error
3+
4+
//// [importTypeWithUnparenthesizedGenericFunctionParsed.js]
5+
"use strict";
6+
exports.__esModule = true;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts ===
2+
export declare const fail1: import("module").Modifier<<T>(x: T) => T>; // shouldn't be a parse error
3+
>fail1 : Symbol(fail1, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 20))
4+
>T : Symbol(T, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 55))
5+
>x : Symbol(x, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 58))
6+
>T : Symbol(T, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 55))
7+
>T : Symbol(T, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 55))
8+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts ===
2+
export declare const fail1: import("module").Modifier<<T>(x: T) => T>; // shouldn't be a parse error
3+
>fail1 : any
4+
>x : T
5+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @declaration: true
2+
// @filename: module.d.ts
3+
declare module "module" {
4+
export interface Modifier<T> { }
5+
6+
export function fn<T>(x: T): Modifier<T>;
7+
}
8+
// @filename: index.ts
9+
import { fn } from "module";
10+
11+
export const fail1 = fn(<T>(x: T): T => x);
12+
export const fail2 = fn(function<T>(x: T): T {
13+
return x;
14+
});
15+
16+
export const works1 = fn((x: number) => x);
17+
type MakeItWork = <T>(x: T) => T;
18+
export const works2 = fn<MakeItWork>(x => x);

0 commit comments

Comments
 (0)