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; }
/** 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); } }
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(); }
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; }
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; }
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; }
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; } }
private boolean hasRTTImplements(ClassElement classElement) { InterfaceType superType = classElement.getSupertype(); return ((superType != null && !superType.getElement().isObject()) || !classElement.getInterfaces().isEmpty()); }
/** * @param classElement * @return Whether the class has type parameters. */ private boolean hasTypeParameters(ClassElement classElement) { return classElement.getTypeParameters().size() > 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()); }