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 8ff84bbd67275d6faad324a2b93e364b48d592c8..c2c49517661540064ba3c8df8283d1b95682ef98 100644 |
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart |
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart |
@@ -1176,14 +1176,8 @@ class Parser { |
} |
if (looksLikeType && token.isIdentifier) { |
- // If the identifier token has a type substitution comment /*=T*/, |
- // then the set of tokens type tokens should be replaced with the |
- // tokens parsed from the comment. |
Token afterId = token.next; |
- begin = |
- listener.replaceTokenWithGenericCommentTypeAssign(begin, token); |
ahe
2017/07/21 16:02:19
This has already been called when we analyze the t
|
- |
int afterIdKind = afterId.kind; |
if (looksLikeVariableDeclarationEnd(afterIdKind)) { |
// We are looking at `type identifier` followed by |
@@ -1197,18 +1191,44 @@ class Parser { |
if (looksLikeFunctionBody(closeBraceTokenFor(afterId).next)) { |
// We are looking at `type identifier '(' ... ')'` followed |
// `( '{' | '=>' | 'async' | 'sync' )`. |
- return parseLocalFunctionDeclaration(begin); |
+ |
+ // Although it looks like there are no type variables here, they |
+ // may get injected from a comment. |
+ Token formals = parseTypeVariablesOpt(afterId); |
+ |
+ listener.beginLocalFunctionDeclaration(begin); |
+ listener.handleModifiers(0); |
+ if (voidToken != null) { |
+ listener.handleVoidKeyword(voidToken); |
+ } else { |
+ commitType(); |
+ } |
+ listener.beginFunctionName(token); |
+ token = parseIdentifier( |
+ token, IdentifierContext.localFunctionDeclaration); |
+ listener.endFunctionName(begin, token); |
+ return parseLocalFunctionDeclarationFromFormals(formals); |
} |
} else if (identical(afterIdKind, LT_TOKEN)) { |
// We are looking at `type identifier '<'`. |
- Token afterTypeVariables = closeBraceTokenFor(afterId)?.next; |
- if (afterTypeVariables != null && |
- optional("(", afterTypeVariables)) { |
- if (looksLikeFunctionBody( |
- closeBraceTokenFor(afterTypeVariables).next)) { |
+ Token formals = closeBraceTokenFor(afterId)?.next; |
+ if (formals != null && optional("(", formals)) { |
+ if (looksLikeFunctionBody(closeBraceTokenFor(formals).next)) { |
// We are looking at "type identifier '<' ... '>' '(' ... ')'" |
// followed by '{', '=>', 'async', or 'sync'. |
- return parseLocalFunctionDeclaration(begin); |
+ parseTypeVariablesOpt(afterId); |
+ listener.beginLocalFunctionDeclaration(begin); |
+ listener.handleModifiers(0); |
+ if (voidToken != null) { |
+ listener.handleVoidKeyword(voidToken); |
+ } else { |
+ commitType(); |
+ } |
+ listener.beginFunctionName(token); |
+ token = parseIdentifier( |
+ token, IdentifierContext.localFunctionDeclaration); |
+ listener.endFunctionName(begin, token); |
+ return parseLocalFunctionDeclarationFromFormals(formals); |
} |
} |
} |
@@ -1219,7 +1239,21 @@ class Parser { |
return parseLabeledStatement(token); |
} else if (optional('(', token.next)) { |
if (looksLikeFunctionBody(closeBraceTokenFor(token.next).next)) { |
- return parseLocalFunctionDeclaration(token); |
+ // We are looking at `identifier '(' ... ')'` followed by `'{'`, |
+ // `'=>'`, `'async'`, or `'sync'`. |
+ |
+ // Although it looks like there are no type variables here, they |
+ // may get injected from a comment. |
+ Token formals = parseTypeVariablesOpt(token.next); |
+ |
+ listener.beginLocalFunctionDeclaration(token); |
+ listener.handleModifiers(0); |
+ listener.handleNoType(token); |
+ listener.beginFunctionName(token); |
+ token = parseIdentifier( |
+ token, IdentifierContext.localFunctionDeclaration); |
+ listener.endFunctionName(begin, token); |
+ return parseLocalFunctionDeclarationFromFormals(formals); |
} |
} else if (optional('<', token.next)) { |
Token afterTypeVariables = closeBraceTokenFor(token.next)?.next; |
@@ -1227,7 +1261,18 @@ class Parser { |
optional("(", afterTypeVariables)) { |
if (looksLikeFunctionBody( |
closeBraceTokenFor(afterTypeVariables).next)) { |
- return parseLocalFunctionDeclaration(token); |
+ // We are looking at `identifier '<' ... '>' '(' ... ')'` |
+ // followed by `'{'`, `'=>'`, `'async'`, or `'sync'`. |
+ parseTypeVariablesOpt(token.next); |
+ listener.beginLocalFunctionDeclaration(token); |
+ listener.handleModifiers(0); |
+ listener.handleNoType(token); |
+ listener.beginFunctionName(token); |
danrubel
2017/07/21 17:11:20
From this line down to the return statement looks
ahe
2017/08/07 11:45:27
You inspired me to go a bit further, and I decided
|
+ token = parseIdentifier( |
+ token, IdentifierContext.localFunctionDeclaration); |
+ listener.endFunctionName(begin, token); |
+ return parseLocalFunctionDeclarationFromFormals( |
+ afterTypeVariables); |
} |
} |
// Fall through to expression statement. |
@@ -2335,16 +2380,17 @@ class Parser { |
return isBlock ? token.next : token; |
} |
- Token parseLocalFunctionDeclaration(Token token) { |
- listener.beginLocalFunctionDeclaration(token); |
- Token beginToken = token; |
- token = parseModifiers(token, MemberKind.Local); |
- listener.beginFunctionName(token); |
- token = parseIdentifier(token, IdentifierContext.localFunctionDeclaration); |
- token = parseQualifiedRestOpt( |
- token, IdentifierContext.localFunctionDeclarationContinuation); |
- listener.endFunctionName(beginToken, token); |
- token = parseTypeVariablesOpt(token); |
+ /// Parses the rest of a local function declaration starting from formal |
+ /// parameters. |
+ /// |
+ /// Precondition: the parser has previously generated these events: |
+ /// |
+ /// - Type variables. |
+ /// - beginLocalFunctionDeclaration. |
+ /// - Modifiers. |
+ /// - Return type. |
+ /// - Function name. |
+ Token parseLocalFunctionDeclarationFromFormals(Token token) { |
token = parseFormalParametersOpt(token, MemberKind.Local); |
token = parseInitializersOpt(token); |
AsyncModifier savedAsyncModifier = asyncState; |