mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-09 12:15:34 -06:00
Fix 8262: allow unparenthesized parameter in async arrow-function (#8444)
* Allow unparenthesize of parameter in async arrow-function * Add tests and baselines * Address PR * Address PR: refactor to use "parseSimpleArrowFunctionExpression" * Address PR: add comment * Address PR
This commit is contained in:
parent
e9122a9f34
commit
7521891760
@ -2685,7 +2685,8 @@ namespace ts {
|
||||
// 2) LeftHandSideExpression = AssignmentExpression[?in,?yield]
|
||||
// 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield]
|
||||
// 4) ArrowFunctionExpression[?in,?yield]
|
||||
// 5) [+Yield] YieldExpression[?In]
|
||||
// 5) AsyncArrowFunctionExpression[in,yield,await]
|
||||
// 6) [+Yield] YieldExpression[?In]
|
||||
//
|
||||
// Note: for ease of implementation we treat productions '2' and '3' as the same thing.
|
||||
// (i.e. they're both BinaryExpressions with an assignment operator in it).
|
||||
@ -2695,11 +2696,18 @@ namespace ts {
|
||||
return parseYieldExpression();
|
||||
}
|
||||
|
||||
// Then, check if we have an arrow function (production '4') that starts with a parenthesized
|
||||
// parameter list. If we do, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
|
||||
// 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.
|
||||
// AsyncArrowFunctionExpression:
|
||||
// 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
|
||||
// 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
|
||||
// Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".
|
||||
// And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
|
||||
//
|
||||
// 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.
|
||||
const arrowExpression = tryParseParenthesizedArrowFunctionExpression();
|
||||
const arrowExpression = tryParseParenthesizedArrowFunctionExpression() || tryParseAsyncSimpleArrowFunctionExpression();
|
||||
if (arrowExpression) {
|
||||
return arrowExpression;
|
||||
}
|
||||
@ -2791,10 +2799,17 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function parseSimpleArrowFunctionExpression(identifier: Identifier): Expression {
|
||||
function parseSimpleArrowFunctionExpression(identifier: Identifier, asyncModifier?: ModifiersArray): ArrowFunction {
|
||||
Debug.assert(token === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>");
|
||||
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, identifier.pos);
|
||||
let node: ArrowFunction;
|
||||
if (asyncModifier) {
|
||||
node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, asyncModifier.pos);
|
||||
setModifiers(node, asyncModifier);
|
||||
}
|
||||
else {
|
||||
node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, identifier.pos);
|
||||
}
|
||||
|
||||
const parameter = <ParameterDeclaration>createNode(SyntaxKind.Parameter, identifier.pos);
|
||||
parameter.name = identifier;
|
||||
@ -2805,7 +2820,7 @@ namespace ts {
|
||||
node.parameters.end = parameter.end;
|
||||
|
||||
node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>");
|
||||
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ false);
|
||||
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier);
|
||||
|
||||
return finishNode(node);
|
||||
}
|
||||
@ -2973,6 +2988,32 @@ namespace ts {
|
||||
return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false);
|
||||
}
|
||||
|
||||
function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction {
|
||||
const isUnParenthesizedAsyncArrowFunction = lookAhead(isUnParenthesizedAsyncArrowFunctionWorker);
|
||||
if (isUnParenthesizedAsyncArrowFunction === Tristate.True) {
|
||||
const asyncModifier = parseModifiersForArrowFunction();
|
||||
const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0);
|
||||
return parseSimpleArrowFunctionExpression(<Identifier>expr, asyncModifier);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate {
|
||||
if (token === SyntaxKind.AsyncKeyword) {
|
||||
nextToken();
|
||||
if (scanner.hasPrecedingLineBreak()) {
|
||||
return Tristate.False;
|
||||
}
|
||||
// Check for un-parenthesized AsyncArrowFunction
|
||||
const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0);
|
||||
if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token === SyntaxKind.EqualsGreaterThanToken) {
|
||||
return Tristate.True;
|
||||
}
|
||||
}
|
||||
|
||||
return Tristate.False;
|
||||
}
|
||||
|
||||
function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction);
|
||||
setModifiers(node, parseModifiersForArrowFunction());
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
//// [asyncUnParenthesizedArrowFunction_es6.ts]
|
||||
|
||||
declare function someOtherFunction(i: any): Promise<void>;
|
||||
const x = async i => await someOtherFunction(i)
|
||||
const x1 = async (i) => await someOtherFunction(i);
|
||||
|
||||
//// [asyncUnParenthesizedArrowFunction_es6.js]
|
||||
const x = (i) => __awaiter(this, void 0, void 0, function* () { return yield someOtherFunction(i); });
|
||||
const x1 = (i) => __awaiter(this, void 0, void 0, function* () { return yield someOtherFunction(i); });
|
||||
@ -0,0 +1,19 @@
|
||||
=== tests/cases/conformance/async/es6/asyncArrowFunction/asyncUnParenthesizedArrowFunction_es6.ts ===
|
||||
|
||||
declare function someOtherFunction(i: any): Promise<void>;
|
||||
>someOtherFunction : Symbol(someOtherFunction, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 0, 0))
|
||||
>i : Symbol(i, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 1, 35))
|
||||
>Promise : Symbol(Promise, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
|
||||
|
||||
const x = async i => await someOtherFunction(i)
|
||||
>x : Symbol(x, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 2, 5))
|
||||
>i : Symbol(i, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 2, 15))
|
||||
>someOtherFunction : Symbol(someOtherFunction, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 0, 0))
|
||||
>i : Symbol(i, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 2, 15))
|
||||
|
||||
const x1 = async (i) => await someOtherFunction(i);
|
||||
>x1 : Symbol(x1, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 3, 5))
|
||||
>i : Symbol(i, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 3, 18))
|
||||
>someOtherFunction : Symbol(someOtherFunction, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 0, 0))
|
||||
>i : Symbol(i, Decl(asyncUnParenthesizedArrowFunction_es6.ts, 3, 18))
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
=== tests/cases/conformance/async/es6/asyncArrowFunction/asyncUnParenthesizedArrowFunction_es6.ts ===
|
||||
|
||||
declare function someOtherFunction(i: any): Promise<void>;
|
||||
>someOtherFunction : (i: any) => Promise<void>
|
||||
>i : any
|
||||
>Promise : Promise<T>
|
||||
|
||||
const x = async i => await someOtherFunction(i)
|
||||
>x : (i: any) => Promise<void>
|
||||
>async i => await someOtherFunction(i) : (i: any) => Promise<void>
|
||||
>i : any
|
||||
>await someOtherFunction(i) : void
|
||||
>someOtherFunction(i) : Promise<void>
|
||||
>someOtherFunction : (i: any) => Promise<void>
|
||||
>i : any
|
||||
|
||||
const x1 = async (i) => await someOtherFunction(i);
|
||||
>x1 : (i: any) => Promise<void>
|
||||
>async (i) => await someOtherFunction(i) : (i: any) => Promise<void>
|
||||
>i : any
|
||||
>await someOtherFunction(i) : void
|
||||
>someOtherFunction(i) : Promise<void>
|
||||
>someOtherFunction : (i: any) => Promise<void>
|
||||
>i : any
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
// @target: ES6
|
||||
// @noEmitHelpers: true
|
||||
|
||||
declare function someOtherFunction(i: any): Promise<void>;
|
||||
const x = async i => await someOtherFunction(i)
|
||||
const x1 = async (i) => await someOtherFunction(i);
|
||||
Loading…
x
Reference in New Issue
Block a user