anchor.diff:    void computeRest(Token token, bool required) {
       while (optional('Function', token)) {
         Token typeVariableStart = token;
  +      // TODO(danrubel): Consider caching TypeParamOrArgInfo
  +      token = computeTypeParamOrArg(token, true).skip(token);
         token = token.next;
  -      if (optional('<', token)) {
  -        token = skipTypeVariables(token);
  -        if (token == null) {
  -          break; // Not a function type.
  -        }
  -        assert(optional('>', token) || optional('>>', token));
  -        token = token.next;
  -      }
         if (!optional('(', token)) {
           break; // Not a function type.
         }
  
positive.code:   return false;
  }
  
  Token skipTypeVariables(Token token) {
    assert(optional('<', token));
    Token endGroup = token.endGroup;
    if (endGroup == null) {
      return null;
    }
  
    // The scanner sets the endGroup in situations like this: C<T && T>U;
    // Scan the type arguments to assert there are no operators.
    // TODO(danrubel): Fix the scanner to do this scanning.
    token = token.next;
    while (token != endGroup) {
      if (token.isKeywordOrIdentifier ||
          optional(',', token) ||
          optional('.', token) ||
          optional('<', token) ||
          optional('>', token) ||
          optional('>>', token) ||
          optional('@', token)) {
        // ok
      } else if (optional('(', token)) {
        token = token.endGroup;
      } else {
        return null;
      }
      token = token.next;
    }
    return endGroup;
  }
  
  /// Instances of [ComplexTypeInfo] are returned by [computeType] to represent
  /// type references that cannot be represented by the constants above.
  class ComplexTypeInfo implements TypeInfo {
  
negative.code:     }
  
      for (Link<Token> t = typeVariableStarters; t.isNotEmpty; t = t.tail) {
        computeTypeParamOrArg(t.head, true).parseVariables(t.head, parser);
        parser.listener.beginFunctionType(start);
      }
  
  