/* * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered * by the modified BSD License. You should have received a copy of the * modified BSD license with this compiler. * * Copyright (c) 2005-2008, Torbjorn Ekman * All rights reserved. */ aspect GreatestLowerBounFactory { syn nta TypeDecl TypeVariable.toInterface() { // convert var to interface InterfaceDecl ITj = new InterfaceDecl(); ITj.setID("ITj_" + hashCode()); // I'm assuming that TypeVariable has no members of it's own. // TODO: would it be enough to add only public members of a bound // that is TypeVariable or ClassDecl and add other (interface) // bounds as superinterfaces to ITj // TODO: Is it really necessary to add public members to the new // interface? Or is an empty interface more than enough since java // has a nominal type system. for (int i = 0; i < getNumTypeBound(); i++) { TypeDecl bound = getTypeBound(i).type(); for (int j = 0; j < bound.getNumBodyDecl(); j++) { BodyDecl bd = bound.getBodyDecl(j); if (bd instanceof FieldDeclaration) { FieldDeclaration fd = (FieldDeclaration) bd.fullCopy(); if (fd.isPublic()) ITj.addBodyDecl(fd); } else if (bd instanceof MethodDecl) { MethodDecl md = (MethodDecl) bd; if (md.isPublic()) ITj.addBodyDecl((BodyDecl)md.fullCopy()); } } } return ITj; } public class GLBTypeFactory { // TODO add support for array types. public static TypeDecl glb(final ArrayList typeList) { TypeDecl retType = ((TypeDecl) typeList.get(0)).unknownType(); TypeDecl cls = mostSpecificSuperClass(typeList); if (cls != null) { ArrayList intersectInterfaceList = new ArrayList(); ArrayList allInterfaceList = new ArrayList(); for (Iterator itera = typeList.iterator(); itera.hasNext();) { TypeDecl typeDecl = (TypeDecl) itera.next(); addInterfaces(intersectInterfaceList, allInterfaceList, typeDecl); } // remove all interfaces that are not most specific. greatestLowerBounds(intersectInterfaceList); // check for interface compatibility. if (checkInterfaceCompatibility(allInterfaceList) && checkClassInterfaceCompatibility(cls, intersectInterfaceList)) { greatestLowerBounds(typeList); if(typeList.size() == 1) { retType = (TypeDecl)typeList.iterator().next(); } else { retType = retType.lookupGLBType(typeList); } } } return retType; } /** * @param intersectInterfaceList * @param allInterfaceList * @param typeDecl */ private static void addInterfaces(ArrayList intersectInterfaceList, ArrayList allInterfaceList, TypeDecl typeDecl) { if(typeDecl.isInterfaceDecl()) { intersectInterfaceList.add((InterfaceDecl)typeDecl); allInterfaceList.add((InterfaceDecl)typeDecl); } else if (typeDecl instanceof TypeVariable) { TypeVariable varTD = (TypeVariable)typeDecl; // add the interfaces created for type variables to // interface list to be checked for compatibility intersectInterfaceList.add(varTD.toInterface()); // add the bounds of the type variable that are interfaces. allInterfaceList.addAll(varTD.implementedInterfaces()); } else if (typeDecl instanceof LUBType) { allInterfaceList.addAll(typeDecl.implementedInterfaces()); } else if (typeDecl instanceof GLBType) { allInterfaceList.addAll(typeDecl.implementedInterfaces()); } } /** * See JLS section 4.9 about Intersection Types *
* For each Ti, 1 ≤ i ≤ n, let Ci * be the most specific class or array type such that Ti * <: Ci Then there must be some Tk * <: Ck such that Ck <: * Ci for any i, 1 ≤ i ≤ n, or a * compile-time error occurs. * * @param T * @param types * @return the most specific class that all elements in types are a * subtype of. Or null if no such class exists. */ public final static TypeDecl mostSpecificSuperClass(final ArrayList types) { ArrayList csList = new ArrayList(); for(Iterator iter = types.iterator(); iter.hasNext(); ) { csList.add(mostSpecificSuperClass((TypeDecl)iter.next())); } // find Tk with Ck greatestLowerBounds(csList); if(csList.size() == 1) { // OK return (TypeDecl) csList.get(0); } else { // Ck does not exist. return null; } } /** * Return most specific superclass of t. * * @param t * @return */ private final static TypeDecl mostSpecificSuperClass(final TypeDecl t) { HashSet superTypes = new HashSet(); addSuperClasses(t, superTypes); if (superTypes.isEmpty()) return t.typeObject(); ArrayList result = new ArrayList(superTypes.size()); result.addAll(superTypes); greatestLowerBounds(result); if (result.size() == 1) return (TypeDecl) result.get(0); else return (TypeDecl) t.typeObject(); } /** * Add the superclasses (Ci) of t to the set * result. *