diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 53e45505014..92792c7a1a2 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1093,6 +1093,10 @@ namespace ts { return currentToken = scanner.reScanTemplateToken(); } + function reScanLessThanToken(): SyntaxKind { + return currentToken = scanner.reScanLessThanToken(); + } + function scanJsxIdentifier(): SyntaxKind { return currentToken = scanner.scanJsxIdentifier(); } @@ -2276,7 +2280,7 @@ namespace ts { function parseTypeReference(): TypeReferenceNode { const node = createNode(SyntaxKind.TypeReference); node.typeName = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected); - if (!scanner.hasPrecedingLineBreak() && token() === SyntaxKind.LessThanToken) { + if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) { node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); } return finishNode(node); @@ -4523,7 +4527,8 @@ namespace ts { function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression { while (true) { expression = parseMemberExpressionRest(expression); - if (token() === SyntaxKind.LessThanToken) { + // handle 'foo<()' + if (token() === SyntaxKind.LessThanToken || token() === SyntaxKind.LessThanLessThanToken) { // See if this is the start of a generic invocation. If so, consume it and // keep checking for postfix expressions. Otherwise, it's just a '<' that's // part of an arithmetic expression. Break out so we consume it higher in the @@ -4565,9 +4570,10 @@ namespace ts { } function parseTypeArgumentsInExpression() { - if (!parseOptional(SyntaxKind.LessThanToken)) { + if (reScanLessThanToken() !== SyntaxKind.LessThanToken) { return undefined; } + nextToken(); const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType); if (!parseExpected(SyntaxKind.GreaterThanToken)) { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index d59be975865..4f3eba37296 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -31,6 +31,7 @@ namespace ts { scanJsxIdentifier(): SyntaxKind; scanJsxAttributeValue(): SyntaxKind; reScanJsxToken(): JsxTokenSyntaxKind; + reScanLessThanToken(): SyntaxKind; scanJsxToken(): JsxTokenSyntaxKind; scanJSDocToken(): JsDocSyntaxKind; scan(): SyntaxKind; @@ -874,6 +875,7 @@ namespace ts { scanJsxIdentifier, scanJsxAttributeValue, reScanJsxToken, + reScanLessThanToken, scanJsxToken, scanJSDocToken, scan, @@ -1939,6 +1941,14 @@ namespace ts { return token = scanJsxToken(); } + function reScanLessThanToken(): SyntaxKind { + if (token === SyntaxKind.LessThanLessThanToken) { + pos = tokenPos + 1; + return token = SyntaxKind.LessThanToken; + } + return token; + } + function scanJsxToken(): JsxTokenSyntaxKind { startPos = tokenPos = pos; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index f71dbc9aa50..4353bbcd8fa 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3097,6 +3097,7 @@ declare namespace ts { scanJsxIdentifier(): SyntaxKind; scanJsxAttributeValue(): SyntaxKind; reScanJsxToken(): JsxTokenSyntaxKind; + reScanLessThanToken(): SyntaxKind; scanJsxToken(): JsxTokenSyntaxKind; scanJSDocToken(): JsDocSyntaxKind; scan(): SyntaxKind; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 03f24988ed3..d8deb32c0ef 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3097,6 +3097,7 @@ declare namespace ts { scanJsxIdentifier(): SyntaxKind; scanJsxAttributeValue(): SyntaxKind; reScanJsxToken(): JsxTokenSyntaxKind; + reScanLessThanToken(): SyntaxKind; scanJsxToken(): JsxTokenSyntaxKind; scanJSDocToken(): JsDocSyntaxKind; scan(): SyntaxKind; diff --git a/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.js b/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.js new file mode 100644 index 00000000000..f1efc8023b5 --- /dev/null +++ b/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.js @@ -0,0 +1,11 @@ +//// [parseGenericArrowRatherThanLeftShift.ts] +type Bar = ReturnType<(x: T) => number>; +declare const a: Bar; + +function foo(_x: T) {} +const b = foo<(x: T) => number>(() => 1); + + +//// [parseGenericArrowRatherThanLeftShift.js] +function foo(_x) { } +var b = foo(function () { return 1; }); diff --git a/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.symbols b/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.symbols new file mode 100644 index 00000000000..335ffd451e4 --- /dev/null +++ b/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.symbols @@ -0,0 +1,25 @@ +=== tests/cases/compiler/parseGenericArrowRatherThanLeftShift.ts === +type Bar = ReturnType<(x: T) => number>; +>Bar : Symbol(Bar, Decl(parseGenericArrowRatherThanLeftShift.ts, 0, 0)) +>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(parseGenericArrowRatherThanLeftShift.ts, 0, 23)) +>x : Symbol(x, Decl(parseGenericArrowRatherThanLeftShift.ts, 0, 26)) +>T : Symbol(T, Decl(parseGenericArrowRatherThanLeftShift.ts, 0, 23)) + +declare const a: Bar; +>a : Symbol(a, Decl(parseGenericArrowRatherThanLeftShift.ts, 1, 13)) +>Bar : Symbol(Bar, Decl(parseGenericArrowRatherThanLeftShift.ts, 0, 0)) + +function foo(_x: T) {} +>foo : Symbol(foo, Decl(parseGenericArrowRatherThanLeftShift.ts, 1, 21)) +>T : Symbol(T, Decl(parseGenericArrowRatherThanLeftShift.ts, 3, 13)) +>_x : Symbol(_x, Decl(parseGenericArrowRatherThanLeftShift.ts, 3, 16)) +>T : Symbol(T, Decl(parseGenericArrowRatherThanLeftShift.ts, 3, 13)) + +const b = foo<(x: T) => number>(() => 1); +>b : Symbol(b, Decl(parseGenericArrowRatherThanLeftShift.ts, 4, 5)) +>foo : Symbol(foo, Decl(parseGenericArrowRatherThanLeftShift.ts, 1, 21)) +>T : Symbol(T, Decl(parseGenericArrowRatherThanLeftShift.ts, 4, 15)) +>x : Symbol(x, Decl(parseGenericArrowRatherThanLeftShift.ts, 4, 18)) +>T : Symbol(T, Decl(parseGenericArrowRatherThanLeftShift.ts, 4, 15)) + diff --git a/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.types b/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.types new file mode 100644 index 00000000000..3f256ffdcaa --- /dev/null +++ b/tests/baselines/reference/parseGenericArrowRatherThanLeftShift.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/parseGenericArrowRatherThanLeftShift.ts === +type Bar = ReturnType<(x: T) => number>; +>Bar : number +>x : T + +declare const a: Bar; +>a : number + +function foo(_x: T) {} +>foo : (_x: T) => void +>_x : T + +const b = foo<(x: T) => number>(() => 1); +>b : void +>foo<(x: T) => number>(() => 1) : void +>foo : (_x: T) => void +>x : T +>() => 1 : () => number +>1 : 1 + diff --git a/tests/cases/compiler/parseGenericArrowRatherThanLeftShift.ts b/tests/cases/compiler/parseGenericArrowRatherThanLeftShift.ts new file mode 100644 index 00000000000..e61f13a8515 --- /dev/null +++ b/tests/cases/compiler/parseGenericArrowRatherThanLeftShift.ts @@ -0,0 +1,5 @@ +type Bar = ReturnType<(x: T) => number>; +declare const a: Bar; + +function foo(_x: T) {} +const b = foo<(x: T) => number>(() => 1);