@SuppressWarnings("TypeEquals")
  private static boolean equal(
      @Nullable TypeMirror a, @Nullable TypeMirror b, Set<ComparedElements> visiting) {
    if (a == b) {
      return true;
    }
    if (a == null || b == null) {
      return false;
    }
    // TypeMirror.equals is not guaranteed to return true for types that are equal, but we can
    // assume that if it does return true then the types are equal. This check also avoids getting
    // stuck in infinite recursion when Eclipse decrees that the upper bound of the second K in
    // <K extends Comparable<K>> is a distinct but equal K.
    // The javac implementation of ExecutableType, at least in some versions, does not take thrown
    // exceptions into account in its equals implementation, so avoid this optimization for
    // ExecutableType.
    @SuppressWarnings("TypesEquals")
    boolean equal = a.equals(b);
    if (equal && a.getKind() != TypeKind.EXECUTABLE) {
      return true;
    }
    EqualVisitorParam p = new EqualVisitorParam();
    p.type = b;
    p.visiting = visiting;
    return a.accept(EqualVisitor.INSTANCE, p);
  }
Returns an {@link Equivalence} that can be used to compare types. The standard way to compare
types is {@link javax.lang.model.util.Types#isSameType Types.isSameType}, but this alternative
may be preferred in a number of cases:

<ul>
  <li>If you don't have an instance of {@code Types}.
  <li>If you want a reliable {@code hashCode()} for the types, for example to construct a set
      of types using {@link java.util.HashSet} with {@link Equivalence#wrap(Object)}.
  <li>If you want distinct type variables to be considered equal if they have the same names
      and bounds.
  <li>If you want wildcard types to compare equal if they have the same bounds. {@code
      Types.isSameType} never considers wildcards equal, even when comparing a type to itself.
</ul>
common/src/main/java/com/google/auto/common/MoreTypes.java