From a1110c5d42b906c15de8df5f679b98e4776ce34a Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk Date: Sat, 17 Oct 2026 23:47:38 +0300 Subject: [PATCH 1/2] fix async and yield parsing --- tsc/internal/parser/parser.go | 111 +++-- tsc/internal/parser/parser_test.go | 455 ++++++++++++++++++ tsc/internal/parser/types.go | 14 +- .../parenthesizedAsyncArrowFunction.js | 79 +++ .../parenthesizedAsyncArrowFunction.symbols | 239 +++++++++ .../parenthesizedAsyncArrowFunction.types | 346 +++++++++++++ .../parenthesizedAsyncArrowFunctionJs.js | 49 ++ .../parenthesizedAsyncArrowFunctionJs.symbols | 75 +++ .../parenthesizedAsyncArrowFunctionJs.types | 108 +++++ .../asyncArrowFunction_allowJs.errors.txt | 16 +- .../asyncArrowFunction_allowJs.symbols | 38 ++ .../asyncArrowFunction_allowJs.types | 55 +++ .../parenthesizedAsyncArrowFunction.ts | 43 ++ .../parenthesizedAsyncArrowFunctionJs.ts | 24 + .../asyncArrowFunction_allowJs.ts | 15 +- 15 files changed, 1616 insertions(+), 51 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.js create mode 100644 tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.types create mode 100644 tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunctionJs.ts diff --git a/tsc/internal/parser/parser.go b/tsc/internal/parser/parser.go index c670d64ad21c2..ce4899a68ab9a 100644 --- a/tsc/internal/parser/parser.go +++ b/tsc/internal/parser/parser.go @@ -342,8 +342,10 @@ type ParserState struct { contextFlags ast.NodeFlags diagnosticsLen int jsDiagnosticsLen int + jsdocDiagnosticsLen int jsdocInfosLen int reparsedClonesLen int + reparseList []*ast.Node statementHasAwaitIdentifier bool hasParseError bool } @@ -354,8 +356,10 @@ func (p *Parser) mark() ParserState { contextFlags: p.contextFlags, diagnosticsLen: len(p.diagnostics), jsDiagnosticsLen: len(p.jsDiagnostics), + jsdocDiagnosticsLen: len(p.jsdocDiagnostics), jsdocInfosLen: len(p.jsdocInfos), reparsedClonesLen: len(p.reparsedClones), + reparseList: p.reparseList, statementHasAwaitIdentifier: p.statementHasAwaitIdentifier, hasParseError: p.hasParseError, } @@ -367,8 +371,10 @@ func (p *Parser) rewind(state ParserState) { p.contextFlags = state.contextFlags p.diagnostics = p.diagnostics[0:state.diagnosticsLen] p.jsDiagnostics = p.jsDiagnostics[0:state.jsDiagnosticsLen] + p.jsdocDiagnostics = p.jsdocDiagnostics[0:state.jsdocDiagnosticsLen] p.jsdocInfos = p.jsdocInfos[0:state.jsdocInfosLen] p.reparsedClones = p.reparsedClones[0:state.reparsedClonesLen] + p.reparseList = state.reparseList p.statementHasAwaitIdentifier = state.statementHasAwaitIdentifier p.hasParseError = state.hasParseError } @@ -4149,10 +4155,10 @@ func (p *Parser) parseExpressionAllowIn() *ast.Expression { } func (p *Parser) parseAssignmentExpressionOrHigher() *ast.Expression { - return p.parseAssignmentExpressionOrHigherWorker(true /*allowReturnTypeInArrowFunction*/) + return p.parseAssignmentExpressionOrHigherWorker(ParseFlagsNone) } -func (p *Parser) parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowFunction bool) *ast.Expression { +func (p *Parser) parseAssignmentExpressionOrHigherWorker(flags ParseFlags) *ast.Expression { // AssignmentExpression[in,yield]: // 1) ConditionalExpression[?in,?yield] // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] @@ -4165,7 +4171,7 @@ func (p *Parser) parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowF // (i.e. they're both BinaryExpressions with an assignment operator in it). // First, do the simple check if we have a YieldExpression (production '6'). if p.isYieldExpression() { - return p.parseYieldExpression() + return p.parseYieldExpression(flags) } // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized // parameter list or is an async arrow function. @@ -4178,15 +4184,15 @@ func (p *Parser) parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowF // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done // with AssignmentExpression if we see one. - arrowExpression := p.tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) + arrowExpression := p.tryParseParenthesizedArrowFunctionExpression(flags) if arrowExpression != nil { return arrowExpression } - arrowExpression = p.tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction) + arrowExpression = p.tryParseAsyncSimpleArrowFunctionExpression(flags) if arrowExpression != nil { return arrowExpression } - // arrowExpression2 := p.tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction) + // arrowExpression2 := p.tryParseAsyncSimpleArrowFunctionExpression(flags) // if arrowExpression2 != nil { // return arrowExpression2 // } @@ -4206,7 +4212,7 @@ func (p *Parser) parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowF // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single // identifier and the current token is an arrow. if expr.Kind == ast.KindIdentifier && p.token == ast.KindEqualsGreaterThanToken { - return p.parseSimpleArrowFunctionExpression(pos, expr, allowReturnTypeInArrowFunction, jsdoc, nil /*asyncModifier*/) + return p.parseSimpleArrowFunctionExpression(pos, expr, flags, jsdoc, nil /*asyncModifier*/) } // Now see if we might be in cases '2' or '3'. // If the expression was a LHS expression, and we have an assignment operator, then @@ -4215,10 +4221,10 @@ func (p *Parser) parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowF // Note: we call reScanGreaterToken so that we get an appropriately merged token // for cases like `> > =` becoming `>>=` if ast.IsLeftHandSideExpression(expr) && ast.IsAssignmentOperator(p.reScanGreaterThanToken()) { - return p.makeBinaryExpression(expr, p.parseTokenNode(), p.parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowFunction), pos) + return p.makeBinaryExpression(expr, p.parseTokenNode(), p.parseAssignmentExpressionOrHigherWorker(flags), pos) } // It wasn't an assignment or a lambda. This is a conditional expression: - return p.parseConditionalExpressionRest(expr, pos, allowReturnTypeInArrowFunction) + return p.parseConditionalExpressionRest(expr, pos, flags) } func (p *Parser) isYieldExpression() bool { @@ -4248,7 +4254,7 @@ func (p *Parser) isYieldExpression() bool { return false } -func (p *Parser) parseYieldExpression() *ast.Node { +func (p *Parser) parseYieldExpression(flags ParseFlags) *ast.Node { pos := p.nodePos() // YieldExpression[In] : // yield @@ -4257,7 +4263,7 @@ func (p *Parser) parseYieldExpression() *ast.Node { p.nextToken() var result *ast.Node if !p.hasPrecedingLineBreak() && (p.token == ast.KindAsteriskToken || p.isStartOfExpression()) { - result = p.factory.NewYieldExpression(p.parseOptionalToken(ast.KindAsteriskToken), p.parseAssignmentExpressionOrHigher()) + result = p.factory.NewYieldExpression(p.parseOptionalToken(ast.KindAsteriskToken), p.parseAssignmentExpressionOrHigherWorker(flags)) } else { // if the next token is not on the same line as yield. or we don't have an '*' or // the start of an expression, then this is just a simple "yield" expression. @@ -4266,10 +4272,10 @@ func (p *Parser) parseYieldExpression() *ast.Node { return p.finishNode(result, pos) } -func (p *Parser) isParenthesizedArrowFunctionExpression() core.Tristate { +func (p *Parser) isParenthesizedArrowFunctionExpression(flags ParseFlags) core.Tristate { if p.token == ast.KindOpenParenToken || p.token == ast.KindLessThanToken || p.token == ast.KindAsyncKeyword { state := p.mark() - result := p.nextIsParenthesizedArrowFunctionExpression() + result := p.nextIsParenthesizedArrowFunctionExpression(flags) p.rewind(state) return result } @@ -4283,8 +4289,9 @@ func (p *Parser) isParenthesizedArrowFunctionExpression() core.Tristate { return core.TSFalse } -func (p *Parser) nextIsParenthesizedArrowFunctionExpression() core.Tristate { - if p.token == ast.KindAsyncKeyword { +func (p *Parser) nextIsParenthesizedArrowFunctionExpression(flags ParseFlags) core.Tristate { + isAsync := p.token == ast.KindAsyncKeyword + if isAsync { p.nextToken() if p.hasPrecedingLineBreak() { return core.TSFalse @@ -4298,16 +4305,30 @@ 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: + if isAsync && flags&ParseFlagsAllowAmbiguousAsyncArrow == 0 { + return core.TSUnknown + } + return core.TSTrue + case ast.KindEqualsGreaterThanToken, ast.KindOpenBraceToken: return core.TSTrue } return core.TSFalse } + // Simple case: "(...". After "async", this could also be a spread argument. + if second == ast.KindDotDotDotToken { + if isAsync { + if flags&ParseFlagsAllowAmbiguousAsyncArrow != 0 { + return core.TSTrue + } + second = p.nextToken() + } else { + return core.TSTrue + } + } // If encounter "([" or "({", this could be the start of a binding pattern. // Examples: // ([ x ]) => { } @@ -4317,11 +4338,6 @@ func (p *Parser) nextIsParenthesizedArrowFunctionExpression() core.Tristate { if second == ast.KindOpenBracketToken || second == ast.KindOpenBraceToken { return core.TSUnknown } - // Simple case: "(..." - // This is an arrow function with a rest parameter. - if second == ast.KindDotDotDotToken { - return core.TSTrue - } // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This // isn't actually allowed, but we want to treat it as a lambda so we can provide // a good error message. @@ -4391,8 +4407,8 @@ func (p *Parser) nextIsParenthesizedArrowFunctionExpression() core.Tristate { } } -func (p *Parser) tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction bool) *ast.Node { - tristate := p.isParenthesizedArrowFunctionExpression() +func (p *Parser) tryParseParenthesizedArrowFunctionExpression(flags ParseFlags) *ast.Node { + tristate := p.isParenthesizedArrowFunctionExpression(flags) if tristate == core.TSFalse { // It's definitely not a parenthesized arrow function expression. return nil @@ -4402,17 +4418,17 @@ func (p *Parser) tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInA // it out, but don't allow any ambiguity, and return 'undefined' if this could be an // expression instead. if tristate == core.TSTrue { - return p.parseParenthesizedArrowFunctionExpression(true /*allowAmbiguity*/, true /*allowReturnTypeInArrowFunction*/) + return p.parseParenthesizedArrowFunctionExpression(true /*allowAmbiguity*/, flags) } state := p.mark() - result := p.parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) + result := p.parsePossibleParenthesizedArrowFunctionExpression(flags) if result == nil { p.rewind(state) } return result } -func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, allowReturnTypeInArrowFunction bool) *ast.Node { +func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, flags ParseFlags) *ast.Node { pos := p.nodePos() jsdoc := p.jsdocScannerInfo() modifiers := p.parseModifiersForArrowFunction() @@ -4426,6 +4442,7 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, // And think that "(b =>" was actually a parenthesized arrow function with a missing // close paren. typeParameters := p.parseTypeParameters() + bodyFlags := flags var parameters *ast.NodeList if !p.parseExpected(ast.KindOpenParenToken) { if !allowAmbiguity { @@ -4433,6 +4450,9 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, } parameters = p.createMissingList() } else { + if isAsync && typeParameters == nil && (p.token == ast.KindCloseParenToken || p.token == ast.KindDotDotDotToken) { + bodyFlags = flags & ParseFlagsAllowAmbiguousAsyncArrow + } if !allowAmbiguity { maybeParameters := p.parseParametersWorker(signatureFlags, allowAmbiguity) if maybeParameters == nil { @@ -4446,7 +4466,7 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, return nil } } - hasReturnColon := p.token == ast.KindColonToken + requiresColon := !allowAmbiguity && p.token == ast.KindColonToken && flags&ParseFlagsDisallowArrowReturnType != 0 returnType := p.parseReturnType(ast.KindColonToken /*isType*/, false) if returnType != nil && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(returnType) { return nil @@ -4475,7 +4495,12 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, equalsGreaterThanToken := p.parseExpectedToken(ast.KindEqualsGreaterThanToken) var body *ast.Node if lastToken == ast.KindEqualsGreaterThanToken || lastToken == ast.KindOpenBraceToken { - body = p.parseArrowFunctionExpressionBody(isAsync, allowReturnTypeInArrowFunction) + if requiresColon { + bodyFlags |= ParseFlagsAllowAmbiguousAsyncArrow + } else { + bodyFlags = flags + } + body = p.parseArrowFunctionExpressionBody(isAsync, bodyFlags) } else { body = p.parseIdentifier() } @@ -4493,7 +4518,7 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, // a() ? (b: number, c?: string): void => d() : e // is determined by isParenthesizedArrowFunctionExpression to unambiguously // be an arrow expression, so we allow a return type. - if !allowReturnTypeInArrowFunction && hasReturnColon { + if requiresColon { // However, if the arrow function we were able to parse is followed by another colon // as in: // a ? (x): string => x : null @@ -4533,7 +4558,7 @@ func typeHasArrowFunctionBlockingParseError(node *ast.TypeNode) bool { return false } -func (p *Parser) parseArrowFunctionExpressionBody(isAsync bool, allowReturnTypeInArrowFunction bool) *ast.Node { +func (p *Parser) parseArrowFunctionExpressionBody(isAsync bool, flags ParseFlags) *ast.Node { if p.token == ast.KindOpenBraceToken { return p.parseFunctionBlock(core.IfElse(isAsync, ParseFlagsAwait, ParseFlagsNone), nil /*diagnosticMessage*/) } @@ -4557,7 +4582,7 @@ func (p *Parser) parseArrowFunctionExpressionBody(isAsync bool, allowReturnTypeI saveContextFlags := p.contextFlags p.setContextFlags(ast.NodeFlagsAwaitContext, isAsync) p.setContextFlags(ast.NodeFlagsYieldContext, false) - node := p.parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowFunction) + node := p.parseAssignmentExpressionOrHigherWorker(flags) p.contextFlags = saveContextFlags return node } @@ -4567,26 +4592,26 @@ func (p *Parser) isStartOfExpressionStatement() bool { return p.token != ast.KindOpenBraceToken && p.token != ast.KindFunctionKeyword && p.token != ast.KindClassKeyword && p.token != ast.KindAtToken && p.isStartOfExpression() } -func (p *Parser) parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction bool) *ast.Node { +func (p *Parser) parsePossibleParenthesizedArrowFunctionExpression(flags ParseFlags) *ast.Node { tokenPos := p.scanner.TokenStart() if p.notParenthesizedArrow.Has(tokenPos) { return nil } - result := p.parseParenthesizedArrowFunctionExpression(false /*allowAmbiguity*/, allowReturnTypeInArrowFunction) + result := p.parseParenthesizedArrowFunctionExpression(false /*allowAmbiguity*/, flags) if result == nil { p.notParenthesizedArrow.Add(tokenPos) } return result } -func (p *Parser) tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction bool) *ast.Node { +func (p *Parser) tryParseAsyncSimpleArrowFunctionExpression(flags ParseFlags) *ast.Node { // We do a check here so that we won't be doing unnecessarily call to "lookAhead" if p.token == ast.KindAsyncKeyword && p.lookAhead((*Parser).nextIsUnParenthesizedAsyncArrowFunction) { pos := p.nodePos() jsdoc := p.jsdocScannerInfo() asyncModifier := p.parseModifiersForArrowFunction() expr := p.parseBinaryExpressionOrHigher(ast.OperatorPrecedenceLowest) - return p.parseSimpleArrowFunctionExpression(pos, expr, allowReturnTypeInArrowFunction, jsdoc, asyncModifier) + return p.parseSimpleArrowFunctionExpression(pos, expr, flags, jsdoc, asyncModifier) } return nil } @@ -4612,18 +4637,18 @@ func (p *Parser) nextIsUnParenthesizedAsyncArrowFunction() bool { return false } -func (p *Parser) parseSimpleArrowFunctionExpression(pos int, identifier *ast.Node, allowReturnTypeInArrowFunction bool, jsdoc jsdocScannerInfo, asyncModifier *ast.ModifierList) *ast.Node { +func (p *Parser) parseSimpleArrowFunctionExpression(pos int, identifier *ast.Node, flags ParseFlags, jsdoc jsdocScannerInfo, asyncModifier *ast.ModifierList) *ast.Node { debug.Assert(p.token == ast.KindEqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>") parameter := p.finishNode(p.factory.NewParameterDeclaration(nil /*modifiers*/, nil /*dotDotDotToken*/, identifier, nil /*questionToken*/, nil /*typeNode*/, nil /*initializer*/), identifier.Pos()) parameters := p.newNodeList(parameter.Loc, []*ast.Node{parameter}) equalsGreaterThanToken := p.parseExpectedToken(ast.KindEqualsGreaterThanToken) - body := p.parseArrowFunctionExpressionBody(asyncModifier != nil /*isAsync*/, allowReturnTypeInArrowFunction) + body := p.parseArrowFunctionExpressionBody(asyncModifier != nil /*isAsync*/, flags) result := p.finishNode(p.factory.NewArrowFunction(asyncModifier, nil /*typeParameters*/, parameters, nil /*returnType*/, nil /*fullSignature*/, equalsGreaterThanToken, body), pos) p.withJSDoc(result, jsdoc) return result } -func (p *Parser) parseConditionalExpressionRest(leftOperand *ast.Expression, pos int, allowReturnTypeInArrowFunction bool) *ast.Expression { +func (p *Parser) parseConditionalExpressionRest(leftOperand *ast.Expression, pos int, flags ParseFlags) *ast.Expression { // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. questionToken := p.parseOptionalToken(ast.KindQuestionToken) if questionToken == nil { @@ -4633,12 +4658,12 @@ func (p *Parser) parseConditionalExpressionRest(leftOperand *ast.Expression, pos // we do not that for the 'whenFalse' part. saveContextFlags := p.contextFlags p.setContextFlags(ast.NodeFlagsDisallowInContext, false) - trueExpression := p.parseAssignmentExpressionOrHigherWorker(false /*allowReturnTypeInArrowFunction*/) + trueExpression := p.parseAssignmentExpressionOrHigherWorker(ParseFlagsDisallowArrowReturnType) p.contextFlags = saveContextFlags colonToken := p.parseExpectedToken(ast.KindColonToken) var falseExpression *ast.Expression if ast.NodeIsPresent(colonToken) { - falseExpression = p.parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowFunction) + falseExpression = p.parseAssignmentExpressionOrHigherWorker(flags) } else { falseExpression = p.createMissingIdentifier() } diff --git a/tsc/internal/parser/parser_test.go b/tsc/internal/parser/parser_test.go index ffa96713eb444..a8b878f031127 100644 --- a/tsc/internal/parser/parser_test.go +++ b/tsc/internal/parser/parser_test.go @@ -188,6 +188,461 @@ class MissingImplements implements B. {} assert.Equal(t, missingImplementsDecl.HeritageClauses.Nodes[0].AsHeritageClause().Types.Nodes[0].Kind, ast.KindExpressionWithTypeArguments) } +func TestConditionalAsyncCall(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "function* g() { const a = b ? async(...c) : 0; }", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + statement := file.Statements.Nodes[0].Body().AsBlock().Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Flags&ast.NodeFlagsYieldContext, ast.NodeFlagsYieldContext) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindNumericLiteral) +} + +func TestConditionalAsyncCallWithArrow(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "function* g() { const a = b ? async(...c) : d => d; }", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + statement := file.Statements.Nodes[0].Body().AsBlock().Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Flags&ast.NodeFlagsYieldContext, ast.NodeFlagsYieldContext) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalAsyncCallYield(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "function* g() { const a = b ? yield async(...c) : 0; }", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + statement := file.Statements.Nodes[0].Body().AsBlock().Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindYieldExpression) + assert.Equal(t, conditional.WhenTrue.Flags&ast.NodeFlagsYieldContext, ast.NodeFlagsYieldContext) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindNumericLiteral) + assert.Equal(t, conditional.WhenTrue.Expression().Kind, ast.KindCallExpression) +} + +func TestConditionalAsyncCallYieldWithArrow(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "function* g() { const a = b ? yield async(...c) : d => d; }", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + statement := file.Statements.Nodes[0].Body().AsBlock().Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindYieldExpression) + assert.Equal(t, conditional.WhenTrue.Flags&ast.NodeFlagsYieldContext, ast.NodeFlagsYieldContext) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Expression().Kind, ast.KindCallExpression) +} + +func TestConditionalAsyncCallJS(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "function* g() { const a = b ? async(...c) : 0; }", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + statement := file.Statements.Nodes[0].Body().AsBlock().Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Flags&ast.NodeFlagsYieldContext, ast.NodeFlagsYieldContext) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindNumericLiteral) +} + +func TestConditionalAsyncCallWithArrowJS(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "function* g() { const a = b ? async(...c) : d => d; }", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + statement := file.Statements.Nodes[0].Body().AsBlock().Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Flags&ast.NodeFlagsYieldContext, ast.NodeFlagsYieldContext) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalAsyncCallYieldJS(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "function* g() { const a = b ? yield async(...c) : 0; }", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + statement := file.Statements.Nodes[0].Body().AsBlock().Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindYieldExpression) + assert.Equal(t, conditional.WhenTrue.Flags&ast.NodeFlagsYieldContext, ast.NodeFlagsYieldContext) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindNumericLiteral) + assert.Equal(t, conditional.WhenTrue.Expression().Kind, ast.KindCallExpression) +} + +func TestConditionalAsyncCallYieldWithArrowJS(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "function* g() { const a = b ? yield async(...c) : d => d; }", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + statement := file.Statements.Nodes[0].Body().AsBlock().Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindYieldExpression) + assert.Equal(t, conditional.WhenTrue.Flags&ast.NodeFlagsYieldContext, ast.NodeFlagsYieldContext) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Expression().Kind, ast.KindCallExpression) +} + +func TestConditionalAsyncCallReturnType(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async() : d => async (...c): Promise => c.length;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + arrow := conditional.WhenFalse.Body() + assert.Equal(t, arrow.Kind, ast.KindArrowFunction) + assert.Equal(t, arrow.Type().Kind, ast.KindTypeReference) +} + +func TestConditionalAsyncCallReturnTypeAlias(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async() : d => async (...c): T => c.length;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + arrow := conditional.WhenFalse.Body() + assert.Equal(t, arrow.Kind, ast.KindArrowFunction) + assert.Equal(t, arrow.Type().Kind, ast.KindTypeReference) +} + +func TestConditionalAsyncCallWithTypedArrow(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async() : d => async (): T => 0;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + arrow := conditional.WhenFalse.Body() + assert.Equal(t, arrow.Kind, ast.KindArrowFunction) + assert.Equal(t, len(arrow.Parameters()), 0) + assert.Equal(t, arrow.Modifiers().Nodes[0].Kind, ast.KindAsyncKeyword) + assert.Equal(t, arrow.Type().Kind, ast.KindTypeReference) + assert.Equal(t, arrow.Type().AsTypeReferenceNode().TypeName.Text(), "T") + assert.Equal(t, arrow.Body().Kind, ast.KindNumericLiteral) +} + +func TestConditionalParenthesizedExpressionWithTypedArrow(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? (value) : d => async (): T => 0;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindParenthesizedExpression) + assert.Equal(t, conditional.WhenTrue.Expression().Text(), "value") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + arrow := conditional.WhenFalse.Body() + assert.Equal(t, arrow.Kind, ast.KindArrowFunction) + assert.Equal(t, len(arrow.Parameters()), 0) + assert.Equal(t, arrow.Modifiers().Nodes[0].Kind, ast.KindAsyncKeyword) + assert.Equal(t, arrow.Type().Kind, ast.KindTypeReference) + assert.Equal(t, arrow.Type().AsTypeReferenceNode().TypeName.Text(), "T") + assert.Equal(t, arrow.Body().Kind, ast.KindNumericLiteral) +} + +func TestConditionalAsyncCallWithParenthesizedTypedArrow(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async() : d => (e): T => 0;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + arrow := conditional.WhenFalse.Body() + assert.Equal(t, arrow.Kind, ast.KindArrowFunction) + assert.Equal(t, len(arrow.Parameters()), 1) + assert.Equal(t, arrow.Parameters()[0].Name().Text(), "e") + assert.Equal(t, arrow.Type().AsTypeReferenceNode().TypeName.Text(), "T") + assert.Equal(t, arrow.Body().Kind, ast.KindNumericLiteral) +} + +func TestConditionalAsyncCallWithGenericTypedArrow(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async() : d => async (): T => 0;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + arrow := conditional.WhenFalse.Body() + assert.Equal(t, arrow.Kind, ast.KindArrowFunction) + assert.Equal(t, len(arrow.TypeParameterList().Nodes), 1) + assert.Equal(t, arrow.TypeParameterList().Nodes[0].Name().Text(), "U") + assert.Equal(t, len(arrow.Parameters()), 0) + assert.Equal(t, arrow.Modifiers().Nodes[0].Kind, ast.KindAsyncKeyword) + assert.Equal(t, arrow.Type().AsTypeReferenceNode().TypeName.Text(), "T") + assert.Equal(t, arrow.Body().Kind, ast.KindNumericLiteral) +} + +func TestConditionalParenthesizedTypedArrowPriority(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? (c) : d => (e): T => 0;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Type().AsTypeReferenceNode().TypeName.Text(), "d") + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindParenthesizedExpression) + assert.Equal(t, conditional.WhenTrue.Body().Expression().Text(), "e") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenFalse.Parameters()[0].Name().Text(), "T") + assert.Equal(t, conditional.WhenFalse.Body().Kind, ast.KindNumericLiteral) +} + +func TestConditionalGenericTypedArrowPriority(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async() : d => (e): T => 0;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, len(conditional.WhenTrue.TypeParameterList().Nodes), 1) + assert.Equal(t, conditional.WhenTrue.Type().AsTypeReferenceNode().TypeName.Text(), "d") + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindParenthesizedExpression) + assert.Equal(t, conditional.WhenTrue.Body().Expression().Text(), "e") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenFalse.Parameters()[0].Name().Text(), "T") + assert.Equal(t, conditional.WhenFalse.Body().Kind, ast.KindNumericLiteral) +} + +func TestConditionalAsyncArrowWithConditionalBody(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async (): Promise => b ? async() : 0 : () => 0;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindConditionalExpression) + body := conditional.WhenTrue.Body().AsConditionalExpression() + assert.Equal(t, body.WhenTrue.Kind, ast.KindCallExpression) + assert.Equal(t, body.WhenFalse.Kind, ast.KindNumericLiteral) +} + +func TestConditionalAsyncArrowBody(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async () => async() : c => c;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Body().Expression().Text(), "async") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalAsyncArrowBodyJS(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "const a = b ? async () => async() : c => c;", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Body().Expression().Text(), "async") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalAsyncRestArrowBody(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async (...c) => async() : d => d;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Body().Expression().Text(), "async") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalAsyncRestArrowBodyJS(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "const a = b ? async (...c) => async() : d => d;", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Body().Expression().Text(), "async") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalArrowBody(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? () => async() : c => c;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Body().Expression().Text(), "async") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalArrowBodyJS(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "const a = b ? () => async() : c => c;", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenTrue.Body().Expression().Text(), "async") + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalTypedAsyncArrowBody(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async (c: number): Promise => async() : d => d;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 0) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + conditional := declaration.Initializer().AsConditionalExpression() + assert.Equal(t, conditional.WhenTrue.Kind, ast.KindArrowFunction) + assert.Equal(t, conditional.WhenTrue.Type().Kind, ast.KindTypeReference) + assert.Equal(t, conditional.WhenTrue.Parameters()[0].Type().Kind, ast.KindNumberKeyword) + assert.Equal(t, conditional.WhenTrue.Body().Kind, ast.KindCallExpression) + assert.Equal(t, conditional.WhenFalse.Kind, ast.KindArrowFunction) +} + +func TestConditionalAsyncCallJSDoc(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "const a = b ? async(...c) : d => /** @param {number */ e => e;", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + assert.Equal(t, len(file.JSDocDiagnostics()), 1) + assert.Equal(t, len(file.Statements.Nodes), 1) + statement := file.Statements.Nodes[0] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + arrow := declaration.Initializer().AsConditionalExpression().WhenFalse.Body() + assert.Equal(t, len(arrow.JSDoc(file)), 1) +} + +func TestConditionalAsyncCallJSDocTypedef(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.js", + PathKey: "/a.js", + }, "const a = b ? async(...c) : d => /** @typedef {number} T */ e => e;", core.ScriptKindJS) + assert.Equal(t, len(file.Diagnostics()), 0) + assert.Equal(t, len(file.JSDiagnostics()), 0) + assert.Equal(t, len(file.JSDocDiagnostics()), 0) + assert.Equal(t, len(file.Statements.Nodes), 2) + statement := file.Statements.Nodes[1] + declaration := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + arrow := declaration.Initializer().AsConditionalExpression().WhenFalse.Body() + assert.Equal(t, len(arrow.JSDoc(file)), 1) +} + +func TestConditionalAsyncCallRecovery(t *testing.T) { + t.Parallel() + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/a.ts", + PathKey: "/a.ts", + }, "const a = b ? async(...c: number[]): Promise => 0;", core.ScriptKindTS) + assert.Equal(t, len(file.Diagnostics()), 1) + assert.Equal(t, file.Diagnostics()[0].Code(), diagnostics.X_0_expected.Code()) + declaration := file.Statements.Nodes[0].AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes[0] + assert.Equal(t, declaration.Initializer().AsConditionalExpression().WhenTrue.Kind, ast.KindArrowFunction) +} + func TestParseStaticSourcePhaseImport(t *testing.T) { t.Parallel() tests := []struct { diff --git a/tsc/internal/parser/types.go b/tsc/internal/parser/types.go index 671189445f1eb..03db776cfd029 100644 --- a/tsc/internal/parser/types.go +++ b/tsc/internal/parser/types.go @@ -5,10 +5,12 @@ package parser type ParseFlags uint32 const ( - ParseFlagsNone ParseFlags = 0 - ParseFlagsYield ParseFlags = 1 << 0 - ParseFlagsAwait ParseFlags = 1 << 1 - ParseFlagsType ParseFlags = 1 << 2 - ParseFlagsIgnoreMissingOpenBrace ParseFlags = 1 << 4 - ParseFlagsJSDoc ParseFlags = 1 << 5 + ParseFlagsNone ParseFlags = 0 + ParseFlagsYield ParseFlags = 1 << 0 + ParseFlagsAwait ParseFlags = 1 << 1 + ParseFlagsType ParseFlags = 1 << 2 + ParseFlagsIgnoreMissingOpenBrace ParseFlags = 1 << 4 + ParseFlagsJSDoc ParseFlags = 1 << 5 + ParseFlagsDisallowArrowReturnType ParseFlags = 1 << 6 + ParseFlagsAllowAmbiguousAsyncArrow ParseFlags = 1 << 7 ) diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.js b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.js index a7b6057753bcf..d6c82758ba444 100644 --- a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.js +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.js @@ -4,6 +4,49 @@ // Repro from #20096 let foo = (async bar => bar); + +const a = true; +const b = 1; +const c = [b]; + +function async(...c: number[]): 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; + +const f9 = a ? async(...c) : 0; +const f10 = a ? async(...c) : x => x; +const f11 = a ? async (...c: number[]): Promise => c.length : () => 0; +const f12 = a ? async() : x => async (...c): Promise => c.length; + +type T = Promise; +const f13 = a ? async() : x => async (): Promise => b; +const f14 = a ? async() : x => async (): T => 0; +const f15 = a ? (b) : x => async (): T => 0; +const f16 = a ? async(...c) : x => async (): T => 0; +const f17 = a ? async() : x => (y): number => y; +const f18 = a ? async() : x => async (): T => 0; +const f19 = a ? async(...c) : x => (y): number => y; +const f20 = a ? async(...c) : x => async (): T => 0; +const f21 = a ? (x): number => (b): T => 0; +const f22 = a ? async (): Promise => (b): T => 0; +const f23 = a ? async () => async() : x => x; +const f24 = a ? async (...c) => async() : x => x; +const f25 = a ? () => async() : x => x; +const f26 = a ? async (c: number): Promise => async() : x => x; + +function* g() { + const f1 = a ? yield async(...c) : 0; + const f2 = a ? yield async(...c) : x => x; +} //// [parenthesizedAsyncArrowFunction.js] @@ -19,3 +62,39 @@ 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; +const c = [b]; +function async(...c) { + 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; +const f9 = a ? async(...c) : 0; +const f10 = a ? async(...c) : x => x; +const f11 = a ? (...c) => __awaiter(void 0, void 0, void 0, function* () { return c.length; }) : () => 0; +const f12 = a ? async() : x => (...c) => __awaiter(void 0, void 0, void 0, function* () { return c.length; }); +const f13 = a ? async() : x => () => __awaiter(void 0, void 0, void 0, function* () { return b; }); +const f14 = a ? async() : x => () => __awaiter(void 0, void 0, void 0, function* () { return 0; }); +const f15 = a ? (b) : x => () => __awaiter(void 0, void 0, void 0, function* () { return 0; }); +const f16 = a ? async(...c) : x => () => __awaiter(void 0, void 0, void 0, function* () { return 0; }); +const f17 = a ? async() : x => (y) => y; +const f18 = a ? async() : x => () => __awaiter(void 0, void 0, void 0, function* () { return 0; }); +const f19 = a ? async(...c) : x => (y) => y; +const f20 = a ? async(...c) : x => () => __awaiter(void 0, void 0, void 0, function* () { return 0; }); +const f21 = a ? (x) => (b) : T => 0; +const f22 = a ? () => __awaiter(void 0, void 0, void 0, function* () { return (b); }) : T => 0; +const f23 = a ? () => __awaiter(void 0, void 0, void 0, function* () { return async(); }) : x => x; +const f24 = a ? (...c) => __awaiter(void 0, void 0, void 0, function* () { return async(); }) : x => x; +const f25 = a ? () => async() : x => x; +const f26 = a ? (c) => __awaiter(void 0, void 0, void 0, function* () { return async(); }) : x => x; +function* g() { + const f1 = a ? yield async(...c) : 0; + const f2 = a ? yield async(...c) : x => x; +} diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.symbols b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.symbols index 53286f39e8465..b1978407861ee 100644 --- a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.symbols +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.symbols @@ -8,3 +8,242 @@ 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)) + +const c = [b]; +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 6, 5)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + +function async(...c: number[]): number { +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 8, 15)) + + return b; +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) +} + +const f1 = a ? async() : 0; +>f1 : Symbol(f1, Decl(parenthesizedAsyncArrowFunction.ts, 12, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) + +const f2 = a ? async() : x => x; +>f2 : Symbol(f2, Decl(parenthesizedAsyncArrowFunction.ts, 13, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 13, 24)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 13, 24)) + +const f3 = a ? a ? async() : 0 : b; +>f3 : Symbol(f3, Decl(parenthesizedAsyncArrowFunction.ts, 14, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + +const f4 = a ? x => async() : x => x; +>f4 : Symbol(f4, Decl(parenthesizedAsyncArrowFunction.ts, 15, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 15, 14)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 15, 29)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 15, 29)) + +const f5 = a ? async (): Promise => b : () => b; +>f5 : Symbol(f5, 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 f6 = a ? async (): Promise => { return b; } : () => b; +>f6 : Symbol(f6, 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, --, --)) +>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, 18, 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, 6, 14)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) + +const f8 = a ? (): number => b : () => b; +>f8 : Symbol(f8, Decl(parenthesizedAsyncArrowFunction.ts, 19, 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)) + +const f9 = a ? async(...c) : 0; +>f9 : Symbol(f9, Decl(parenthesizedAsyncArrowFunction.ts, 21, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 6, 5)) + +const f10 = a ? async(...c) : x => x; +>f10 : Symbol(f10, Decl(parenthesizedAsyncArrowFunction.ts, 22, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 6, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 22, 29)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 22, 29)) + +const f11 = a ? async (...c: number[]): Promise => c.length : () => 0; +>f11 : Symbol(f11, Decl(parenthesizedAsyncArrowFunction.ts, 23, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 23, 23)) +>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, --, --)) +>c.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 23, 23)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + +const f12 = a ? async() : x => async (...c): Promise => c.length; +>f12 : Symbol(f12, Decl(parenthesizedAsyncArrowFunction.ts, 24, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 24, 25)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 24, 38)) +>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, --, --)) +>c.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 24, 38)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + +type T = Promise; +>T : Symbol(T, Decl(parenthesizedAsyncArrowFunction.ts, 24, 73)) +>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, --, --)) + +const f13 = a ? async() : x => async (): Promise => b; +>f13 : Symbol(f13, Decl(parenthesizedAsyncArrowFunction.ts, 27, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 27, 25)) +>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)) + +const f14 = a ? async() : x => async (): T => 0; +>f14 : Symbol(f14, Decl(parenthesizedAsyncArrowFunction.ts, 28, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 28, 25)) +>T : Symbol(T, Decl(parenthesizedAsyncArrowFunction.ts, 24, 73)) + +const f15 = a ? (b) : x => async (): T => 0; +>f15 : Symbol(f15, Decl(parenthesizedAsyncArrowFunction.ts, 29, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 29, 21)) +>T : Symbol(T, Decl(parenthesizedAsyncArrowFunction.ts, 24, 73)) + +const f16 = a ? async(...c) : x => async (): T => 0; +>f16 : Symbol(f16, Decl(parenthesizedAsyncArrowFunction.ts, 30, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 6, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 30, 29)) +>T : Symbol(T, Decl(parenthesizedAsyncArrowFunction.ts, 24, 73)) + +const f17 = a ? async() : x => (y): number => y; +>f17 : Symbol(f17, Decl(parenthesizedAsyncArrowFunction.ts, 31, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 31, 25)) +>y : Symbol(y, Decl(parenthesizedAsyncArrowFunction.ts, 31, 32)) +>y : Symbol(y, Decl(parenthesizedAsyncArrowFunction.ts, 31, 32)) + +const f18 = a ? async() : x => async (): T => 0; +>f18 : Symbol(f18, Decl(parenthesizedAsyncArrowFunction.ts, 32, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 32, 25)) +>U : Symbol(U, Decl(parenthesizedAsyncArrowFunction.ts, 32, 38)) +>T : Symbol(T, Decl(parenthesizedAsyncArrowFunction.ts, 24, 73)) + +const f19 = a ? async(...c) : x => (y): number => y; +>f19 : Symbol(f19, Decl(parenthesizedAsyncArrowFunction.ts, 33, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 6, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 33, 29)) +>y : Symbol(y, Decl(parenthesizedAsyncArrowFunction.ts, 33, 36)) +>y : Symbol(y, Decl(parenthesizedAsyncArrowFunction.ts, 33, 36)) + +const f20 = a ? async(...c) : x => async (): T => 0; +>f20 : Symbol(f20, Decl(parenthesizedAsyncArrowFunction.ts, 34, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 6, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 34, 29)) +>U : Symbol(U, Decl(parenthesizedAsyncArrowFunction.ts, 34, 42)) +>T : Symbol(T, Decl(parenthesizedAsyncArrowFunction.ts, 24, 73)) + +const f21 = a ? (x): number => (b): T => 0; +>f21 : Symbol(f21, Decl(parenthesizedAsyncArrowFunction.ts, 35, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 35, 17)) +>b : Symbol(b, Decl(parenthesizedAsyncArrowFunction.ts, 5, 5)) +>T : Symbol(T, Decl(parenthesizedAsyncArrowFunction.ts, 35, 35)) + +const f22 = a ? async (): Promise => (b): T => 0; +>f22 : Symbol(f22, Decl(parenthesizedAsyncArrowFunction.ts, 36, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>U : Symbol(U, Decl(parenthesizedAsyncArrowFunction.ts, 36, 23)) +>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)) +>T : Symbol(T, Decl(parenthesizedAsyncArrowFunction.ts, 36, 52)) + +const f23 = a ? async () => async() : x => x; +>f23 : Symbol(f23, Decl(parenthesizedAsyncArrowFunction.ts, 37, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 37, 37)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 37, 37)) + +const f24 = a ? async (...c) => async() : x => x; +>f24 : Symbol(f24, Decl(parenthesizedAsyncArrowFunction.ts, 38, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 38, 23)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 38, 41)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 38, 41)) + +const f25 = a ? () => async() : x => x; +>f25 : Symbol(f25, Decl(parenthesizedAsyncArrowFunction.ts, 39, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 39, 31)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 39, 31)) + +const f26 = a ? async (c: number): Promise => async() : x => x; +>f26 : Symbol(f26, Decl(parenthesizedAsyncArrowFunction.ts, 40, 5)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 40, 23)) +>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, --, --)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 40, 63)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 40, 63)) + +function* g() { +>g : Symbol(g, Decl(parenthesizedAsyncArrowFunction.ts, 40, 71)) + + const f1 = a ? yield async(...c) : 0; +>f1 : Symbol(f1, Decl(parenthesizedAsyncArrowFunction.ts, 43, 9)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 6, 5)) + + const f2 = a ? yield async(...c) : x => x; +>f2 : Symbol(f2, Decl(parenthesizedAsyncArrowFunction.ts, 44, 9)) +>a : Symbol(a, Decl(parenthesizedAsyncArrowFunction.ts, 4, 5)) +>async : Symbol(async, Decl(parenthesizedAsyncArrowFunction.ts, 6, 14)) +>c : Symbol(c, Decl(parenthesizedAsyncArrowFunction.ts, 6, 5)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 44, 38)) +>x : Symbol(x, Decl(parenthesizedAsyncArrowFunction.ts, 44, 38)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.types b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.types index 9f5aa33f8d645..231e4f8adb549 100644 --- a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.types +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunction.types @@ -10,3 +10,349 @@ let foo = (async bar => bar); >bar : any >bar : any +const a = true; +>a : true +>true : true + +const b = 1; +>b : 1 +>1 : 1 + +const c = [b]; +>c : number[] +>[b] : number[] +>b : 1 + +function async(...c: number[]): number { +>async : (...c: number[]) => number +>c : number[] + + return b; +>b : 1 +} + +const f1 = a ? async() : 0; +>f1 : number +>a ? async() : 0 : number +>a : true +>async() : number +>async : (...c: number[]) => 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 : (...c: number[]) => 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 : (...c: number[]) => 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 : (...c: number[]) => 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 : (...c: number[]) => 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 + +const f9 = a ? async(...c) : 0; +>f9 : number +>a ? async(...c) : 0 : number +>a : true +>async(...c) : number +>async : (...c: number[]) => number +>...c : number +>c : number[] +>0 : 0 + +const f10 = a ? async(...c) : x => x; +>f10 : number | ((x: any) => any) +>a ? async(...c) : x => x : number | ((x: any) => any) +>a : true +>async(...c) : number +>async : (...c: number[]) => number +>...c : number +>c : number[] +>x => x : (x: any) => any +>x : any +>x : any + +const f11 = a ? async (...c: number[]): Promise => c.length : () => 0; +>f11 : ((...c: number[]) => Promise) | (() => number) +>a ? async (...c: number[]): Promise => c.length : () => 0 : ((...c: number[]) => Promise) | (() => number) +>a : true +>async (...c: number[]): Promise => c.length : (...c: number[]) => Promise +>c : number[] +>c.length : number +>c : number[] +>length : number +>() => 0 : () => number +>0 : 0 + +const f12 = a ? async() : x => async (...c): Promise => c.length; +>f12 : number | ((x: any) => (...c: any[]) => Promise) +>a ? async() : x => async (...c): Promise => c.length : number | ((x: any) => (...c: any[]) => Promise) +>a : true +>async() : number +>async : (...c: number[]) => number +>x => async (...c): Promise => c.length : (x: any) => (...c: any[]) => Promise +>x : any +>async (...c): Promise => c.length : (...c: any[]) => Promise +>c : any[] +>c.length : number +>c : any[] +>length : number + +type T = Promise; +>T : T + +const f13 = a ? async() : x => async (): Promise => b; +>f13 : number | ((x: any) => () => Promise) +>a ? async() : x => async (): Promise => b : number | ((x: any) => () => Promise) +>a : true +>async() : number +>async : (...c: number[]) => number +>x => async (): Promise => b : (x: any) => () => Promise +>x : any +>async (): Promise => b : () => Promise +>b : 1 + +const f14 = a ? async() : x => async (): T => 0; +>f14 : number | ((x: any) => () => T) +>a ? async() : x => async (): T => 0 : number | ((x: any) => () => T) +>a : true +>async() : number +>async : (...c: number[]) => number +>x => async (): T => 0 : (x: any) => () => T +>x : any +>async (): T => 0 : () => T +>0 : 0 + +const f15 = a ? (b) : x => async (): T => 0; +>f15 : 1 | ((x: any) => () => T) +>a ? (b) : x => async (): T => 0 : 1 | ((x: any) => () => T) +>a : true +>(b) : 1 +>b : 1 +>x => async (): T => 0 : (x: any) => () => T +>x : any +>async (): T => 0 : () => T +>0 : 0 + +const f16 = a ? async(...c) : x => async (): T => 0; +>f16 : number | ((x: any) => () => T) +>a ? async(...c) : x => async (): T => 0 : number | ((x: any) => () => T) +>a : true +>async(...c) : number +>async : (...c: number[]) => number +>...c : number +>c : number[] +>x => async (): T => 0 : (x: any) => () => T +>x : any +>async (): T => 0 : () => T +>0 : 0 + +const f17 = a ? async() : x => (y): number => y; +>f17 : number | ((x: any) => (y: any) => number) +>a ? async() : x => (y): number => y : number | ((x: any) => (y: any) => number) +>a : true +>async() : number +>async : (...c: number[]) => number +>x => (y): number => y : (x: any) => (y: any) => number +>x : any +>(y): number => y : (y: any) => number +>y : any +>y : any + +const f18 = a ? async() : x => async (): T => 0; +>f18 : number | ((x: any) => () => T) +>a ? async() : x => async (): T => 0 : number | ((x: any) => () => T) +>a : true +>async() : number +>async : (...c: number[]) => number +>x => async (): T => 0 : (x: any) => () => T +>x : any +>async (): T => 0 : () => T +>0 : 0 + +const f19 = a ? async(...c) : x => (y): number => y; +>f19 : number | ((x: any) => (y: any) => number) +>a ? async(...c) : x => (y): number => y : number | ((x: any) => (y: any) => number) +>a : true +>async(...c) : number +>async : (...c: number[]) => number +>...c : number +>c : number[] +>x => (y): number => y : (x: any) => (y: any) => number +>x : any +>(y): number => y : (y: any) => number +>y : any +>y : any + +const f20 = a ? async(...c) : x => async (): T => 0; +>f20 : number | ((x: any) => () => T) +>a ? async(...c) : x => async (): T => 0 : number | ((x: any) => () => T) +>a : true +>async(...c) : number +>async : (...c: number[]) => number +>...c : number +>c : number[] +>x => async (): T => 0 : (x: any) => () => T +>x : any +>async (): T => 0 : () => T +>0 : 0 + +const f21 = a ? (x): number => (b): T => 0; +>f21 : (x: any) => number +>a ? (x): number => (b): T => 0 : (x: any) => number +>a : true +>(x): number => (b) : (x: any) => number +>x : any +>(b) : 1 +>b : 1 +>T => 0 : (T: any) => number +>T : any +>0 : 0 + +const f22 = a ? async (): Promise => (b): T => 0; +>f22 : (() => Promise) | ((T: any) => number) +>a ? async (): Promise => (b): T => 0 : (() => Promise) | ((T: any) => number) +>a : true +>async (): Promise => (b) : () => Promise +>(b) : 1 +>b : 1 +>T => 0 : (T: any) => number +>T : any +>0 : 0 + +const f23 = a ? async () => async() : x => x; +>f23 : (x: any) => any +>a ? async () => async() : x => x : (x: any) => any +>a : true +>async () => async() : () => Promise +>async() : number +>async : (...c: number[]) => number +>x => x : (x: any) => any +>x : any +>x : any + +const f24 = a ? async (...c) => async() : x => x; +>f24 : ((...c: any[]) => Promise) | ((x: any) => any) +>a ? async (...c) => async() : x => x : ((...c: any[]) => Promise) | ((x: any) => any) +>a : true +>async (...c) => async() : (...c: any[]) => Promise +>c : any[] +>async() : number +>async : (...c: number[]) => number +>x => x : (x: any) => any +>x : any +>x : any + +const f25 = a ? () => async() : x => x; +>f25 : (x: any) => any +>a ? () => async() : x => x : (x: any) => any +>a : true +>() => async() : () => number +>async() : number +>async : (...c: number[]) => number +>x => x : (x: any) => any +>x : any +>x : any + +const f26 = a ? async (c: number): Promise => async() : x => x; +>f26 : (x: any) => any +>a ? async (c: number): Promise => async() : x => x : (x: any) => any +>a : true +>async (c: number): Promise => async() : (c: number) => Promise +>c : number +>async() : number +>async : (...c: number[]) => number +>x => x : (x: any) => any +>x : any +>x : any + +function* g() { +>g : () => Generator + + const f1 = a ? yield async(...c) : 0; +>f1 : any +>a ? yield async(...c) : 0 : any +>a : true +>yield async(...c) : any +>async(...c) : number +>async : (...c: number[]) => number +>...c : number +>c : number[] +>0 : 0 + + const f2 = a ? yield async(...c) : x => x; +>f2 : any +>a ? yield async(...c) : x => x : any +>a : true +>yield async(...c) : any +>async(...c) : number +>async : (...c: number[]) => number +>...c : number +>c : number[] +>x => x : (x: any) => any +>x : any +>x : any +} + diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.js b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.js new file mode 100644 index 0000000000000..feeaf996546a8 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.js @@ -0,0 +1,49 @@ +//// [tests/cases/compiler/parenthesizedAsyncArrowFunctionJs.ts] //// + +//// [a.js] +const a = true; +const b = 1; +const c = [b]; + +function async(...c) { + return b; +} + +const f1 = a ? async(...c) : 0; +const f2 = a ? async(...c) : x => x; +const f3 = a ? async () => async() : x => x; +const f4 = a ? async (...c) => async() : x => x; +const f5 = a ? () => async() : x => x; + +function* g() { + const f1 = a ? yield async(...c) : 0; + const f2 = a ? yield async(...c) : x => x; +} + + +//// [a.js] +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +const a = true; +const b = 1; +const c = [b]; +function async(...c) { + return b; +} +const f1 = a ? async(...c) : 0; +const f2 = a ? async(...c) : x => x; +const f3 = a ? () => __awaiter(void 0, void 0, void 0, function* () { return async(); }) : x => x; +const f4 = a ? (...c) => __awaiter(void 0, void 0, void 0, function* () { return async(); }) : x => x; +const f5 = a ? () => async() : x => x; +function* g() { + const f1 = a ? yield async(...c) : 0; + const f2 = a ? yield async(...c) : x => x; +} diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.symbols b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.symbols new file mode 100644 index 0000000000000..2a779b0db2291 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.symbols @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/parenthesizedAsyncArrowFunctionJs.ts] //// + +=== a.js === +const a = true; +>a : Symbol(a, Decl(a.js, 0, 5)) + +const b = 1; +>b : Symbol(b, Decl(a.js, 1, 5)) + +const c = [b]; +>c : Symbol(c, Decl(a.js, 2, 5)) +>b : Symbol(b, Decl(a.js, 1, 5)) + +function async(...c) { +>async : Symbol(async, Decl(a.js, 2, 14)) +>c : Symbol(c, Decl(a.js, 4, 15)) + + return b; +>b : Symbol(b, Decl(a.js, 1, 5)) +} + +const f1 = a ? async(...c) : 0; +>f1 : Symbol(f1, Decl(a.js, 8, 5)) +>a : Symbol(a, Decl(a.js, 0, 5)) +>async : Symbol(async, Decl(a.js, 2, 14)) +>c : Symbol(c, Decl(a.js, 2, 5)) + +const f2 = a ? async(...c) : x => x; +>f2 : Symbol(f2, Decl(a.js, 9, 5)) +>a : Symbol(a, Decl(a.js, 0, 5)) +>async : Symbol(async, Decl(a.js, 2, 14)) +>c : Symbol(c, Decl(a.js, 2, 5)) +>x : Symbol(x, Decl(a.js, 9, 28)) +>x : Symbol(x, Decl(a.js, 9, 28)) + +const f3 = a ? async () => async() : x => x; +>f3 : Symbol(f3, Decl(a.js, 10, 5)) +>a : Symbol(a, Decl(a.js, 0, 5)) +>async : Symbol(async, Decl(a.js, 2, 14)) +>x : Symbol(x, Decl(a.js, 10, 36)) +>x : Symbol(x, Decl(a.js, 10, 36)) + +const f4 = a ? async (...c) => async() : x => x; +>f4 : Symbol(f4, Decl(a.js, 11, 5)) +>a : Symbol(a, Decl(a.js, 0, 5)) +>c : Symbol(c, Decl(a.js, 11, 22)) +>async : Symbol(async, Decl(a.js, 2, 14)) +>x : Symbol(x, Decl(a.js, 11, 40)) +>x : Symbol(x, Decl(a.js, 11, 40)) + +const f5 = a ? () => async() : x => x; +>f5 : Symbol(f5, Decl(a.js, 12, 5)) +>a : Symbol(a, Decl(a.js, 0, 5)) +>async : Symbol(async, Decl(a.js, 2, 14)) +>x : Symbol(x, Decl(a.js, 12, 30)) +>x : Symbol(x, Decl(a.js, 12, 30)) + +function* g() { +>g : Symbol(g, Decl(a.js, 12, 38)) + + const f1 = a ? yield async(...c) : 0; +>f1 : Symbol(f1, Decl(a.js, 15, 9)) +>a : Symbol(a, Decl(a.js, 0, 5)) +>async : Symbol(async, Decl(a.js, 2, 14)) +>c : Symbol(c, Decl(a.js, 2, 5)) + + const f2 = a ? yield async(...c) : x => x; +>f2 : Symbol(f2, Decl(a.js, 16, 9)) +>a : Symbol(a, Decl(a.js, 0, 5)) +>async : Symbol(async, Decl(a.js, 2, 14)) +>c : Symbol(c, Decl(a.js, 2, 5)) +>x : Symbol(x, Decl(a.js, 16, 38)) +>x : Symbol(x, Decl(a.js, 16, 38)) +} + diff --git a/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.types b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.types new file mode 100644 index 0000000000000..61e4470d50c75 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/parenthesizedAsyncArrowFunctionJs.types @@ -0,0 +1,108 @@ +//// [tests/cases/compiler/parenthesizedAsyncArrowFunctionJs.ts] //// + +=== a.js === +const a = true; +>a : true +>true : true + +const b = 1; +>b : 1 +>1 : 1 + +const c = [b]; +>c : number[] +>[b] : number[] +>b : 1 + +function async(...c) { +>async : (...c: any[]) => number +>c : any[] + + return b; +>b : 1 +} + +const f1 = a ? async(...c) : 0; +>f1 : number +>a ? async(...c) : 0 : number +>a : true +>async(...c) : number +>async : (...c: any[]) => number +>...c : number +>c : number[] +>0 : 0 + +const f2 = a ? async(...c) : x => x; +>f2 : number | ((x: any) => any) +>a ? async(...c) : x => x : number | ((x: any) => any) +>a : true +>async(...c) : number +>async : (...c: any[]) => number +>...c : number +>c : number[] +>x => x : (x: any) => any +>x : any +>x : any + +const f3 = a ? async () => async() : x => x; +>f3 : (x: any) => any +>a ? async () => async() : x => x : (x: any) => any +>a : true +>async () => async() : () => Promise +>async() : number +>async : (...c: any[]) => number +>x => x : (x: any) => any +>x : any +>x : any + +const f4 = a ? async (...c) => async() : x => x; +>f4 : ((...c: any[]) => Promise) | ((x: any) => any) +>a ? async (...c) => async() : x => x : ((...c: any[]) => Promise) | ((x: any) => any) +>a : true +>async (...c) => async() : (...c: any[]) => Promise +>c : any[] +>async() : number +>async : (...c: any[]) => number +>x => x : (x: any) => any +>x : any +>x : any + +const f5 = a ? () => async() : x => x; +>f5 : (x: any) => any +>a ? () => async() : x => x : (x: any) => any +>a : true +>() => async() : () => number +>async() : number +>async : (...c: any[]) => number +>x => x : (x: any) => any +>x : any +>x : any + +function* g() { +>g : () => Generator + + const f1 = a ? yield async(...c) : 0; +>f1 : any +>a ? yield async(...c) : 0 : any +>a : true +>yield async(...c) : any +>async(...c) : number +>async : (...c: any[]) => number +>...c : number +>c : number[] +>0 : 0 + + const f2 = a ? yield async(...c) : x => x; +>f2 : any +>a ? yield async(...c) : x => x : any +>a : true +>yield async(...c) : any +>async(...c) : number +>async : (...c: any[]) => number +>...c : number +>c : number[] +>x => x : (x: any) => any +>x : any +>x : any +} + 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..e19686811884a 100644 --- a/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts +++ b/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts @@ -3,3 +3,46 @@ // Repro from #20096 let foo = (async bar => bar); + +const a = true; +const b = 1; +const c = [b]; + +function async(...c: number[]): 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; + +const f9 = a ? async(...c) : 0; +const f10 = a ? async(...c) : x => x; +const f11 = a ? async (...c: number[]): Promise => c.length : () => 0; +const f12 = a ? async() : x => async (...c): Promise => c.length; + +type T = Promise; +const f13 = a ? async() : x => async (): Promise => b; +const f14 = a ? async() : x => async (): T => 0; +const f15 = a ? (b) : x => async (): T => 0; +const f16 = a ? async(...c) : x => async (): T => 0; +const f17 = a ? async() : x => (y): number => y; +const f18 = a ? async() : x => async (): T => 0; +const f19 = a ? async(...c) : x => (y): number => y; +const f20 = a ? async(...c) : x => async (): T => 0; +const f21 = a ? (x): number => (b): T => 0; +const f22 = a ? async (): Promise => (b): T => 0; +const f23 = a ? async () => async() : x => x; +const f24 = a ? async (...c) => async() : x => x; +const f25 = a ? () => async() : x => x; +const f26 = a ? async (c: number): Promise => async() : x => x; + +function* g() { + const f1 = a ? yield async(...c) : 0; + const f2 = a ? yield async(...c) : x => x; +} diff --git a/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunctionJs.ts b/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunctionJs.ts new file mode 100644 index 0000000000000..1e01dd2edac1d --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/parenthesizedAsyncArrowFunctionJs.ts @@ -0,0 +1,24 @@ +// @target: es2015 +// @strict: false +// @checkJs: true +// @outDir: out +// @filename: a.js + +const a = true; +const b = 1; +const c = [b]; + +function async(...c) { + return b; +} + +const f1 = a ? async(...c) : 0; +const f2 = a ? async(...c) : x => x; +const f3 = a ? async () => async() : x => x; +const f4 = a ? async (...c) => async() : x => x; +const f5 = a ? () => async() : x => x; + +function* g() { + const f1 = a ? yield async(...c) : 0; + const f2 = a ? yield async(...c) : x => x; +} 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; From 8a8315d9468b67fa580931b003944374815bed0a Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk Date: Sun, 18 Oct 2026 14:16:47 +0300 Subject: [PATCH 2/2] separate expression parsing flags --- tsc/internal/parser/parser.go | 36 +++++++++++++++++------------------ tsc/internal/parser/types.go | 22 +++++++++++++-------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/tsc/internal/parser/parser.go b/tsc/internal/parser/parser.go index ce4899a68ab9a..3665680f0af26 100644 --- a/tsc/internal/parser/parser.go +++ b/tsc/internal/parser/parser.go @@ -4155,10 +4155,10 @@ func (p *Parser) parseExpressionAllowIn() *ast.Expression { } func (p *Parser) parseAssignmentExpressionOrHigher() *ast.Expression { - return p.parseAssignmentExpressionOrHigherWorker(ParseFlagsNone) + return p.parseAssignmentExpressionOrHigherWorker(ExpressionParseFlagsNone) } -func (p *Parser) parseAssignmentExpressionOrHigherWorker(flags ParseFlags) *ast.Expression { +func (p *Parser) parseAssignmentExpressionOrHigherWorker(flags ExpressionParseFlags) *ast.Expression { // AssignmentExpression[in,yield]: // 1) ConditionalExpression[?in,?yield] // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] @@ -4254,7 +4254,7 @@ func (p *Parser) isYieldExpression() bool { return false } -func (p *Parser) parseYieldExpression(flags ParseFlags) *ast.Node { +func (p *Parser) parseYieldExpression(flags ExpressionParseFlags) *ast.Node { pos := p.nodePos() // YieldExpression[In] : // yield @@ -4272,7 +4272,7 @@ func (p *Parser) parseYieldExpression(flags ParseFlags) *ast.Node { return p.finishNode(result, pos) } -func (p *Parser) isParenthesizedArrowFunctionExpression(flags ParseFlags) core.Tristate { +func (p *Parser) isParenthesizedArrowFunctionExpression(flags ExpressionParseFlags) core.Tristate { if p.token == ast.KindOpenParenToken || p.token == ast.KindLessThanToken || p.token == ast.KindAsyncKeyword { state := p.mark() result := p.nextIsParenthesizedArrowFunctionExpression(flags) @@ -4289,7 +4289,7 @@ func (p *Parser) isParenthesizedArrowFunctionExpression(flags ParseFlags) core.T return core.TSFalse } -func (p *Parser) nextIsParenthesizedArrowFunctionExpression(flags ParseFlags) core.Tristate { +func (p *Parser) nextIsParenthesizedArrowFunctionExpression(flags ExpressionParseFlags) core.Tristate { isAsync := p.token == ast.KindAsyncKeyword if isAsync { p.nextToken() @@ -4309,7 +4309,7 @@ func (p *Parser) nextIsParenthesizedArrowFunctionExpression(flags ParseFlags) co // but this is probably what the user intended. switch p.nextToken() { case ast.KindColonToken: - if isAsync && flags&ParseFlagsAllowAmbiguousAsyncArrow == 0 { + if isAsync && flags&ExpressionParseFlagsAllowAmbiguousAsyncArrow == 0 { return core.TSUnknown } return core.TSTrue @@ -4321,7 +4321,7 @@ func (p *Parser) nextIsParenthesizedArrowFunctionExpression(flags ParseFlags) co // Simple case: "(...". After "async", this could also be a spread argument. if second == ast.KindDotDotDotToken { if isAsync { - if flags&ParseFlagsAllowAmbiguousAsyncArrow != 0 { + if flags&ExpressionParseFlagsAllowAmbiguousAsyncArrow != 0 { return core.TSTrue } second = p.nextToken() @@ -4407,7 +4407,7 @@ func (p *Parser) nextIsParenthesizedArrowFunctionExpression(flags ParseFlags) co } } -func (p *Parser) tryParseParenthesizedArrowFunctionExpression(flags ParseFlags) *ast.Node { +func (p *Parser) tryParseParenthesizedArrowFunctionExpression(flags ExpressionParseFlags) *ast.Node { tristate := p.isParenthesizedArrowFunctionExpression(flags) if tristate == core.TSFalse { // It's definitely not a parenthesized arrow function expression. @@ -4428,7 +4428,7 @@ func (p *Parser) tryParseParenthesizedArrowFunctionExpression(flags ParseFlags) return result } -func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, flags ParseFlags) *ast.Node { +func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, flags ExpressionParseFlags) *ast.Node { pos := p.nodePos() jsdoc := p.jsdocScannerInfo() modifiers := p.parseModifiersForArrowFunction() @@ -4451,7 +4451,7 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, parameters = p.createMissingList() } else { if isAsync && typeParameters == nil && (p.token == ast.KindCloseParenToken || p.token == ast.KindDotDotDotToken) { - bodyFlags = flags & ParseFlagsAllowAmbiguousAsyncArrow + bodyFlags = flags & ExpressionParseFlagsAllowAmbiguousAsyncArrow } if !allowAmbiguity { maybeParameters := p.parseParametersWorker(signatureFlags, allowAmbiguity) @@ -4466,7 +4466,7 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, return nil } } - requiresColon := !allowAmbiguity && p.token == ast.KindColonToken && flags&ParseFlagsDisallowArrowReturnType != 0 + requiresColon := !allowAmbiguity && p.token == ast.KindColonToken && flags&ExpressionParseFlagsDisallowArrowReturnType != 0 returnType := p.parseReturnType(ast.KindColonToken /*isType*/, false) if returnType != nil && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(returnType) { return nil @@ -4496,7 +4496,7 @@ func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, var body *ast.Node if lastToken == ast.KindEqualsGreaterThanToken || lastToken == ast.KindOpenBraceToken { if requiresColon { - bodyFlags |= ParseFlagsAllowAmbiguousAsyncArrow + bodyFlags |= ExpressionParseFlagsAllowAmbiguousAsyncArrow } else { bodyFlags = flags } @@ -4558,7 +4558,7 @@ func typeHasArrowFunctionBlockingParseError(node *ast.TypeNode) bool { return false } -func (p *Parser) parseArrowFunctionExpressionBody(isAsync bool, flags ParseFlags) *ast.Node { +func (p *Parser) parseArrowFunctionExpressionBody(isAsync bool, flags ExpressionParseFlags) *ast.Node { if p.token == ast.KindOpenBraceToken { return p.parseFunctionBlock(core.IfElse(isAsync, ParseFlagsAwait, ParseFlagsNone), nil /*diagnosticMessage*/) } @@ -4592,7 +4592,7 @@ func (p *Parser) isStartOfExpressionStatement() bool { return p.token != ast.KindOpenBraceToken && p.token != ast.KindFunctionKeyword && p.token != ast.KindClassKeyword && p.token != ast.KindAtToken && p.isStartOfExpression() } -func (p *Parser) parsePossibleParenthesizedArrowFunctionExpression(flags ParseFlags) *ast.Node { +func (p *Parser) parsePossibleParenthesizedArrowFunctionExpression(flags ExpressionParseFlags) *ast.Node { tokenPos := p.scanner.TokenStart() if p.notParenthesizedArrow.Has(tokenPos) { return nil @@ -4604,7 +4604,7 @@ func (p *Parser) parsePossibleParenthesizedArrowFunctionExpression(flags ParseFl return result } -func (p *Parser) tryParseAsyncSimpleArrowFunctionExpression(flags ParseFlags) *ast.Node { +func (p *Parser) tryParseAsyncSimpleArrowFunctionExpression(flags ExpressionParseFlags) *ast.Node { // We do a check here so that we won't be doing unnecessarily call to "lookAhead" if p.token == ast.KindAsyncKeyword && p.lookAhead((*Parser).nextIsUnParenthesizedAsyncArrowFunction) { pos := p.nodePos() @@ -4637,7 +4637,7 @@ func (p *Parser) nextIsUnParenthesizedAsyncArrowFunction() bool { return false } -func (p *Parser) parseSimpleArrowFunctionExpression(pos int, identifier *ast.Node, flags ParseFlags, jsdoc jsdocScannerInfo, asyncModifier *ast.ModifierList) *ast.Node { +func (p *Parser) parseSimpleArrowFunctionExpression(pos int, identifier *ast.Node, flags ExpressionParseFlags, jsdoc jsdocScannerInfo, asyncModifier *ast.ModifierList) *ast.Node { debug.Assert(p.token == ast.KindEqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>") parameter := p.finishNode(p.factory.NewParameterDeclaration(nil /*modifiers*/, nil /*dotDotDotToken*/, identifier, nil /*questionToken*/, nil /*typeNode*/, nil /*initializer*/), identifier.Pos()) parameters := p.newNodeList(parameter.Loc, []*ast.Node{parameter}) @@ -4648,7 +4648,7 @@ func (p *Parser) parseSimpleArrowFunctionExpression(pos int, identifier *ast.Nod return result } -func (p *Parser) parseConditionalExpressionRest(leftOperand *ast.Expression, pos int, flags ParseFlags) *ast.Expression { +func (p *Parser) parseConditionalExpressionRest(leftOperand *ast.Expression, pos int, flags ExpressionParseFlags) *ast.Expression { // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. questionToken := p.parseOptionalToken(ast.KindQuestionToken) if questionToken == nil { @@ -4658,7 +4658,7 @@ func (p *Parser) parseConditionalExpressionRest(leftOperand *ast.Expression, pos // we do not that for the 'whenFalse' part. saveContextFlags := p.contextFlags p.setContextFlags(ast.NodeFlagsDisallowInContext, false) - trueExpression := p.parseAssignmentExpressionOrHigherWorker(ParseFlagsDisallowArrowReturnType) + trueExpression := p.parseAssignmentExpressionOrHigherWorker(ExpressionParseFlagsDisallowArrowReturnType) p.contextFlags = saveContextFlags colonToken := p.parseExpectedToken(ast.KindColonToken) var falseExpression *ast.Expression diff --git a/tsc/internal/parser/types.go b/tsc/internal/parser/types.go index 03db776cfd029..c2295bb1976c8 100644 --- a/tsc/internal/parser/types.go +++ b/tsc/internal/parser/types.go @@ -5,12 +5,18 @@ package parser type ParseFlags uint32 const ( - ParseFlagsNone ParseFlags = 0 - ParseFlagsYield ParseFlags = 1 << 0 - ParseFlagsAwait ParseFlags = 1 << 1 - ParseFlagsType ParseFlags = 1 << 2 - ParseFlagsIgnoreMissingOpenBrace ParseFlags = 1 << 4 - ParseFlagsJSDoc ParseFlags = 1 << 5 - ParseFlagsDisallowArrowReturnType ParseFlags = 1 << 6 - ParseFlagsAllowAmbiguousAsyncArrow ParseFlags = 1 << 7 + ParseFlagsNone ParseFlags = 0 + ParseFlagsYield ParseFlags = 1 << 0 + ParseFlagsAwait ParseFlags = 1 << 1 + ParseFlagsType ParseFlags = 1 << 2 + ParseFlagsIgnoreMissingOpenBrace ParseFlags = 1 << 4 + ParseFlagsJSDoc ParseFlags = 1 << 5 +) + +type ExpressionParseFlags uint32 + +const ( + ExpressionParseFlagsNone ExpressionParseFlags = 0 + ExpressionParseFlagsDisallowArrowReturnType ExpressionParseFlags = 1 << 0 + ExpressionParseFlagsAllowAmbiguousAsyncArrow ExpressionParseFlags = 1 << 1 )