private boolean compatibleTypes(TypeMirror parameterType, TypeMirror memberType) {
    if (typeUtils.isAssignable(parameterType, memberType)) {
      // parameterType assignable to memberType, which in the restricted world of annotations
      // means they are the same type, or maybe memberType is an annotation type and parameterType
      // is a subtype of that annotation interface (why would you do that?).
      return true;
    }
    // They're not the same, but we could still consider them compatible if for example
    // parameterType is List<Integer> and memberType is int[]. We accept any type that is assignable
    // to Collection<Integer> (in this example).
    if (memberType.getKind() != TypeKind.ARRAY) {
      return false;
    }
    TypeMirror arrayElementType = MoreTypes.asArray(memberType).getComponentType();
    TypeMirror wrappedArrayElementType =
        arrayElementType.getKind().isPrimitive()
            ? typeUtils.boxedClass((PrimitiveType) arrayElementType).asType()
            : arrayElementType;
    TypeElement javaUtilCollection =
        elementUtils.getTypeElement(Collection.class.getCanonicalName());
    DeclaredType collectionOfElement =
        typeUtils.getDeclaredType(javaUtilCollection, wrappedArrayElementType);
    return typeUtils.isAssignable(parameterType, collectionOfElement);
  }
Returns true if {@code parameterType} can be used to provide the value of an annotation member
of type {@code memberType}. They must either be the same type, or the member type must be an
array and the parameter type must be a collection of a compatible type.
value/src/main/java/com/google/auto/value/processor/AutoAnnotationProcessor.java