/* * 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 Generics { refine TypeAnalysis eq MethodAccess.type() { if(getNumArg() == 0 && name().equals("getClass") && decl().hostType().isObject()) { TypeDecl bound = isQualified() ? qualifier().type() : hostType(); ArrayList args = new ArrayList(); args.add(bound.erasure().asWildcardExtends()); return ((GenericClassDecl)lookupType("java.lang", "Class")).lookupParTypeDecl(args); } else return TypeAnalysis.MethodAccess.type(); } // imported types are considered raw types by the name resolver // here we replace them by their generic counter parts refine LookupType eq CompilationUnit.getChild().lookupType(String name) { SimpleSet result = SimpleSet.emptySet; for(Iterator iter = LookupType.CompilationUnit.getChild().lookupType(name).iterator(); iter.hasNext(); ) { TypeDecl typeDecl = (TypeDecl)iter.next(); if(typeDecl instanceof ParTypeDecl) result = result.add(((ParTypeDecl)typeDecl).genericDecl()); else result = result.add(typeDecl); } return result; } refine TypeAnalysis eq ClassDecl.castingConversionTo(TypeDecl type) { TypeDecl S = this; TypeDecl T = type; if(T instanceof TypeVariable) { TypeVariable t = (TypeVariable)T; if(t.getNumTypeBound() == 0) return true; for(int i = 0; i < t.getNumTypeBound(); i++) if(castingConversionTo(t.getTypeBound(i).type())) return true; return false; } if(T.isClassDecl() && (S.erasure() != S || T.erasure() != T)) return S.erasure().castingConversionTo(T.erasure()); return TypeAnalysis.ClassDecl.castingConversionTo(type); } refine TypeAnalysis eq InterfaceDecl.castingConversionTo(TypeDecl type) { TypeDecl S = this; TypeDecl T = type; if(T.isArrayDecl()) return T.instanceOf(S); else if(T.isReferenceType() && !T.isFinal()) { return true; } else { return T.instanceOf(S); } } eq TypeVariable.castingConversionTo(TypeDecl type) { if(!type.isReferenceType()) return false; if(getNumTypeBound() == 0) return true; for(int i = 0; i < getNumTypeBound(); i++) if(getTypeBound(i).type().castingConversionTo(type)) return true; return false; } refine TypeAnalysis eq ArrayDecl.castingConversionTo(TypeDecl type) { TypeDecl S = this; TypeDecl T = type; if(T instanceof TypeVariable) { TypeVariable t = (TypeVariable)T; if(!type.isReferenceType()) return false; if(t.getNumTypeBound() == 0) return true; for(int i = 0; i < t.getNumTypeBound(); i++) { TypeDecl bound = t.getTypeBound(i).type(); if(bound.isObject() || bound == typeSerializable() || bound == typeCloneable()) return true; if(bound.isTypeVariable() && castingConversionTo(bound)) return true; if(bound.isArrayDecl() && castingConversionTo(bound)) return true; } return false; } else return TypeAnalysis.ArrayDecl.castingConversionTo(type); } refine TypeAnalysis eq ClassAccess.type() { GenericClassDecl d = (GenericClassDecl)TypeAnalysis.ClassAccess.type(); TypeDecl type = qualifier().type(); if(type.isPrimitive()) type = type.boxed(); ArrayList list = new ArrayList(); list.add(type); return d.lookupParTypeDecl(list); } refine AutoBoxing eq ConditionalExpr.type() { TypeDecl type = AutoBoxing.ConditionalExpr.type(); TypeDecl trueType = getTrueExpr().type(); TypeDecl falseType = getFalseExpr().type(); if(type.isUnknown() && (trueType.isReferenceType() || falseType.isReferenceType())) { if(!trueType.isReferenceType() && !trueType.boxed().isUnknown()) trueType = trueType.boxed(); if(!falseType.isReferenceType() && !falseType.boxed().isUnknown()) falseType = falseType.boxed(); if(trueType.isReferenceType() && falseType.isReferenceType()) { ArrayList list = new ArrayList(); list.add(trueType); list.add(falseType); return type.lookupLUBType(list); } } return type; } syn boolean TypeVariable.isNestedType() = false; // accessibility for members in generic classes // the accessibility for parameterized and raw versions of a generic class // should be the same as for the generic class, in other words the erasure of the // paramterized version. eq ParClassDecl.topLevelType() = erasure().topLevelType(); interface GenericTypeDecl { syn boolean isGenericType(); TypeDecl original(); int getNumTypeParameter(); TypeVariable getTypeParameter(int index); List getTypeParameterList(); syn lazy TypeDecl rawType(); public String fullName(); public String typeName(); sons BodyDecl:BodyDecl* TypeParameter:TypeVariable* ParTypeDecl:ParTypeDecl*; } GenericClassDecl implements GenericTypeDecl; GenericInterfaceDecl implements GenericTypeDecl; eq GenericClassDecl.rawType() = lookupParTypeDecl(new ArrayList()); eq GenericInterfaceDecl.rawType() = lookupParTypeDecl(new ArrayList()); syn boolean TypeDecl.isGenericType() = false; eq GenericTypeDecl.isGenericType() = true; // Brute force replacesment with generic one in AST // make sure that the AST has not beed traversed yet! public TypeDecl TypeDecl.makeGeneric(Signatures.ClassSignature s) { return this; } public TypeDecl ClassDecl.makeGeneric(Signatures.ClassSignature s) { if(s.hasFormalTypeParameters()) { ASTNode node = getParent(); int index = node.getIndexOfChild(this); node.setChild( new GenericClassDecl( getModifiersNoTransform(), getID(), s.hasSuperclassSignature() ? new Opt(s.superclassSignature()) : getSuperClassAccessOptNoTransform(), s.hasSuperinterfaceSignature() ? s.superinterfaceSignature() : getImplementsListNoTransform(), getBodyDeclListNoTransform(), s.typeParameters() ), index ); return (TypeDecl)node.getChildNoTransform(index); } else { if(s.hasSuperclassSignature()) setSuperClassAccessOpt(new Opt(s.superclassSignature())); if(s.hasSuperinterfaceSignature()) setImplementsList(s.superinterfaceSignature()); return this; } } public TypeDecl InterfaceDecl.makeGeneric(Signatures.ClassSignature s) { if(s.hasFormalTypeParameters()) { ASTNode node = getParent(); int index = node.getIndexOfChild(this); node.setChild( new GenericInterfaceDecl( getModifiersNoTransform(), getID(), s.hasSuperinterfaceSignature() ? s.superinterfaceSignature() : getSuperInterfaceIdListNoTransform(), getBodyDeclListNoTransform(), s.typeParameters() ), index ); return (TypeDecl)node.getChildNoTransform(index); } else { if(s.hasSuperinterfaceSignature()) setSuperInterfaceIdList(s.superinterfaceSignature()); return this; } } public TypeDecl GenericTypeDecl.makeGeneric(Signatures.ClassSignature s) { return (TypeDecl)this; } interface ParTypeDecl { //syn String name(); int getNumArgument(); Access getArgument(int index); syn boolean isParameterizedType(); syn boolean isRawType(); public String typeName(); } ParClassDecl implements ParTypeDecl; ParInterfaceDecl implements ParTypeDecl; syn boolean TypeDecl.isParameterizedType() = false; eq ParTypeDecl.isParameterizedType() = true; syn boolean TypeDecl.isRawType() = isNestedType() && enclosingType().isRawType(); eq ParClassDecl.isRawType() = isNestedType() && enclosingType().isRawType(); eq ParInterfaceDecl.isRawType() = isNestedType() && enclosingType().isRawType(); eq RawClassDecl.isRawType() = true; eq RawInterfaceDecl.isRawType() = true; } aspect GenericsTypeAnalysis { eq ParTypeAccess.unqualifiedScope() = getParent() instanceof Access ? ((Access)getParent()).unqualifiedScope() : super.unqualifiedScope(); eq ParTypeAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name); eq ParTypeAccess.type() { TypeDecl typeDecl = genericDecl(); if(typeDecl instanceof GenericTypeDecl) { // use signature in lookup for types that are used in extends and implements clauses if(unqualifiedScope().getParent().getParent() instanceof TypeDecl) return ((GenericTypeDecl)typeDecl).lookupParTypeDecl(this); ArrayList args = new ArrayList(); for(int i = 0; i < getNumTypeArgument(); i++) args.add(getTypeArgument(i).type()); return ((GenericTypeDecl)typeDecl).lookupParTypeDecl(args); } return typeDecl; } syn TypeDecl ParTypeAccess.genericDecl() = getTypeAccess().type(); eq ParTypeAccess.isTypeAccess() = true; refine LookupType eq TypeAccess.decl() { TypeDecl decl = LookupType.TypeAccess.decl(); if(decl instanceof GenericTypeDecl && isRaw()) return ((GenericTypeDecl)decl).lookupParTypeDecl(new ArrayList()); return decl; } // this method assumes that the bound type is generic public boolean TypeAccess.isRaw() { /* if(hasNextAccess()) return false; */ ASTNode parent = getParent(); while(parent instanceof AbstractDot) parent = parent.getParent(); if(parent instanceof ParTypeAccess) return false; if(parent instanceof ImportDecl) return false; /* Access a = this; while(a.isTypeAccess() && hasNextAccess()) a = a.nextAccess(); if(a.isThisAccess() || a.isSuperAccess()) return false; */ return true; } refine LookupType eq ThisAccess.decl() { TypeDecl typeDecl = LookupType.ThisAccess.decl(); if(typeDecl instanceof ParTypeDecl) typeDecl = ((ParTypeDecl)typeDecl).genericDecl(); return typeDecl; } refine LookupType eq SuperAccess.decl() { TypeDecl typeDecl = LookupType.SuperAccess.decl(); if(typeDecl instanceof ParTypeDecl) typeDecl = ((ParTypeDecl)typeDecl).genericDecl(); return typeDecl; } public boolean BoundTypeAccess.isRaw() { return getTypeDecl().isRawType(); } public boolean ParTypeAccess.isRaw() { return false; } } aspect GenericsErasure { syn lazy TypeDecl TypeDecl.erasure() { if(isAnonymous() || isLocalClass()) return this; if(!isNestedType()) return this; return extractSingleType(enclosingType().erasure().memberTypes(name())); } eq ParClassDecl.erasure() = genericDecl(); eq ParInterfaceDecl.erasure() = genericDecl(); eq TypeVariable.erasure() = getTypeBound(0).type().erasure(); // Skip last erasure? eq ArrayDecl.erasure() = componentType().erasure().arrayType(); } aspect GenericsTypeCheck { // different parameterizations of the same generic interface may not be implemented refine TypeHierarchyCheck public void TypeDecl.typeCheck() { TypeHierarchyCheck.TypeDecl.typeCheck(); ArrayList list = new ArrayList(); list.addAll(implementedInterfaces()); for(int i = 0; i < list.size(); i++) { InterfaceDecl decl = (InterfaceDecl)list.get(i); if(decl instanceof ParInterfaceDecl) { ParInterfaceDecl p = (ParInterfaceDecl)decl; for(Iterator i2 = list.listIterator(i); i2.hasNext(); ) { InterfaceDecl decl2 = (InterfaceDecl)i2.next(); if(decl2 instanceof ParInterfaceDecl) { ParInterfaceDecl q = (ParInterfaceDecl)decl2; if(p != q && p.genericDecl() == q.genericDecl() && !p.sameArgument(q)) error(p.genericDecl().name() + " cannot be inherited with different arguments: " + p.typeName() + " and " + q.typeName()); } } } } } syn boolean ParTypeDecl.sameArgument(ParTypeDecl decl) { if(this == decl) return true; if(genericDecl() != decl.genericDecl()) return false; for(int i = 0; i < getNumArgument(); i++) { TypeDecl t1 = getArgument(i).type(); TypeDecl t2 = decl.getArgument(i).type(); if(t1 instanceof ParTypeDecl && t2 instanceof ParTypeDecl) { if(!((ParTypeDecl)t1).sameArgument((ParTypeDecl)t2)) return false; } else { if(t1 != t2) return false; } } return true; } syn lazy HashSet TypeDecl.implementedInterfaces() = new HashSet(); eq ClassDecl.implementedInterfaces() { HashSet set = new HashSet(); if(hasSuperclass()) set.addAll(superclass().implementedInterfaces()); for(Iterator iter = interfacesIterator(); iter.hasNext(); ) { InterfaceDecl decl = (InterfaceDecl)iter.next(); set.add(decl); set.addAll(decl.implementedInterfaces()); } return set; } eq InterfaceDecl.implementedInterfaces() { HashSet set= new HashSet(); set.addAll(typeObject().implementedInterfaces()); for(Iterator iter = superinterfacesIterator(); iter.hasNext(); ) { InterfaceDecl decl = (InterfaceDecl)iter.next(); set.add(decl); set.addAll(decl.implementedInterfaces()); } return set; } public void GenericClassDecl.typeCheck() { super.typeCheck(); if(instanceOf(typeThrowable())) error(" generic class " + typeName() + " may not directly or indirectly inherit java.lang.Throwable"); } public void GenericInterfaceDecl.typeCheck() { super.typeCheck(); if(instanceOf(typeThrowable())) error(" generic interface " + typeName() + " may not directly or indirectly inherit java.lang.Throwable"); } inh TypeDecl GenericClassDecl.typeThrowable(); inh TypeDecl GenericInterfaceDecl.typeThrowable(); public void TypeAccess.typeCheck() { TypeDecl type = type(); if(type.isRawType() && type.isNestedType() && type.enclosingType().isParameterizedType() && !type.enclosingType().isRawType()) error("Can not access a member type of a paramterized type as a raw type"); } public void ParTypeAccess.typeCheck() { super.typeCheck(); if(!genericDecl().isUnknown()) { TypeDecl type = type(); if(!genericDecl().isGenericType()) { error(genericDecl().typeName() + " is not a generic type but used as one in " + this); } else if(!type.isRawType() && type.isNestedType() && type.enclosingType().isRawType()) error("Can not access a member type of a raw type as a parameterized type"); else { GenericTypeDecl decl = (GenericTypeDecl)genericDecl(); GenericTypeDecl original = (GenericTypeDecl)decl.original(); if(original.getNumTypeParameter() != getNumTypeArgument()) { error(decl.typeName() + " takes " + original.getNumTypeParameter() + " type parameters, not " + getNumTypeArgument() + " as used in " + this); } else { ParTypeDecl typeDecl = (ParTypeDecl)type(); for(int i = 0; i < getNumTypeArgument(); i++) { if(!getTypeArgument(i).type().instanceOf(original.getTypeParameter(i))) { error("type argument " + i + " is of type " + getTypeArgument(i).type().typeName() + " which is not a subtype of " + original.getTypeParameter(i).typeName()); } } } } } } } aspect GenericsNameBinding { eq ParClassDecl.getArgument().nameType() = NameType.TYPE_NAME; eq ParInterfaceDecl.getArgument().nameType() = NameType.TYPE_NAME; //eq GenericClassDecl.getParTypeDecl().isNestedType() = isNestedType(); //eq GenericClassDecl.getParTypeDecl().enclosingType() = enclosingType(); eq GenericClassDecl.getTypeParameter().isNestedType() = true; eq GenericClassDecl.getTypeParameter().enclosingType() = this; //eq GenericInterfaceDecl.getParTypeDecl().isNestedType() = isNestedType(); //eq GenericInterfaceDecl.getParTypeDecl().enclosingType() = enclosingType(); eq GenericInterfaceDecl.getTypeParameter().isNestedType() = true; eq GenericInterfaceDecl.getTypeParameter().enclosingType() = this; public SimpleSet GenericTypeDecl.addTypeVariables(SimpleSet c, String name) { GenericTypeDecl original = (GenericTypeDecl)original(); for(int i = 0; i < original.getNumTypeParameter(); i++) { TypeVariable p = original.getTypeParameter(i); if(p.name().equals(name)) c = c.add(p); } return c; } eq GenericInterfaceDecl.getSuperInterfaceId().lookupType(String name) { SimpleSet c = addTypeVariables(SimpleSet.emptySet, name); return !c.isEmpty() ? c : lookupType(name); } eq GenericClassDecl.getSuperClassAccess().lookupType(String name) { SimpleSet c = addTypeVariables(SimpleSet.emptySet, name); return !c.isEmpty() ? c : lookupType(name); } eq GenericClassDecl.getImplements().lookupType(String name) { SimpleSet c = addTypeVariables(SimpleSet.emptySet, name); return !c.isEmpty() ? c : lookupType(name); } eq GenericTypeDecl.getTypeParameter().lookupType(String name) { SimpleSet c = memberTypes(name); c = addTypeVariables(c, name); if(!c.isEmpty()) return c; // 8.5.2 if(isClassDecl() && isStatic() && !isTopLevelType()) { for(Iterator iter = lookupType(name).iterator(); iter.hasNext(); ) { TypeDecl d = (TypeDecl)iter.next(); if(d.isStatic() || (d.enclosingType() != null && instanceOf(d.enclosingType()))) { c = c.add(d); } } } else c = lookupType(name); if(!c.isEmpty()) return c; return topLevelType().lookupType(name); // Fix to search imports } eq GenericTypeDecl.getBodyDecl(int index).lookupType(String name) { SimpleSet c = memberTypes(name); if(getBodyDecl(index).visibleTypeParameters()) c = addTypeVariables(c, name); if(!c.isEmpty()) return c; // 8.5.2 if(isClassDecl() && isStatic() && !isTopLevelType()) { for(Iterator iter = lookupType(name).iterator(); iter.hasNext(); ) { TypeDecl d = (TypeDecl)iter.next(); if(d.isStatic() || (d.enclosingType() != null && instanceOf(d.enclosingType()))) { c = c.add(d); } } } else c = lookupType(name); if(!c.isEmpty()) return c; return topLevelType().lookupType(name); // Fix to search imports // include type parameters if not static } public void ParClassDecl.collectErrors() { // Disable error check for ParClassDecl which is an instanciated GenericClassDecl } public void ParInterfaceDecl.collectErrors() { // Disable error check for ParInterfaceDecl which is an instanciated GenericInterfaceDecl } } aspect LookupParTypeDecl { eq TypeVariable.fullName() { if(getParent().getParent() instanceof TypeDecl) { TypeDecl typeDecl = (TypeDecl)getParent().getParent(); return typeDecl.fullName() + "@" + name(); } return super.fullName(); } syn boolean TypeDecl.sameSignature(Access a) { if(a instanceof ParTypeAccess) return false; if(a instanceof AbstractWildcard) return false; return this == a.type(); } eq TypeVariable.sameSignature(Access a) = a.type() == this; syn boolean ParTypeDecl.sameSignature(Access a){ if(a instanceof ParTypeAccess) { ParTypeAccess ta = (ParTypeAccess)a; if(genericDecl() != ta.genericDecl()) return false; if(getNumArgument() != ta.getNumTypeArgument()) return false; for(int i = 0; i < getNumArgument(); i++) if(!getArgument(i).type().sameSignature(ta.getTypeArgument(i))) return false; return true; } else if(a instanceof TypeAccess && ((TypeAccess)a).isRaw()) return false; return super.sameSignature(a); } eq RawClassDecl.sameSignature(Access a) = a instanceof TypeAccess && a.type() == this; eq RawInterfaceDecl.sameSignature(Access a) = a instanceof TypeAccess && a.type() == this; eq WildcardType.sameSignature(Access a) { if(a instanceof Wildcard) return true; return super.sameSignature(a); } eq WildcardExtendsType.sameSignature(Access a) { if(a instanceof WildcardExtends) return getAccess().type().sameSignature(((WildcardExtends)a).getAccess()); return super.sameSignature(a); } eq WildcardSuperType.sameSignature(Access a) { if(a instanceof WildcardSuper) return getAccess().type().sameSignature(((WildcardSuper)a).getAccess()); return super.sameSignature(a); } syn lazy boolean ParTypeDecl.sameSignature(ArrayList list) circular [true] { if(getNumArgument() != list.size()) return false; for(int i = 0; i < list.size(); i++) if(getArgument(i).type() != list.get(i)) return false; return true; } syn lazy final List GenericClassDecl.getParTypeDeclList() = new List(); syn lazy final List GenericInterfaceDecl.getParTypeDeclList() = new List(); syn lazy TypeDecl GenericTypeDecl.lookupParTypeDecl(ParTypeAccess p); eq GenericClassDecl.lookupParTypeDecl(ParTypeAccess p) { for(int i = 0; i < getNumParTypeDecl(); i++) { ParTypeDecl decl = (ParTypeDecl)getParTypeDecl(i); if(decl.sameSignature(p)) return (TypeDecl)decl; } ParClassDecl typeDecl = new ParClassDecl(); typeDecl.setModifiers((Modifiers)getModifiers().fullCopy()); typeDecl.setID(getID()); addParTypeDecl(typeDecl); List list = new List(); for(int i = 0; i < p.getNumTypeArgument(); i++) list.add(p.getTypeArgument(i).type().createBoundAccess()); typeDecl.setArgumentList(list); typeDecl.is$Final = true; return typeDecl; } eq GenericInterfaceDecl.lookupParTypeDecl(ParTypeAccess p) { for(int i = 0; i < getNumParTypeDecl(); i++) { ParTypeDecl decl = (ParTypeDecl)getParTypeDecl(i); if(decl.sameSignature(p)) return (TypeDecl)decl; } ParInterfaceDecl typeDecl = new ParInterfaceDecl(); typeDecl.setModifiers((Modifiers)getModifiers().fullCopy()); typeDecl.setID(getID()); addParTypeDecl(typeDecl); List list = new List(); for(int i = 0; i < p.getNumTypeArgument(); i++) list.add(p.getTypeArgument(i).type().createBoundAccess()); typeDecl.setArgumentList(list); typeDecl.is$Final = true; return typeDecl; } // used by methods inference when looking up paramterizations from wildcards syn lazy final TypeDecl GenericTypeDecl.lookupParTypeDecl(ArrayList list); eq GenericClassDecl.lookupParTypeDecl(ArrayList list) { for(int i = 0; i < getNumParTypeDecl(); i++) { ParTypeDecl decl = (ParTypeDecl)getParTypeDecl(i); if(decl.isRawType() ? list.isEmpty() : decl.sameSignature(list)) return (TypeDecl)decl; } ParClassDecl typeDecl = list.size() == 0 ? new RawClassDecl() : new ParClassDecl(); typeDecl.setModifiers((Modifiers)getModifiers().fullCopy()); typeDecl.setID(getID()); typeDecl.setArgumentList(createArgumentList(list)); typeDecl.is$Final = true; addParTypeDecl(typeDecl); return typeDecl; } eq GenericInterfaceDecl.lookupParTypeDecl(ArrayList list) { for(int i = 0; i < getNumParTypeDecl(); i++) { ParTypeDecl decl = (ParTypeDecl)getParTypeDecl(i); if(decl.isRawType() ? list.isEmpty() : decl.sameSignature(list)) return (TypeDecl)decl; } ParInterfaceDecl typeDecl = list.size() == 0 ? new RawInterfaceDecl() : new ParInterfaceDecl(); typeDecl.setModifiers((Modifiers)getModifiers().fullCopy()); typeDecl.setID(getID()); typeDecl.setArgumentList(createArgumentList(list)); typeDecl.is$Final = true; addParTypeDecl(typeDecl); return typeDecl; } public List GenericTypeDecl.createArgumentList(ArrayList params) { GenericTypeDecl original = (GenericTypeDecl)original(); List list = new List(); if(params.isEmpty()) for(int i = 0; i < original.getNumTypeParameter(); i++) list.add(original.getTypeParameter(i).erasure().createBoundAccess()); else for(Iterator iter = params.iterator(); iter.hasNext(); ) list.add(((TypeDecl)iter.next()).createBoundAccess()); return list; } interface Parameterization { boolean isRawType(); TypeDecl substitute(TypeVariable typeVariable); } ParTypeDecl implements Parameterization; interface MemberSubstitutor extends Parameterization { TypeDecl original(); void addBodyDecl(BodyDecl b); TypeDecl substitute(TypeVariable typeVariable); } ParClassDecl implements MemberSubstitutor; ParInterfaceDecl implements MemberSubstitutor; ClassDeclSubstituted implements MemberSubstitutor; InterfaceDeclSubstituted implements MemberSubstitutor; GenericClassDeclSubstituted implements MemberSubstitutor; GenericInterfaceDeclSubstituted implements MemberSubstitutor; public TypeDecl TypeDecl.substitute(TypeVariable typeVariable) { if(isTopLevelType()) return typeVariable; return enclosingType().substitute(typeVariable); } public TypeDecl ParTypeDecl.substitute(TypeVariable typeVariable) { for(int i = 0; i < numTypeParameter(); i++) if(typeParameter(i) == typeVariable) return getArgument(i).type(); return super.substitute(typeVariable); } public TypeDecl ParMethodDecl.substitute(TypeVariable typeVariable) { for(int i = 0; i < numTypeParameter(); i++) if(typeParameter(i) == typeVariable) return getTypeArgument(i).type(); return hostType().substitute(typeVariable); } public int ParTypeDecl.numTypeParameter() { return ((GenericTypeDecl)original()).getNumTypeParameter(); } public TypeVariable ParTypeDecl.typeParameter(int index) { return ((GenericTypeDecl)original()).getTypeParameter(index); } ParMethodDecl implements Parameterization; public boolean ParMethodDecl.isRawType() { return false; } public int ParMethodDecl.numTypeParameter() { return genericMethodDecl().original().getNumTypeParameter(); } public TypeVariable ParMethodDecl.typeParameter(int index) { return genericMethodDecl().original().getTypeParameter(index); } public Access TypeDecl.substitute(Parameterization parTypeDecl) { if(parTypeDecl instanceof ParTypeDecl && ((ParTypeDecl)parTypeDecl).genericDecl() == this) return ((TypeDecl)parTypeDecl).createBoundAccess(); if(isTopLevelType()) return createBoundAccess(); return enclosingType().substitute(parTypeDecl).qualifiesAccess(new TypeAccess(name())); } public Access ArrayDecl.substitute(Parameterization parTypeDecl) { return new ArrayTypeAccess(componentType().substitute(parTypeDecl)); } public Access TypeVariable.substitute(Parameterization parTypeDecl) { if(parTypeDecl.isRawType()) return erasure().createBoundAccess(); return parTypeDecl.substitute(this).createBoundAccess(); } public Access ParTypeDecl.substitute(Parameterization parTypeDecl) { // TODO: include nesting as well.... if(parTypeDecl.isRawType()) return ((GenericTypeDecl)genericDecl()).rawType().createBoundAccess(); if(!usesTypeVariable()) return super.substitute(parTypeDecl); List list = new List(); for(int i = 0; i < getNumArgument(); i++) list.add(getArgument(i).type().substitute(parTypeDecl)); return new ParTypeAccess(genericDecl().createQualifiedAccess(), list); } public Access RawClassDecl.substitute(Parameterization parTypeDecl) { return createBoundAccess(); } public Access RawInterfaceDecl.substitute(Parameterization parTypeDecl) { return createBoundAccess(); } public Access WildcardExtendsType.substitute(Parameterization parTypeDecl) { if(!usesTypeVariable()) return super.substitute(parTypeDecl); return new WildcardExtends(getAccess().type().substitute(parTypeDecl)); } public Access WildcardSuperType.substitute(Parameterization parTypeDecl) { if(!usesTypeVariable()) return super.substitute(parTypeDecl); return new WildcardSuper(getAccess().type().substitute(parTypeDecl)); } public Access TypeDecl.substituteReturnType(Parameterization parTypeDecl) { return substitute(parTypeDecl); } public Access ArrayDecl.substituteReturnType(Parameterization parTypeDecl) { return new ArrayTypeAccess(componentType().substituteReturnType(parTypeDecl)); } inh TypeDecl TypeVariable.typeObject(); syn lazy TypeDecl TypeVariable.lubType() { ArrayList list = new ArrayList(); for(int i = 0; i < getNumTypeBound(); i++) list.add(getTypeBound(i).type()); return lookupLUBType(list); } public Access TypeVariable.substituteReturnType(Parameterization parTypeDecl) { if(parTypeDecl.isRawType()) return erasure().createBoundAccess(); TypeDecl typeDecl = parTypeDecl.substitute(this); if(typeDecl instanceof WildcardType) { // the bound of this type variable return createBoundAccess(); //return lubType().createBoundAccess(); //return typeObject().createBoundAccess(); } else if(typeDecl instanceof WildcardExtendsType) { if(typeDecl.instanceOf(this)) return ((WildcardExtendsType)typeDecl).extendsType().createBoundAccess(); else return createBoundAccess(); // the bound of this type variable of the bound of the wild card if it is more specific //return ((WildcardExtendsType)typeDecl).extendsType().createBoundAccess(); } else if(typeDecl instanceof WildcardSuperType) { // the bound of this type variable return createBoundAccess(); //return typeObject().createBoundAccess(); } return typeDecl.createBoundAccess(); } public Access RawClassDecl.substituteReturnType(Parameterization parTypeDecl) { return createBoundAccess(); } public Access RawInterfaceDecl.substituteReturnType(Parameterization parTypeDecl) { return createBoundAccess(); } public Access TypeDecl.substituteParameterType(Parameterization parTypeDecl) { return substitute(parTypeDecl); } inh TypeDecl TypeVariable.typeNull(); public Access TypeVariable.substituteParameterType(Parameterization parTypeDecl) { if(parTypeDecl.isRawType()) return erasure().createBoundAccess(); TypeDecl typeDecl = parTypeDecl.substitute(this); if(typeDecl instanceof WildcardType) return typeNull().createQualifiedAccess(); else if(typeDecl instanceof WildcardExtendsType) return typeNull().createQualifiedAccess(); else if(typeDecl instanceof WildcardSuperType) return ((WildcardSuperType)typeDecl).superType().createBoundAccess(); return typeDecl.createBoundAccess(); } public Access RawClassDecl.substituteParameterType(Parameterization parTypeDecl) { return createBoundAccess(); } public Access RawInterfaceDecl.substituteParameterType(Parameterization parTypeDecl) { return createBoundAccess(); } public List List.substitute(Parameterization parTypeDecl) { List list = new List(); for(int i = 0; i < getNumChild(); i++) { ASTNode node = getChild(i); if(node instanceof Access) { Access a = (Access)node; list.add(a.type().substitute(parTypeDecl)); } else if(node instanceof VariableArityParameterDeclaration) { VariableArityParameterDeclaration p = (VariableArityParameterDeclaration)node; list.add( new VariableArityParameterDeclarationSubstituted( (Modifiers)p.getModifiers().fullCopy(), // use the type acces since VariableArity adds to the dimension p.getTypeAccess().type().substituteParameterType(parTypeDecl), p.getID(), p ) ); } else if(node instanceof ParameterDeclaration) { ParameterDeclaration p = (ParameterDeclaration)node; list.add( new ParameterDeclarationSubstituted( (Modifiers)p.getModifiers().fullCopy(), p.type().substituteParameterType(parTypeDecl), p.getID(), p ) ); } else { throw new Error("Can only substitute lists of access nodes but node number " + i + " is of type " + node.getClass().getName()); } } return list; } syn lazy Opt ParClassDecl.getSuperClassAccessOpt() { GenericClassDecl decl = (GenericClassDecl)genericDecl(); Opt opt; //System.err.println("Begin substituting extends clause"); if(decl.hasSuperClassAccess()) opt = new Opt((decl.getSuperClassAccess().type().substitute(this))); else opt = new Opt(); //System.err.println("End substituting extends clause"); return opt; } syn lazy List ParClassDecl.getImplementsList() { GenericClassDecl decl = (GenericClassDecl)genericDecl(); //System.err.println("Begin substituting implements list"); List list = decl.getImplementsList().substitute(this); //System.err.println("End substituting implements list"); return list; } syn lazy List ParClassDecl.getBodyDeclList() = new List(); syn lazy List ParInterfaceDecl.getSuperInterfaceIdList() { GenericInterfaceDecl decl = (GenericInterfaceDecl)genericDecl(); //System.err.println("Begin substituting implements list"); List list = decl.getSuperInterfaceIdList().substitute(this); //System.err.println("End substituting implements list"); return list; } syn lazy List ParInterfaceDecl.getBodyDeclList() = new List(); syn boolean ASTNode.usesTypeVariable() { for(int i = 0; i < getNumChild(); i++) if(getChild(i).usesTypeVariable()) return true; return false; } syn lazy boolean MethodDecl.usesTypeVariable() = getModifiers().usesTypeVariable() || getTypeAccess().usesTypeVariable() || getParameterList().usesTypeVariable() || getExceptionList().usesTypeVariable(); syn lazy boolean FieldDeclaration.usesTypeVariable() = getTypeAccess().usesTypeVariable(); eq TypeAccess.usesTypeVariable() = decl().usesTypeVariable() || super.usesTypeVariable(); syn lazy boolean TypeDecl.usesTypeVariable() circular [false] = isNestedType() && enclosingType().usesTypeVariable(); eq ParTypeDecl.usesTypeVariable() { if(super.usesTypeVariable()) return true; for(int i = 0; i < getNumArgument(); i++) if(getArgument(i).type().usesTypeVariable()) return true; return false; } eq GenericClassDecl.usesTypeVariable() = true; eq GenericInterfaceDecl.usesTypeVariable() = true; eq TypeVariable.usesTypeVariable() = true; eq WildcardExtendsType.usesTypeVariable() = getAccess().type().usesTypeVariable(); eq WildcardSuperType.usesTypeVariable() = getAccess().type().usesTypeVariable(); eq ArrayDecl.usesTypeVariable() = elementType().usesTypeVariable(); syn lazy final HashMap MemberSubstitutor.localMethodsSignatureMap() { HashMap map = new HashMap(); for(Iterator iter = original().localMethodsIterator(); iter.hasNext(); ) { MethodDecl decl = (MethodDecl)iter.next(); if(!decl.isStatic() && (decl.usesTypeVariable() || isRawType())) { BodyDecl b = decl.p(this); b.is$Final = true; addBodyDecl(b); decl = (MethodDecl)b; } map.put(decl.signature(), decl); } return map; } syn lazy final SimpleSet MemberSubstitutor.localFields(String name) { SimpleSet set = SimpleSet.emptySet; for(Iterator iter = original().localFields(name).iterator(); iter.hasNext(); ) { FieldDeclaration f = (FieldDeclaration)iter.next(); if(!f.isStatic() && (f.usesTypeVariable() || isRawType())) { BodyDecl b = f.p(this); b.is$Final = true; addBodyDecl(b); f = (FieldDeclaration)b; } set = set.add(f); } return set; } syn lazy final SimpleSet MemberSubstitutor.localTypeDecls(String name) { SimpleSet set = SimpleSet.emptySet; for(Iterator iter = original().localTypeDecls(name).iterator(); iter.hasNext(); ) { TypeDecl t = (TypeDecl)iter.next(); if(t.isStatic()) set = set.add(t); else { BodyDecl b; TypeDecl typeDecl; if(t instanceof ClassDecl) { ClassDecl classDecl = (ClassDecl)t; typeDecl = classDecl.p(this); b = new MemberClassDecl((ClassDecl)typeDecl); b.is$Final = true; addBodyDecl(b); set = set.add(typeDecl); } else if(t instanceof InterfaceDecl) { InterfaceDecl interfaceDecl = (InterfaceDecl)t; typeDecl = interfaceDecl.p(this); b = new MemberInterfaceDecl((InterfaceDecl)typeDecl); b.is$Final = true; addBodyDecl(b); set = set.add(typeDecl); } } } return set; } syn lazy Collection MemberSubstitutor.constructors() { Collection set = new ArrayList(); for(Iterator iter = original().constructors().iterator(); iter.hasNext(); ) { ConstructorDecl c = (ConstructorDecl)iter.next(); BodyDecl b = c.p(this); b.is$Final = true; addBodyDecl(b); set.add(b); } return set; } // TODO: for a substituted class decl we need to search the original, substitute with the enclosing type of this // substituted type that is a paramterized type, and return the new value /* eq ClassDeclSubstituted.localMethodsSignatureMap() = original().localMethodsSignatureMap(); eq ClassDeclSubstituted.memberFields(String name) = original().memberFields(name); eq ClassDeclSubstituted.localFields(String name) = original().localFields(name); eq ClassDeclSubstituted.memberTypes(String name) = original().memberTypes(name); eq ClassDeclSubstituted.localTypeDecls(String name) = original().localTypeDecls(name); eq ClassDeclSubstituted.constructors() = original().constructors(); eq InterfaceDeclSubstituted.localMethodsSignatureMap() = original().localMethodsSignatureMap(); eq InterfaceDeclSubstituted.memberFields(String name) = original().memberFields(name); eq InterfaceDeclSubstituted.localFields(String name) = original().localFields(name); eq InterfaceDeclSubstituted.memberTypes(String name) = original().memberTypes(name); eq InterfaceDeclSubstituted.localTypeDecls(String name) = original().localTypeDecls(name); eq InterfaceDeclSubstituted.constructors() = original().constructors(); */ /* eq GenericClassDeclSubstituted.localMethodsSignatureMap() = original().localMethodsSignatureMap(); eq GenericClassDeclSubstituted.memberFields(String name) = original().memberFields(name); eq GenericClassDeclSubstituted.localFields(String name) = original().localFields(name); eq GenericClassDeclSubstituted.memberTypes(String name) = original().memberTypes(name); eq GenericClassDeclSubstituted.localTypeDecls(String name) = original().localTypeDecls(name); eq GenericClassDeclSubstituted.constructors() = original().constructors(); eq GenericInterfaceDeclSubstituted.localMethodsSignatureMap() = original().localMethodsSignatureMap(); eq GenericInterfaceDeclSubstituted.memberFields(String name) = original().memberFields(name); eq GenericInterfaceDeclSubstituted.localFields(String name) = original().localFields(name); eq GenericInterfaceDeclSubstituted.memberTypes(String name) = original().memberTypes(name); eq GenericInterfaceDeclSubstituted.localTypeDecls(String name) = original().localTypeDecls(name); eq GenericInterfaceDeclSubstituted.constructors() = original().constructors(); */ public BodyDecl BodyDecl.p(Parameterization parTypeDecl) { throw new Error("Operation p not supported for " + getClass().getName()); } public BodyDecl MethodDecl.p(Parameterization parTypeDecl) { //System.out.println("Begin substituting " + signature() + " in " + hostType().typeName() + " with " + parTypeDecl.typeSignature()); MethodDecl m = new MethodDeclSubstituted( (Modifiers)getModifiers().fullCopy(), getTypeAccess().type().substituteReturnType(parTypeDecl), getID(), getParameterList().substitute(parTypeDecl), getExceptionList().substitute(parTypeDecl), new Opt(), this ); //System.out.println("End substituting " + signature()); return m; } public BodyDecl GenericMethodDecl.p(Parameterization parTypeDecl) { //System.out.println("Begin substituting generic " + signature() + " in " + hostType().typeName() + " with " + parTypeDecl.typeSignature()); GenericMethodDecl m = new GenericMethodDecl( (Modifiers)getModifiers().fullCopy(), getTypeAccess().type().substituteReturnType(parTypeDecl), getID(), getParameterList().substitute(parTypeDecl), getExceptionList().substitute(parTypeDecl), new Opt(), (List)getTypeParameterList().fullCopy() ); m.original = this; //System.out.println("End substituting generic " + signature()); return m; } syn GenericMethodDecl GenericMethodDecl.original() = original != null ? original : this; public GenericMethodDecl GenericMethodDecl.original; syn GenericConstructorDecl GenericConstructorDecl.original() = original != null ? original : this; public GenericConstructorDecl GenericConstructorDecl.original; public BodyDecl ConstructorDecl.p(Parameterization parTypeDecl) { ConstructorDecl c = new ConstructorDeclSubstituted( (Modifiers)getModifiers().fullCopy(), getID(), getParameterList().substitute(parTypeDecl), getExceptionList().substitute(parTypeDecl), new Opt(), new Block(), this ); return c; } public BodyDecl FieldDeclaration.p(Parameterization parTypeDecl) { FieldDeclaration f = new FieldDeclarationSubstituted( (Modifiers)getModifiers().fullCopy(), getTypeAccess().type().substituteReturnType(parTypeDecl), getID(), new Opt(), this ); return f; } syn TypeDecl TypeDecl.original() = this; eq ClassDeclSubstituted.original() = getOriginal().original(); eq InterfaceDeclSubstituted.original() = getOriginal().original(); eq GenericClassDeclSubstituted.original() = getOriginal().original(); eq GenericInterfaceDeclSubstituted.original() = getOriginal().original(); eq ParTypeDecl.original() = genericDecl().original(); public ClassDecl ClassDecl.p(Parameterization parTypeDecl) { ClassDecl c = new ClassDeclSubstituted( (Modifiers)getModifiers().fullCopy(), getID(), hasSuperClassAccess() ? new Opt(getSuperClassAccess().type().substitute(parTypeDecl)) : new Opt(), getImplementsList().substitute(parTypeDecl), new List(), this ); return c; } public ClassDecl GenericClassDecl.p(Parameterization parTypeDecl) { GenericClassDecl c = new GenericClassDeclSubstituted( (Modifiers)getModifiers().fullCopy(), getID(), hasSuperClassAccess() ? new Opt(getSuperClassAccess().type().substitute(parTypeDecl)) : new Opt(), getImplementsList().substitute(parTypeDecl), new List(), new List(), // delegates TypeParameter lookup to original this ); return c; } public InterfaceDecl InterfaceDecl.p(Parameterization parTypeDecl) { InterfaceDecl c = new InterfaceDeclSubstituted( (Modifiers)getModifiers().fullCopy(), getID(), getSuperInterfaceIdList().substitute(parTypeDecl), new List(), this ); return c; } public InterfaceDecl GenericInterfaceDecl.p(Parameterization parTypeDecl) { GenericInterfaceDecl c = new GenericInterfaceDeclSubstituted( (Modifiers)getModifiers().fullCopy(), getID(), getSuperInterfaceIdList().substitute(parTypeDecl), new List(), new List(), // delegates TypeParameter lookup to original this ); return c; } syn nta WildcardsCompilationUnit Program.wildcards() { return new WildcardsCompilationUnit( "wildcards", new List(), new List() ); } syn TypeDecl WildcardExtendsType.extendsType() = getAccess().type(); syn TypeDecl WildcardSuperType.superType() = getAccess().type(); eq Wildcard.type() = typeWildcard(); eq WildcardExtends.type() = lookupWildcardExtends(getAccess().type()); eq WildcardSuper.type() = lookupWildcardSuper(getAccess().type()); inh TypeDecl WildcardSuper.lookupWildcardSuper(TypeDecl bound); inh TypeDecl WildcardExtends.lookupWildcardExtends(TypeDecl bound); inh TypeDecl Wildcard.typeWildcard(); syn nta TypeDecl WildcardsCompilationUnit.typeWildcard() { TypeDecl decl = new WildcardType( new Modifiers(new List().add(new Modifier("public"))), "?", new List() ); return decl; } inh TypeDecl TypeDecl.typeWildcard(); eq Program.getChild().typeWildcard() = wildcards().typeWildcard(); syn nta TypeDecl WildcardsCompilationUnit.lookupWildcardExtends(TypeDecl bound) { TypeDecl decl = new WildcardExtendsType( new Modifiers(new List().add(new Modifier("public"))), "? extends " + bound.fullName(), new List(), bound.createBoundAccess() ); return decl; } eq Program.getChild().lookupWildcardExtends(TypeDecl typeDecl) = wildcards().lookupWildcardExtends(typeDecl); inh TypeDecl TypeDecl.lookupWildcardExtends(TypeDecl typeDecl); syn TypeDecl TypeDecl.asWildcardExtends() = lookupWildcardExtends(this); syn nta TypeDecl WildcardsCompilationUnit.lookupWildcardSuper(TypeDecl bound) { TypeDecl decl = new WildcardSuperType( new Modifiers(new List().add(new Modifier("public"))), "? super " + bound.fullName(), new List(), bound.createBoundAccess() ); return decl; } eq Program.getChild().lookupWildcardSuper(TypeDecl typeDecl) = wildcards().lookupWildcardSuper(typeDecl); inh TypeDecl TypeDecl.lookupWildcardSuper(TypeDecl typeDecl); syn TypeDecl TypeDecl.asWildcardSuper() = lookupWildcardSuper(this); syn nta LUBType WildcardsCompilationUnit.lookupLUBType(Collection bounds) { List boundList = new List(); StringBuffer name = new StringBuffer(); for(Iterator iter = bounds.iterator(); iter.hasNext(); ) { TypeDecl typeDecl = (TypeDecl)iter.next(); boundList.add(typeDecl.createBoundAccess()); name.append("& " + typeDecl.typeName()); } LUBType decl = new LUBType( new Modifiers(new List().add(new Modifier("public"))), name.toString(), new List(), boundList ); return decl; } inh LUBType TypeDecl.lookupLUBType(Collection bounds); eq Program.getChild().lookupLUBType(Collection bounds) = wildcards().lookupLUBType(bounds); syn String LUBType.typeName() { if(getNumTypeBound() == 0) return ""; StringBuffer s = new StringBuffer(); s.append(getTypeBound(0).type().typeName()); for(int i = 1; i < getNumTypeBound(); i++) s.append(" & " + getTypeBound(i).type().typeName()); return s.toString(); } public HashSet LUBType.implementedInterfaces(){ HashSet ret = new HashSet(); for (int i = 0; i < getNumTypeBound(); i++) { ret.addAll(getTypeBound(i).type().implementedInterfaces()); } return ret; } syn nta GLBType WildcardsCompilationUnit.lookupGLBType(ArrayList bounds) { List boundList = new List(); StringBuffer name = new StringBuffer(); for(Iterator iter = bounds.iterator(); iter.hasNext(); ) { TypeDecl typeDecl = (TypeDecl)iter.next(); boundList.add(typeDecl.createBoundAccess()); name.append("& " + typeDecl.typeName()); } GLBType decl = new GLBType( new Modifiers(new List().add(new Modifier("public"))), name.toString(), new List(), boundList ); return decl; } inh GLBType TypeDecl.lookupGLBType(ArrayList bounds); eq Program.getChild().lookupGLBType(ArrayList bounds) = wildcards().lookupGLBType(bounds); syn String GLBType.typeName() { if(getNumTypeBound() == 0) return ""; StringBuffer s = new StringBuffer(); s.append(getTypeBound(0).type().typeName()); for(int i = 1; i < getNumTypeBound(); i++) s.append(" & " + getTypeBound(i).type().typeName()); return s.toString(); } public HashSet GLBType.implementedInterfaces(){ HashSet ret = new HashSet(); for (int i = 0; i < getNumTypeBound(); i++) { ret.addAll(getTypeBound(i).type().implementedInterfaces()); } return ret; } } aspect NewGenerics { public Access TypeVariable.createQualifiedAccess() { return createBoundAccess(); } eq TypeVariable.accessibleFrom(TypeDecl type) = true; eq TypeVariable.typeName() = name(); } aspect SourceDeclarations { syn lazy TypeDecl TypeDecl.sourceTypeDecl() = this; eq ParTypeDecl.sourceTypeDecl() = genericDecl().original().sourceTypeDecl(); eq ClassDeclSubstituted.sourceTypeDecl() = original().sourceTypeDecl(); eq InterfaceDeclSubstituted.sourceTypeDecl() = original().sourceTypeDecl(); eq GenericClassDeclSubstituted.sourceTypeDecl() = original().sourceTypeDecl(); eq GenericInterfaceDeclSubstituted.sourceTypeDecl() = original().sourceTypeDecl(); syn lazy MethodDecl MethodDecl.sourceMethodDecl() = this; eq ParMethodDecl.sourceMethodDecl() = genericMethodDecl().original().sourceMethodDecl(); eq MethodDeclSubstituted.sourceMethodDecl() = getOriginal().sourceMethodDecl(); syn lazy ConstructorDecl ConstructorDecl.sourceConstructorDecl() = this; eq ParConstructorDecl.sourceConstructorDecl() = genericConstructorDecl().original().sourceConstructorDecl(); eq ConstructorDeclSubstituted.sourceConstructorDecl() = getOriginal().sourceConstructorDecl(); syn lazy Variable Variable.sourceVariableDecl(); eq VariableDeclaration.sourceVariableDecl() = this; eq FieldDeclaration.sourceVariableDecl() = this; eq FieldDeclarationSubstituted.sourceVariableDecl() = getOriginal().sourceVariableDecl(); eq ParameterDeclaration.sourceVariableDecl() = this; eq ParameterDeclarationSubstituted.sourceVariableDecl() = getOriginal().sourceVariableDecl(); }