Revise order of type variable declaration events

As of this CL, events for type variable declarations occur
in the following order:

* beginTypeVariables
* beginTypeVariable for each type variable in the declaration
* handleTypeVariablesDefined
* endTypeVariable for eah type variable in the declaration
* endTypeVariables

Revising the order of events facilitate removing the hack
in BodyBuilder.beginTypeVariables in a future CL.

This is another slice of https://dart-review.googlesource.com/c/sdk/+/57661
so that it can be landed in a more incremental fashion.

Change-Id: Ief0ad766c12f1ca9d53a8ec8d3c08b41166b2897
Reviewed-on: https://dart-review.googlesource.com/61940
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 54f5982..097764a 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2166,35 +2166,44 @@
   }
 
   @override
-  void beginTypeVariable(Token name) {
+  void beginTypeVariable(Token token) {
     debugEvent("beginTypeVariable");
+    SimpleIdentifier name = pop();
+    List<Annotation> metadata = pop();
+
+    Comment comment = _findComment(metadata, name.beginToken);
+    push(ast.typeParameter(comment, metadata, name, null, null));
   }
 
   @override
-  void endTypeVariable(Token token, Token extendsOrSuper) {
-    // TODO(paulberry): set up scopes properly to resolve parameters and type
-    // variables.  Note that this is tricky due to the handling of initializers
-    // in constructors, so the logic should be shared with BodyBuilder as much
-    // as possible.
+  void handleTypeVariablesDefined(Token token, int count) {
+    debugEvent("handleTypeVariablesDefined");
+    assert(count > 0);
+    push(popTypedList(count, new List<TypeParameter>(count)));
+  }
+
+  @override
+  void endTypeVariable(Token token, int index, Token extendsOrSuper) {
+    debugEvent("TypeVariable");
     assert(extendsOrSuper == null ||
         optional('extends', extendsOrSuper) ||
         optional('super', extendsOrSuper));
-    debugEvent("TypeVariable");
-
     TypeAnnotation bound = pop();
-    SimpleIdentifier name = pop();
-    List<Annotation> metadata = pop();
-    Comment comment = _findComment(metadata, name.beginToken);
-    push(ast.typeParameter(comment, metadata, name, extendsOrSuper, bound));
+
+    // Peek to leave type parameters on top of stack.
+    List<TypeParameter> typeParameters = peek();
+    typeParameters[index]
+      ..extendsKeyword = extendsOrSuper
+      ..bound = bound;
   }
 
   @override
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
+  void endTypeVariables(Token beginToken, Token endToken) {
     assert(optional('<', beginToken));
     assert(optional('>', endToken));
     debugEvent("TypeVariables");
 
-    List<TypeParameter> typeParameters = popTypedList(count);
+    List<TypeParameter> typeParameters = pop();
     push(ast.typeParameterList(beginToken, typeParameters, endToken));
   }
 
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index a341ce7..9697a3c 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -508,8 +508,8 @@
   }
 
   @override
-  void beginTypeVariable(Token name) {
-    super.beginTypeVariable(name);
+  void beginTypeVariable(Token token) {
+    super.beginTypeVariable(token);
     begin('TypeVariable');
   }
 
@@ -1037,15 +1037,15 @@
   }
 
   @override
-  void endTypeVariable(Token token, Token extendsOrSuper) {
+  void endTypeVariable(Token token, int index, Token extendsOrSuper) {
     end('TypeVariable');
-    super.endTypeVariable(token, extendsOrSuper);
+    super.endTypeVariable(token, index, extendsOrSuper);
   }
 
   @override
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
+  void endTypeVariables(Token beginToken, Token endToken) {
     end('TypeVariables');
-    super.endTypeVariables(count, beginToken, endToken);
+    super.endTypeVariables(beginToken, endToken);
   }
 
   @override
@@ -1169,4 +1169,9 @@
     expectIn('CompilationUnit');
     listener.handleScript(token);
   }
+
+  @override
+  void handleTypeVariablesDefined(Token token, int count) {
+    listener.handleTypeVariablesDefined(token, count);
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index da8635e..b4f7c02 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -3641,6 +3641,11 @@
   @override
   void beginTypeVariables(Token token) {
     debugEvent("beginTypeVariables");
+
+    // TODO(danrubel): Now that the type variable events have been reordered,
+    // we should be able to cleanup body builder type variable declaration
+    // handling and remove this hack.
+
     OutlineBuilder listener = new OutlineBuilder(library);
     // TODO(dmitryas):  [ClassMemberParser] shouldn't be used to parse and build
     // the type variables for the local function.  It also causes the unresolved
@@ -3664,23 +3669,11 @@
   }
 
   @override
-  void beginTypeVariable(Token name) {
+  void beginTypeVariable(Token token) {
     debugEvent("beginTypeVariable");
-  }
-
-  @override
-  void handleNoTypeVariables(Token token) {
-    debugEvent("NoTypeVariables");
-    enterFunctionTypeScope(null);
-    push(NullValue.TypeVariables);
-  }
-
-  @override
-  void endTypeVariable(Token token, Token extendsOrSuper) {
-    debugEvent("TypeVariable");
-    DartType bound = pop();
     Identifier name = pop();
     List<Expression> annotations = pop();
+
     KernelTypeVariableBuilder variable;
     Object inScope = scopeLookup(scope, name.name, token);
     if (inScope is TypeUseGenerator) {
@@ -3692,7 +3685,6 @@
       variable = new KernelTypeVariableBuilder(
           name.name, library, offsetForToken(name.token), null);
     }
-    variable.parameter.bound = bound;
     if (annotations != null) {
       _typeInferrer.inferMetadata(this, factory, annotations);
       for (Expression annotation in annotations) {
@@ -3703,39 +3695,66 @@
   }
 
   @override
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
+  void handleTypeVariablesDefined(Token token, int count) {
+    debugEvent("handleTypeVariablesDefined");
+    assert(count > 0);
+    List<KernelTypeVariableBuilder> typeVariables =
+        popList(count, new List<KernelTypeVariableBuilder>(count));
+
+    // TODO(danrubel): Call enterFunctionScope here
+    // once the hack in beginTypeVariables has been removed.
+    //enterFunctionTypeScope(typeVariables);
+    push(typeVariables);
+  }
+
+  @override
+  void endTypeVariable(Token token, int index, Token extendsOrSuper) {
+    debugEvent("TypeVariable");
+    DartType bound = pop();
+    // Peek to leave type parameters on top of stack.
+    List<KernelTypeVariableBuilder> typeVariables = peek();
+
+    KernelTypeVariableBuilder variable = typeVariables[index];
+    variable.parameter.bound = bound;
+  }
+
+  @override
+  void endTypeVariables(Token beginToken, Token endToken) {
     debugEvent("TypeVariables");
-    List<KernelTypeVariableBuilder> typeVariables = popList(
-        count,
-        new List<KernelTypeVariableBuilder>.filled(count, null,
-            growable: true));
-    if (typeVariables != null) {
-      if (library.loader.target.strongMode) {
-        List<KernelTypeBuilder> calculatedBounds = calculateBounds(
-            typeVariables,
-            library.loader.target.dynamicType,
-            library.loader.target.bottomType,
-            library.loader.target.objectClassBuilder);
-        for (int i = 0; i < typeVariables.length; ++i) {
-          typeVariables[i].defaultType = calculatedBounds[i];
-          typeVariables[i].defaultType.resolveIn(scope,
-              typeVariables[i].charOffset, typeVariables[i].fileUri, library);
-          typeVariables[i].finish(
-              library,
-              library.loader.target.objectClassBuilder,
-              library.loader.target.dynamicType);
-        }
-      } else {
-        for (int i = 0; i < typeVariables.length; ++i) {
-          typeVariables[i].defaultType = library.loader.target.dynamicType;
-          typeVariables[i].finish(
-              library,
-              library.loader.target.objectClassBuilder,
-              library.loader.target.dynamicType);
-        }
+    // Peek to leave type parameters on top of stack.
+    List<KernelTypeVariableBuilder> typeVariables = peek();
+
+    if (library.loader.target.strongMode) {
+      List<KernelTypeBuilder> calculatedBounds = calculateBounds(
+          typeVariables,
+          library.loader.target.dynamicType,
+          library.loader.target.bottomType,
+          library.loader.target.objectClassBuilder);
+      for (int i = 0; i < typeVariables.length; ++i) {
+        typeVariables[i].defaultType = calculatedBounds[i];
+        typeVariables[i].defaultType.resolveIn(scope,
+            typeVariables[i].charOffset, typeVariables[i].fileUri, library);
+        typeVariables[i].finish(
+            library,
+            library.loader.target.objectClassBuilder,
+            library.loader.target.dynamicType);
+      }
+    } else {
+      for (int i = 0; i < typeVariables.length; ++i) {
+        typeVariables[i].defaultType = library.loader.target.dynamicType;
+        typeVariables[i].finish(
+            library,
+            library.loader.target.objectClassBuilder,
+            library.loader.target.dynamicType);
       }
     }
-    push(typeVariables ?? NullValue.TypeVariables);
+  }
+
+  @override
+  void handleNoTypeVariables(Token token) {
+    debugEvent("NoTypeVariables");
+    enterFunctionTypeScope(null);
+    push(NullValue.TypeVariables);
   }
 
   List<TypeParameter> typeVariableBuildersToKernel(
diff --git a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
index 0abc7d3..a9d32fe 100644
--- a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
@@ -392,8 +392,8 @@
   }
 
   @override
-  void beginTypeVariable(Token name) {
-    listener?.beginTypeVariable(name);
+  void beginTypeVariable(Token token) {
+    listener?.beginTypeVariable(token);
   }
 
   @override
@@ -842,13 +842,13 @@
   }
 
   @override
-  void endTypeVariable(Token token, Token extendsOrSuper) {
-    listener?.endTypeVariable(token, extendsOrSuper);
+  void endTypeVariable(Token token, int index, Token extendsOrSuper) {
+    listener?.endTypeVariable(token, index, extendsOrSuper);
   }
 
   @override
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
-    listener?.endTypeVariables(count, beginToken, endToken);
+  void endTypeVariables(Token beginToken, Token endToken) {
+    listener?.endTypeVariables(beginToken, endToken);
   }
 
   @override
@@ -1285,6 +1285,11 @@
   }
 
   @override
+  void handleTypeVariablesDefined(Token token, int count) {
+    listener?.handleTypeVariablesDefined(token, count);
+  }
+
+  @override
   void handleUnaryPostfixAssignmentExpression(Token token) {
     listener?.handleUnaryPostfixAssignmentExpression(token);
   }
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
index b75076e..40995c9 100644
--- a/pkg/front_end/lib/src/fasta/parser/listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -904,20 +904,28 @@
   /// Substructures:
   /// - Metadata
   /// - Name (identifier)
-  void beginTypeVariable(Token name) {}
+  void beginTypeVariable(Token token) {}
 
-  /// Handle the end of a type formal parameter (e.g. "X extends Y").
+  /// Called when [beginTypeVariable] has been called for all of the variables
+  /// in a group, and before [endTypeVariable] has been called for any of the
+  /// variables in that same group.
+  void handleTypeVariablesDefined(Token token, int count) {}
+
+  /// Handle the end of a type formal parameter (e.g. "X extends Y")
+  /// where [index] is the index of the type variable in the list of
+  /// type variables being declared.
+  ///
   /// Substructures:
   /// - Type bound
   ///
   /// See [beginTypeVariable] for additional substructures.
-  void endTypeVariable(Token token, Token extendsOrSuper) {
+  void endTypeVariable(Token token, int index, Token extendsOrSuper) {
     logEvent("TypeVariable");
   }
 
   void beginTypeVariables(Token token) {}
 
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
+  void endTypeVariables(Token beginToken, Token endToken) {
     logEvent("TypeVariables");
   }
 
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
index 66c4fb2..9a1a945 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
@@ -513,10 +513,11 @@
     listener.endMetadataStar(0);
     listener.handleIdentifier(token, IdentifierContext.typeVariableDeclaration);
     listener.beginTypeVariable(token);
+    listener.handleTypeVariablesDefined(token, 1);
     listener.handleNoType(token);
     token = processEndGroup(token, start, parser);
-    listener.endTypeVariable(token, null);
-    listener.endTypeVariables(1, start, token);
+    listener.endTypeVariable(token, 0, null);
+    listener.endTypeVariables(start, token);
     return token;
   }
 
@@ -654,25 +655,32 @@
   @override
   Token parseVariables(Token token, Parser parser) {
     Token next = start;
-    parser.listener.beginTypeVariables(start);
+    Listener listener = parser.listener;
+    listener.beginTypeVariables(start);
     Token innerEndGroup = processBeginGroup(start, parser);
     int count = 0;
+
+    Link<Token> typeStarts = const Link<Token>();
+    Link<TypeInfo> superTypeInfos = const Link<TypeInfo>();
+
     while (true) {
       token = parser.parseMetadataStar(next);
       token = parser.ensureIdentifier(
           token, IdentifierContext.typeVariableDeclaration);
-      parser.listener.beginTypeVariable(token);
-      Token extendsOrSuper = null;
+      listener.beginTypeVariable(token);
+      typeStarts = typeStarts.prepend(token);
+
       next = token.next;
       if (optional('extends', next) || optional('super', next)) {
-        extendsOrSuper = next;
-        token = computeType(next, true, inDeclaration, innerEndGroup)
-            .ensureTypeOrVoid(next, parser);
+        TypeInfo typeInfo =
+            computeType(next, true, inDeclaration, innerEndGroup);
+        token = typeInfo.skipType(next);
         next = token.next;
+        superTypeInfos = superTypeInfos.prepend(typeInfo);
       } else {
-        parser.listener.handleNoType(token);
+        superTypeInfos = superTypeInfos.prepend(null);
       }
-      parser.listener.endTypeVariable(next, extendsOrSuper);
+
       ++count;
       if (!optional(',', next)) {
         if (!looksLikeTypeParamOrArg(inDeclaration, next)) {
@@ -688,8 +696,39 @@
             .next;
       }
     }
+
+    assert(count > 0);
+    assert(typeStarts.slowLength() == count);
+    assert(superTypeInfos.slowLength() == count);
+    listener.handleTypeVariablesDefined(token, count);
+
+    token = null;
+    while (typeStarts.isNotEmpty) {
+      Token token2 = typeStarts.head;
+      TypeInfo typeInfo = superTypeInfos.head;
+
+      Token extendsOrSuper = null;
+      Token next2 = token2.next;
+      if (typeInfo != null) {
+        assert(optional('extends', next2) || optional('super', next2));
+        extendsOrSuper = next2;
+        token2 = typeInfo.ensureTypeOrVoid(next2, parser);
+        next2 = token2.next;
+      } else {
+        assert(!optional('extends', next2) && !optional('super', next2));
+        listener.handleNoType(token2);
+      }
+      // Type variables are "completed" in reverse order, so capture the last
+      // consumed token from the first "completed" type variable.
+      token ??= token2;
+      listener.endTypeVariable(next2, --count, extendsOrSuper);
+
+      typeStarts = typeStarts.tail;
+      superTypeInfos = superTypeInfos.tail;
+    }
+
     end = processEndGroup(token, start, parser);
-    parser.listener.endTypeVariables(count, start, end);
+    listener.endTypeVariables(start, end);
     return end;
   }
 
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 961ebe3..722435f 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -447,13 +447,18 @@
   }
 
   @override
-  void endTypeVariable(Token token, Token extendsOrSuper) {
-    debugEvent("TypeVariable");
+  void beginTypeVariable(Token token) {
+    debugEvent("beginTypeVariable");
     discard(2); // Name and metadata.
   }
 
   @override
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
+  void endTypeVariable(Token token, int index, Token extendsOrSuper) {
+    debugEvent("endTypeVariable");
+  }
+
+  @override
+  void endTypeVariables(Token beginToken, Token endToken) {
     debugEvent("TypeVariables");
   }
 
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 316c66a..5fe18f8 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -80,8 +80,7 @@
     show
         KernelFormalParameterBuilder,
         KernelNamedTypeBuilder,
-        KernelTypeBuilder,
-        KernelTypeVariableBuilder;
+        KernelTypeBuilder;
 
 enum MethodBody {
   Abstract,
@@ -819,21 +818,6 @@
   }
 
   @override
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
-    debugEvent("TypeVariables");
-    push(popList(
-            count,
-            new List<KernelTypeVariableBuilder>.filled(count, null,
-                growable: true)) ??
-        NullValue.TypeVariables);
-    if (inConstructorName) {
-      addProblem(messageConstructorWithTypeParameters,
-          offsetForToken(beginToken), lengthOfSpan(beginToken, endToken));
-      inConstructorName = false;
-    }
-  }
-
-  @override
   void handleNoTypeVariables(Token token) {
     super.handleNoTypeVariables(token);
     inConstructorName = false;
@@ -1122,18 +1106,41 @@
   @override
   void beginTypeVariable(Token token) {
     debugEvent("beginTypeVariable");
-  }
-
-  @override
-  void endTypeVariable(Token token, Token extendsOrSuper) {
-    debugEvent("endTypeVariable");
-    TypeBuilder bound = pop();
     int charOffset = pop();
     String name = pop();
     // TODO(paulberry): type variable metadata should not be ignored.  See
     // dartbug.com/28981.
     /* List<MetadataBuilder> metadata = */ pop();
-    push(library.addTypeVariable(name, bound, charOffset));
+
+    push(library.addTypeVariable(name, null, charOffset));
+  }
+
+  @override
+  void handleTypeVariablesDefined(Token token, int count) {
+    debugEvent("TypeVariablesDefined");
+    assert(count > 0);
+    push(popList(count, new List<TypeVariableBuilder>(count)));
+  }
+
+  @override
+  void endTypeVariable(Token token, int index, Token extendsOrSuper) {
+    debugEvent("endTypeVariable");
+    TypeBuilder bound = pop();
+    // Peek to leave type parameters on top of stack.
+    List typeParameters = peek();
+
+    typeParameters[index].bound = bound;
+  }
+
+  @override
+  void endTypeVariables(Token beginToken, Token endToken) {
+    debugEvent("endTypeVariables");
+
+    if (inConstructorName) {
+      addProblem(messageConstructorWithTypeParameters,
+          offsetForToken(beginToken), lengthOfSpan(beginToken, endToken));
+      inConstructorName = false;
+    }
   }
 
   @override
diff --git a/pkg/front_end/test/fasta/parser/type_info_test.dart b/pkg/front_end/test/fasta/parser/type_info_test.dart
index bf26a57..6cde453 100644
--- a/pkg/front_end/test/fasta/parser/type_info_test.dart
+++ b/pkg/front_end/test/fasta/parser/type_info_test.dart
@@ -285,9 +285,10 @@
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined T 1',
       'handleNoType T',
-      'endTypeVariable > null',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 null',
+      'endTypeVariables < >',
       'beginFunctionType Function',
       'handleNoType ',
       'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
@@ -307,7 +308,7 @@
       'handleType int )',
       'handleNoName )',
       'handleFormalParameterWithoutValue )',
-      'beginTypeVariables null null ) FormalParameterKind.mandatory '
+      'endFormalParameter null null ) FormalParameterKind.mandatory '
           'MemberKind.GeneralizedFunctionType',
       'endFormalParameters 1 ( ) MemberKind.GeneralizedFunctionType',
       'endFunctionType Function m',
@@ -318,9 +319,10 @@
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined T 1',
       'handleNoType T',
-      'endTypeVariable > null',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 null',
+      'endTypeVariables < >',
       'beginFunctionType Function',
       'handleNoType ',
       'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
@@ -332,7 +334,7 @@
       'handleType int )',
       'handleNoName )',
       'handleFormalParameterWithoutValue )',
-      'beginTypeVariables null null ) FormalParameterKind.mandatory'
+      'endFormalParameter null null ) FormalParameterKind.mandatory'
           ' MemberKind.GeneralizedFunctionType',
       'endFormalParameters 1 ( ) MemberKind.GeneralizedFunctionType',
       'endFunctionType Function m',
@@ -687,18 +689,20 @@
           'endMetadataStar 0',
           'handleIdentifier T typeVariableDeclaration',
           'beginTypeVariable T',
+          'handleTypeVariablesDefined T 1',
           'handleNoType T',
-          'endTypeVariable > null',
-          'endTypeVariables 1 < >',
+          'endTypeVariable > 0 null',
+          'endTypeVariables < >',
           'beginFunctionType C',
           'beginTypeVariables <',
           'beginMetadataStar T',
           'endMetadataStar 0',
           'handleIdentifier T typeVariableDeclaration',
           'beginTypeVariable T',
+          'handleTypeVariablesDefined T 1',
           'handleNoType T',
-          'endTypeVariable > null',
-          'endTypeVariables 1 < >',
+          'endTypeVariable > 0 null',
+          'endTypeVariables < >',
           'beginFunctionType C',
           'handleIdentifier C prefixedTypeReference',
           'handleIdentifier a typeReferenceContinuation',
@@ -718,7 +722,7 @@
           'handleType int x',
           'handleIdentifier x formalParameterDeclaration',
           'handleFormalParameterWithoutValue )',
-          'beginTypeVariables null null x FormalParameterKind.mandatory '
+          'endFormalParameter null null x FormalParameterKind.mandatory '
               'MemberKind.GeneralizedFunctionType',
           'endFormalParameters 1 ( ) MemberKind.GeneralizedFunctionType',
           'endFunctionType Function Function',
@@ -731,7 +735,7 @@
           'handleType int x',
           'handleIdentifier x formalParameterDeclaration',
           'handleFormalParameterWithoutValue )',
-          'beginTypeVariables null null x FormalParameterKind.mandatory '
+          'endFormalParameter null null x FormalParameterKind.mandatory '
               'MemberKind.GeneralizedFunctionType',
           'endFormalParameters 1 ( ) MemberKind.GeneralizedFunctionType',
           'endFunctionType Function ',
@@ -866,9 +870,10 @@
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined T 1',
       'handleNoType T',
-      'endTypeVariable > null',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 null',
+      'endTypeVariables < >',
     ]);
     expect(listener.errors, isNull);
   }
@@ -1044,15 +1049,16 @@
       'endMetadataStar 0',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
-      'handleNoType S',
-      'endTypeVariable , null',
       'beginMetadataStar T',
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined T 2',
       'handleNoType T',
-      'endTypeVariable > null',
-      'endTypeVariables 2 < >',
+      'endTypeVariable > 1 null',
+      'handleNoType S',
+      'endTypeVariable , 0 null',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<S extends T>', expectedCalls: [
       'beginTypeVariables <',
@@ -1060,11 +1066,12 @@
       'endMetadataStar 0',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
+      'handleTypeVariablesDefined T 1',
       'handleIdentifier T typeReference',
       'handleNoTypeArguments >',
       'handleType T >',
-      'endTypeVariable > extends',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 extends',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<S super T>', expectedCalls: [
       'beginTypeVariables <',
@@ -1072,11 +1079,12 @@
       'endMetadataStar 0',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
+      'handleTypeVariablesDefined T 1',
       'handleIdentifier T typeReference',
       'handleNoTypeArguments >',
       'handleType T >',
-      'endTypeVariable > super',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 super',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<S extends List<T>>', expectedCalls: [
       'beginTypeVariables <',
@@ -1084,6 +1092,7 @@
       'endMetadataStar 0',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
+      'handleTypeVariablesDefined > 1',
       'handleIdentifier List typeReference',
       'beginTypeArguments <',
       'handleIdentifier T typeReference',
@@ -1091,8 +1100,8 @@
       'handleType T >',
       'endTypeArguments 1 < >',
       'handleType List >',
-      'endTypeVariable > extends',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 extends',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<R, S extends void Function()>', expectedCalls: [
       'beginTypeVariables <',
@@ -1100,20 +1109,21 @@
       'endMetadataStar 0',
       'handleIdentifier R typeVariableDeclaration',
       'beginTypeVariable R',
-      'handleNoType R',
-      'endTypeVariable , null',
       'beginMetadataStar S',
       'endMetadataStar 0',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
+      'handleTypeVariablesDefined ) 2',
       'handleNoTypeVariables (',
       'beginFunctionType void',
       'handleVoidKeyword void',
       'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
       'endFormalParameters 0 ( ) MemberKind.GeneralizedFunctionType',
       'endFunctionType Function >',
-      'endTypeVariable > extends',
-      'endTypeVariables 2 < >',
+      'endTypeVariable > 1 extends',
+      'handleNoType R',
+      'endTypeVariable , 0 null',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<@A S,T>', expectedCalls: [
       'beginTypeVariables <',
@@ -1126,15 +1136,16 @@
       'endMetadataStar 1',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
-      'handleNoType S',
-      'endTypeVariable , null',
       'beginMetadataStar T',
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined T 2',
       'handleNoType T',
-      'endTypeVariable > null',
-      'endTypeVariables 2 < >',
+      'endTypeVariable > 1 null',
+      'handleNoType S',
+      'endTypeVariable , 0 null',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<@A() S,T>', expectedCalls: [
       'beginTypeVariables <',
@@ -1148,15 +1159,16 @@
       'endMetadataStar 1',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
-      'handleNoType S',
-      'endTypeVariable , null',
       'beginMetadataStar T',
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined T 2',
       'handleNoType T',
-      'endTypeVariable > null',
-      'endTypeVariables 2 < >',
+      'endTypeVariable > 1 null',
+      'handleNoType S',
+      'endTypeVariable , 0 null',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<@A() @B S,T>', expectedCalls: [
       'beginTypeVariables <',
@@ -1175,15 +1187,16 @@
       'endMetadataStar 2',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
-      'handleNoType S',
-      'endTypeVariable , null',
       'beginMetadataStar T',
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined T 2',
       'handleNoType T',
-      'endTypeVariable > null',
-      'endTypeVariables 2 < >',
+      'endTypeVariable > 1 null',
+      'handleNoType S',
+      'endTypeVariable , 0 null',
+      'endTypeVariables < >',
     ]);
   }
 
@@ -1196,9 +1209,10 @@
       'endMetadataStar 0',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
+      'handleTypeVariablesDefined S 1',
       'handleNoType S',
-      'endTypeVariable Function null',
-      'endTypeVariables 1 < >',
+      'endTypeVariable Function 0 null',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<void Function()>', expectedErrors: [
       error(codeExpectedIdentifier, 1, 4),
@@ -1209,9 +1223,10 @@
       'endMetadataStar 0',
       'handleIdentifier  typeVariableDeclaration',
       'beginTypeVariable ',
+      'handleTypeVariablesDefined  1',
       'handleNoType ',
-      'endTypeVariable void null',
-      'endTypeVariables 1 < >',
+      'endTypeVariable void 0 null',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<S<T>>', expectedErrors: [
       error(codeUnexpectedToken, 2, 1),
@@ -1221,9 +1236,10 @@
       'endMetadataStar 0',
       'handleIdentifier S typeVariableDeclaration',
       'beginTypeVariable S',
+      'handleTypeVariablesDefined S 1',
       'handleNoType S',
-      'endTypeVariable < null',
-      'endTypeVariables 1 < >',
+      'endTypeVariable < 0 null',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<S T>', inDeclaration: true, expectedErrors: [
       error(codeExpectedButGot, 3, 1),
@@ -1242,6 +1258,7 @@
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined > 1',
       'handleIdentifier Comparable typeReference',
       'beginTypeArguments <',
       'handleIdentifier T typeReference',
@@ -1249,8 +1266,8 @@
       'handleType T >',
       'endTypeArguments 1 < >',
       'handleType Comparable >',
-      'endTypeVariable > extends',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 extends',
+      'endTypeVariables < >',
     ]);
     expectComplexTypeParam('<T extends Comparable<S>, S>', expectedCalls: [
       'beginTypeVariables <',
@@ -1258,6 +1275,13 @@
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'beginMetadataStar S',
+      'endMetadataStar 0',
+      'handleIdentifier S typeVariableDeclaration',
+      'beginTypeVariable S',
+      'handleTypeVariablesDefined S 2',
+      'handleNoType S',
+      'endTypeVariable > 1 null',
       'handleIdentifier Comparable typeReference',
       'beginTypeArguments <',
       'handleIdentifier S typeReference',
@@ -1265,14 +1289,8 @@
       'handleType S >',
       'endTypeArguments 1 < >',
       'handleType Comparable ,',
-      'endTypeVariable , extends',
-      'beginMetadataStar S',
-      'endMetadataStar 0',
-      'handleIdentifier S typeVariableDeclaration',
-      'beginTypeVariable S',
-      'handleNoType S',
-      'endTypeVariable > null',
-      'endTypeVariables 2 < >',
+      'endTypeVariable , 0 extends',
+      'endTypeVariables < >'
     ]);
     expectComplexTypeParam('<T extends Function(T)>', expectedCalls: [
       'beginTypeVariables <',
@@ -1280,6 +1298,7 @@
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined ) 1',
       'handleNoTypeVariables (',
       'beginFunctionType Function',
       'handleNoType extends',
@@ -1292,11 +1311,11 @@
       'handleType T )',
       'handleNoName )',
       'handleFormalParameterWithoutValue )',
-      'beginTypeVariables null null ) FormalParameterKind.mandatory MemberKind.GeneralizedFunctionType',
+      'endFormalParameter null null ) FormalParameterKind.mandatory MemberKind.GeneralizedFunctionType',
       'endFormalParameters 1 ( ) MemberKind.GeneralizedFunctionType',
       'endFunctionType Function >',
-      'endTypeVariable > extends',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 extends',
+      'endTypeVariables < >'
     ]);
     expectComplexTypeParam('<T extends List<List<T>>>', expectedCalls: [
       'beginTypeVariables <',
@@ -1304,6 +1323,7 @@
       'endMetadataStar 0',
       'handleIdentifier T typeVariableDeclaration',
       'beginTypeVariable T',
+      'handleTypeVariablesDefined >> 1',
       'handleIdentifier List typeReference',
       'beginTypeArguments <',
       'handleIdentifier List typeReference',
@@ -1315,8 +1335,8 @@
       'handleType List >',
       'endTypeArguments 1 < >',
       'handleType List >',
-      'endTypeVariable > extends',
-      'endTypeVariables 1 < >',
+      'endTypeVariable > 0 extends',
+      'endTypeVariables < >'
     ]);
   }
 }
@@ -1564,8 +1584,8 @@
   }
 
   @override
-  void beginTypeVariable(Token name) {
-    calls.add('beginTypeVariable $name');
+  void beginTypeVariable(Token token) {
+    calls.add('beginTypeVariable $token');
   }
 
   @override
@@ -1591,7 +1611,7 @@
   @override
   void endFormalParameter(Token thisKeyword, Token periodAfterThis,
       Token nameToken, FormalParameterKind kind, MemberKind memberKind) {
-    calls.add('beginTypeVariables $thisKeyword $periodAfterThis '
+    calls.add('endFormalParameter $thisKeyword $periodAfterThis '
         '$nameToken $kind $memberKind');
   }
 
@@ -1620,13 +1640,13 @@
   }
 
   @override
-  void endTypeVariable(Token token, Token extendsOrSuper) {
-    calls.add('endTypeVariable $token $extendsOrSuper');
+  void endTypeVariable(Token token, int index, Token extendsOrSuper) {
+    calls.add('endTypeVariable $token $index $extendsOrSuper');
   }
 
   @override
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
-    calls.add('endTypeVariables $count $beginToken $endToken');
+  void endTypeVariables(Token beginToken, Token endToken) {
+    calls.add('endTypeVariables $beginToken $endToken');
   }
 
   @override
@@ -1687,6 +1707,11 @@
   }
 
   @override
+  void handleTypeVariablesDefined(Token token, int count) {
+    calls.add('handleTypeVariablesDefined $token $count');
+  }
+
+  @override
   void handleVoidKeyword(Token token) {
     calls.add('handleVoidKeyword $token');
   }