[JSR308] Creating new annotated types.

Niko Matsakis niko at alum.mit.edu
Wed Nov 12 10:56:51 EST 2008


> This is intentional.  The goal was to deter checkers from  
> manipulating the java type and from breaking java conformity.
> Can you explained your desired type changes further?

I would be more wary of hindering people from creating the type system  
they want than of people making bad type systems.  I mean, ultimately,  
the type system can't make a program whose Java types are wrong pass,  
it can only make otherwise good programs fail to compile, right?   
Therefore, if it's causing too many correct programs to fail, people  
can just stop using it.  That said, in most cases it is not necessary  
to manipulate the AnnotatedTypeMirrors-- except when it is.

>> In my case, the method is declared as:
>>
>> 	public static <X> X free(X ptr) { return ptr; }
>>
>> What I want to do is to change the annotations on the return type.
>> Because the return type and the argument type are linked, [...]
> Annotating type parameter (explicitly or effectively) is not kosher.
>
> You can special case the given senario, modifying the return type of  
> the method invocation tree of the method (e.g. free()).   
> annotateImplicit({MethodInvocation}Tree, AnnotatedTypeMirror) should  
> be passed the resolved type of such method.

I'm not quite sure what you think is not kosher.  However,  
annotateImplicit() does not solve my problem, because -- due to the  
use of a type parameter -- the ExecutableType I get back has linked  
the return type and the type of the argument (they are the same  
pointer).  So if I modify the annotations on one, I modify the  
annotations on the other.  This is incorrect.

What free() does in my system is to indicate that the region in which  
'ptr' is stored will not be used anymore, effectively.  This does not  
mean the data is gone (hence the return), but it does mean the data is  
unaliased and can be transferred into another region and has other  
nice properties.  So, the region annotation on 'ptr' changes, but the  
traditional Java type does not (likewise, any other annotations on  
'ptr' such as Nonnull or Immutability would also not change).   
Effectively, I want to substitute a completely different signature for  
free(), but only in my type system -- therefore, the Java type  
signature I showed above is the fallback.

>> It does a deep clone of a
>> type with appropriate overloadable methods at each point.
> Be careful with recursive type parameters (e.g. <T extends Enum<T>>).

Yes, I believe I handle such cases.  In fact, I may have been overly  
paranoid, in that I also catch circular uses of any type (which I  
think cannot occur, but it was just as easy).  The code is attached  
below.


Niko

package checkers.types;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import checkers.types.AnnotatedTypeMirror.AnnotatedArrayType;
import checkers.types.AnnotatedTypeMirror.AnnotatedDeclaredType;
import checkers.types.AnnotatedTypeMirror.AnnotatedExecutableType;
import checkers.types.AnnotatedTypeMirror.AnnotatedNoType;
import checkers.types.AnnotatedTypeMirror.AnnotatedNullType;
import checkers.types.AnnotatedTypeMirror.AnnotatedPrimitiveType;
import checkers.types.AnnotatedTypeMirror.AnnotatedTypeVariable;
import checkers.types.AnnotatedTypeMirror.AnnotatedWildcardType;
import checkers.types.visitors.AnnotatedTypeVisitor;

/**
  * Performs a deep clone of a type.  Subclasses may override
  * at various points to introduce changes.
  *
  * <p>The {@code visit}
  * methods from {@link AnnotatedTypeVisitor} are invoked
  * with a source type and a destination type, which is a shallow
  * copy of the source type.  Their job
  * is to clone the fields from the source type and then
  * set the corresponding entries in the destination type.
  * Overloading these methods gives you complete control
  * over what values are eventually used.
  *
  * <p>The default implementations of the {@code visit}
  * methods simply recurse using {@code scan} to copy any
  * subtypes, and then invoke the
  * {@code setFieldsForClonedXxxType} methods.
  * These can also be a convenient place to overload.
  *
  * @author NDM
  */
public class AnnotatedTypeCloner
	implements AnnotatedTypeVisitor<Void, AnnotatedTypeMirror>
{
	/** set to false to avoid including annotations from the existing  
type by default */
	protected boolean includeAnnotationsInCopies = true;
	
	/** set to false to avoid detecting duplicates in {@link  
#scan(AnnotatedTypeMirror)} */
	protected boolean preserveGraph = true;
	
	protected Map<AnnotatedTypeMirror, AnnotatedTypeMirror> cloned = new  
HashMap<AnnotatedTypeMirror, AnnotatedTypeMirror>();
	
	/** The outside entry method.  */
	@SuppressWarnings("unchecked")
	public <X extends AnnotatedTypeMirror> X clone(X type) {
		cloned.clear();
		AnnotatedTypeMirror result = scan(type);
		assert type.getClass() == result.getClass();
		return (X)result;
	}
	
	/**
	 * Useful static method for when you just want to deep-clone a type
	 * without introducting any changes */
	public static <X extends AnnotatedTypeMirror> X cloneStatic(X type) {
		return new AnnotatedTypeCloner().clone(type);
	}

	protected AnnotatedTypeMirror scan(AnnotatedTypeMirror type) {
		if (preserveGraph) {
			AnnotatedTypeMirror result = cloned.get(type);
			if (result != null)
				return result;
		}
		
		AnnotatedTypeMirror result = type.getCopy(includeAnnotationsInCopies);
		if (preserveGraph)
			cloned.put(type, result);
		type.accept(this, result);
		return result;
	}	

	protected List<AnnotatedTypeMirror> scanAll(Iterable<? extends  
AnnotatedTypeMirror> types) {
		List<AnnotatedTypeMirror> result = new  
ArrayList<AnnotatedTypeMirror>();
		for (AnnotatedTypeMirror type : types)
			result.add(scan(type));
		return result;
	}

	public Void visitArray(AnnotatedArrayType type, AnnotatedTypeMirror  
result) {
		AnnotatedTypeMirror compType = scan(type.getComponentType());
		setFieldsForClonedArray(type, compType, (AnnotatedArrayType) result);
		return null;
	}

	protected void setFieldsForClonedArray(
			AnnotatedArrayType origType,
			AnnotatedTypeMirror compType,
			AnnotatedArrayType result)
	{
		result.setComponentType(compType);
	}

	public Void visitDeclared(AnnotatedDeclaredType type,  
AnnotatedTypeMirror result) {
		List<AnnotatedTypeMirror> typeArguments =  
scanAll(type.getTypeArguments());
		setFieldsForClonedDeclaredType(
				type,
				typeArguments,
				(AnnotatedDeclaredType) result);
		return null;
	}

	protected void setFieldsForClonedDeclaredType(
			AnnotatedDeclaredType origType,
			List<AnnotatedTypeMirror> typeArguments,
			AnnotatedDeclaredType result)
	{
		result.setTypeArguments(typeArguments);
	}

	public Void visitExecutable(AnnotatedExecutableType type,  
AnnotatedTypeMirror result)
	{
         AnnotatedTypeMirror returnType = scan(type.getReturnType());
         AnnotatedDeclaredType rcvrType = (AnnotatedDeclaredType)  
scan(type.getReceiverType());
         List<AnnotatedTypeMirror> paramTypes =  
scanAll(type.getParameterTypes());
         List<AnnotatedTypeMirror> thrownTypes =  
scanAll(type.getThrownTypes());
         List<AnnotatedTypeMirror> typeVariablesMirrors =  
scanAll(type.getTypeVariables());
         List<AnnotatedTypeVariable> typeVariables = new  
ArrayList<AnnotatedTypeVariable>();
         for (AnnotatedTypeMirror typeVariableMirror :  
typeVariablesMirrors)
         	typeVariables.add((AnnotatedTypeVariable) typeVariableMirror);

		setFieldsForClonedExecutableType(
				type,
				returnType,
				rcvrType,
				paramTypes,
				thrownTypes,
				typeVariables,
				(AnnotatedExecutableType) result);
		
		return null;
     }

	protected void setFieldsForClonedExecutableType(
			AnnotatedExecutableType origType,
			AnnotatedTypeMirror returnType,
			AnnotatedDeclaredType rcvrType,
			List<AnnotatedTypeMirror> paramTypes,
			List<AnnotatedTypeMirror> thrownTypes,
			List<AnnotatedTypeVariable> typeVariables,
			AnnotatedExecutableType result)
	{
		result.setReturnType(returnType);
		result.setReceiverType(rcvrType);
		result.setParameterTypes(paramTypes);
		result.setThrownTypes(thrownTypes);
		result.setTypeVariables(typeVariables);
	}

	public Void visitNoType(AnnotatedNoType type, AnnotatedTypeMirror  
result) {
		return null;
	}

	public Void visitNull(AnnotatedNullType type, AnnotatedTypeMirror  
result) {
		return null;
	}

	public Void visitPrimitive(AnnotatedPrimitiveType type,  
AnnotatedTypeMirror result)	{
		return null;
	}

	public Void visitTypeVariable(AnnotatedTypeVariable type,  
AnnotatedTypeMirror result)
	{
		AnnotatedTypeMirror lowerBound = scan(type.getLowerBound());
		AnnotatedTypeMirror upperBound = scan(type.getUpperBound());
         setFieldsForClonedTypeVariable(
         		type,
         		lowerBound,
         		upperBound,
         		(AnnotatedTypeVariable) result);
         return null;
	}

	protected void setFieldsForClonedTypeVariable(
			AnnotatedTypeVariable origType,
			AnnotatedTypeMirror lowerBound,
			AnnotatedTypeMirror upperBound,
			AnnotatedTypeVariable result)
	{
		result.setLowerBound(lowerBound);
		result.setUpperBound(upperBound);
	}

	public Void visitWildcard(AnnotatedWildcardType type,  
AnnotatedTypeMirror result) {
		AnnotatedTypeMirror extendsBound = scan(type.getExtendsBound());
		AnnotatedTypeMirror superBound = scan(type.getSuperBound());
         setFieldsForClonedWildcardType(
         		type,
         		extendsBound,
         		superBound,
         		(AnnotatedWildcardType) result);
         return null;
     }
	
	protected void setFieldsForClonedWildcardType(
			AnnotatedWildcardType origType,
			AnnotatedTypeMirror extendsBound,
			AnnotatedTypeMirror superBound,
			AnnotatedWildcardType result)
	{
		result.setExtendsBound(extendsBound);
		result.setSuperBound(superBound);
	}

	/** use {@link #clone(Object)} instead */
	@Deprecated
	public Void visit(AnnotatedTypeMirror type) {
		return visit(type, null);
	}

	/** use {@link #clone(Object)} instead */
	@Deprecated
	public Void visit(AnnotatedTypeMirror type, AnnotatedTypeMirror  
result) {		
		throw new UnsupportedOperationException();
	}

}




More information about the JSR308 mailing list