diff --git a/tsc/internal/parser/parser.go b/tsc/internal/parser/parser.go index 8eef8b7a7da8d..eca19fd2e97b6 100644 --- a/tsc/internal/parser/parser.go +++ b/tsc/internal/parser/parser.go @@ -4263,7 +4263,8 @@ func (p *Parser) isParenthesizedArrowFunctionExpression() core.Tristate { } func (p *Parser) nextIsParenthesizedArrowFunctionExpression() core.Tristate { - if p.token == ast.KindAsyncKeyword { + isAsync := p.token == ast.KindAsyncKeyword + if isAsync { p.nextToken() if p.hasPrecedingLineBreak() { return core.TSFalse @@ -4282,7 +4283,12 @@ func (p *Parser) nextIsParenthesizedArrowFunctionExpression() core.Tristate { // but this is probably what the user intended. third := p.nextToken() switch third { - case ast.KindEqualsGreaterThanToken, ast.KindColonToken, ast.KindOpenBraceToken: + case ast.KindEqualsGreaterThanToken, ast.KindOpenBraceToken: + return core.TSTrue + case ast.KindColonToken: + if isAsync { + return core.TSUnknown + } return core.TSTrue } return core.TSFalse diff --git a/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.js b/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.js new file mode 100644 index 0000000000000..c9907e1ad7500 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.js @@ -0,0 +1,45 @@ +//// [tests/cases/compiler/asyncCallInConditionalExpression.ts] //// + +//// [a.ts] +declare const a: boolean; +declare function async(...args: any[]): number; + +const c1 = a ? async() : 0; +const c2 = a ? async() : (x: number) => x; +const c3 = a ? async(1) : 0; +const c4 = a ? async() : a ? async() : 0; + +const f1 = async(): Promise => 1; +const f2 = async (): Promise => 1; +const f3 = a ? async(): Promise => 1 : 2; +const f4 = a ? async () => 1 : 2; +const f5 = a ? 1 : async(): Promise => 1; + +export {}; + +//// [b.js] +const t = true; +function async() { return 1; } +const j1 = t ? async() : 0; +const j2 = t ? async() : x => x; + +export {}; + + +//// [a.js] +const c1 = a ? async() : 0; +const c2 = a ? async() : (x) => x; +const c3 = a ? async(1) : 0; +const c4 = a ? async() : a ? async() : 0; +const f1 = async () => 1; +const f2 = async () => 1; +const f3 = a ? async () => 1 : 2; +const f4 = a ? async () => 1 : 2; +const f5 = a ? 1 : async () => 1; +export {}; +//// [b.js] +const t = true; +function async() { return 1; } +const j1 = t ? async() : 0; +const j2 = t ? async() : x => x; +export {}; diff --git a/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.symbols b/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.symbols new file mode 100644 index 0000000000000..f61cf151358ab --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.symbols @@ -0,0 +1,79 @@ +//// [tests/cases/compiler/asyncCallInConditionalExpression.ts] //// + +=== a.ts === +declare const a: boolean; +>a : Symbol(a, Decl(a.ts, 0, 13)) + +declare function async(...args: any[]): number; +>async : Symbol(async, Decl(a.ts, 0, 25)) +>args : Symbol(args, Decl(a.ts, 1, 23)) + +const c1 = a ? async() : 0; +>c1 : Symbol(c1, Decl(a.ts, 3, 5)) +>a : Symbol(a, Decl(a.ts, 0, 13)) +>async : Symbol(async, Decl(a.ts, 0, 25)) + +const c2 = a ? async() : (x: number) => x; +>c2 : Symbol(c2, Decl(a.ts, 4, 5)) +>a : Symbol(a, Decl(a.ts, 0, 13)) +>async : Symbol(async, Decl(a.ts, 0, 25)) +>x : Symbol(x, Decl(a.ts, 4, 26)) +>x : Symbol(x, Decl(a.ts, 4, 26)) + +const c3 = a ? async(1) : 0; +>c3 : Symbol(c3, Decl(a.ts, 5, 5)) +>a : Symbol(a, Decl(a.ts, 0, 13)) +>async : Symbol(async, Decl(a.ts, 0, 25)) + +const c4 = a ? async() : a ? async() : 0; +>c4 : Symbol(c4, Decl(a.ts, 6, 5)) +>a : Symbol(a, Decl(a.ts, 0, 13)) +>async : Symbol(async, Decl(a.ts, 0, 25)) +>a : Symbol(a, Decl(a.ts, 0, 13)) +>async : Symbol(async, Decl(a.ts, 0, 25)) + +const f1 = async(): Promise => 1; +>f1 : Symbol(f1, Decl(a.ts, 8, 5)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) + +const f2 = async (): Promise => 1; +>f2 : Symbol(f2, Decl(a.ts, 9, 5)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) + +const f3 = a ? async(): Promise => 1 : 2; +>f3 : Symbol(f3, Decl(a.ts, 10, 5)) +>a : Symbol(a, Decl(a.ts, 0, 13)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) + +const f4 = a ? async () => 1 : 2; +>f4 : Symbol(f4, Decl(a.ts, 11, 5)) +>a : Symbol(a, Decl(a.ts, 0, 13)) + +const f5 = a ? 1 : async(): Promise => 1; +>f5 : Symbol(f5, Decl(a.ts, 12, 5)) +>a : Symbol(a, Decl(a.ts, 0, 13)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) + +export {}; + +=== b.js === +const t = true; +>t : Symbol(t, Decl(b.js, 0, 5)) + +function async() { return 1; } +>async : Symbol(async, Decl(b.js, 0, 15)) + +const j1 = t ? async() : 0; +>j1 : Symbol(j1, Decl(b.js, 2, 5)) +>t : Symbol(t, Decl(b.js, 0, 5)) +>async : Symbol(async, Decl(b.js, 0, 15)) + +const j2 = t ? async() : x => x; +>j2 : Symbol(j2, Decl(b.js, 3, 5)) +>t : Symbol(t, Decl(b.js, 0, 5)) +>async : Symbol(async, Decl(b.js, 0, 15)) +>x : Symbol(x, Decl(b.js, 3, 24)) +>x : Symbol(x, Decl(b.js, 3, 24)) + +export {}; + diff --git a/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.types b/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.types new file mode 100644 index 0000000000000..e143b0673baf3 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/asyncCallInConditionalExpression.types @@ -0,0 +1,114 @@ +//// [tests/cases/compiler/asyncCallInConditionalExpression.ts] //// + +=== a.ts === +declare const a: boolean; +>a : boolean + +declare function async(...args: any[]): number; +>async : (...args: any[]) => number +>args : any[] + +const c1 = a ? async() : 0; +>c1 : number +>a ? async() : 0 : number +>a : boolean +>async() : number +>async : (...args: any[]) => number +>0 : 0 + +const c2 = a ? async() : (x: number) => x; +>c2 : number | ((x: number) => number) +>a ? async() : (x: number) => x : number | ((x: number) => number) +>a : boolean +>async() : number +>async : (...args: any[]) => number +>(x: number) => x : (x: number) => number +>x : number +>x : number + +const c3 = a ? async(1) : 0; +>c3 : number +>a ? async(1) : 0 : number +>a : boolean +>async(1) : number +>async : (...args: any[]) => number +>1 : 1 +>0 : 0 + +const c4 = a ? async() : a ? async() : 0; +>c4 : number +>a ? async() : a ? async() : 0 : number +>a : boolean +>async() : number +>async : (...args: any[]) => number +>a ? async() : 0 : number +>a : false +>async() : number +>async : (...args: any[]) => number +>0 : 0 + +const f1 = async(): Promise => 1; +>f1 : () => Promise +>async(): Promise => 1 : () => Promise +>1 : 1 + +const f2 = async (): Promise => 1; +>f2 : () => Promise +>async (): Promise => 1 : () => Promise +>1 : 1 + +const f3 = a ? async(): Promise => 1 : 2; +>f3 : 2 | (() => Promise) +>a ? async(): Promise => 1 : 2 : 2 | (() => Promise) +>a : boolean +>async(): Promise => 1 : () => Promise +>1 : 1 +>2 : 2 + +const f4 = a ? async () => 1 : 2; +>f4 : 2 | (() => Promise) +>a ? async () => 1 : 2 : 2 | (() => Promise) +>a : boolean +>async () => 1 : () => Promise +>1 : 1 +>2 : 2 + +const f5 = a ? 1 : async(): Promise => 1; +>f5 : 1 | (() => Promise) +>a ? 1 : async(): Promise => 1 : 1 | (() => Promise) +>a : boolean +>1 : 1 +>async(): Promise => 1 : () => Promise +>1 : 1 + +export {}; + +=== b.js === +const t = true; +>t : true +>true : true + +function async() { return 1; } +>async : () => number +>1 : 1 + +const j1 = t ? async() : 0; +>j1 : number +>t ? async() : 0 : number +>t : true +>async() : number +>async : () => number +>0 : 0 + +const j2 = t ? async() : x => x; +>j2 : number | ((x: any) => any) +>t ? async() : x => x : number | ((x: any) => any) +>t : true +>async() : number +>async : () => number +>x => x : (x: any) => any +>x : any +>x : any + +export {}; + diff --git a/tsc/testdata/tests/cases/compiler/asyncCallInConditionalExpression.ts b/tsc/testdata/tests/cases/compiler/asyncCallInConditionalExpression.ts new file mode 100644 index 0000000000000..d695c5021479b --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/asyncCallInConditionalExpression.ts @@ -0,0 +1,27 @@ +// @target: esnext +// @allowJs: true +// @outDir: ./out +// @filename: a.ts +declare const a: boolean; +declare function async(...args: any[]): number; + +const c1 = a ? async() : 0; +const c2 = a ? async() : (x: number) => x; +const c3 = a ? async(1) : 0; +const c4 = a ? async() : a ? async() : 0; + +const f1 = async(): Promise => 1; +const f2 = async (): Promise => 1; +const f3 = a ? async(): Promise => 1 : 2; +const f4 = a ? async () => 1 : 2; +const f5 = a ? 1 : async(): Promise => 1; + +export {}; + +// @filename: b.js +const t = true; +function async() { return 1; } +const j1 = t ? async() : 0; +const j2 = t ? async() : x => x; + +export {};