Index: pkg/dart_parser/lib/src/parser.dart |
diff --git a/pkg/dart_parser/lib/src/parser.dart b/pkg/dart_parser/lib/src/parser.dart |
index c578bff6250f27e407b53d1d94cb39bfe5e4947f..12b020295a6dc29583c4aeb99bf97c93aee3dfe5 100644 |
--- a/pkg/dart_parser/lib/src/parser.dart |
+++ b/pkg/dart_parser/lib/src/parser.dart |
@@ -115,11 +115,7 @@ class Parser { |
bool asyncAwaitKeywordsEnabled; |
- final bool enableGenericMethodSyntax; |
- |
- Parser(this.listener, |
- {this.asyncAwaitKeywordsEnabled: false, |
- this.enableGenericMethodSyntax: false}); |
+ Parser(this.listener, {this.asyncAwaitKeywordsEnabled: false}); |
Token parseUnit(Token token) { |
listener.beginCompilationUnit(token); |
@@ -383,30 +379,12 @@ class Parser { |
Token parseTypedef(Token token) { |
Token typedefKeyword = token; |
- if (optional('=', peekAfterType(token.next))) { |
- // TODO(aprelev@gmail.com): Remove deprecated 'typedef' mixin application, |
- // remove corresponding diagnostic from members.dart. |
- listener.beginNamedMixinApplication(token); |
- token = parseIdentifier(token.next); |
- token = parseTypeVariablesOpt(token); |
- token = expect('=', token); |
- token = parseModifiers(token); |
- token = parseMixinApplication(token); |
- Token implementsKeyword = null; |
- if (optional('implements', token)) { |
- implementsKeyword = token; |
- token = parseTypeList(token.next); |
- } |
- listener.endNamedMixinApplication( |
- typedefKeyword, implementsKeyword, token); |
- } else { |
- listener.beginFunctionTypeAlias(token); |
- token = parseReturnTypeOpt(token.next); |
- token = parseIdentifier(token); |
- token = parseTypeVariablesOpt(token); |
- token = parseFormalParameters(token); |
- listener.endFunctionTypeAlias(typedefKeyword, token); |
- } |
+ listener.beginFunctionTypeAlias(token); |
+ token = parseReturnTypeOpt(token.next); |
+ token = parseIdentifier(token); |
+ token = parseTypeVariablesOpt(token); |
+ token = parseFormalParameters(token); |
+ listener.endFunctionTypeAlias(typedefKeyword, token); |
return expect(';', token); |
} |
@@ -465,6 +443,15 @@ class Parser { |
Token parseFormalParameter(Token token, FormalParameterType type) { |
token = parseMetadataStar(token, forParameter: true); |
listener.beginFormalParameter(token); |
+ |
+ // Skip over `covariant` token, if the next token is an identifier or |
+ // modifier. |
+ // This enables the case where `covariant` is the name of the parameter: |
+ // void foo(covariant); |
+ if (identical(token.stringValue, 'covariant') && |
+ (token.next.isIdentifier() || isModifier(token.next))) { |
+ token = token.next; |
+ } |
token = parseModifiers(token); |
// TODO(ahe): Validate that there are formal parameters if void. |
token = parseReturnTypeOpt(token); |
@@ -481,7 +468,7 @@ class Parser { |
listener.handleNoTypeVariables(token); |
token = parseFormalParameters(token); |
listener.handleFunctionTypedFormalParameter(token); |
- } else if (enableGenericMethodSyntax && optional('<', token)) { |
+ } else if (optional('<', token)) { |
listener.beginFunctionTypedFormalParameter(token); |
token = parseTypeVariablesOpt(token); |
token = parseFormalParameters(token); |
@@ -600,7 +587,7 @@ class Parser { |
/// Returns token after match if [token] matches identifier ('.' identifier)?, |
/// and otherwise returns null. Does not produce listener events. |
Token tryParseQualified(Token token) { |
- if (!identical(token.kind, IDENTIFIER_TOKEN)) return null; |
+ if (!isValidTypeReference(token)) return null; |
token = token.next; |
if (!identical(token.kind, PERIOD_TOKEN)) return token; |
token = token.next; |
@@ -705,17 +692,10 @@ class Parser { |
var isMixinApplication = optional('=', peekAfterType(token.next)); |
if (isMixinApplication) { |
listener.beginNamedMixinApplication(begin); |
- token = parseIdentifier(token.next); |
- token = parseTypeVariablesOpt(token); |
- token = expect('=', token); |
} else { |
listener.beginClassDeclaration(begin); |
} |
- // TODO(aprelev@gmail.com): Once 'typedef' named mixin application is |
- // removed, move modifiers for named mixin application to the bottom of |
- // listener stack. This is so stacks for class declaration and named |
- // mixin application look similar. |
int modifierCount = 0; |
if (abstractKeyword != null) { |
parseModifier(abstractKeyword); |
@@ -724,6 +704,9 @@ class Parser { |
listener.handleModifiers(modifierCount); |
if (isMixinApplication) { |
+ token = parseIdentifier(token.next); |
+ token = parseTypeVariablesOpt(token); |
+ token = expect('=', token); |
return parseNamedMixinApplication(token, classKeyword); |
} else { |
return parseClass(begin, classKeyword); |
@@ -799,8 +782,7 @@ class Parser { |
listener.beginTypeVariable(token); |
token = parseIdentifier(token); |
Token extendsOrSuper = null; |
- if (optional('extends', token) || |
- (enableGenericMethodSyntax && optional('super', token))) { |
+ if (optional('extends', token) || optional('super', token)) { |
extendsOrSuper = token; |
token = parseType(token.next); |
} else { |
@@ -1027,9 +1009,29 @@ class Parser { |
return null; |
} |
+ /// Removes the optional `covariant` token from the modifiers, if there |
+ /// is no `static` in the list, and `covariant` is the first modifier. |
+ Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) { |
+ if (modifiers.isEmpty || |
+ !identical(modifiers.first.stringValue, 'covariant')) { |
+ return modifiers; |
+ } |
+ for (Token modifier in modifiers.tail) { |
+ if (identical(modifier.stringValue, 'static')) { |
+ return modifiers; |
+ } |
+ } |
+ return modifiers.tail; |
+ } |
+ |
Token parseFields(Token start, Link<Token> modifiers, Token type, |
Token getOrSet, Token name, bool isTopLevel) { |
bool hasType = type != null; |
+ |
+ if (getOrSet == null && !isTopLevel) { |
+ modifiers = removeOptCovariantTokenIfNotStatic(modifiers); |
+ } |
+ |
Token varFinalOrConst = |
expectVarFinalOrConst(modifiers, hasType, !isTopLevel); |
bool isVar = false; |
@@ -1108,7 +1110,7 @@ class Parser { |
} |
Token token = parseIdentifier(name); |
- if (enableGenericMethodSyntax && getOrSet == null) { |
+ if (getOrSet == null) { |
token = parseTypeVariablesOpt(token); |
} else { |
listener.handleNoTypeVariables(token); |
@@ -1393,7 +1395,7 @@ class Parser { |
if (isFactoryDeclaration(token)) { |
token = parseFactoryMethod(token); |
listener.endMember(); |
- assert (token != null); |
+ assert(token != null); |
return token; |
} |
@@ -1440,7 +1442,7 @@ class Parser { |
(identical(value, '.')) || |
(identical(value, '{')) || |
(identical(value, '=>')) || |
- (enableGenericMethodSyntax && identical(value, '<'))) { |
+ (identical(value, '<'))) { |
isField = false; |
break; |
} else if (identical(value, ';')) { |
@@ -1535,7 +1537,7 @@ class Parser { |
} |
token = parseQualifiedRestOpt(token); |
- if (enableGenericMethodSyntax && getOrSet == null) { |
+ if (getOrSet == null) { |
token = parseTypeVariablesOpt(token); |
} else { |
listener.handleNoTypeVariables(token); |
@@ -1626,7 +1628,7 @@ class Parser { |
} |
token = parseQualifiedRestOpt(token); |
listener.endFunctionName(token); |
- if (enableGenericMethodSyntax && getOrSet == null) { |
+ if (getOrSet == null) { |
token = parseTypeVariablesOpt(token); |
} else { |
listener.handleNoTypeVariables(token); |
@@ -1671,11 +1673,7 @@ class Parser { |
listener.beginFunctionName(token); |
token = parseIdentifier(token); |
listener.endFunctionName(token); |
- if (enableGenericMethodSyntax) { |
- token = parseTypeVariablesOpt(token); |
- } else { |
- listener.handleNoTypeVariables(token); |
- } |
+ token = parseTypeVariablesOpt(token); |
token = parseFormalParameters(token); |
listener.handleNoInitializers(); |
bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
@@ -1951,8 +1949,7 @@ class Parser { |
// by '{', '=>', 'async', or 'sync'. |
return parseFunctionDeclaration(token); |
} |
- } else if (enableGenericMethodSyntax && |
- identical(afterIdKind, LT_TOKEN)) { |
+ } else if (identical(afterIdKind, LT_TOKEN)) { |
// We are looking at "type identifier '<'". |
BeginGroupToken beginAngle = afterId; |
Token endAngle = beginAngle.endGroup; |
@@ -1987,7 +1984,7 @@ class Parser { |
identical(afterParens, 'sync')) { |
return parseFunctionDeclaration(token); |
} |
- } else if (enableGenericMethodSyntax && optional('<', token.next)) { |
+ } else if (optional('<', token.next)) { |
BeginGroupToken beginAngle = token.next; |
Token endAngle = beginAngle.endGroup; |
if (endAngle != null && |
@@ -2501,8 +2498,7 @@ class Parser { |
Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) { |
assert(optional('<', token)); |
BeginGroupToken begin = token; |
- if (enableGenericMethodSyntax && |
- constKeyword == null && |
+ if (constKeyword == null && |
begin.endGroup != null && |
identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) { |
token = parseTypeVariablesOpt(token); |
@@ -2545,7 +2541,7 @@ class Parser { |
} |
bool isFunctionDeclaration(Token token) { |
- if (enableGenericMethodSyntax && optional('<', token)) { |
+ if (optional('<', token)) { |
BeginGroupToken begin = token; |
if (begin.endGroup == null) return false; |
token = begin.endGroup.next; |
@@ -2694,7 +2690,7 @@ class Parser { |
Token parseSend(Token token) { |
listener.beginSend(token); |
token = parseIdentifier(token); |
- if (enableGenericMethodSyntax && isValidMethodTypeArguments(token)) { |
+ if (isValidMethodTypeArguments(token)) { |
token = parseTypeArgumentsOpt(token); |
} else { |
listener.handleNoTypeArguments(token); |