anchor.diff:        'endFormalParameters 0 ( ) MemberKind.GeneralizedFunctionType',
         'endFunctionType Function ',
       ]);
  -    tComplex('void Function<T>()');
  -    tComplex('void Function(int)');
  -    tComplex('void Function<T>(int)');
  -    tComplex('void Function(int x)');
  -    tComplex('void Function<T>(int x)');
  -    tComplex('void Function<T>(int x) Function<T>(int x)');
  -  }
  +    expectComplexInfo('void Function<T>()');
  +    expectComplexInfo('void Function(int)');
  +    expectComplexInfo('void Function<T>(int)');
  +    expectComplexInfo('void Function(int x)');
  +    expectComplexInfo('void Function<T>(int x)');
  +    expectComplexInfo('void Function<T>(int x) Function<T>(int x)');
  +  }
  +}
  +
  +void expectInfo(expectedInfo, String source,
  +    {bool required, String expectedAfter, List<String> expectedCalls}) {
  +  Token start = scan(source);
  +  if (required == null) {
  +    compute(expectedInfo, source, start, true, expectedAfter, expectedCalls);
  +    compute(expectedInfo, source, start, false, expectedAfter, expectedCalls);
  +  } else {
  +    compute(
  +        expectedInfo, source, start, required, expectedAfter, expectedCalls);
  +  }
  +}
  +
  +void expectComplexInfo(String source,
  +    {bool required, String tokenAfter, List<String> expectedCalls}) {
  +  expectInfo(const isInstanceOf<ComplexTypeInfo>(), source,
  +      required: required,
  +      expectedAfter: tokenAfter,
  +      expectedCalls: expectedCalls);
  +}
  +
  +void compute(expectedInfo, String source, Token start, bool required,
  +    String expectedAfter, List<String> expectedCalls) {
  +  TypeInfo typeInfo = computeType(start, required);
  +  expect(typeInfo, expectedInfo, reason: source);
  +  if (typeInfo is ComplexTypeInfo) {
  +    TypeInfoListener listener = new TypeInfoListener();
  +    Parser parser = new Parser(listener);
  +    expect(typeInfo.start, start.next, reason: source);
  +    expectEnd(expectedAfter, typeInfo.skipType(start));
  +    expectEnd(expectedAfter, typeInfo.parseType(start, parser));
  +    if (expectedCalls != null) {
  +      // TypeInfoListener listener2 = new TypeInfoListener();
  +      // new Parser(listener2).parseType(start, TypeContinuation.Required);
  +      // print('[');
  +      // for (String call in listener2.calls) {
  +      //   print("'$call',");
  +      // }
  +      // print(']');
  +
  +      expect(listener.calls, expectedCalls, reason: source);
  +    }
  +  }
  +}
  +
  +void expectEnd(String tokenAfter, Token end) {
  +  if (tokenAfter == null) {
  +    expect(end.isEof, isFalse);
  +    expect(end.next.isEof, isTrue);
  +  } else {
  +    expect(end.next.lexeme, tokenAfter);
  +  }
  +}
  +
  +Token scan(String source) {
  +  Token start = scanString(source).tokens;
  +  while (start is ErrorToken) {
  +    start = start.next;
  +  }
  +  return new SyntheticToken(TokenType.EOF, 0)..setNext(start);
   }
   
   class TypeInfoListener implements Listener {
  
positive.code:     ]);
    }
  
    void test_computeType() {
      Token scan(String source) {
        Token start = scanString(source).tokens;
        while (start is ErrorToken) {
          start = start.next;
        }
        return new SyntheticToken(TokenType.EOF, 0)..setNext(start);
      }
  
      void expectEnd(String tokenAfter, Token end) {
        if (tokenAfter == null) {
          expect(end.isEof, isFalse);
          expect(end.next.isEof, isTrue);
        } else {
          expect(end.next.lexeme, tokenAfter);
        }
      }
  
      void compute(expectedInfo, String source, Token start, bool required,
          String expectedAfter, List<String> expectedCalls) {
        TypeInfo typeInfo = computeType(start, required);
        expect(typeInfo, expectedInfo, reason: source);
        if (typeInfo is ComplexTypeInfo) {
          TypeInfoListener listener = new TypeInfoListener();
          Parser parser = new Parser(listener);
          expect(typeInfo.start, start.next, reason: source);
          expectEnd(expectedAfter, typeInfo.skipType(start));
          expectEnd(expectedAfter, typeInfo.parseType(start, parser));
          if (expectedCalls != null) {
            // TypeInfoListener listener2 = new TypeInfoListener();
            // new Parser(listener2).parseType(start, TypeContinuation.Required);
            // print('[');
            // for (String call in listener2.calls) {
            //   print("'$call',");
            // }
            // print(']');
  
            expect(listener.calls, expectedCalls, reason: source);
          }
        }
      }
  
      void t(expectedInfo, String source,
          {bool required, String expectedAfter, List<String> expectedCalls}) {
        Token start = scan(source);
        if (required == null) {
          compute(
              expectedInfo, source, start, true, expectedAfter, expectedCalls);
          compute(
              expectedInfo, source, start, false, expectedAfter, expectedCalls);
        } else {
          compute(expectedInfo, source, start, required, expectedAfter,
              expectedCalls);
        }
      }
  
      void tComplex(String source,
          {bool required, String tokenAfter, List<String> expectedCalls}) {
        t(const isInstanceOf<ComplexTypeInfo>(), source,
            required: required,
            expectedAfter: tokenAfter,
            expectedCalls: expectedCalls);
      }
  
      t(noTypeInfo, '');
      t(noTypeInfo, ';');
      t(noTypeInfo, '( foo');
      t(noTypeInfo, '< foo');
      t(noTypeInfo, '= foo');
      t(noTypeInfo, '* foo');
      t(noTypeInfo, 'do foo');
      t(noTypeInfo, 'get foo');
      t(noTypeInfo, 'set foo');
      t(noTypeInfo, 'operator *');
  
      // TOOD(danrubel): dynamic, do, other keywords, malformed, recovery
      // <T>
  
      t(voidTypeInfo, 'void');
      t(voidTypeInfo, 'void;');
      t(voidTypeInfo, 'void(');
      t(voidTypeInfo, 'void<');
      t(voidTypeInfo, 'void=');
      t(voidTypeInfo, 'void*');
      t(voidTypeInfo, 'void<T>');
      t(voidTypeInfo, 'void do');
      t(voidTypeInfo, 'void foo');
      t(voidTypeInfo, 'void get');
      t(voidTypeInfo, 'void set');
      t(voidTypeInfo, 'void operator');
      t(voidTypeInfo, 'void Function');
      tComplex('void Function(', // Scanner inserts synthetic ')'.
          expectedCalls: [
            'handleNoTypeVariables (',
            'beginFunctionType void',
            'handleVoidKeyword void',
            'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
            'endFormalParameters 0 ( ) MemberKind.GeneralizedFunctionType',
            'endFunctionType Function ',
          ]);
  
      t(noTypeInfo, 'C', required: false);
      t(noTypeInfo, 'C;', required: false);
      t(noTypeInfo, 'C(', required: false);
      t(noTypeInfo, 'C<', required: false);
      t(noTypeInfo, 'C.', required: false);
      t(noTypeInfo, 'C=', required: false);
      t(noTypeInfo, 'C*', required: false);
      t(noTypeInfo, 'C do', required: false);
  
      t(simpleTypeInfo, 'C', required: true);
      t(simpleTypeInfo, 'C;', required: true);
      t(simpleTypeInfo, 'C(', required: true);
      t(simpleTypeInfo, 'C<', required: true);
      t(simpleTypeInfo, 'C.', required: true);
      t(simpleTypeInfo, 'C=', required: true);
      t(simpleTypeInfo, 'C*', required: true);
      t(simpleTypeInfo, 'C do', required: true);
  
      t(noTypeInfo, 'C<>', required: false);
      tComplex('C<>', required: true, expectedCalls: [
        'handleIdentifier C typeReference',
        'beginTypeArguments <',
        'handleIdentifier  typeReference',
        'handleNoTypeArguments >',
        'handleType > >',
        'endTypeArguments 1 < >',
        'handleType C ',
      ]);
      tComplex('C<> f', required: true, tokenAfter: 'f', expectedCalls: [
        'handleIdentifier C typeReference',
        'beginTypeArguments <',
        'handleIdentifier  typeReference',
        'handleNoTypeArguments >',
        'handleType > >',
        'endTypeArguments 1 < >',
        'handleType C f',
      ]);
  
      t(simpleTypeInfo, 'C foo');
      t(simpleTypeInfo, 'C get');
      t(simpleTypeInfo, 'C set');
      t(simpleTypeInfo, 'C operator');
      t(simpleTypeInfo, 'C this');
      t(simpleTypeInfo, 'C Function');
      tComplex('C Function(', // Scanner inserts synthetic ')'.
          expectedCalls: [
            'handleNoTypeVariables (',
            'beginFunctionType C',
            'handleIdentifier C typeReference',
            'handleNoTypeArguments Function',
            'handleType C Function',
            'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
            'endFormalParameters 0 ( ) MemberKind.GeneralizedFunctionType',
            'endFunctionType Function ',
          ]);
  
      t(noTypeInfo, 'C<T>', required: false);
      t(noTypeInfo, 'C<T>;', required: false);
      t(noTypeInfo, 'C<T>(', required: false);
      t(noTypeInfo, 'C<T> do', required: false);
  
      t(simpleTypeArgumentsInfo, 'C<T>', required: true);
      t(simpleTypeArgumentsInfo, 'C<T>;', required: true);
      t(simpleTypeArgumentsInfo, 'C<T>(', required: true);
      t(simpleTypeArgumentsInfo, 'C<T> do', required: true);
  
      t(simpleTypeArgumentsInfo, 'C<T> foo');
      t(simpleTypeArgumentsInfo, 'C<T> get');
      t(simpleTypeArgumentsInfo, 'C<T> set');
      t(simpleTypeArgumentsInfo, 'C<T> operator');
      t(simpleTypeArgumentsInfo, 'C<T> Function');
      tComplex('C<T> Function(', // Scanner inserts synthetic ')'.
          expectedCalls: [
            'handleNoTypeVariables (',
            'beginFunctionType C',
            'handleIdentifier C typeReference',
            'beginTypeArguments <',
            'handleIdentifier T typeReference',
            'handleNoTypeArguments >',
            'handleType T >',
            'endTypeArguments 1 < >',
            'handleType C Function',
            'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
            'endFormalParameters 0 ( ) MemberKind.GeneralizedFunctionType',
            'endFunctionType Function ',
          ]);
  
      // Statements that should not have a type
      t(noTypeInfo, 'C<T ; T>U;', required: false);
      t(noTypeInfo, 'C<T && T>U;', required: false);
  
      t(noTypeInfo, 'C.a', required: false);
      t(noTypeInfo, 'C.a;', required: false);
      t(noTypeInfo, 'C.a(', required: false);
      t(noTypeInfo, 'C.a<', required: false);
      t(noTypeInfo, 'C.a=', required: false);
      t(noTypeInfo, 'C.a*', required: false);
      t(noTypeInfo, 'C.a do', required: false);
  
      t(prefixedTypeInfo, 'C.a', required: true);
      t(prefixedTypeInfo, 'C.a;', required: true);
      t(prefixedTypeInfo, 'C.a(', required: true);
      t(prefixedTypeInfo, 'C.a<', required: true);
      t(prefixedTypeInfo, 'C.a=', required: true);
      t(prefixedTypeInfo, 'C.a*', required: true);
      t(prefixedTypeInfo, 'C.a do', required: true);
  
      t(prefixedTypeInfo, 'C.a foo');
      t(prefixedTypeInfo, 'C.a get');
      t(prefixedTypeInfo, 'C.a set');
      t(prefixedTypeInfo, 'C.a operator');
      t(prefixedTypeInfo, 'C.a Function');
      tComplex('C.a Function(', // Scanner inserts synthetic ')'.
          expectedCalls: [
            'handleNoTypeVariables (',
            'beginFunctionType C',
            'handleIdentifier C prefixedTypeReference',
            'handleIdentifier a typeReferenceContinuation',
            'handleQualified .',
            'handleNoTypeArguments Function',
            'handleType C Function',
            'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
            'endFormalParameters 0 ( ) MemberKind.GeneralizedFunctionType',
            'endFunctionType Function ',
          ]);
  
      t(noTypeInfo, 'C<S,T>', required: false);
      t(noTypeInfo, 'C<S<T>>', required: false);
      t(noTypeInfo, 'C.a<T>', required: false);
  
      tComplex('C<S,T>', required: true, expectedCalls: [
        'handleIdentifier C typeReference',
        'beginTypeArguments <',
        'handleIdentifier S typeReference',
        'handleNoTypeArguments ,',
        'handleType S ,',
        'handleIdentifier T typeReference',
        'handleNoTypeArguments >',
        'handleType T >',
        'endTypeArguments 2 < >',
        'handleType C ',
      ]);
      tComplex('C<S<T>>', required: true, expectedCalls: [
        'handleIdentifier C typeReference',
        'beginTypeArguments <',
        'handleIdentifier S typeReference',
        'beginTypeArguments <',
        'handleIdentifier T typeReference',
        'handleNoTypeArguments >',
        'handleType T >',
        'endTypeArguments 1 < >',
        'handleType S >',
        'endTypeArguments 1 < >',
        'handleType C ',
      ]);
      tComplex('C.a<T>', required: true, expectedCalls: [
        'handleIdentifier C prefixedTypeReference',
        'handleIdentifier a typeReferenceContinuation',
        'handleQualified .',
        'beginTypeArguments <',
        'handleIdentifier T typeReference',
        'handleNoTypeArguments >',
        'handleType T >',
        'endTypeArguments 1 < >',
        'handleType C ',
      ]);
  
      tComplex('C<S,T> f', tokenAfter: 'f', expectedCalls: [
        'handleIdentifier C typeReference',
        'beginTypeArguments <',
        'handleIdentifier S typeReference',
        'handleNoTypeArguments ,',
        'handleType S ,',
        'handleIdentifier T typeReference',
        'handleNoTypeArguments >',
        'handleType T >',
        'endTypeArguments 2 < >',
        'handleType C f',
      ]);
      tComplex('C<S<T>> f', tokenAfter: 'f', expectedCalls: [
        'handleIdentifier C typeReference',
        'beginTypeArguments <',
        'handleIdentifier S typeReference',
        'beginTypeArguments <',
        'handleIdentifier T typeReference',
        'handleNoTypeArguments >',
        'handleType T >',
        'endTypeArguments 1 < >',
        'handleType S >',
        'endTypeArguments 1 < >',
        'handleType C f',
      ]);
      tComplex('C.a<T> f', tokenAfter: 'f', expectedCalls: [
        'handleIdentifier C prefixedTypeReference',
        'handleIdentifier a typeReferenceContinuation',
        'handleQualified .',
        'beginTypeArguments <',
        'handleIdentifier T typeReference',
        'handleNoTypeArguments >',
        'handleType T >',
        'endTypeArguments 1 < >',
        'handleType C f',
      ]);
  
      tComplex('Function()', expectedCalls: [
        'handleNoTypeVariables (',
        'beginFunctionType Function',
        'handleNoType ',
  
negative.code:       'endFormalParameters 1 ( ) MemberKind.GeneralizedFunctionType',
        'endFunctionType Function ',
      ]);
      expectComplexInfo('Function<T>(int)', expectedCalls: [
        'beginTypeVariables <',
        'beginTypeVariable T',
        'beginMetadataStar T',
  