Exemple #1
0
 private Map<ClassElement, String> makeBuiltinTypes(CoreTypeProvider typeProvider) {
   Map<ClassElement, String> builtinTypes = Maps.newHashMap();
   builtinTypes.put(typeProvider.getBoolType().getElement(), "$isBool");
   builtinTypes.put(typeProvider.getIntType().getElement(), "$isNum");
   builtinTypes.put(typeProvider.getDoubleType().getElement(), "$isNum");
   builtinTypes.put(typeProvider.getStringType().getElement(), "$isString");
   return builtinTypes;
 }
  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;
  }
Exemple #3
0
  private JsExpression generateRawInterfaceTypeComparison(
      JsExpression lhs, DartTypeNode typeNode, SourceInfo src) {
    ClassElement element = (ClassElement) typeNode.getType().getElement();
    if (element.equals(typeProvider.getObjectType().getElement())) {
      // Everything is an object, including null
      return this.translationContext.getProgram().getTrueLiteral();
    }
    String builtin = builtInTypeChecks.get(element);
    if (builtin != null) {
      return call(src, nameref(src, builtin), lhs);
    }

    // Due to implementing implied interfaces of classes, we always have to
    // use $implements$ rather than using JS instanceof for classes.

    // Inject: !!(tmp = target, tmp && tmp.$implements$type)
    JsProgram program = translationContext.getProgram();
    JsName tmp = context.createTemporary();
    String mangledClass = translationContext.getMangler().mangleClassName(element);
    return not(
        src,
        not(
            src,
            comma(
                src,
                assign(src, tmp.makeRef(), lhs),
                and(
                    src,
                    neq(src, tmp.makeRef().setSourceRef(src), program.getNullLiteral()),
                    nameref(src, tmp, "$implements$" + mangledClass)))));
  }
Exemple #4
0
  /** Add runtime type information to a "new" expression, if necessary. */
  void mayAddRuntimeTypeToConstrutorOrFactoryCall(
      ClassElement enclosingClass, DartNewExpression x, JsInvocation invoke) {
    // TODO(johnlenz):in optimized mode, only add this where it is needed.

    InterfaceType instanceType = Types.constructorType(x);
    if (instanceType == null) {
      // TODO(johnlenz): HackHack. Currently the "new FallThroughError" injected by the
      // Normalizer does not have the instance type attached. But in this
      // case we know it does not have any type parameters.
      // reportError(x.getParent().getParent(), new AssertionError("missing type information"));
      assert typeProvider
          .getFallThroughError()
          .getElement()
          .lookupConstructor("")
          .equals(x.getSymbol());
    } else if (constructorHasTypeParameters(x)) {
      ConstructorElement constructor = x.getSymbol();
      ClassElement containingClassElement = enclosingClass;
      if (constructor.getModifiers().isFactory()) {
        // We are calling a factory, this is either in a class
        FunctionType functionType = (FunctionType) constructor.getType();
        JsExpression typeArgs =
            generateTypeArgsArrayForFactory(functionType, instanceType, containingClassElement);
        assert typeArgs != null;
        invoke.getArguments().add(0, typeArgs);
      } else {
        ClassElement constructorClassElement = constructor.getConstructorType();
        invoke
            .getArguments()
            .add(
                0,
                generateRTTLookup(constructorClassElement, instanceType, containingClassElement));
      }
    }
  }
Exemple #5
0
 /** Add a runtime type information to a array literal, if necessary. */
 JsExpression maybeAddRuntimeTypeForArrayLiteral(
     ClassElement enclosingClass, DartArrayLiteral x, JsArrayLiteral jsArray) {
   // TODO(johnlenz):in optimized mode, only add this where it is needed.
   InterfaceType instanceType =
       typeProvider.getArrayLiteralType(x.getType().getArguments().get(0));
   JsExpression rtt = generateRTTLookup(instanceType, enclosingClass);
   // Bind the runtime type information to the native array expression
   return call(x, newQualifiedNameRef("RTT.setTypeInfo"), jsArray, rtt);
 }
Exemple #6
0
  /** Add a runtime type information to a map literal, if necessary. */
  void maybeAddRuntimeTypeToMapLiteralConstructor(
      ClassElement enclosingClass, DartMapLiteral x, JsInvocation invoke) {
    // TODO(johnlenz):in optimized mode, only add this where it is needed.

    // Fixup the type for map literal type to be the implementing type.
    List<? extends Type> typeArgs = x.getType().getArguments();
    InterfaceType instanceType = typeProvider.getMapLiteralType(typeArgs.get(0), typeArgs.get(1));
    JsExpression rtt = generateRTTLookup(instanceType, enclosingClass);
    invoke.getArguments().add(rtt);
  }
 /**
  * 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;
   }
 }
 public Type leastUpperBound(Type t, Type s) {
   if (isSubtype(t, s)) {
     return s;
   } else if (isSubtype(s, t)) {
     return t;
   } else {
     List<InterfaceType> tTypes = getSuperTypes(t);
     List<InterfaceType> sTypes = getSuperTypes(s);
     for (InterfaceType tType : tTypes) {
       if (sTypes.contains(tType)) {
         return tType;
       }
     }
     return typeProvider.getObjectType();
   }
 }
 public Type intersection(List<Type> types) {
   // exclude 'dynamic' type
   {
     List<Type> newTypes = Lists.newArrayList();
     for (Type type : types) {
       if (TypeKind.of(type) != TypeKind.DYNAMIC) {
         newTypes.add(type);
       }
     }
     types = newTypes;
   }
   // no types, so Dynamic
   if (types.isEmpty()) {
     return typeProvider.getDynamicType();
   }
   // prepare all super types
   List<List<InterfaceType>> superTypesLists = Lists.newArrayList();
   List<Map<InterfaceType, InterfaceType>> superTypesMaps = Lists.newArrayList();
   for (Type type : types) {
     List<InterfaceType> superTypes = getSuperTypes(type);
     superTypesLists.add(superTypes);
     Map<InterfaceType, InterfaceType> superTypesMap = Maps.newHashMap();
     for (InterfaceType superType : superTypes) {
       superTypesMap.put(superType.asRawType(), superType);
     }
     superTypesMaps.add(superTypesMap);
   }
   // find intersection of super types
   LinkedList<InterfaceType> interTypes = Lists.newLinkedList();
   if (superTypesLists.size() > 0) {
     for (InterfaceType superType : superTypesLists.get(0)) {
       boolean inAll = true;
       for (Map<InterfaceType, InterfaceType> otherTypesMap : superTypesMaps) {
         InterfaceType superTypeRaw = superType.asRawType();
         InterfaceType otherType = otherTypesMap.get(superTypeRaw);
         // no such raw type, exclude from intersection
         if (otherType == null) {
           inAll = false;
           break;
         }
         // if not raw, choose type arguments
         if (!superType.getArguments().isEmpty()) {
           InterfaceType t0 = superType;
           InterfaceType t1 = otherType;
           // if two-way sub-type, then has Dynamic(s), choose with least number
           if (isSubtype(t0, t1) && isSubtype(t1, t0)) {
             int dynamics0 = getDynamicArgumentsCount(t0);
             int dynamics1 = getDynamicArgumentsCount(t1);
             if (dynamics0 < dynamics1) {
               superType = t0;
             } else {
               superType = t1;
             }
             continue;
           }
           // use super-type of t0 and t1
           if (isSubtype(t0, t1)) {
             superType = t1;
           }
           if (isSubtype(t1, t0)) {
             superType = t0;
           }
         }
       }
       if (inAll && !interTypes.contains(superType)) {
         interTypes.add(superType);
       }
     }
   }
   // try to remove sub-types already covered by existing types
   for (Iterator<InterfaceType> i = interTypes.descendingIterator(); i.hasNext(); ) {
     InterfaceType subType = i.next();
     boolean hasSuperType = false;
     for (InterfaceType superType : interTypes) {
       if (superType != subType && isSubtype(superType, subType)) {
         hasSuperType = true;
         break;
       }
     }
     if (hasSuperType) {
       i.remove();
     }
   }
   // use single type
   if (interTypes.size() == 0) {
     return typeProvider.getObjectType();
   }
   if (interTypes.size() == 1) {
     return interTypes.get(0);
   }
   // create union
   return unionTypes(interTypes);
 }
 private InterfaceType checkedAsInstanceOf(
     Type t, ClassElement element, Set<TypeVariable> variablesReferenced, Set<Type> checkedTypes) {
   // check for recursion
   if (checkedTypes.contains(t)) {
     return null;
   }
   checkedTypes.add(t);
   // check current Type
   switch (TypeKind.of(t)) {
     case FUNCTION_ALIAS:
     case INTERFACE:
       {
         if (t.getElement().equals(element)) {
           return (InterfaceType) t;
         }
         InterfaceType ti = (InterfaceType) t;
         ClassElement tElement = ti.getElement();
         InterfaceType supertype = tElement.getSupertype();
         // super type
         if (supertype != null) {
           InterfaceType result =
               checkedAsInstanceOf(
                   asSupertype(ti, supertype), element, variablesReferenced, checkedTypes);
           if (result != null) {
             return result;
           }
         }
         // interfaces
         for (InterfaceType intf : tElement.getInterfaces()) {
           InterfaceType result =
               checkedAsInstanceOf(
                   asSupertype(ti, intf), element, variablesReferenced, checkedTypes);
           if (result != null) {
             return result;
           }
         }
         // mixins
         for (InterfaceType mixin : tElement.getMixins()) {
           if (mixin.getElement().equals(element)) {
             return asSupertype(ti, mixin);
           }
         }
         // no
         return null;
       }
     case FUNCTION:
       {
         Element e = t.getElement();
         switch (e.getKind()) {
           case CLASS:
             // e should be the interface Function in the core library. See the
             // documentation comment on FunctionType.
             InterfaceType ti = (InterfaceType) e.getType();
             return checkedAsInstanceOf(ti, element, variablesReferenced, checkedTypes);
           default:
             return null;
         }
       }
     case VARIABLE:
       {
         TypeVariable v = (TypeVariable) t;
         Type bound = v.getTypeVariableElement().getBound();
         // Check for previously encountered variables to avoid getting stuck in an infinite loop.
         if (variablesReferenced.contains(v)) {
           if (bound instanceof InterfaceType) {
             return (InterfaceType) bound;
           }
           return typeProvider.getObjectType();
         }
         variablesReferenced.add(v);
         return checkedAsInstanceOf(bound, element, variablesReferenced, checkedTypes);
       }
     default:
       return null;
   }
 }
  /**
   * 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());
  }