| Index: pkg/front_end/lib/src/fasta/parser/parser.dart
|
| diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
|
| index c2c49517661540064ba3c8df8283d1b95682ef98..695981294cb8538d0d51dcc91d8163122f69bebc 100644
|
| --- a/pkg/front_end/lib/src/fasta/parser/parser.dart
|
| +++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
|
| @@ -1203,11 +1203,7 @@ class Parser {
|
| } else {
|
| commitType();
|
| }
|
| - listener.beginFunctionName(token);
|
| - token = parseIdentifier(
|
| - token, IdentifierContext.localFunctionDeclaration);
|
| - listener.endFunctionName(begin, token);
|
| - return parseLocalFunctionDeclarationFromFormals(formals);
|
| + return parseLocalFunctionDeclarationRest(begin, token, formals);
|
| }
|
| } else if (identical(afterIdKind, LT_TOKEN)) {
|
| // We are looking at `type identifier '<'`.
|
| @@ -1224,11 +1220,7 @@ class Parser {
|
| } else {
|
| commitType();
|
| }
|
| - listener.beginFunctionName(token);
|
| - token = parseIdentifier(
|
| - token, IdentifierContext.localFunctionDeclaration);
|
| - listener.endFunctionName(begin, token);
|
| - return parseLocalFunctionDeclarationFromFormals(formals);
|
| + return parseLocalFunctionDeclarationRest(begin, token, formals);
|
| }
|
| }
|
| }
|
| @@ -1249,11 +1241,7 @@ class Parser {
|
| listener.beginLocalFunctionDeclaration(token);
|
| listener.handleModifiers(0);
|
| listener.handleNoType(token);
|
| - listener.beginFunctionName(token);
|
| - token = parseIdentifier(
|
| - token, IdentifierContext.localFunctionDeclaration);
|
| - listener.endFunctionName(begin, token);
|
| - return parseLocalFunctionDeclarationFromFormals(formals);
|
| + return parseLocalFunctionDeclarationRest(begin, token, formals);
|
| }
|
| } else if (optional('<', token.next)) {
|
| Token afterTypeVariables = closeBraceTokenFor(token.next)?.next;
|
| @@ -1267,12 +1255,8 @@ class Parser {
|
| listener.beginLocalFunctionDeclaration(token);
|
| listener.handleModifiers(0);
|
| listener.handleNoType(token);
|
| - listener.beginFunctionName(token);
|
| - token = parseIdentifier(
|
| - token, IdentifierContext.localFunctionDeclaration);
|
| - listener.endFunctionName(begin, token);
|
| - return parseLocalFunctionDeclarationFromFormals(
|
| - afterTypeVariables);
|
| + return parseLocalFunctionDeclarationRest(
|
| + begin, token, afterTypeVariables);
|
| }
|
| }
|
| // Fall through to expression statement.
|
| @@ -2371,17 +2355,14 @@ class Parser {
|
| Token beginToken = token;
|
| listener.beginFunctionExpression(token);
|
| token = parseFormalParameters(token, MemberKind.Local);
|
| - AsyncModifier savedAsyncModifier = asyncState;
|
| - token = parseAsyncModifier(token);
|
| - bool isBlock = optional('{', token);
|
| - token = parseFunctionBody(token, true, false);
|
| - asyncState = savedAsyncModifier;
|
| + token = parseAsyncOptBody(token, true, false);
|
| listener.endFunctionExpression(beginToken, token);
|
| - return isBlock ? token.next : token;
|
| + return token;
|
| }
|
|
|
| - /// Parses the rest of a local function declaration starting from formal
|
| - /// parameters.
|
| + /// Parses the rest of a local function declaration starting from its [name]
|
| + /// but then skips any type parameters and continue parsing from [formals]
|
| + /// (the formal parameters).
|
| ///
|
| /// Precondition: the parser has previously generated these events:
|
| ///
|
| @@ -2389,17 +2370,17 @@ class Parser {
|
| /// - beginLocalFunctionDeclaration.
|
| /// - Modifiers.
|
| /// - Return type.
|
| - /// - Function name.
|
| - Token parseLocalFunctionDeclarationFromFormals(Token token) {
|
| - token = parseFormalParametersOpt(token, MemberKind.Local);
|
| + Token parseLocalFunctionDeclarationRest(
|
| + Token begin, Token name, Token formals) {
|
| + Token token = name;
|
| + listener.beginFunctionName(token);
|
| + token = parseIdentifier(token, IdentifierContext.localFunctionDeclaration);
|
| + listener.endFunctionName(begin, token);
|
| + token = parseFormalParametersOpt(formals, MemberKind.Local);
|
| token = parseInitializersOpt(token);
|
| - AsyncModifier savedAsyncModifier = asyncState;
|
| - token = parseAsyncModifier(token);
|
| - token = parseFunctionBody(token, false, true);
|
| - asyncState = savedAsyncModifier;
|
| - token = token.next;
|
| + token = parseAsyncOptBody(token, false, false);
|
| listener.endLocalFunctionDeclaration(token);
|
| - return token;
|
| + return token.next;
|
| }
|
|
|
| /// Parses a named function expression which isn't legal syntax in Dart.
|
| @@ -2422,13 +2403,24 @@ class Parser {
|
| token = parseTypeVariablesOpt(token);
|
| token = parseFormalParameters(token, MemberKind.Local);
|
| listener.handleNoInitializers();
|
| + token = parseAsyncOptBody(token, true, false);
|
| + listener.endNamedFunctionExpression(token);
|
| + return token;
|
| + }
|
| +
|
| + /// Parses a function body optionally preceded by an async modifier (see
|
| + /// [parseAsyncModifier]). This method is used in both expression context
|
| + /// (when [isExpression] is true) and statement context. In statement context
|
| + /// (when [isExpression] is false), and if the function body is on the form
|
| + /// `=> expression`, a trailing semicolon is required.
|
| + ///
|
| + /// It's an error if there's no function body unless [allowAbstract] is true.
|
| + Token parseAsyncOptBody(Token token, bool isExpression, bool allowAbstract) {
|
| AsyncModifier savedAsyncModifier = asyncState;
|
| token = parseAsyncModifier(token);
|
| - bool isBlock = optional('{', token);
|
| - token = parseFunctionBody(token, true, false);
|
| + token = parseFunctionBody(token, isExpression, allowAbstract);
|
| asyncState = savedAsyncModifier;
|
| - listener.endNamedFunctionExpression(token);
|
| - return isBlock ? token.next : token;
|
| + return token;
|
| }
|
|
|
| Token parseConstructorReference(Token token) {
|
| @@ -2489,6 +2481,12 @@ class Parser {
|
| return token;
|
| }
|
|
|
| + /// Parses a function body. This method is used in both expression context
|
| + /// (when [isExpression] is true) and statement context. In statement context
|
| + /// (when [isExpression] is false), and if the function body is on the form
|
| + /// `=> expression`, a trailing semicolon is required.
|
| + ///
|
| + /// It's an error if there's no function body unless [allowAbstract] is true.
|
| Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
|
| if (optional(';', token)) {
|
| if (!allowAbstract) {
|
| @@ -2537,7 +2535,7 @@ class Parser {
|
| }
|
| listener.endBlockFunctionBody(statementCount, begin, token);
|
| expect('}', token);
|
| - return token;
|
| + return isExpression ? token.next : token;
|
| }
|
|
|
| Token skipAsyncModifier(Token token) {
|
|
|