Пример #1
0
  /**
   * Implement the Dart function subtype rule. Unlike the classic arrow rule (return type is
   * covariant, and parameter types are contravariant), in Dart they must just be assignable.
   */
  private boolean isSubtypeOfFunction(FunctionType t, FunctionType s) {
    if (s.getKind() == TypeKind.DYNAMIC || t.getKind() == TypeKind.DYNAMIC) {
      return true;
    }
    // Classic: return type is covariant; Dart: assignable.
    if (!isAssignable(t.getReturnType(), s.getReturnType())) {
      // A function that returns a value can be used as a function where you ignore the value.
      if (!s.getReturnType().equals(typeProvider.getVoidType())) {
        return false;
      }
    }
    Type tRest = t.getRest();
    Type sRest = s.getRest();
    if ((tRest == null) != (sRest == null)) {
      return false;
    }
    if (tRest != null) {
      // Classic: parameter types are contravariant; Dart: assignable.
      if (!isAssignable(sRest, tRest)) {
        return false;
      }
    }

    {
      Map<String, Type> sOpti = s.getOptionalParameterTypes();
      Map<String, Type> tOpti = t.getOptionalParameterTypes();
      if (tOpti.size() < sOpti.size()) {
        return false;
      }
      Iterator<Entry<String, Type>> tList = tOpti.entrySet().iterator();
      Iterator<Entry<String, Type>> sList = sOpti.entrySet().iterator();
      while (sList.hasNext()) {
        if (!tList.hasNext()) {
          return false;
        }
        Entry<String, Type> sEntry = sList.next();
        Entry<String, Type> tEntry = tList.next();
        if (!isAssignable(tEntry.getValue(), sEntry.getValue())) {
          return false;
        }
      }
    }

    Map<String, Type> tNamed = t.getNamedParameterTypes();
    Map<String, Type> sNamed = s.getNamedParameterTypes();
    if (tNamed.isEmpty() && !sNamed.isEmpty()) {
      return false;
    }

    // T's named parameters must be in the same order and assignable to S's but
    // maybe a superset.
    if (!sNamed.isEmpty()) {
      LinkedHashMap<String, Type> tMap = (LinkedHashMap<String, Type>) (tNamed);
      LinkedHashMap<String, Type> sMap = (LinkedHashMap<String, Type>) (sNamed);
      if (!tMap.keySet().containsAll(sMap.keySet())) {
        return false;
      }
      for (Entry<String, Type> entry : sMap.entrySet()) {
        String name = entry.getKey();
        Type sType = sMap.get(name);
        Type tType = tMap.get(name);
        if (!isAssignable(tType, sType)) {
          return false;
        }
      }
      //      Iterator<Entry<String, Type>> tList = tMap.entrySet().iterator();
      //      Iterator<Entry<String, Type>> sList = sMap.entrySet().iterator();
      //      // t named parameters must start with the named parameters of s
      //      while (sList.hasNext()) {
      //        if (!tList.hasNext()) {
      //          return false;
      //        }
      //        Entry<String, Type> sEntry = sList.next();
      //        Entry<String, Type> tEntry = tList.next();
      //        if (!sEntry.getKey().equals(tEntry.getKey())) {
      //          return false;
      //        }
      //        // Classic: parameter types are contravariant; Dart: assignable.
      //        if (!isAssignable(tEntry.getValue(), sEntry.getValue())) {
      //          return false;
      //        }
      //      }
    }

    // Classic: parameter types are contravariant; Dart: assignable.
    return areAssignable(s.getParameterTypes().iterator(), t.getParameterTypes().iterator());
  }