| 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 02bee28ffd2e7a27d90d854c873a7754b8e2dd98..81ced1ac698c110ed1707340a35e180645f9432d 100644 | 
| --- a/pkg/front_end/lib/src/fasta/parser/parser.dart | 
| +++ b/pkg/front_end/lib/src/fasta/parser/parser.dart | 
| @@ -180,6 +180,29 @@ enum Assert { | 
| Statement, | 
| } | 
|  | 
| +/// Indication of how the parser should continue after (attempting) to parse a | 
| +/// type. | 
| +/// | 
| +/// Depending on the continuation, the parser may not parse a type at all. | 
| +enum TypeContinuation { | 
| +  /// Indicates that a type is unconditionally expected. | 
| +  Required, | 
| + | 
| +  /// Indicates that a type may follow. If the following matches one of these | 
| +  /// productions, it is parsed as a type: | 
| +  /// | 
| +  ///  - `'void'` | 
| +  ///  - `'Function' ( '(' | '<' )` | 
| +  ///  - `identifier ('.' identifier)? ('<' ... '>')? identifer` | 
| +  /// | 
| +  /// Otherwise, do nothing. | 
| +  Optional, | 
| + | 
| +  /// Indicates that the keyword `typedef` has just been seen, and the parser | 
| +  /// should parse the following as a type unless it is followed by `=`. | 
| +  Typedef, | 
| +} | 
| + | 
| /// An event generating parser of Dart programs. This parser expects all tokens | 
| /// in a linked list (aka a token stream). | 
| /// | 
| @@ -615,14 +638,15 @@ class Parser { | 
| Token typedefKeyword = token; | 
| listener.beginFunctionTypeAlias(token); | 
| Token equals; | 
| -    if (optional('=', peekAfterNominalType(token.next))) { | 
| +    Token afterType = parseType(token.next, TypeContinuation.Typedef); | 
| +    if (afterType == null) { | 
| token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); | 
| token = parseTypeVariablesOpt(token); | 
| equals = token; | 
| token = expect('=', token); | 
| token = parseType(token); | 
| } else { | 
| -      token = parseType(token.next, isOptional: true); | 
| +      token = afterType; | 
| token = parseIdentifier(token, IdentifierContext.typedefDeclaration); | 
| token = parseTypeVariablesOpt(token); | 
| token = parseFormalParameters(token, MemberKind.FunctionTypeAlias); | 
| @@ -968,40 +992,28 @@ class Parser { | 
| } | 
|  | 
| Token parseClassOrNamedMixinApplication(Token token) { | 
| +    listener.beginClassOrNamedMixinApplication(token); | 
| Token begin = token; | 
| -    Token abstractKeyword; | 
| -    Token classKeyword = token; | 
| if (optional('abstract', token)) { | 
| -      abstractKeyword = token; | 
| -      token = token.next; | 
| -      classKeyword = token; | 
| -    } | 
| -    assert(optional('class', classKeyword)); | 
| -    int modifierCount = 0; | 
| -    if (abstractKeyword != null) { | 
| -      parseModifier(abstractKeyword); | 
| -      modifierCount++; | 
| -    } | 
| -    listener.handleModifiers(modifierCount); | 
| -    bool isMixinApplication = optional('=', peekAfterNominalType(token)); | 
| -    Token name = token.next; | 
| - | 
| -    if (isMixinApplication) { | 
| -      token = parseIdentifier(name, IdentifierContext.namedMixinDeclaration); | 
| -      listener.beginNamedMixinApplication(begin, name); | 
| +      token = parseModifier(token); | 
| +      listener.handleModifiers(1); | 
| } else { | 
| -      token = parseIdentifier(name, IdentifierContext.classDeclaration); | 
| -      listener.beginClassDeclaration(begin, name); | 
| +      listener.handleModifiers(0); | 
| } | 
| - | 
| +    Token classKeyword = token; | 
| +    token = expect("class", token); | 
| +    Token name = token; | 
| +    token = | 
| +        parseIdentifier(name, IdentifierContext.classOrNamedMixinDeclaration); | 
| token = parseTypeVariablesOpt(token); | 
| - | 
| if (optional('=', token)) { | 
| +      listener.beginNamedMixinApplication(begin, name); | 
| Token equals = token; | 
| token = token.next; | 
| return parseNamedMixinApplication( | 
| token, begin, classKeyword, name, equals); | 
| } else { | 
| +      listener.beginClassDeclaration(begin, name); | 
| return parseClass(token, begin, classKeyword, name); | 
| } | 
| } | 
| @@ -1139,9 +1151,21 @@ class Parser { | 
| (optional('<', token.next) || optional('(', token.next)); | 
| } | 
|  | 
| -  Token parseType(Token token, {bool isOptional: false}) { | 
| -    if (isOptional) { | 
| -      do { | 
| +  /// Parse a type, if it is appropriate to do so. | 
| +  /// | 
| +  /// If this method can parse a type, it will return the next (non-null) token | 
| +  /// after the type. Otherwise, it returns null. | 
| +  Token parseType(Token token, | 
| +      [TypeContinuation continuation = TypeContinuation.Required]) { | 
| +    switch (continuation) { | 
| +      case TypeContinuation.Typedef: | 
| +        if (optional('=', peekAfterNominalType(token))) { | 
| +          return null; // This isn't a type, it's a new-style typedef. | 
| +        } | 
| +        continue optional; | 
| + | 
| +      optional: | 
| +      case TypeContinuation.Optional: | 
| if (optional("void", token)) { | 
| if (isGeneralizedFunctionType(token.next)) { | 
| // This is a type, parse it. | 
| @@ -1164,7 +1188,13 @@ class Parser { | 
| listener.handleNoType(token); | 
| return token; | 
| } | 
| -      } while (false); | 
| +        break; | 
| + | 
| +      case TypeContinuation.Required: | 
| +        break; | 
| + | 
| +      default: | 
| +        throw "Internal error: Unhandled continuation '$continuation'."; | 
| } | 
| Token begin = token; | 
| if (isGeneralizedFunctionType(token)) { | 
| @@ -1399,7 +1429,7 @@ class Parser { | 
| if (type == null) { | 
| listener.handleNoType(name); | 
| } else { | 
| -      parseType(type, isOptional: true); | 
| +      parseType(type, TypeContinuation.Optional); | 
| } | 
| Token token = | 
| parseIdentifier(name, IdentifierContext.topLevelFunctionDeclaration); | 
| @@ -1799,7 +1829,11 @@ class Parser { | 
| listener.handleModifiers(count); | 
|  | 
| Token beforeType = token; | 
| -    token = parseType(token, isOptional: returnTypeAllowed || !typeRequired); | 
| +    token = parseType( | 
| +        token, | 
| +        returnTypeAllowed || !typeRequired | 
| +            ? TypeContinuation.Optional | 
| +            : TypeContinuation.Required); | 
| if (typeRequired && beforeType == token) { | 
| reportRecoverableErrorCode(token, codeTypeRequired); | 
| } | 
| @@ -2104,7 +2138,7 @@ class Parser { | 
| if (type == null) { | 
| listener.handleNoType(name); | 
| } else { | 
| -      parseType(type, isOptional: true); | 
| +      parseType(type, TypeContinuation.Optional); | 
| } | 
| Token token; | 
| if (optional('operator', name)) { | 
| @@ -2238,7 +2272,7 @@ class Parser { | 
| Token beginToken = token; | 
| listener.beginFunction(token); | 
| listener.handleModifiers(0); | 
| -    token = parseType(token, isOptional: true); | 
| +    token = parseType(token, TypeContinuation.Optional); | 
| listener.beginFunctionName(token); | 
| token = parseIdentifier(token, IdentifierContext.functionExpressionName); | 
| listener.endFunctionName(beginToken, token); | 
|  |