Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tsc/internal/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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<<T>(x: T) => T>(g)`. If parsing such a list reported errors,
// we instead treat `<<` as a left shift operator, as in `1 << f<T[]>()`.
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()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//// [tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts] ////

//// [leftShiftBeforeTypeArgumentCall.ts]
// https://github.com/microsoft/TypeScript/issues/37760

function alignof<T>(): number { return 1; }

function f1<T>(): number { return 1 << alignof<T[]>(); }
function f2<T>(): number { return 1 >> alignof<T[]>(); }
function f3<T>(): number { return 1 >>> alignof<T[]>(); }
function f4<T>(): number { return 1 << (alignof<T[]>()); }
function f5<T>(x: number): number { x <<= alignof<T[]>(); return x; }
function f6<T>(x: number): number { x >>= alignof<T[]>(); return x; }
function f7<T>(x: number): number { x >>>= alignof<T[]>(); return x; }
function f8<T>(): number { return 1 < alignof<T[]>() ? 1 : 0; }
function f9(): number { return 1 << alignof<string>(); }

// `<<` that starts a type argument list with a generic function type is still a type argument list.
declare function g<F>(f: F): F;
const h = g<<U>(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);
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//// [tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts] ////

=== leftShiftBeforeTypeArgumentCall.ts ===
// https://github.com/microsoft/TypeScript/issues/37760

function alignof<T>(): number { return 1; }
>alignof : Symbol(alignof, Decl(leftShiftBeforeTypeArgumentCall.ts, 0, 0))
>T : Symbol(T, Decl(leftShiftBeforeTypeArgumentCall.ts, 2, 17))

function f1<T>(): number { return 1 << alignof<T[]>(); }
>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<T>(): number { return 1 >> alignof<T[]>(); }
>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<T>(): number { return 1 >>> alignof<T[]>(); }
>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<T>(): number { return 1 << (alignof<T[]>()); }
>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<T>(x: number): number { x <<= alignof<T[]>(); 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<T>(x: number): number { x >>= alignof<T[]>(); 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<T>(x: number): number { x >>>= alignof<T[]>(); 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<T>(): number { return 1 < alignof<T[]>() ? 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<string>(); }
>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): 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<<U>(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))

Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//// [tests/cases/compiler/leftShiftBeforeTypeArgumentCall.ts] ////

=== leftShiftBeforeTypeArgumentCall.ts ===
// https://github.com/microsoft/TypeScript/issues/37760

function alignof<T>(): number { return 1; }
>alignof : <T>() => number
>1 : 1

function f1<T>(): number { return 1 << alignof<T[]>(); }
>f1 : <T>() => number
>1 << alignof<T[]>() : number
>1 : 1
>alignof<T[]>() : number
>alignof : <T_1>() => number

function f2<T>(): number { return 1 >> alignof<T[]>(); }
>f2 : <T>() => number
>1 >> alignof<T[]>() : number
>1 : 1
>alignof<T[]>() : number
>alignof : <T_1>() => number

function f3<T>(): number { return 1 >>> alignof<T[]>(); }
>f3 : <T>() => number
>1 >>> alignof<T[]>() : number
>1 : 1
>alignof<T[]>() : number
>alignof : <T_1>() => number

function f4<T>(): number { return 1 << (alignof<T[]>()); }
>f4 : <T>() => number
>1 << (alignof<T[]>()) : number
>1 : 1
>(alignof<T[]>()) : number
>alignof<T[]>() : number
>alignof : <T_1>() => number

function f5<T>(x: number): number { x <<= alignof<T[]>(); return x; }
>f5 : <T>(x: number) => number
>x : number
>x <<= alignof<T[]>() : number
>x : number
>alignof<T[]>() : number
>alignof : <T_1>() => number
>x : number

function f6<T>(x: number): number { x >>= alignof<T[]>(); return x; }
>f6 : <T>(x: number) => number
>x : number
>x >>= alignof<T[]>() : number
>x : number
>alignof<T[]>() : number
>alignof : <T_1>() => number
>x : number

function f7<T>(x: number): number { x >>>= alignof<T[]>(); return x; }
>f7 : <T>(x: number) => number
>x : number
>x >>>= alignof<T[]>() : number
>x : number
>alignof<T[]>() : number
>alignof : <T_1>() => number
>x : number

function f8<T>(): number { return 1 < alignof<T[]>() ? 1 : 0; }
>f8 : <T>() => number
>1 < alignof<T[]>() ? 1 : 0 : 0 | 1
>1 < alignof<T[]>() : boolean
>1 : 1
>alignof<T[]>() : number
>alignof : <T_1>() => number
>1 : 1
>0 : 0

function f9(): number { return 1 << alignof<string>(); }
>f9 : () => number
>1 << alignof<string>() : number
>1 : 1
>alignof<string>() : number
>alignof : <T>() => number

// `<<` that starts a type argument list with a generic function type is still a type argument list.
declare function g<F>(f: F): F;
>g : <F>(f: F) => F
>f : F

const h = g<<U>(x: U) => U>((x) => x);
>h : <U>(x: U) => U
>g<<U>(x: U) => U>((x) => x) : <U>(x: U) => U
>g : <F>(f: F) => F
>x : U
>(x) => x : <U>(x: U) => U
>x : U
>x : U

const n: number = h(1);
>n : number
>h(1) : 1
>h : <U>(x: U) => U
>1 : 1

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @target: es2015

// https://github.com/microsoft/TypeScript/issues/37760

function alignof<T>(): number { return 1; }

function f1<T>(): number { return 1 << alignof<T[]>(); }
function f2<T>(): number { return 1 >> alignof<T[]>(); }
function f3<T>(): number { return 1 >>> alignof<T[]>(); }
function f4<T>(): number { return 1 << (alignof<T[]>()); }
function f5<T>(x: number): number { x <<= alignof<T[]>(); return x; }
function f6<T>(x: number): number { x >>= alignof<T[]>(); return x; }
function f7<T>(x: number): number { x >>>= alignof<T[]>(); return x; }
function f8<T>(): number { return 1 < alignof<T[]>() ? 1 : 0; }
function f9(): number { return 1 << alignof<string>(); }

// `<<` that starts a type argument list with a generic function type is still a type argument list.
declare function g<F>(f: F): F;
const h = g<<U>(x: U) => U>((x) => x);
const n: number = h(1);