/* * 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. *

* * @param t * @param result */ private static final void addSuperClasses(final TypeDecl t, final HashSet result) { if (t == null) return; // class if (t.isClassDecl() && !result.contains(t)) { result.add((ClassDecl) t); } // type variable, probably called from from 1st if case. else if (t.isTypeVariable()) { TypeVariable var = (TypeVariable) t; for (int i = 0; i < var.getNumTypeBound(); i++) addSuperClasses(var.getTypeBound(i).type(), result); } // intersection type else if (t instanceof LUBType || t instanceof GLBType) { result.add(t); } // interface else if (t.isInterfaceDecl()) result.add((ClassDecl) t.typeObject()); } /** * @param T * @param ifaceList * @return */ private static boolean checkInterfaceCompatibility(ArrayList ifaceList) { for (int i = 0; i < ifaceList.size(); i++) { HashSet superISet_i = Constraints .parameterizedSupertypes((TypeDecl) ifaceList.get(i)); for (Iterator iter1 = superISet_i.iterator(); iter1.hasNext();) { InterfaceDecl superIface_i = (InterfaceDecl) iter1.next(); if (superIface_i instanceof ParInterfaceDecl) { ParInterfaceDecl pi = (ParInterfaceDecl) superIface_i; for (int j = i + 1; j < ifaceList.size(); j++) { HashSet superISet_j = Constraints .parameterizedSupertypes((TypeDecl) ifaceList .get(j)); for (Iterator iter2 = superISet_j.iterator(); iter2 .hasNext();) { InterfaceDecl superIface_j = (InterfaceDecl) iter2 .next(); if (superIface_j instanceof ParInterfaceDecl) { ParInterfaceDecl pj = (ParInterfaceDecl) superIface_j; if (pi != pj && pi.genericDecl() == pj.genericDecl() && !pi.sameArgument(pj)) { return false; } } } } } } } return true; } /** * @param t * @param cls * @param ifaceList * @return */ private static boolean checkClassInterfaceCompatibility(TypeDecl cls, ArrayList ifaceList) { HashSet implementedInterfaces = cls.implementedInterfaces(); for (Iterator iter1 = implementedInterfaces.iterator(); iter1.hasNext();) { InterfaceDecl impInterface = (InterfaceDecl) iter1.next(); if (impInterface instanceof ParInterfaceDecl) { ParInterfaceDecl impParIface = (ParInterfaceDecl) impInterface; for (Iterator iter2 = ifaceList.iterator(); iter2.hasNext();) { InterfaceDecl iface = (InterfaceDecl) iter2.next(); if (iface instanceof ParInterfaceDecl) { ParInterfaceDecl parIface = (ParInterfaceDecl) iface; if (parIface != impParIface && parIface.genericDecl() == impParIface .genericDecl() && !parIface.sameArgument(impParIface)) { return false; } } } } } return true; } /** * Find the greatest lower bound(s). * * @param types */ public static final void greatestLowerBounds(ArrayList types) { for (int i = 0; i < types.size(); i++) { TypeDecl U = (TypeDecl) types.get(i); for (int j = i + 1; j < types.size(); j++) { TypeDecl V = (TypeDecl) types.get(j); if (U == null || V == null) continue; if (U.instanceOf(V)) types.set(j, null); else if (V.instanceOf(U)) types.set(i, null); } } // filter null's removeNullValues(types); } /** * Remove null values from the given list * * @param types */ public static final void removeNullValues(ArrayList types) { ArrayList filter = new ArrayList(1); filter.add(null); types.removeAll(filter); } } }