diff --git a/tsc/internal/parser/parser.go b/tsc/internal/parser/parser.go index c670d64ad21c2..c8b80994399e4 100644 --- a/tsc/internal/parser/parser.go +++ b/tsc/internal/parser/parser.go @@ -5338,9 +5338,17 @@ func (p *Parser) tryParseTypeArgumentsInExpression() *ast.NodeList { return nil } state := p.mark() + isLessThanLessThan := p.token == ast.KindLessThanLessThanToken if p.reScanLessThanToken() == ast.KindLessThanToken { p.nextToken() typeArguments := p.parseDelimitedList(PCTypeArguments, (*Parser).parseType) + // A `<<` can only start a type argument list whose first type argument is a generic function + // or constructor type, as in `f<(x: T) => T>(g)`. If parsing such a list reported errors, + // we instead treat `<<` as a left shift operator, as in `1 << f()`. + if isLessThanLessThan && len(p.diagnostics) != state.diagnosticsLen { + p.rewind(state) + return nil + } // If it doesn't have the closing `>` then it's definitely not an type argument list. if p.reScanGreaterThanToken() == ast.KindGreaterThanToken { p.nextToken() diff --git a/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.js b/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.js new file mode 100644 index 0000000000000..1f5e656e6c75f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.js @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts] //// + +//// [leftShiftBeforeTypeArgumentCall.ts] +// https://github.com/microsoft/TypeScript/issues/37760 + +function alignof(): number { return 1; } + +function f1(): number { return 1 << alignof(); } +function f2(): number { return 1 >> alignof(); } +function f3(): number { return 1 >>> alignof(); } +function f4(): number { return 1 << (alignof()); } +function f5(x: number): number { x <<= alignof(); return x; } +function f6(x: number): number { x >>= alignof(); return x; } +function f7(x: number): number { x >>>= alignof(); return x; } +function f8(): number { return 1 < alignof() ? 1 : 0; } +function f9(): number { return 1 << alignof(); } + +// `<<` that starts a type argument list with a generic function type is still a type argument list. +declare function g(f: F): F; +const h = g<(x: U) => U>((x) => x); +const n: number = h(1); + + +//// [leftShiftBeforeTypeArgumentCall.js] +"use strict"; +// https://github.com/microsoft/TypeScript/issues/37760 +function alignof() { return 1; } +function f1() { return 1 << alignof(); } +function f2() { return 1 >> alignof(); } +function f3() { return 1 >>> alignof(); } +function f4() { return 1 << (alignof()); } +function f5(x) { x <<= alignof(); return x; } +function f6(x) { x >>= alignof(); return x; } +function f7(x) { x >>>= alignof(); return x; } +function f8() { return 1 < alignof() ? 1 : 0; } +function f9() { return 1 << alignof(); } +const h = g((x) => x); +const n = h(1); diff --git a/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.symbols b/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.symbols new file mode 100644 index 0000000000000..518c4dee8ddf8 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.symbols @@ -0,0 +1,92 @@ +//// [tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts] //// + +=== leftShiftBeforeTypeArgumentCall.ts === +// https://github.com/microsoft/TypeScript/issues/37760 + +function alignof(): number { return 1; } +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 2, 17)) + +function f1(): number { return 1 << alignof(); } +>f1 : Symbol(f1, Decl(leftShiftBeforeTypeArgumentCall.ts, 2, 43)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 4, 12)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 4, 12)) + +function f2(): number { return 1 >> alignof(); } +>f2 : Symbol(f2, Decl(leftShiftBeforeTypeArgumentCall.ts, 4, 56)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 5, 12)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 5, 12)) + +function f3(): number { return 1 >>> alignof(); } +>f3 : Symbol(f3, Decl(leftShiftBeforeTypeArgumentCall.ts, 5, 56)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 6, 12)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 6, 12)) + +function f4(): number { return 1 << (alignof()); } +>f4 : Symbol(f4, Decl(leftShiftBeforeTypeArgumentCall.ts, 6, 57)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 7, 12)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 7, 12)) + +function f5(x: number): number { x <<= alignof(); return x; } +>f5 : Symbol(f5, Decl(leftShiftBeforeTypeArgumentCall.ts, 7, 58)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 8, 12)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 8, 15)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 8, 15)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 8, 12)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 8, 15)) + +function f6(x: number): number { x >>= alignof(); return x; } +>f6 : Symbol(f6, Decl(leftShiftBeforeTypeArgumentCall.ts, 8, 69)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 9, 12)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 9, 15)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 9, 15)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 9, 12)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 9, 15)) + +function f7(x: number): number { x >>>= alignof(); return x; } +>f7 : Symbol(f7, Decl(leftShiftBeforeTypeArgumentCall.ts, 9, 69)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 10, 12)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 10, 15)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 10, 15)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 10, 12)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 10, 15)) + +function f8(): number { return 1 < alignof() ? 1 : 0; } +>f8 : Symbol(f8, Decl(leftShiftBeforeTypeArgumentCall.ts, 10, 70)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 11, 12)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) +>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 11, 12)) + +function f9(): number { return 1 << alignof(); } +>f9 : Symbol(f9, Decl(leftShiftBeforeTypeArgumentCall.ts, 11, 63)) +>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0)) + +// `<<` that starts a type argument list with a generic function type is still a type argument list. +declare function g(f: F): F; +>g : Symbol(g, Decl(leftShiftBeforeTypeArgumentCall.ts, 12, 56)) +>F : Symbol(F, Decl(leftShiftBeforeTypeArgumentCall.ts, 15, 19)) +>f : Symbol(f, Decl(leftShiftBeforeTypeArgumentCall.ts, 15, 22)) +>F : Symbol(F, Decl(leftShiftBeforeTypeArgumentCall.ts, 15, 19)) +>F : Symbol(F, Decl(leftShiftBeforeTypeArgumentCall.ts, 15, 19)) + +const h = g<(x: U) => U>((x) => x); +>h : Symbol(h, Decl(leftShiftBeforeTypeArgumentCall.ts, 16, 5)) +>g : Symbol(g, Decl(leftShiftBeforeTypeArgumentCall.ts, 12, 56)) +>U : Symbol(U, Decl(leftShiftBeforeTypeArgumentCall.ts, 16, 13)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 16, 16)) +>U : Symbol(U, Decl(leftShiftBeforeTypeArgumentCall.ts, 16, 13)) +>U : Symbol(U, Decl(leftShiftBeforeTypeArgumentCall.ts, 16, 13)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 16, 29)) +>x : Symbol(x, Decl(leftShiftBeforeTypeArgumentCall.ts, 16, 29)) + +const n: number = h(1); +>n : Symbol(n, Decl(leftShiftBeforeTypeArgumentCall.ts, 17, 5)) +>h : Symbol(h, Decl(leftShiftBeforeTypeArgumentCall.ts, 16, 5)) + diff --git a/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.types b/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.types new file mode 100644 index 0000000000000..8249f248cf784 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/leftShiftBeforeTypeArgumentCall.types @@ -0,0 +1,102 @@ +//// [tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts] //// + +=== leftShiftBeforeTypeArgumentCall.ts === +// https://github.com/microsoft/TypeScript/issues/37760 + +function alignof(): number { return 1; } +>alignof : () => number +>1 : 1 + +function f1(): number { return 1 << alignof(); } +>f1 : () => number +>1 << alignof() : number +>1 : 1 +>alignof() : number +>alignof : () => number + +function f2(): number { return 1 >> alignof(); } +>f2 : () => number +>1 >> alignof() : number +>1 : 1 +>alignof() : number +>alignof : () => number + +function f3(): number { return 1 >>> alignof(); } +>f3 : () => number +>1 >>> alignof() : number +>1 : 1 +>alignof() : number +>alignof : () => number + +function f4(): number { return 1 << (alignof()); } +>f4 : () => number +>1 << (alignof()) : number +>1 : 1 +>(alignof()) : number +>alignof() : number +>alignof : () => number + +function f5(x: number): number { x <<= alignof(); return x; } +>f5 : (x: number) => number +>x : number +>x <<= alignof() : number +>x : number +>alignof() : number +>alignof : () => number +>x : number + +function f6(x: number): number { x >>= alignof(); return x; } +>f6 : (x: number) => number +>x : number +>x >>= alignof() : number +>x : number +>alignof() : number +>alignof : () => number +>x : number + +function f7(x: number): number { x >>>= alignof(); return x; } +>f7 : (x: number) => number +>x : number +>x >>>= alignof() : number +>x : number +>alignof() : number +>alignof : () => number +>x : number + +function f8(): number { return 1 < alignof() ? 1 : 0; } +>f8 : () => number +>1 < alignof() ? 1 : 0 : 0 | 1 +>1 < alignof() : boolean +>1 : 1 +>alignof() : number +>alignof : () => number +>1 : 1 +>0 : 0 + +function f9(): number { return 1 << alignof(); } +>f9 : () => number +>1 << alignof() : number +>1 : 1 +>alignof() : number +>alignof : () => number + +// `<<` that starts a type argument list with a generic function type is still a type argument list. +declare function g(f: F): F; +>g : (f: F) => F +>f : F + +const h = g<(x: U) => U>((x) => x); +>h : (x: U) => U +>g<(x: U) => U>((x) => x) : (x: U) => U +>g : (f: F) => F +>x : U +>(x) => x : (x: U) => U +>x : U +>x : U + +const n: number = h(1); +>n : number +>h(1) : 1 +>h : (x: U) => U +>1 : 1 + diff --git a/tsc/testdata/tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts b/tsc/testdata/tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts new file mode 100644 index 0000000000000..59fd05d37add9 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts @@ -0,0 +1,20 @@ +// @target: es2015 + +// https://github.com/microsoft/TypeScript/issues/37760 + +function alignof(): number { return 1; } + +function f1(): number { return 1 << alignof(); } +function f2(): number { return 1 >> alignof(); } +function f3(): number { return 1 >>> alignof(); } +function f4(): number { return 1 << (alignof()); } +function f5(x: number): number { x <<= alignof(); return x; } +function f6(x: number): number { x >>= alignof(); return x; } +function f7(x: number): number { x >>>= alignof(); return x; } +function f8(): number { return 1 < alignof() ? 1 : 0; } +function f9(): number { return 1 << alignof(); } + +// `<<` that starts a type argument list with a generic function type is still a type argument list. +declare function g(f: F): F; +const h = g<(x: U) => U>((x) => x); +const n: number = h(1);