@Nullable ImmutableList<TypeMirror> erasedParameterTypes(
          ExecutableElement method, TypeElement in) {
        if (method.getEnclosingElement().equals(in)) {
          ImmutableList.Builder<TypeMirror> params = ImmutableList.builder();
          for (VariableElement param : method.getParameters()) {
            params.add(typeUtils.erasure(visit(param.asType())));
          }
          return params.build();
        }
        // Make a list of supertypes we are going to visit recursively: the superclass, if there
        // is one, plus the superinterfaces.
        List<TypeMirror> supers = Lists.newArrayList();
        if (in.getSuperclass().getKind() == TypeKind.DECLARED) {
          supers.add(in.getSuperclass());
        }
        supers.addAll(in.getInterfaces());
        for (TypeMirror supertype : supers) {
          DeclaredType declared = MoreTypes.asDeclared(supertype);
          TypeElement element = MoreElements.asType(declared.asElement());
          List<? extends TypeMirror> actuals = declared.getTypeArguments();
          List<? extends TypeParameterElement> formals = element.getTypeParameters();
          if (actuals.isEmpty()) {
            // Either the formal type arguments are also empty or `declared` is raw.
            actuals = formals.stream().map(t -> t.getBounds().get(0)).collect(toList());
          }
          Verify.verify(actuals.size() == formals.size());
          for (int i = 0; i < actuals.size(); i++) {
            typeBindings.put(formals.get(i), actuals.get(i));
          }
          ImmutableList<TypeMirror> params = erasedParameterTypes(method, element);
          if (params != null) {
            return params;
          }
        }
        return null;
      }
Type elements that we are currently visiting. This helps us stay out of trouble when
looking at something like {@code Enum<E extends Enum<E>>}. At the second {@code Enum} we
will just return raw {@code Enum}.
common/src/main/java/com/google/auto/common/Overrides.java