@Override
  public Void visitWildcard(AnnotatedWildcardType type, Tree tree) {
    if (visitedNodes.containsKey(type)) {
      return visitedNodes.get(type);
    }

    // Keep in sync with visitTypeVariable
    Set<AnnotationMirror> onVar = type.getAnnotations();
    if (!onVar.isEmpty()) {
      // System.out.printf("BaseTypeVisitor.TypeValidator.visitWildcard(type: %s, tree: %s)",
      // type, tree);

      // TODO: the following check should not be necessary, once we are
      // able to
      // recurse on type parameters in AnnotatedTypes.isValidType (see
      // todo there).
      {
        // Check whether multiple qualifiers from the same hierarchy
        // appear.
        Set<AnnotationMirror> seenTops = AnnotationUtils.createAnnotationSet();
        for (AnnotationMirror aOnVar : onVar) {
          AnnotationMirror top = atypeFactory.getQualifierHierarchy().getTopAnnotation(aOnVar);
          if (seenTops.contains(top)) {
            this.reportError(type, tree);
          }
          seenTops.add(top);
        }
      }

      /* TODO: see note with visitTypeVariable
      if (type.getExtendsBoundField() != null) {
          AnnotatedTypeMirror upper = type.getExtendsBoundField();
          for (AnnotationMirror aOnVar : onVar) {
              if (upper.isAnnotatedInHierarchy(aOnVar) &&
                      !atypeFactory.getQualifierHierarchy().isSubtype(aOnVar,
                              upper.getAnnotationInHierarchy(aOnVar))) {
                  this.reportError(type, tree);
              }
          }
          upper.replaceAnnotations(onVar);
      }
      */

      if (type.getSuperBoundField() != null) {
        AnnotatedTypeMirror lower = type.getSuperBoundField();
        for (AnnotationMirror aOnVar : onVar) {
          if (lower.isAnnotatedInHierarchy(aOnVar)
              && !atypeFactory
                  .getQualifierHierarchy()
                  .isSubtype(lower.getAnnotationInHierarchy(aOnVar), aOnVar)) {
            this.reportError(type, tree);
          }
        }
        lower.replaceAnnotations(onVar);
      }
    }
    return super.visitWildcard(type, tree);
  }
 @Override
 public R visitWildcard(AnnotatedWildcardType type, P p) {
   if (visitedNodes.containsKey(type)) {
     return visitedNodes.get(type);
   }
   visitedNodes.put(type, null);
   R r = scan(type.getExtendsBound(), p);
   visitedNodes.put(type, r);
   r = scanAndReduce(type.getSuperBound(), p, r);
   visitedNodes.put(type, r);
   return r;
 }