mirror of
https://github.com/dart-lang/sdk
synced 2024-09-21 07:31:32 +00:00
Fix parsing of generic function types as return types
R=scheglov@google.com Review-Url: https://codereview.chromium.org/2809773005 .
This commit is contained in:
parent
7b5010d440
commit
492eab84ec
|
@ -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()) {
|
||||
|
|
|
@ -10040,6 +10040,26 @@ class SimpleParserTest extends ParserTestCase {
|
|||
expect(arguments, hasLength(3));
|
||||
}
|
||||
|
||||
void test_parseClassMember_method_gftReturnType() {
|
||||
createParser('''
|
||||
void Function<A>(core.List<core.int> x) m() => null;
|
||||
''');
|
||||
ClassMember member = parser.parseClassMember('C');
|
||||
expect(member, new isInstanceOf<MethodDeclaration>());
|
||||
expect((member as MethodDeclaration).body,
|
||||
new isInstanceOf<ExpressionFunctionBody>());
|
||||
}
|
||||
|
||||
void test_parseClassMember_method_noReturnType() {
|
||||
createParser('''
|
||||
Function<A>(core.List<core.int> x) m() => null;
|
||||
''');
|
||||
ClassMember member = parser.parseClassMember('C');
|
||||
expect(member, new isInstanceOf<MethodDeclaration>());
|
||||
expect((member as MethodDeclaration).body,
|
||||
new isInstanceOf<ExpressionFunctionBody>());
|
||||
}
|
||||
|
||||
void test_parseCombinator_hide() {
|
||||
createParser('hide a;');
|
||||
Combinator combinator = parser.parseCombinator();
|
||||
|
@ -10640,6 +10660,24 @@ void''');
|
|||
expect(reference.offset, 15);
|
||||
}
|
||||
|
||||
void test_parseCompilationUnitMember_function_gftReturnType() {
|
||||
createParser('''
|
||||
void Function<A>(core.List<core.int> x) f() => null;
|
||||
''');
|
||||
CompilationUnit unit = parser.parseCompilationUnit2();
|
||||
expect(unit, isNotNull);
|
||||
expect(unit.declarations, hasLength(1));
|
||||
}
|
||||
|
||||
void test_parseCompilationUnitMember_function_noReturnType() {
|
||||
createParser('''
|
||||
Function<A>(core.List<core.int> x) f() => null;
|
||||
''');
|
||||
CompilationUnit unit = parser.parseCompilationUnit2();
|
||||
expect(unit, isNotNull);
|
||||
expect(unit.declarations, hasLength(1));
|
||||
}
|
||||
|
||||
void test_parseConfiguration_noOperator_dottedIdentifier() {
|
||||
createParser("if (a.b) 'c.dart'");
|
||||
Configuration configuration = parser.parseConfiguration();
|
||||
|
@ -11303,6 +11341,34 @@ void''');
|
|||
expect(typeName.typeArguments, isNull);
|
||||
}
|
||||
|
||||
void test_parseStatement_function_gftReturnType() {
|
||||
createParser('''
|
||||
void Function<A>(core.List<core.int> x) m() => null;
|
||||
''');
|
||||
Statement statement = parser.parseStatement2();
|
||||
expect(statement, new isInstanceOf<FunctionDeclarationStatement>());
|
||||
expect(
|
||||
(statement as FunctionDeclarationStatement)
|
||||
.functionDeclaration
|
||||
.functionExpression
|
||||
.body,
|
||||
new isInstanceOf<ExpressionFunctionBody>());
|
||||
}
|
||||
|
||||
void test_parseStatement_function_noReturnType() {
|
||||
createParser('''
|
||||
Function<A>(core.List<core.int> x) m() => null;
|
||||
''');
|
||||
Statement statement = parser.parseStatement2();
|
||||
expect(statement, new isInstanceOf<FunctionDeclarationStatement>());
|
||||
expect(
|
||||
(statement as FunctionDeclarationStatement)
|
||||
.functionDeclaration
|
||||
.functionExpression
|
||||
.body,
|
||||
new isInstanceOf<ExpressionFunctionBody>());
|
||||
}
|
||||
|
||||
void test_parseStatements_multiple() {
|
||||
List<Statement> statements = parseStatements("return; return;", 2);
|
||||
expect(statements, hasLength(2));
|
||||
|
|
Loading…
Reference in a new issue