Beispiel #1
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)))));
  }
 ClassElement element(String name, InterfaceType supertype, TypeVariable... parameters) {
   ClassElement element = Elements.classNamed(name);
   element.setSupertype(supertype);
   element.setType(itype(element, parameters));
   coreElements.put(name, element);
   return element;
 }
Beispiel #3
0
  /** Generate the code necessary to allow for runtime type checks */
  void generateRuntimeTypeInfo(DartClass x) {
    generateRuntimeTypeInfoMethods(x);

    ClassElement classElement = x.getSymbol();
    if (!classElement.isInterface()) {
      injectInterfaceMarkers(classElement, x);
    }
  }
Beispiel #4
0
  private void generateRTTImplementsMethod(DartClass x) {
    ClassElement classElement = x.getSymbol();

    // 1) create static type information construction function
    // function Foo$lookupOrCreateRTT(rtt, typeArgs) {
    //
    //   // superclass
    //   FooSuper$addTo(rtt, superTypeArg1, ...);
    //   // interfaces
    //   FooInterface1$addTo(rtt, interface1TypeArg1, ...);
    //
    //   // fill in derived types
    //   rtt.derivedTypes = [
    //      FirstRef$lookupOrCreateRTT(typearg1, ...),
    //      ...
    //      ]
    // }

    boolean hasTypeParams = classElement.getTypeParameters().size() > 0;

    // Build the function
    JsFunction implementsFn = new JsFunction(globalScope);
    implementsFn.setBody(new JsBlock());
    List<JsStatement> body = implementsFn.getBody().getStatements();
    JsScope scope = new JsScope(globalScope, "temp");

    JsName rtt = scope.declareName("rtt");
    implementsFn.getParameters().add(new JsParameter(rtt));
    JsName typeArgs = null;
    if (hasTypeParams) {
      typeArgs = scope.declareName("typeArgs");
      implementsFn.getParameters().add(new JsParameter(typeArgs));
    }

    JsInvocation callAddTo = newInvocation(getRTTAddToMethodName(classElement), rtt.makeRef());
    if (hasTypeParams) {
      typeArgs = scope.declareName("typeArgs");
      callAddTo.getArguments().add(typeArgs.makeRef());
    }
    body.add(callAddTo.makeStmt());

    // Add the derived types

    if (hasTypeParams) {
      // Populated the list of derived types
      JsArrayLiteral derivedTypesArray = new JsArrayLiteral();
      // TODO(johnlenz): Add needed types here.
      JsExpression addDerivedTypes =
          assign(null, nameref(null, rtt.makeRef(), "derivedTypes"), derivedTypesArray);
      body.add(addDerivedTypes.makeStmt());
    }

    // Finally, Add the function
    JsExpression fnDecl = assign(null, getRTTImplementsMethodName(classElement), implementsFn);
    globalBlock.getStatements().add(fnDecl.makeStmt());
  }
 /**
  * Return the superclass of the given class, or <code>null</code> if the given class does not have
  * a superclass or if the superclass cannot be determined.
  *
  * @param classElement the class being accessed
  * @return the superclass of the given class
  */
 private ClassElement getSuperclass(ClassElement classElement) {
   InterfaceType superType = classElement.getSupertype();
   if (superType == null) {
     return null;
   }
   return superType.getElement();
 }
Beispiel #6
0
 private JsExpression generateTypeArgsArrayForFactory(
     FunctionType functionType, InterfaceType instanceType, ClassElement contextClassElement) {
   JsExpression typeArgs;
   if (inFactoryOrStatic(contextClassElement)) {
     if (inFactory()) {
       // When building a type list in a static context like a factory, type
       // variables are
       // resolved from the type parameters to the static method.
       DartClassMember<?> member = context.getCurrentClassMember();
       DartMethodDefinition containingMethod = (DartMethodDefinition) member;
       ConstructorElement contextElement = (ConstructorElement) containingMethod.getSymbol();
       typeArgs =
           buildTypeArgsForFactory(
               functionType,
               instanceType,
               ((FunctionType) contextElement.getType()).getTypeVariables(),
               buildFactoryTypeInfoReference());
     } else {
       typeArgs = buildTypeArgsForFactory(functionType, instanceType, null, null);
     }
   } else {
     // Build type args in a class context:
     // When building a type list in a class instance, type variables are
     // resolved from the runtime type information on the instance of the
     // object.
     JsExpression typeArgContextExpr = buildTypeArgsReference(contextClassElement);
     typeArgs =
         buildTypeArgsForFactory(
             functionType,
             instanceType,
             contextClassElement.getTypeParameters(),
             typeArgContextExpr);
   }
   return typeArgs;
 }
Beispiel #7
0
 private boolean inFactoryOrStatic(ClassElement containingClass) {
   DartClassMember<?> member = context.getCurrentClassMember();
   return containingClass == null
       || containingClass.getKind() != ElementKind.CLASS
       || member == null
       || member.getModifiers().isFactory()
       || member.getModifiers().isStatic();
 }
 /**
  * Return the method defined in the given type that matches the given method.
  *
  * @param method the method being matched against
  * @param type the type in which the candidate methods are declared
  * @return the method defined in the type that matches the method
  */
 private MethodElement findMatchingMethod(MethodElement method, ClassElement type) {
   if (method instanceof ConstructorElement) {
     for (ConstructorElement candidateMethod : type.getConstructors()) {
       if (matches(method, candidateMethod)) {
         return candidateMethod;
       }
     }
   } else {
     for (Element member : type.getMembers()) {
       if (member instanceof MethodElement) {
         MethodElement candidateMethod = (MethodElement) member;
         if (matches(method, candidateMethod)) {
           return candidateMethod;
         }
       }
     }
   }
   return null;
 }
Beispiel #9
0
  private Set<InterfaceType> getAllInterfaces(ClassElement classElement) {
    // TODO(johnlenz): All interfaces here should not include the super class implemented interfaces
    // those are handled by the super-class definition.
    Set<InterfaceType> interfaces = Sets.newLinkedHashSet();
    if (classElement.getType() == null) {
      throw new InternalCompilerException("type is null on ClassElement " + classElement);
    }
    // A class needs to implement its own implied interface so the "is"
    // implementation works properly.
    interfaces.add(classElement.getType());

    for (InterfaceType current = classElement.getType();
        current != null;
        current = current.getElement().getSupertype()) {
      // TODO(johnlenz): Maybe use "getAllSupertypes" on the interface element instead
      addAllInterfaces(interfaces, current);
    }
    return interfaces;
  }
Beispiel #10
0
 private JsExpression getReifiedTypeVariableRTT(
     TypeVariable type, ClassElement contextClassElement) {
   JsExpression rttContext;
   if (!inFactory()) {
     // build: this.typeinfo.implementedTypes['class'].typeArgs;
     rttContext = buildTypeArgsReference(contextClassElement);
   } else {
     // build: $typeArgs
     rttContext = buildFactoryTypeInfoReference();
   }
   // rtt = rttContext.typeArgs[x]
   JsExpression rtt =
       buildTypeLookupExpression(type, contextClassElement.getTypeParameters(), rttContext);
   return rtt;
 }
 private void process(DartIdentifier node, ClassElement binding) {
   InterfaceType element = binding.getType();
   if (element != null) {
     processType(node, element);
   }
 }
 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;
   }
 }
Beispiel #13
0
 private boolean hasRTTImplements(ClassElement classElement) {
   InterfaceType superType = classElement.getSupertype();
   return ((superType != null && !superType.getElement().isObject())
       || !classElement.getInterfaces().isEmpty());
 }
Beispiel #14
0
 /**
  * @param classElement
  * @return Whether the class has type parameters.
  */
 private boolean hasTypeParameters(ClassElement classElement) {
   return classElement.getTypeParameters().size() > 0;
 }
Beispiel #15
0
  private void generateRTTAddToMethod(DartClass x) {
    ClassElement classElement = x.getSymbol();

    // 2) create "addTo" method
    // Foo$Type$addTo(target, typeargs) {
    //   var rtt = Foo$lookupOrCreateRTT(typeargs)
    //   target.implementedTypes[rtt.classkey] = rtt;
    // }

    // Build the function
    JsFunction addToFn = new JsFunction(globalScope);
    addToFn.setBody(new JsBlock());
    JsScope scope = new JsScope(globalScope, "temp");

    JsName targetType = scope.declareName("target");
    addToFn.getParameters().add(new JsParameter(targetType));

    // Get the RTT info object
    JsName rtt = scope.declareName("rtt");
    List<JsStatement> body = addToFn.getBody().getStatements();
    JsInvocation callLookup = newInvocation(getRTTLookupMethodName(classElement));

    if (hasTypeParameters(classElement)) {
      JsName typeArgs = scope.declareName("typeArgs");
      addToFn.getParameters().add(new JsParameter(typeArgs));
      callLookup.getArguments().add(new JsNameRef(typeArgs));
    }

    JsStatement rttLookup = newVar((SourceInfo) null, rtt, callLookup);
    body.add(rttLookup);

    // store it.
    JsExpression addToTypes =
        newAssignment(
            new JsArrayAccess(
                newNameRef(targetType.makeRef(), "implementedTypes"),
                newNameRef(rtt.makeRef(), "classKey")),
            rtt.makeRef());
    body.add(addToTypes.makeStmt());

    InterfaceType superType = classElement.getSupertype();
    if (superType != null && !superType.getElement().isObject()) {
      ClassElement interfaceElement = superType.getElement();
      JsInvocation callAddTo =
          newInvocation(getRTTAddToMethodName(interfaceElement), targetType.makeRef());
      if (hasTypeParameters(interfaceElement) && !superType.hasDynamicTypeArgs()) {
        JsArrayLiteral superTypeArgs = new JsArrayLiteral();
        List<? extends Type> typeParams = classElement.getTypeParameters();
        for (Type arg : superType.getArguments()) {
          superTypeArgs
              .getExpressions()
              .add(
                  buildTypeLookupExpression(
                      arg, typeParams, nameref(null, targetType.makeRef(), "typeArgs")));
        }
        callAddTo.getArguments().add(superTypeArgs);
      }
      body.add(callAddTo.makeStmt());
    }

    // Add the interfaces

    for (InterfaceType interfaceType : classElement.getInterfaces()) {
      ClassElement interfaceElement = interfaceType.getElement();
      JsInvocation callAddTo =
          call(null, getRTTAddToMethodName(interfaceElement), targetType.makeRef());
      if (hasTypeParameters(interfaceElement) && !interfaceType.hasDynamicTypeArgs()) {
        JsArrayLiteral interfaceTypeArgs = new JsArrayLiteral();
        List<? extends Type> typeParams = classElement.getTypeParameters();
        for (Type arg : interfaceType.getArguments()) {
          interfaceTypeArgs
              .getExpressions()
              .add(
                  buildTypeLookupExpression(
                      arg, typeParams, nameref(null, targetType.makeRef(), "typeArgs")));
        }
        callAddTo.getArguments().add(interfaceTypeArgs);
      }
      body.add(callAddTo.makeStmt());
    }

    // Add the function statement
    JsExpression fnDecl = newAssignment(getRTTAddToMethodName(classElement), addToFn);
    globalBlock.getStatements().add(fnDecl.makeStmt());
  }