Index: pkg/analyzer/lib/src/generated/parser.dart |
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart |
index 26ee60613be6b5055b1191e563a1bf34cab90f24..ea555a569a305cacc769e3b6a14d38730087a094 100644 |
--- a/pkg/analyzer/lib/src/generated/parser.dart |
+++ b/pkg/analyzer/lib/src/generated/parser.dart |
@@ -1234,9 +1234,19 @@ class Parser { |
CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
Modifiers modifiers = parseModifiers(); |
Keyword keyword = _currentToken.keyword; |
- if (keyword == Keyword.VOID) { |
- TypeName returnType = astFactory.typeName( |
- astFactory.simpleIdentifier(getAndAdvance()), null); |
+ if (keyword == Keyword.VOID || |
+ _atGenericFunctionTypeAfterReturnType(_currentToken)) { |
+ TypeAnnotation returnType; |
+ if (keyword == Keyword.VOID) { |
+ if (_atGenericFunctionTypeAfterReturnType(_peek())) { |
+ returnType = parseTypeAnnotation(false); |
+ } else { |
+ returnType = astFactory.typeName( |
+ astFactory.simpleIdentifier(getAndAdvance()), null); |
+ } |
+ } else { |
+ returnType = parseTypeAnnotation(false); |
+ } |
keyword = _currentToken.keyword; |
Token next = _peek(); |
bool isFollowedByIdentifier = _tokenMatchesIdentifier(next); |
@@ -2031,9 +2041,19 @@ class Parser { |
} else if (keyword == Keyword.ENUM) { |
_validateModifiersForEnum(modifiers); |
return parseEnumDeclaration(commentAndMetadata); |
- } else if (keyword == Keyword.VOID) { |
- TypeName returnType = astFactory.typeName( |
- astFactory.simpleIdentifier(getAndAdvance()), null); |
+ } else if (keyword == Keyword.VOID || |
+ _atGenericFunctionTypeAfterReturnType(_currentToken)) { |
+ TypeAnnotation returnType; |
+ if (keyword == Keyword.VOID) { |
+ if (_atGenericFunctionTypeAfterReturnType(next)) { |
+ returnType = parseTypeAnnotation(false); |
+ } else { |
+ returnType = astFactory.typeName( |
+ astFactory.simpleIdentifier(getAndAdvance()), null); |
+ } |
+ } else { |
+ returnType = parseTypeAnnotation(false); |
+ } |
keyword = _currentToken.keyword; |
next = _peek(); |
if ((keyword == Keyword.GET || keyword == Keyword.SET) && |
@@ -4019,8 +4039,13 @@ class Parser { |
return parseVariableDeclarationStatementAfterMetadata( |
commentAndMetadata); |
} else if (keyword == Keyword.VOID) { |
- TypeName returnType = astFactory.typeName( |
- astFactory.simpleIdentifier(getAndAdvance()), null); |
+ TypeAnnotation returnType; |
+ if (_atGenericFunctionTypeAfterReturnType(_peek())) { |
+ returnType = parseTypeAnnotation(false); |
+ } else { |
+ returnType = astFactory.typeName( |
+ astFactory.simpleIdentifier(getAndAdvance()), null); |
+ } |
Token next = _currentToken.next; |
if (_matchesIdentifier() && |
next.matchesAny(const <TokenType>[ |
@@ -4101,6 +4126,48 @@ class Parser { |
return astFactory |
.emptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); |
} |
+ } else if (_atGenericFunctionTypeAfterReturnType(_currentToken)) { |
+ TypeAnnotation returnType = parseTypeAnnotation(false); |
+ Token next = _currentToken.next; |
+ if (_matchesIdentifier() && |
+ next.matchesAny(const <TokenType>[ |
+ TokenType.OPEN_PAREN, |
+ TokenType.OPEN_CURLY_BRACKET, |
+ TokenType.FUNCTION, |
+ TokenType.LT |
+ ])) { |
+ return _parseFunctionDeclarationStatementAfterReturnType( |
+ commentAndMetadata, returnType); |
+ } else { |
+ // |
+ // We have found an error of some kind. Try to recover. |
+ // |
+ if (_matchesIdentifier()) { |
+ if (next.matchesAny(const <TokenType>[ |
+ TokenType.EQ, |
+ TokenType.COMMA, |
+ TokenType.SEMICOLON |
+ ])) { |
+ // |
+ // We appear to have a variable declaration with a type of "void". |
+ // |
+ _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); |
+ return parseVariableDeclarationStatementAfterMetadata( |
+ commentAndMetadata); |
+ } |
+ } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
+ // |
+ // We appear to have found an incomplete statement at the end of a |
+ // block. Parse it as a variable declaration. |
+ // |
+ return _parseVariableDeclarationStatementAfterType( |
+ commentAndMetadata, null, returnType); |
+ } |
+ _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); |
+ // TODO(brianwilkerson) Recover from this error. |
+ return astFactory |
+ .emptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); |
+ } |
} else if (_inGenerator && _matchesKeyword(Keyword.YIELD)) { |
return parseYieldStatement(); |
} else if (_inAsync && _matchesKeyword(Keyword.AWAIT)) { |
@@ -4618,8 +4685,12 @@ class Parser { |
*/ |
TypeAnnotation parseReturnType(bool inExpression) { |
if (_currentToken.keyword == Keyword.VOID) { |
- return astFactory.typeName( |
- astFactory.simpleIdentifier(getAndAdvance()), null); |
+ if (_atGenericFunctionTypeAfterReturnType(_peek())) { |
+ return parseTypeAnnotation(false); |
+ } else { |
+ return astFactory.typeName( |
+ astFactory.simpleIdentifier(getAndAdvance()), null); |
+ } |
} else { |
return parseTypeAnnotation(inExpression); |
} |
@@ -5480,6 +5551,9 @@ class Parser { |
*/ |
Token skipReturnType(Token startToken) { |
if (_tokenMatchesKeyword(startToken, Keyword.VOID)) { |
+ if (_atGenericFunctionTypeAfterReturnType(_peek())) { |
+ return skipTypeAnnotation(startToken); |
+ } |
return startToken.next; |
} else { |
return skipTypeAnnotation(startToken); |
@@ -7148,6 +7222,9 @@ class Parser { |
} |
Keyword keyword = _currentToken.keyword; |
if (keyword == Keyword.VOID) { |
+ if (_atGenericFunctionTypeAfterReturnType(_peek())) { |
+ return parseTypeAnnotation(false); |
+ } |
return astFactory.typeName( |
astFactory.simpleIdentifier(getAndAdvance()), null); |
} else if (_matchesIdentifier()) { |