private boolean isSubtypeOfInterface(Type t, InterfaceType s) {
    // Special handling for union.
    if (t instanceof InterfaceTypeUnion) {
      InterfaceTypeUnion tUnion = (InterfaceTypeUnion) t;
      for (InterfaceType unionPart : tUnion.getTypes()) {
        if (isSubtype(unionPart, s)) {
          return true;
        }
      }
      return false;
    }

    // class "t" implements call() and "s" is Function
    if (TypeKind.of(t) == TypeKind.INTERFACE
        && typeProvider != null
        && s == typeProvider.getFunctionType()) {
      InterfaceType ti = (InterfaceType) t;
      if (ti.lookupMember("call") != null) {
        return true;
      }
    }

    // Try to cast "t" to "s".
    final Type sup = asInstanceOf(t, s.getElement());
    if (TypeKind.of(sup) == TypeKind.INTERFACE) {
      InterfaceType ti = (InterfaceType) sup;
      assert ti.getElement().equals(s.getElement());
      if (ti.isRaw() || s.isRaw()) {
        return true;
      }
      // Type arguments are covariant.
      return areSubtypes(ti.getArguments().iterator(), s.getArguments().iterator());
    }
    return false;
  }
 /**
  * Return an interface type representing the given interface, function or variable type.
  *
  * @return An interface type or null if the argument is neither an interface function or variable
  *     type.
  */
 public InterfaceType getInterfaceType(Type type) {
   switch (TypeKind.of(type)) {
     case VARIABLE:
       {
         TypeVariableElement element = ((TypeVariable) type).getTypeVariableElement();
         if (element.getBound() == null) {
           return typeProvider.getObjectType();
         } else {
           return getInterfaceType(element.getBound());
         }
       }
     case FUNCTION:
     case FUNCTION_ALIAS:
       return typeProvider.getFunctionType();
     case INTERFACE:
       return (InterfaceType) type;
     case DYNAMIC:
     case NONE:
     case VOID:
     default:
       return null;
   }
 }