From d7f03fb0fa356b23f77deb2ea2cdf4206022964e Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 23 Apr 2019 14:48:31 -0700 Subject: [PATCH] Parse generic function types in import type argument lists (#31079) * Parenthesize in import type node factory * And now parse unparenthesized generic functions so we can handle parsing the older output --- src/compiler/factory.ts | 2 +- src/compiler/parser.ts | 4 +- ...importTypeGenericArrowTypeParenthesized.js | 41 ++++++++++++ ...tTypeGenericArrowTypeParenthesized.symbols | 62 +++++++++++++++++++ ...ortTypeGenericArrowTypeParenthesized.types | 54 ++++++++++++++++ ...enthesizedGenericFunctionParsed.errors.txt | 7 +++ ...ithUnparenthesizedGenericFunctionParsed.js | 6 ++ ...parenthesizedGenericFunctionParsed.symbols | 8 +++ ...UnparenthesizedGenericFunctionParsed.types | 5 ++ ...importTypeGenericArrowTypeParenthesized.ts | 18 ++++++ ...ithUnparenthesizedGenericFunctionParsed.ts | 1 + 11 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/importTypeGenericArrowTypeParenthesized.js create mode 100644 tests/baselines/reference/importTypeGenericArrowTypeParenthesized.symbols create mode 100644 tests/baselines/reference/importTypeGenericArrowTypeParenthesized.types create mode 100644 tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.errors.txt create mode 100644 tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.js create mode 100644 tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.symbols create mode 100644 tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.types create mode 100644 tests/cases/compiler/importTypeGenericArrowTypeParenthesized.ts create mode 100644 tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 5f4299f1e20..3742f2d5fdf 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -845,7 +845,7 @@ namespace ts { const node = createSynthesizedNode(SyntaxKind.ImportType); node.argument = argument; node.qualifier = qualifier; - node.typeArguments = asNodeArray(typeArguments); + node.typeArguments = parenthesizeTypeParameters(typeArguments); node.isTypeOf = isTypeOf; return node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ada42889032..481a601118e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2922,7 +2922,9 @@ namespace ts { if (parseOptional(SyntaxKind.DotToken)) { node.qualifier = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected); } - node.typeArguments = tryParseTypeArguments(); + if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) { + node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + } return finishNode(node); } diff --git a/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.js b/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.js new file mode 100644 index 00000000000..e74990005db --- /dev/null +++ b/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.js @@ -0,0 +1,41 @@ +//// [tests/cases/compiler/importTypeGenericArrowTypeParenthesized.ts] //// + +//// [module.d.ts] +declare module "module" { + export interface Modifier { } + + export function fn(x: T): Modifier; +} +//// [index.ts] +import { fn } from "module"; + +export const fail1 = fn((x: T): T => x); +export const fail2 = fn(function(x: T): T { + return x; +}); + +export const works1 = fn((x: number) => x); +type MakeItWork = (x: T) => T; +export const works2 = fn(x => x); + + +//// [index.js] +"use strict"; +exports.__esModule = true; +var module_1 = require("module"); +exports.fail1 = module_1.fn(function (x) { return x; }); +exports.fail2 = module_1.fn(function (x) { + return x; +}); +exports.works1 = module_1.fn(function (x) { return x; }); +exports.works2 = module_1.fn(function (x) { return x; }); + + +//// [index.d.ts] +/// +export declare const fail1: import("module").Modifier<((x: T) => T)>; +export declare const fail2: import("module").Modifier<((x: T) => T)>; +export declare const works1: import("module").Modifier<(x: number) => number>; +declare type MakeItWork = (x: T) => T; +export declare const works2: import("module").Modifier; +export {}; diff --git a/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.symbols b/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.symbols new file mode 100644 index 00000000000..b6d30bcb8ad --- /dev/null +++ b/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.symbols @@ -0,0 +1,62 @@ +=== tests/cases/compiler/module.d.ts === +declare module "module" { +>"module" : Symbol("module", Decl(module.d.ts, 0, 0)) + + export interface Modifier { } +>Modifier : Symbol(Modifier, Decl(module.d.ts, 0, 25)) +>T : Symbol(T, Decl(module.d.ts, 1, 30)) + + export function fn(x: T): Modifier; +>fn : Symbol(fn, Decl(module.d.ts, 1, 36)) +>T : Symbol(T, Decl(module.d.ts, 3, 23)) +>x : Symbol(x, Decl(module.d.ts, 3, 26)) +>T : Symbol(T, Decl(module.d.ts, 3, 23)) +>Modifier : Symbol(Modifier, Decl(module.d.ts, 0, 25)) +>T : Symbol(T, Decl(module.d.ts, 3, 23)) +} +=== tests/cases/compiler/index.ts === +import { fn } from "module"; +>fn : Symbol(fn, Decl(index.ts, 0, 8)) + +export const fail1 = fn((x: T): T => x); +>fail1 : Symbol(fail1, Decl(index.ts, 2, 12)) +>fn : Symbol(fn, Decl(index.ts, 0, 8)) +>T : Symbol(T, Decl(index.ts, 2, 25)) +>x : Symbol(x, Decl(index.ts, 2, 28)) +>T : Symbol(T, Decl(index.ts, 2, 25)) +>T : Symbol(T, Decl(index.ts, 2, 25)) +>x : Symbol(x, Decl(index.ts, 2, 28)) + +export const fail2 = fn(function(x: T): T { +>fail2 : Symbol(fail2, Decl(index.ts, 3, 12)) +>fn : Symbol(fn, Decl(index.ts, 0, 8)) +>T : Symbol(T, Decl(index.ts, 3, 33)) +>x : Symbol(x, Decl(index.ts, 3, 36)) +>T : Symbol(T, Decl(index.ts, 3, 33)) +>T : Symbol(T, Decl(index.ts, 3, 33)) + + return x; +>x : Symbol(x, Decl(index.ts, 3, 36)) + +}); + +export const works1 = fn((x: number) => x); +>works1 : Symbol(works1, Decl(index.ts, 7, 12)) +>fn : Symbol(fn, Decl(index.ts, 0, 8)) +>x : Symbol(x, Decl(index.ts, 7, 26)) +>x : Symbol(x, Decl(index.ts, 7, 26)) + +type MakeItWork = (x: T) => T; +>MakeItWork : Symbol(MakeItWork, Decl(index.ts, 7, 43)) +>T : Symbol(T, Decl(index.ts, 8, 19)) +>x : Symbol(x, Decl(index.ts, 8, 22)) +>T : Symbol(T, Decl(index.ts, 8, 19)) +>T : Symbol(T, Decl(index.ts, 8, 19)) + +export const works2 = fn(x => x); +>works2 : Symbol(works2, Decl(index.ts, 9, 12)) +>fn : Symbol(fn, Decl(index.ts, 0, 8)) +>MakeItWork : Symbol(MakeItWork, Decl(index.ts, 7, 43)) +>x : Symbol(x, Decl(index.ts, 9, 37)) +>x : Symbol(x, Decl(index.ts, 9, 37)) + diff --git a/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.types b/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.types new file mode 100644 index 00000000000..1da9f590697 --- /dev/null +++ b/tests/baselines/reference/importTypeGenericArrowTypeParenthesized.types @@ -0,0 +1,54 @@ +=== tests/cases/compiler/module.d.ts === +declare module "module" { +>"module" : typeof import("module") + + export interface Modifier { } + + export function fn(x: T): Modifier; +>fn : (x: T) => Modifier +>x : T +} +=== tests/cases/compiler/index.ts === +import { fn } from "module"; +>fn : (x: T) => import("module").Modifier + +export const fail1 = fn((x: T): T => x); +>fail1 : import("module").Modifier<((x: T) => T)> +>fn((x: T): T => x) : import("module").Modifier<((x: T) => T)> +>fn : (x: T) => import("module").Modifier +>(x: T): T => x : (x: T) => T +>x : T +>x : T + +export const fail2 = fn(function(x: T): T { +>fail2 : import("module").Modifier<((x: T) => T)> +>fn(function(x: T): T { return x;}) : import("module").Modifier<((x: T) => T)> +>fn : (x: T) => import("module").Modifier +>function(x: T): T { return x;} : (x: T) => T +>x : T + + return x; +>x : T + +}); + +export const works1 = fn((x: number) => x); +>works1 : import("module").Modifier<(x: number) => number> +>fn((x: number) => x) : import("module").Modifier<(x: number) => number> +>fn : (x: T) => import("module").Modifier +>(x: number) => x : (x: number) => number +>x : number +>x : number + +type MakeItWork = (x: T) => T; +>MakeItWork : MakeItWork +>x : T + +export const works2 = fn(x => x); +>works2 : import("module").Modifier +>fn(x => x) : import("module").Modifier +>fn : (x: T) => import("module").Modifier +>x => x : (x: T) => T +>x : T +>x : T + diff --git a/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.errors.txt b/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.errors.txt new file mode 100644 index 00000000000..4c40245d8da --- /dev/null +++ b/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.errors.txt @@ -0,0 +1,7 @@ +tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts(1,36): error TS2307: Cannot find module 'module'. + + +==== tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts (1 errors) ==== + export declare const fail1: import("module").Modifier<(x: T) => T>; // shouldn't be a parse error + ~~~~~~~~ +!!! error TS2307: Cannot find module 'module'. \ No newline at end of file diff --git a/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.js b/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.js new file mode 100644 index 00000000000..2ff17635dbc --- /dev/null +++ b/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.js @@ -0,0 +1,6 @@ +//// [importTypeWithUnparenthesizedGenericFunctionParsed.ts] +export declare const fail1: import("module").Modifier<(x: T) => T>; // shouldn't be a parse error + +//// [importTypeWithUnparenthesizedGenericFunctionParsed.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.symbols b/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.symbols new file mode 100644 index 00000000000..33c9bdfb0ed --- /dev/null +++ b/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts === +export declare const fail1: import("module").Modifier<(x: T) => T>; // shouldn't be a parse error +>fail1 : Symbol(fail1, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 20)) +>T : Symbol(T, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 55)) +>x : Symbol(x, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 58)) +>T : Symbol(T, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 55)) +>T : Symbol(T, Decl(importTypeWithUnparenthesizedGenericFunctionParsed.ts, 0, 55)) + diff --git a/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.types b/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.types new file mode 100644 index 00000000000..6a0ae0401cd --- /dev/null +++ b/tests/baselines/reference/importTypeWithUnparenthesizedGenericFunctionParsed.types @@ -0,0 +1,5 @@ +=== tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts === +export declare const fail1: import("module").Modifier<(x: T) => T>; // shouldn't be a parse error +>fail1 : any +>x : T + diff --git a/tests/cases/compiler/importTypeGenericArrowTypeParenthesized.ts b/tests/cases/compiler/importTypeGenericArrowTypeParenthesized.ts new file mode 100644 index 00000000000..d8a212b1e86 --- /dev/null +++ b/tests/cases/compiler/importTypeGenericArrowTypeParenthesized.ts @@ -0,0 +1,18 @@ +// @declaration: true +// @filename: module.d.ts +declare module "module" { + export interface Modifier { } + + export function fn(x: T): Modifier; +} +// @filename: index.ts +import { fn } from "module"; + +export const fail1 = fn((x: T): T => x); +export const fail2 = fn(function(x: T): T { + return x; +}); + +export const works1 = fn((x: number) => x); +type MakeItWork = (x: T) => T; +export const works2 = fn(x => x); diff --git a/tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts b/tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts new file mode 100644 index 00000000000..725870c5da6 --- /dev/null +++ b/tests/cases/compiler/importTypeWithUnparenthesizedGenericFunctionParsed.ts @@ -0,0 +1 @@ +export declare const fail1: import("module").Modifier<(x: T) => T>; // shouldn't be a parse error \ No newline at end of file