aspect Generics { public String ASTNode.location() { ASTNode n = this; int i = getLine(n.getStart()); while(i == 0 && getParent() != null) { n = n.getParent(); i = getLine(n.getStart()); } return i + ""; } public String ASTNode.errorPrefix() { return "*** Semantic Error at " + location() + ": "; } interface GenericTypeDecl { syn boolean isGenericType(); int getNumTypeParameter(); TypeVariable getTypeParameter(int index); public String fullName(); sons BodyDecl:BodyDecl* TypeParameter:TypeVariable* ParTypeDecl:ParTypeDecl*; } GenericClassDecl implements GenericTypeDecl; GenericInterfaceDecl implements GenericTypeDecl; syn boolean TypeDecl.isGenericType() = false; eq GenericTypeDecl.isGenericType() = true; interface ParTypeDecl { syn String name(); int getNumArgument(); Access getArgument(int index); int getNumTypeParameter(); TypeVariable getTypeParameter(int index); syn boolean isParameterizedType(); syn boolean isRawType(); } ParClassDecl implements ParTypeDecl; ParInterfaceDecl implements ParTypeDecl; syn boolean TypeDecl.isParameterizedType() = false; eq ParTypeDecl.isParameterizedType() = true; syn boolean TypeDecl.isRawType() = false; eq ParClassDecl.isRawType() = false; eq ParInterfaceDecl.isRawType() = false; eq RawClassDecl.isRawType() = true; eq RawInterfaceDecl.isRawType() = true; } aspect GenericsTypeAnalysis { eq WildcardExtendsType.instanceOf(TypeDecl type) = type.isSupertypeOfWildcardExtends(this); public boolean TypeDecl.isSupertypeOfWildcardExtends(WildcardExtendsType type) { return false; } public boolean WildcardExtendsType.isSupertypeOfWildcardExtends(WildcardExtendsType type) { return type.extendsType().instanceOf(extendsType()); } public boolean TypeVariable.isSupertypeOfWildcardExtends(WildcardExtendsType type) { return type.extendsType().instanceOf(this); } public boolean WildcardExtendsType.isSupertypeOfTypeVariable(TypeVariable type) { return type.instanceOf(extendsType()); } eq WildcardSuperType.instanceOf(TypeDecl type) = type.isSupertypeOfWildcardSuper(this); public boolean TypeDecl.isSupertypeOfWildcardSuper(WildcardSuperType type) { return false; } public boolean WildcardSuperType.isSupertypeOfWildcardSuper(WildcardSuperType type) { return type.superType().instanceOf(superType()); } public boolean TypeVariable.isSupertypeOfWildcardSuper(WildcardSuperType type) { return type.superType().instanceOf(this); } public boolean WildcardSuperType.isSupertypeOfTypeVariable(TypeVariable type) { return type.instanceOf(superType()); } syn boolean TypeDecl.isWildcard() = false; eq WildcardType.isWildcard() = true; syn boolean TypeDecl.wildcardSubtype(TypeDecl typeDecl) { if(typeDecl instanceof WildcardExtendsType) { WildcardExtendsType other = (WildcardExtendsType)typeDecl; return instanceOf(other.extendsType()); } else if(typeDecl instanceof WildcardSuperType) { WildcardSuperType other = (WildcardSuperType)typeDecl; return other.superType().instanceOf(this); } return false; } eq WildcardExtendsType.wildcardSubtype(TypeDecl typeDecl) { if(typeDecl instanceof WildcardExtendsType) { WildcardExtendsType other = (WildcardExtendsType)typeDecl; return extendsType().instanceOf(other.extendsType()); } return false; } eq WildcardSuperType.wildcardSubtype(TypeDecl typeDecl) { if(typeDecl instanceof WildcardSuperType) { WildcardSuperType other = (WildcardSuperType)typeDecl; return other.superType().instanceOf(superType()); } if(typeDecl instanceof WildcardExtendsType) { return true; // Dragons? } return false; } eq ParTypeDecl.instanceOf(TypeDecl type) { if(super.instanceOf(type)) return true; if(type instanceof ParTypeDecl) { ParTypeDecl typeDecl = (ParTypeDecl)type; //System.err.println("Computing " + fullName() + " isSubtypeOf " + ((TypeDecl)typeDecl).fullName()); TypeDecl g1 = genericDecl(); TypeDecl g2 = typeDecl.genericDecl(); if(g1 == g2 && (isRawType() || type.isRawType())) return true; if(g1.instanceOf(g2)) { //System.err.println("Checking type arguments"); if(getNumArgument() == typeDecl.getNumArgument()) { for(int i = 0; i < getNumArgument(); i++) { if(typeDecl.getArgument(i).type().isTypeVariable()) { if(!getArgument(i).type().instanceOf(typeDecl.getArgument(i).type())) { //System.err.println("Argument " + getArgument(i).type().fullName() + " and " + typeDecl.getArgument(i).type().fullName() + " are not subtypes"); return false; } } else if(!getArgument(i).type().wildcardSubtype(typeDecl.getArgument(i).type())) { //System.err.println("Argument " + getArgument(i).type().fullName() + " and " + typeDecl.getArgument(i).type().fullName() + " are not wildcard subtypes"); return false; } } return true; } else { //System.err.println("Number of type arguments does not match"); } } else { //System.err.println("Generic type " + g1.fullName() + " is not an instanceof " + g2.fullName()); } } Object that = this; if(that instanceof ParClassDecl) { ParClassDecl p = (ParClassDecl)that; if(p.hasSuperClass() && p.getSuperClass().instanceOf(type)) return true; for(int i = 0; i < p.getNumImplements(); i++) if(p.getImplements(i).type().instanceOf(type)) return true; } else if(that instanceof ParInterfaceDecl) { ParInterfaceDecl p = (ParInterfaceDecl)that; for(int i = 0; i < p.getNumSuperInterfaceId(); i++) if(p.getSuperInterfaceId(i).type().instanceOf(type)) return true; } return false; } eq ParameterizedTypeAccess.type() { //System.err.println("Computing type for parameterized type access " + getIdUse().getID()); if(decl() instanceof GenericTypeDecl) { GenericTypeDecl decl = (GenericTypeDecl)decl(); //System.err.println(" need to lookupParTypeDecl"); //dumpNoRewrite(2); TypeDecl result = (TypeDecl)decl.lookupParTypeDecl(this); //System.err.println(" type computed"); return result; } return decl(); } } aspect GenericsErasure { syn TypeDecl TypeDecl.erasure() { if(!isNestedType()) return this; return extractSingleType(enclosingType().erasure().remoteLookupType(name())); } eq ParClassDecl.erasure() = genericDecl(); eq ParInterfaceDecl.erasure() = genericDecl(); eq TypeVariable.erasure() = getTypeBound(0).type().erasure(); // Skip last erasure? eq ArrayDecl.erasure() = getElementType().erasure(); } aspect GenericsTypeCheck { public void GenericClassDecl.typeCheck() { super.typeCheck(); if(instanceOf(typeThrowable())) error(errorPrefix() + " generic class " + fullName() + " may not directly or indirectly inherit java.lang.Throwable"); } public void GenericInterfaceDecl.typeCheck() { super.typeCheck(); if(instanceOf(typeThrowable())) error(errorPrefix() + " generic interface " + fullName() + " may not directly or indirectly inherit java.lang.Throwable"); } inh TypeDecl GenericClassDecl.typeThrowable(); inh TypeDecl GenericInterfaceDecl.typeThrowable(); public void ParameterizedTypeAccess.typeCheck() { super.typeCheck(); if(!decl().isGenericType()) { error(errorPrefix() + decl().fullName() + " is not a generic type but used as one in " + this); } else { GenericTypeDecl decl = (GenericTypeDecl)decl(); if(decl.getNumTypeParameter() != getNumTypeArgument()) { error(errorPrefix() + decl.fullName() + " takes " + decl.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(decl.getTypeParameter(i))) { // error(errorPrefix() + "type argument " + i + " is of type " + getTypeArgument(i).type().fullName() // + " which is not a subtype of " + decl.getTypeParameter(i)); //} if(!typeDecl.getTypeParameter(i).validArgument(getTypeArgument(i).type())) { //if(!getTypeArgument(i).type().instanceOf(typeDecl.getTypeParameter(i))) { error(errorPrefix() + "type argument " + i + " is of type " + getTypeArgument(i).type().fullName() + " which is not a valid argument to type parameter " + typeDecl.getTypeParameter(i)); } } } } } syn lazy boolean TypeVariable.validArgument(TypeDecl type) { // here be dragons if(type.isWildcard()) return true; if(type instanceof TypeVariable) { type = type.erasure(); } for(int i = 0; i < getNumTypeBound(); i++) if(!type.instanceOf(getTypeBound(i).type())) { return false; } return true; } } aspect GenericsNameBinding { eq ParClassDecl.getArgument().nameType() = NameType.TYPE_NAME; eq ParInterfaceDecl.getArgument().nameType() = NameType.TYPE_NAME; // Type arguments lookup types in unqualified scope and not in remote type when using dot notation eq ParameterizedTypeAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name); eq ParTypeAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(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 TypeCollection GenericTypeDecl.addTypeVariables(TypeCollection c, String name) { for(int i = 0; i < getNumTypeParameter(); i++) { TypeVariable p = getTypeParameter(i); if(p.name().equals(name)) { c = c.add(p); } } return c; } eq GenericInterfaceDecl.getSuperInterfaceId().lookupType(String name) { TypeCollection c = TypeCollection.emptyCollection(); c = addTypeVariables(c, name); if(!c.isEmpty()) return c; return lookupType(name); } eq GenericClassDecl.getSuperClassAccess().lookupType(String name) { TypeCollection c = TypeCollection.emptyCollection(); c = addTypeVariables(c, name); if(!c.isEmpty()) return c; return lookupType(name); } eq GenericClassDecl.getImplements().lookupType(String name) { TypeCollection c = TypeCollection.emptyCollection(); c = addTypeVariables(c, name); if(!c.isEmpty()) return c; return lookupType(name); } eq GenericTypeDecl.getTypeParameter().lookupType(String name) { TypeCollection c = localLookupType(name); c = addTypeVariables(c, name); if(!c.isEmpty()) return c; c = lookupType(name); // 8.5.2 if(isClassDecl() && isStatic() && !isTopLevelType()) { for(TypeCollection.TypeIterator iter = c.iterator(); iter.hasNext(); ) { TypeDecl d = (TypeDecl)iter.next(); if(!d.isStatic() && !instanceOf(d.enclosingType())) { c = iter.remove(); } } } if(!c.isEmpty()) return c; return topLevelType().lookupType(name); // Fix to search imports } eq GenericTypeDecl.getBodyDecl(int index).lookupType(String name) { TypeCollection c = localLookupType(name); if(getBodyDecl(index).visibleTypeParameters()) c = addTypeVariables(c, name); if(!c.isEmpty()) return c; c = lookupType(name); // 8.5.2 if(isClassDecl() && isStatic() && !isTopLevelType()) { for(TypeCollection.TypeIterator iter = c.iterator(); iter.hasNext(); ) { TypeDecl d = (TypeDecl)iter.next(); if(!d.isStatic() && !instanceOf(d.enclosingType())) { c = iter.remove(); } } } if(!c.isEmpty()) return c; return topLevelType().lookupType(name); // Fix to search imports // include type parameters if not static } public TypeCollection GenericTypeDecl.remoteLookupType(String name) { // a type variable may be used in extends and implements clauses // type variable may then be used qualified when instantiating extends and implements clauses // this will result in remote lookups of the type variables // therefore they alone must be considered and not include localLookupType that // will result in a circularity TypeCollection c = TypeCollection.emptyCollection(); c = addTypeVariables(c, name); if(!c.isEmpty()) return c; return localLookupType(name); } public void ParClassDecl.errorCheck(Collection collection) { // Disable error check for ParClassDecl which is an instanciated GenericClassDecl } public void ParInterfaceDecl.errorCheck(Collection collection) { // Disable error check for ParClassDecl which is an instanciated GenericClassDecl } syn boolean Wildcard.isExactWildcard() = true; eq WildcardExtends.isExactWildcard() = false; eq WildcardSuper.isExactWildcard() = false; rewrite Wildcard { when(isExactWildcard()) to Wildcard new WildcardExtends(typeObject().createQualifiedAccess()); } inh TypeDecl Wildcard.typeObject(); rewrite ParTypeAccess { when(getTypeAccess() instanceof TypeAccess) to TypeAccess { TypeAccess t = (TypeAccess)getTypeAccess(); return new ParameterizedTypeAccess(t.getPackageList(), t.getIdUse(), getTypeArgumentList()); } when(getTypeAccess() instanceof TypeDot) to TypeAccess { TypeDot dot = (TypeDot)getTypeAccess(); TypeAccess t = (TypeAccess)dot.getRight(); dot.setRight(new ParameterizedTypeAccess(t.getPackageList(), t.getIdUse(), getTypeArgumentList())); return dot; } } syn boolean TypeAccess.isExactTypeAccess() = true; eq ArrayTypeAccess.isExactTypeAccess() = false; eq ThisAccess.isExactTypeAccess() = false; eq SuperAccess.isExactTypeAccess() = false; eq ParameterizedTypeAccess.isExactTypeAccess() = false; eq RawTypeAccess.isExactTypeAccess() = false; /* rewrite TypeAccess { when(isExactTypeAccess() && decl().isGenericType()) to RawTypeAccess new RawTypeAccess(getPackageList(), getIdUse()); } */ syn boolean TypeAccess.isRaw() { if(!decl().isGenericType()) return false; if(getParent() instanceof ParTypeAccess) return false; if(!(getParent() instanceof AbstractDot)) return true; AbstractDot d = (AbstractDot)getParent(); if(d.isThisAccess()) return false; if(d.isTypeAccess() && d.type().isTypeVariable()) return false; return true; } rewrite TypeAccess { when(isExactTypeAccess() && isRaw()) to ParameterizedTypeAccess { GenericTypeDecl decl = (GenericTypeDecl)decl(); List list = new List(); for(int i = 0; i < decl.getNumTypeParameter(); i++) list.add(decl.getTypeParameter(i).erasure().createQualifiedAccess()); return new RawTypeAccess(getPackageList(), getIdUse(), list); } } syn boolean ParameterizedTypeAccess.isRawAccess() = false; eq RawTypeAccess.isRawAccess() = true; } aspect LookupParTypeDecl { syn lazy TypeDecl GenericTypeDecl.lookupParTypeDecl(ParameterizedTypeAccess p) { ParTypeDecl typeDecl = null; for(int i = 0; i < getNumParTypeDecl() && typeDecl == null; i++) { ParTypeDecl decl = getParTypeDecl(i); boolean match = true; if(decl.getNumArgument() == p.getNumTypeArgument()) { for(int j = 0; j < decl.getNumArgument(); j++) { if(decl.getArgument(j).type() != p.getTypeArgument(j).type()) match = false; } } else { match = false; } if(match) typeDecl = decl; } if(typeDecl == null) { //System.err.println("Building paramterized version of " + fullName() + " with parameters: "); //p.dumpNoRewrite(2); typeDecl = (ParTypeDecl)p(p); } return (TypeDecl)typeDecl; } public Access TypeDecl.substitute(ParTypeDecl parTypeDecl) { return createQualifiedAccess(); } public Access TypeVariable.substitute(ParTypeDecl parTypeDecl) { TypeDecl typeDecl = this; //System.err.println("Searching for substitution for variable " + this); GenericTypeDecl g = (GenericTypeDecl)parTypeDecl.genericDecl(); //System.err.println(" searching candidate class " + g.fullName()); for(int i = 0; i < g.getNumTypeParameter(); i++) { if(g.getTypeParameter(i) == typeDecl) { //System.err.println(" found variable as parameter " + i); typeDecl = parTypeDecl.getArgument(i).type(); return typeDecl.createTypeVariableAccess(); } } return typeDecl.createQualifiedAccess(); } public Access TypeDecl.substituteReturnType(ParTypeDecl parTypeDecl) { return createQualifiedAccess(); } inh TypeDecl TypeVariable.typeObject(); public Access TypeVariable.substituteReturnType(ParTypeDecl parTypeDecl) { TypeDecl typeDecl = this; //System.err.println("Searching for substitution for variable " + name()); GenericTypeDecl g = (GenericTypeDecl)parTypeDecl.genericDecl(); for(int i = 0; i < g.getNumTypeParameter(); i++) { if(g.getTypeParameter(i) == typeDecl) { //System.err.println(" found variable as parameter " + i); //parTypeDecl.getArgument(i).dumpNoRewrite(2); typeDecl = parTypeDecl.getArgument(i).type(); //System.err.println(" computed type of argument"); if(typeDecl instanceof WildcardExtendsType) { WildcardExtendsType t = (WildcardExtendsType)typeDecl; return t.extendsType().createQualifiedAccess(); } else if(typeDecl instanceof WildcardSuperType) { return typeObject().createQualifiedAccess(); } return typeDecl.createTypeVariableAccess(); } } return typeDecl.createQualifiedAccess(); } public Access TypeDecl.substituteParameterType(ParTypeDecl parTypeDecl) { return createQualifiedAccess(); } inh TypeDecl TypeVariable.typeNull(); public Access TypeVariable.substituteParameterType(ParTypeDecl parTypeDecl) { TypeDecl typeDecl = this; //System.err.println("Searching for substitution for variable " + this); GenericTypeDecl g = (GenericTypeDecl)parTypeDecl.genericDecl(); //System.err.println(" searching candidate class " + g.fullName()); for(int i = 0; i < g.getNumTypeParameter(); i++) { if(g.getTypeParameter(i) == typeDecl) { //System.err.println(" found variable as parameter " + i); typeDecl = parTypeDecl.getArgument(i).type(); if(typeDecl instanceof WildcardExtendsType) { return typeNull().createQualifiedAccess(); } else if(typeDecl instanceof WildcardSuperType) { WildcardSuperType t = (WildcardSuperType)typeDecl; return t.superType().createQualifiedAccess(); } return typeDecl.createTypeVariableAccess(); } } return typeDecl.createQualifiedAccess(); } public Access Access.substitute(ParTypeDecl parTypeDecl) { // can find context return type().substitute(parTypeDecl); } public Access ParameterizedTypeAccess.substitute(ParTypeDecl parTypeDecl) { // can find context return new ParameterizedTypeAccess((List)getPackageList().fullCopy(), (IdUse)getIdUse().fullCopy(), getTypeArgumentList().substitute(parTypeDecl)); } public Access Access.substituteReturnType(ParTypeDecl parTypeDecl) { // can find context return type().substituteReturnType(parTypeDecl); } public Access ParameterizedTypeAccess.substituteReturnType(ParTypeDecl parTypeDecl) { // can find context return new ParameterizedTypeAccess((List)getPackageList().fullCopy(), (IdUse)getIdUse().fullCopy(), getTypeArgumentList().substitute(parTypeDecl)); } public Access Access.substituteParameterType(ParTypeDecl parTypeDecl) { // can find context return type().substituteParameterType(parTypeDecl); } public Access ParameterizedTypeAccess.substituteParameterType(ParTypeDecl parTypeDecl) { // can find context return new ParameterizedTypeAccess((List)getPackageList().fullCopy(), (IdUse)getIdUse().fullCopy(), getTypeArgumentList().substitute(parTypeDecl)); } public List List.substitute(ParTypeDecl parTypeDecl) { // can find context 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.substitute(parTypeDecl)); } else if(node instanceof ParameterDeclaration) { // this is always parameters ParameterDeclaration p = (ParameterDeclaration)node; list.add( new ParameterDeclaration( (Modifiers)p.getModifiers().fullCopy(), p.getTypeAccess().substituteParameterType(parTypeDecl), (IdDecl)p.getIdDecl().fullCopy() ) ); } else if(node instanceof TypeVariable) { TypeVariable tv = (TypeVariable)node; list.add( new TypeVariable( (Modifiers)tv.getModifiers().fullCopy(), (IdDecl)tv.getIdDecl().fullCopy(), (List)tv.getBodyDeclList().fullCopy(), tv.getTypeBoundList().substitute(parTypeDecl) ) ); } else { throw new Error("Can only substitute lists of access nodes but node number " + i + " is of type " + node.getClass().getName()); } } return list; } public TypeDecl TypeDecl.p(ParameterizedTypeAccess params) { throw new Error("Operation p not supported for " + getClass().getName()); } protected List GenericTypeDecl.createArgumentList(ParameterizedTypeAccess params) { List list = new List(); for(int i = 0; i < params.getNumTypeArgument(); i++) { TypeDecl arg = params.getTypeArgument(i).type(); if(arg.isTypeVariable()) { list.add(arg.createTypeVariableAccess()); } else { list.add(arg.createQualifiedAccess()); } } return list; } public TypeDecl GenericClassDecl.p(ParameterizedTypeAccess params) { // build parameterized type decl using arguments from distant type access ParClassDecl typeDecl = params.isRawAccess() ? new RawClassDecl() : new ParClassDecl(); typeDecl.setModifiers((Modifiers)getModifiers().fullCopy()); typeDecl.setIdDecl((IdDecl)getIdDecl().fullCopy()); addParTypeDecl(typeDecl); //System.err.print("Building instantiation of " + name() + " with arguments: "); //for(int i = 0; i < params.getNumTypeArgument(); i++) { // System.out.print(params.getTypeArgument(i) + ", "); //} //System.out.println(); typeDecl.setArgumentList(createArgumentList(params)); //System.err.println("Begin substituting type parameter list"); typeDecl.setTypeParameterList(getTypeParameterList().substitute(typeDecl)); //System.err.println("End substituting type parameter list"); //System.err.println("ParTypeDecl added to GenericClassDecl"); if(hasSuperClass()) { typeDecl.setSuperClassAccess(getSuperClassAccess().substitute(typeDecl)); } //System.err.println("SuperClassAccess substituted"); //typeDecl.setSuperClassAccessOpt((Opt)getSuperClassAccessOpt().fullCopy()); typeDecl.setImplementsList(getImplementsList().substitute(typeDecl)); //typeDecl.setImplementsList((List)getImplementsList().fullCopy()); //System.err.println("ImplementsList substituted"); for(int i = 0; i < getNumBodyDecl(); i++) { //System.err.println("Substituting bodydecl " + i + " of type " + getBodyDecl(i).getClass().getName()); typeDecl.addBodyDecl(getBodyDecl(i).p(typeDecl)); } //System.err.println("BodyDeclList substituted"); //System.err.print("End instantiation of " + name() + " with arguments: "); for(int i = 0; i < params.getNumTypeArgument(); i++) { System.out.print(params.getTypeArgument(i) + ", "); } System.out.println(); return typeDecl; } public TypeDecl GenericInterfaceDecl.p(ParameterizedTypeAccess params) { // build parameterized type decl using arguments from distant type access ParInterfaceDecl typeDecl = params.isRawAccess() ? new RawInterfaceDecl() : new ParInterfaceDecl(); addParTypeDecl(typeDecl); typeDecl.setArgumentList(createArgumentList(params)); typeDecl.setTypeParameterList(getTypeParameterList().substitute(typeDecl)); typeDecl.setModifiers((Modifiers)getModifiers().fullCopy()); typeDecl.setIdDecl((IdDecl)getIdDecl().fullCopy()); typeDecl.setSuperInterfaceIdList(getSuperInterfaceIdList().substitute(typeDecl)); for(int i = 0; i < getNumBodyDecl(); i++) { typeDecl.addBodyDecl(getBodyDecl(i).p(typeDecl)); } return typeDecl; } public BodyDecl BodyDecl.p(ParTypeDecl parTypeDecl) { throw new Error("Operation p not supported for " + getClass().getName()); } public BodyDecl MethodDecl.p(ParTypeDecl parTypeDecl) { MethodDecl m = new MethodDecl( (Modifiers)getModifiers().fullCopy(), getTypeAccess().substituteReturnType(parTypeDecl), (IdDecl)getIdDecl().fullCopy(), getParameterList().substitute(parTypeDecl), new List(), getExceptionList().substitute(parTypeDecl), new Opt() ); return m; } public BodyDecl ConstructorDecl.p(ParTypeDecl parTypeDecl) { ConstructorDecl c = new ConstructorDecl( (Modifiers)getModifiers().fullCopy(), (IdDecl)getIdDecl().fullCopy(), getParameterList().substitute(parTypeDecl), getExceptionList().substitute(parTypeDecl), new Opt(), new Block() ); return c; } protected String ASTNode.dumpString() { return getClass().getName(); } protected String IdUse.dumpString() { return super.dumpString() + "[" + getID() + "]"; } protected String ArrayNameAccess.dumpString() { return super.dumpString() + ", dimension: " + getDimension(); } protected void ASTNode.dumpNoRewrite(int indent) { StringBuffer s = new StringBuffer(); for(int i = 0; i < indent; i++) s.append(" "); s.append(dumpString()); System.out.println(s.toString()); for(int i = 0; i < getNumChild(); i++) { getChildNoTransform(i).dumpNoRewrite(indent+1); } } // Check that this does not interfere with name analysis for fields // of array types.... in Resolve unbiguous names rewrite ArrayNameDot { when(((ArrayNameAccess)getRight()).getDimension() == 0) to Access getLeft(); } public BodyDecl FieldDeclaration.p(ParTypeDecl parTypeDecl) { FieldDeclaration f = new FieldDeclaration( (Modifiers)getModifiers().fullCopy(), getTypeAccess().substituteReturnType(parTypeDecl), (IdDecl)getIdDecl().fullCopy(), new Opt() ); return f; } public BodyDecl MemberClass.p(ParTypeDecl parTypeDecl) { return new MemberClass((ClassDecl)getClassDecl().p(parTypeDecl)); } public ClassDecl ClassDecl.p(ParTypeDecl parTypeDecl) { ClassDecl c = new ClassDecl( (Modifiers)getModifiers().fullCopy(), (IdDecl)getIdDecl().fullCopy(), (Opt)getSuperClassAccessOpt().fullCopy(), getImplementsList().substitute(parTypeDecl), new List() ); for(int i = 0; i < getNumBodyDecl(); i++) c.addBodyDecl(getBodyDecl(i).p(parTypeDecl)); return c; } public ClassDecl GenericClassDecl.p(ParTypeDecl parTypeDecl) { GenericClassDecl c = new GenericClassDecl( (Modifiers)getModifiers().fullCopy(), (IdDecl)getIdDecl().fullCopy(), (Opt)getSuperClassAccessOpt().fullCopy(), getImplementsList().substitute(parTypeDecl), new List(), (List)getTypeParameterList().fullCopy(), new List(), new Opt() ); for(int i = 0; i < getNumBodyDecl(); i++) c.addBodyDecl(getBodyDecl(i).p(parTypeDecl)); return c; } public BodyDecl MemberInterface.p(ParTypeDecl parTypeDecl) { return new MemberInterface((InterfaceDecl)getInterfaceDecl().p(parTypeDecl)); } public InterfaceDecl InterfaceDecl.p(ParTypeDecl parTypeDecl) { InterfaceDecl c = new InterfaceDecl( (Modifiers)getModifiers().fullCopy(), (IdDecl)getIdDecl().fullCopy(), getSuperInterfaceIdList().substitute(parTypeDecl), new List() ); for(int i = 0; i < getNumBodyDecl(); i++) c.addBodyDecl(getBodyDecl(i).p(parTypeDecl)); return c; } public InterfaceDecl GenericInterfaceDecl.p(ParTypeDecl parTypeDecl) { GenericInterfaceDecl c = new GenericInterfaceDecl( (Modifiers)getModifiers().fullCopy(), (IdDecl)getIdDecl().fullCopy(), getSuperInterfaceIdList().substitute(parTypeDecl), new List(), (List)getTypeParameterList().fullCopy(), new List(), new Opt() ); for(int i = 0; i < getNumBodyDecl(); i++) c.addBodyDecl(getBodyDecl(i).p(parTypeDecl)); return c; } syn lazy CompilationUnit Program.wildcards() { CompilationUnit cu = new CompilationUnit( new List().add(new IdDecl("wildcards")), new List(), new List() ); addCompilationUnit(cu); return cu; } syn boolean TypeDecl.matches(Wildcard wildcard) = false; eq WildcardType.matches(Wildcard wildcard) = wildcard.matches(this); eq WildcardExtendsType.matches(Wildcard wildcard) = wildcard.matchesExtends(this); eq WildcardSuperType.matches(Wildcard wildcard) = wildcard.matchesSuper(this); syn boolean Wildcard.matches(WildcardType type) = true; eq WildcardExtends.matches(WildcardType type) = false; eq WildcardSuper.matches(WildcardType type) = false; syn boolean Wildcard.matchesExtends(WildcardExtendsType type) = false; eq WildcardExtends.matchesExtends(WildcardExtendsType type) = type.extendsType() == getAccess().type(); syn TypeDecl WildcardExtendsType.extendsType() = getAccess().type(); syn boolean Wildcard.matchesSuper(WildcardSuperType type) = false; eq WildcardSuper.matchesSuper(WildcardSuperType type) = type.superType() == getAccess().type(); syn TypeDecl WildcardSuperType.superType() = getAccess().type(); public TypeDecl Wildcard.buildTypeDecl() { return new WildcardType( new Modifiers(new List().add(new Modifier("public"))), new IdDecl("?"), new List() ); } public TypeDecl WildcardExtends.buildTypeDecl() { return new WildcardExtendsType( new Modifiers(new List().add(new Modifier("public"))), new IdDecl("? extends " + getAccess().type().fullName()), new List(), getAccess().type().createQualifiedAccess() ); } public TypeDecl WildcardSuper.buildTypeDecl() { return new WildcardSuperType( new Modifiers(new List().add(new Modifier("public"))), new IdDecl("? super " + getAccess().type().fullName()), new List(), getAccess().type().createQualifiedAccess() ); } syn lazy TypeDecl Program.lookupWildcard(Wildcard wildcard) { CompilationUnit cu = wildcards(); for(int i = 0; i < cu.getNumTypeDecl(); i++) { TypeDecl typeDecl = cu.getTypeDecl(i); if(typeDecl.matches(wildcard)) return typeDecl; } TypeDecl decl = wildcard.buildTypeDecl(); cu.addTypeDecl(decl); return decl; } eq Program.getCompilationUnit().lookupWildcard(Wildcard wildcard) = lookupWildcard(wildcard); inh TypeDecl Wildcard.lookupWildcard(Wildcard wildcard); eq Wildcard.type() = lookupWildcard(this); }