diff --git a/tsc/internal/parser/parser.go b/tsc/internal/parser/parser.go index 8eef8b7a7da8d..896f567d99450 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 @@ -4277,12 +4278,12 @@ func (p *Parser) nextIsParenthesizedArrowFunctionExpression() core.Tristate { if first == ast.KindOpenParenToken { if second == ast.KindCloseParenToken { // Simple cases: "() =>", "(): ", and "() {". - // This is an arrow function with no parameters. // The last one is not actually an arrow function, // but this is probably what the user intended. - third := p.nextToken() - switch third { - case ast.KindEqualsGreaterThanToken, ast.KindColonToken, ast.KindOpenBraceToken: + switch p.nextToken() { + case ast.KindColonToken: + return core.IfElse(isAsync, core.TSUnknown, core.TSTrue) + case ast.KindEqualsGreaterThanToken, ast.KindOpenBraceToken: return core.TSTrue } return core.TSFalse diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.js b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.js index a7b6057753bcf..85e1d1e699bd0 100644 --- a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.js +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.js @@ -4,6 +4,22 @@ // Repro from #20096 let foo = (async bar => bar); + +const a = true; +const b = 1; + +function async(): number { + return b; +} + +const f1 = a ? async() : 0; +const f2 = a ? async() : x => x; +const f3 = a ? a ? async() : 0 : b; +const f4 = a ? x => async() : x => x; +const f5 = a ? async (): Promise => b : () => b; +const f6 = a ? async (): Promise => { return b; } : () => b; +const f7 = a ? async (): Promise => a ? async() : 0 : () => b; +const f8 = a ? (): number => b : () => b; //// [parenthesizedAsyncArrowFunction.js] @@ -19,3 +35,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; let foo = ((bar) => __awaiter(void 0, void 0, void 0, function* () { return bar; })); +const a = true; +const b = 1; +function async() { + return b; +} +const f1 = a ? async() : 0; +const f2 = a ? async() : x => x; +const f3 = a ? a ? async() : 0 : b; +const f4 = a ? x => async() : x => x; +const f5 = a ? () => __awaiter(void 0, void 0, void 0, function* () { return b; }) : () => b; +const f6 = a ? () => __awaiter(void 0, void 0, void 0, function* () { return b; }) : () => b; +const f7 = a ? () => __awaiter(void 0, void 0, void 0, function* () { return a ? async() : 0; }) : () => b; +const f8 = a ? () => b : () => b; diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.symbols b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.symbols index 53286f39e8465..633089a2bb1d6 100644 --- a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.symbols +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.symbols @@ -8,3 +8,71 @@ let foo = (async bar => bar); >bar : Symbol(bar, Decl(parenthesizedAsyncArrowFunction.ts, 2, 16)) >bar : Symbol(bar, Decl(parenthesizedAsyncArrowFunction.ts, 2, 16)) +const a = true; +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) + +const b = 1; +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + +function async(): number { +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 5, 12)) + + return b; +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) +} + +const f1 = a ? async() : 0; +>f1 : Symbol(f1, Decl(parenthesizedAsyncArrowFunction.ts, 11, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 5, 12)) + +const f2 = a ? async() : x => x; +>f2 : Symbol(f2, Decl(parenthesizedAsyncArrowFunction.ts, 12, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 5, 12)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 12, 24)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 12, 24)) + +const f3 = a ? a ? async() : 0 : b; +>f3 : Symbol(f3, Decl(parenthesizedAsyncArrowFunction.ts, 13, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 5, 12)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + +const f4 = a ? x => async() : x => x; +>f4 : Symbol(f4, Decl(parenthesizedAsyncArrowFunction.ts, 14, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 14, 14)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 5, 12)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 14, 29)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 14, 29)) + +const f5 = a ? async (): Promise => b : () => b; +>f5 : Symbol(f5, Decl(parenthesizedAsyncArrowFunction.ts, 15, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 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, --, --)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + +const f6 = a ? async (): Promise => { return b; } : () => b; +>f6 : Symbol(f6, Decl(parenthesizedAsyncArrowFunction.ts, 16, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 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, --, --)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + +const f7 = a ? async (): Promise => a ? async() : 0 : () => b; +>f7 : Symbol(f7, Decl(parenthesizedAsyncArrowFunction.ts, 17, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 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, --, --)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 5, 12)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + +const f8 = a ? (): number => b : () => b; +>f8 : Symbol(f8, Decl(parenthesizedAsyncArrowFunction.ts, 18, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.types b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.types index 9f5aa33f8d645..7730643f9a392 100644 --- a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.types +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.types @@ -10,3 +10,99 @@ let foo = (async bar => bar); >bar : any >bar : any +const a = true; +>a : true +>true : true + +const b = 1; +>b : 1 +>1 : 1 + +function async(): number { +>async : () => number + + return b; +>b : 1 +} + +const f1 = a ? async() : 0; +>f1 : number +>a ? async() : 0 : number +>a : true +>async() : number +>async : () => number +>0 : 0 + +const f2 = a ? async() : x => x; +>f2 : number | ((x: any) => any) +>a ? async() : x => x : number | ((x: any) => any) +>a : true +>async() : number +>async : () => number +>x => x : (x: any) => any +>x : any +>x : any + +const f3 = a ? a ? async() : 0 : b; +>f3 : number +>a ? a ? async() : 0 : b : number +>a : true +>a ? async() : 0 : number +>a : true +>async() : number +>async : () => number +>0 : 0 +>b : 1 + +const f4 = a ? x => async() : x => x; +>f4 : (x: any) => any +>a ? x => async() : x => x : (x: any) => any +>a : true +>x => async() : (x: any) => number +>x : any +>async() : number +>async : () => number +>x => x : (x: any) => any +>x : any +>x : any + +const f5 = a ? async (): Promise => b : () => b; +>f5 : (() => Promise) | (() => number) +>a ? async (): Promise => b : () => b : (() => Promise) | (() => number) +>a : true +>async (): Promise => b : () => Promise +>b : 1 +>() => b : () => number +>b : 1 + +const f6 = a ? async (): Promise => { return b; } : () => b; +>f6 : (() => Promise) | (() => number) +>a ? async (): Promise => { return b; } : () => b : (() => Promise) | (() => number) +>a : true +>async (): Promise => { return b; } : () => Promise +>b : 1 +>() => b : () => number +>b : 1 + +const f7 = a ? async (): Promise => a ? async() : 0 : () => b; +>f7 : (() => Promise) | (() => number) +>a ? async (): Promise => a ? async() : 0 : () => b : (() => Promise) | (() => number) +>a : true +>async (): Promise => a ? async() : 0 : () => Promise +>a ? async() : 0 : number +>a : true +>async() : number +>async : () => number +>0 : 0 +>() => b : () => number +>b : 1 + +const f8 = a ? (): number => b : () => b; +>f8 : () => number +>a ? (): number => b : () => b : () => number +>a : true +>(): number => b : () => number +>b : 1 +>() => b : () => number +>b : 1 + diff --git a/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.errors.txt b/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.errors.txt index 08dc36a626764..e322798fd3804 100644 --- a/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.errors.txt +++ b/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.errors.txt @@ -45,4 +45,18 @@ file.js(22,12): error TS7006: Parameter 'p' implicitly has an 'any' type. // Error (good) f(async () => { return 0 - }) \ No newline at end of file + }) + + const g = true; + + function async() { + return 1; + } + + const f1 = g ? async() : 0; + /** @type {number | ((x: number) => number)} */ + const f2 = g ? async() : x => x; + const f3 = g ? g ? async() : 0 : 1; + /** @type {(x: number) => number} */ + const f4 = g ? x => async() : x => x; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.symbols b/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.symbols index 40bae3eb3736c..4fc7c6c17c44c 100644 --- a/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.symbols +++ b/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.symbols @@ -38,3 +38,41 @@ f(async () => { return 0 }) + +const g = true; +>g : Symbol(g, Decl(file.js, 28, 5)) + +function async() { +>async : Symbol(async, Decl(file.js, 28, 15)) + + return 1; +} + +const f1 = g ? async() : 0; +>f1 : Symbol(f1, Decl(file.js, 34, 5)) +>g : Symbol(g, Decl(file.js, 28, 5)) +>async : Symbol(async, Decl(file.js, 28, 15)) + +/** @type {number | ((x: number) => number)} */ +const f2 = g ? async() : x => x; +>f2 : Symbol(f2, Decl(file.js, 36, 5)) +>g : Symbol(g, Decl(file.js, 28, 5)) +>async : Symbol(async, Decl(file.js, 28, 15)) +>x : Symbol(x, Decl(file.js, 36, 24)) +>x : Symbol(x, Decl(file.js, 36, 24)) + +const f3 = g ? g ? async() : 0 : 1; +>f3 : Symbol(f3, Decl(file.js, 37, 5)) +>g : Symbol(g, Decl(file.js, 28, 5)) +>g : Symbol(g, Decl(file.js, 28, 5)) +>async : Symbol(async, Decl(file.js, 28, 15)) + +/** @type {(x: number) => number} */ +const f4 = g ? x => async() : x => x; +>f4 : Symbol(f4, Decl(file.js, 39, 5)) +>g : Symbol(g, Decl(file.js, 28, 5)) +>x : Symbol(x, Decl(file.js, 39, 14)) +>async : Symbol(async, Decl(file.js, 28, 15)) +>x : Symbol(x, Decl(file.js, 39, 29)) +>x : Symbol(x, Decl(file.js, 39, 29)) + diff --git a/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.types b/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.types index d8d3316603e0e..376d8932fec68 100644 --- a/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.types +++ b/tsc/testdata/baselines/reference/conformance/asyncArrowFunction_allowJs.types @@ -51,3 +51,58 @@ f(async () => { >0 : 0 }) + +const g = true; +>g : true +>true : true + +function async() { +>async : () => number + + return 1; +>1 : 1 +} + +const f1 = g ? async() : 0; +>f1 : number +>g ? async() : 0 : number +>g : true +>async() : number +>async : () => number +>0 : 0 + +/** @type {number | ((x: number) => number)} */ +const f2 = g ? async() : x => x; +>f2 : number | ((x: number) => number) +>g ? async() : x => x : number | ((x: number) => number) +>g : true +>async() : number +>async : () => number +>x => x : (x: number) => number +>x : number +>x : number + +const f3 = g ? g ? async() : 0 : 1; +>f3 : number +>g ? g ? async() : 0 : 1 : number +>g : true +>g ? async() : 0 : number +>g : true +>async() : number +>async : () => number +>0 : 0 +>1 : 1 + +/** @type {(x: number) => number} */ +const f4 = g ? x => async() : x => x; +>f4 : (x: number) => number +>g ? x => async() : x => x : (x: number) => number +>g : true +>x => async() : (x: number) => number +>x : number +>async() : number +>async : () => number +>x => x : (x: number) => number +>x : number +>x : number + diff --git a/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts b/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts index 057eb64c82138..8e323ebb3b172 100644 --- a/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts +++ b/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts @@ -3,3 +3,19 @@ // Repro from #20096 let foo = (async bar => bar); + +const a = true; +const b = 1; + +function async(): number { + return b; +} + +const f1 = a ? async() : 0; +const f2 = a ? async() : x => x; +const f3 = a ? a ? async() : 0 : b; +const f4 = a ? x => async() : x => x; +const f5 = a ? async (): Promise => b : () => b; +const f6 = a ? async (): Promise => { return b; } : () => b; +const f7 = a ? async (): Promise => a ? async() : 0 : () => b; +const f8 = a ? (): number => b : () => b; diff --git a/tsc/testdata/tests/cases/conformance/async/es2017/asyncArrowFunction/asyncArrowFunction_allowJs.ts b/tsc/testdata/tests/cases/conformance/async/es2017/asyncArrowFunction/asyncArrowFunction_allowJs.ts index 9f1f76100434d..39759f6cb41d8 100644 --- a/tsc/testdata/tests/cases/conformance/async/es2017/asyncArrowFunction/asyncArrowFunction_allowJs.ts +++ b/tsc/testdata/tests/cases/conformance/async/es2017/asyncArrowFunction/asyncArrowFunction_allowJs.ts @@ -30,4 +30,17 @@ const f = (p) => {} // Error (good) f(async () => { return 0 -}) \ No newline at end of file +}) + +const g = true; + +function async() { + return 1; +} + +const f1 = g ? async() : 0; +/** @type {number | ((x: number) => number)} */ +const f2 = g ? async() : x => x; +const f3 = g ? g ? async() : 0 : 1; +/** @type {(x: number) => number} */ +const f4 = g ? x => async() : x => x;