diff --git a/src/checkers/inference/InferenceVisitor.java b/src/checkers/inference/InferenceVisitor.java index df07527f..d41a71b0 100644 --- a/src/checkers/inference/InferenceVisitor.java +++ b/src/checkers/inference/InferenceVisitor.java @@ -1,7 +1,5 @@ package checkers.inference; -import com.sun.source.tree.ClassTree; -import com.sun.source.util.TreePath; import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeVisitor; @@ -22,11 +20,13 @@ import java.lang.annotation.Annotation; import java.util.Arrays; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.logging.Logger; import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; @@ -40,11 +40,14 @@ import checkers.inference.util.InferenceUtil; import com.sun.source.tree.CatchTree; +import com.sun.source.tree.ClassTree; import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodTree; import com.sun.source.tree.ThrowTree; import com.sun.source.tree.Tree; import com.sun.source.tree.Tree.Kind; import com.sun.source.tree.VariableTree; +import com.sun.source.util.TreePath; import org.plumelib.util.ArraysPlume; @@ -848,4 +851,38 @@ protected void checkConstructorResult( } } + @Override + public boolean validateTypeOf(Tree tree) { + boolean res = true; + if (infer && tree.getKind() == Kind.METHOD) { + // Validate implicit receiver parameters separately, while explicit receivers are validated + // in the super.validateTypeOf() + AnnotatedExecutableType methodType = (AnnotatedExecutableType) atypeFactory.getAnnotatedType(tree); + AnnotatedDeclaredType type = methodType.getReceiverType(); + if (type != null && ((MethodTree) tree).getReceiverParameter() == null) { + res = validateType(tree, type); + + // receiver type arguments are bounded by the declaration upper/lower bounds + List typeArgs = type.getTypeArguments(); + Element declarationEle = type.getUnderlyingType().asElement(); + AnnotatedDeclaredType declaration = + (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(declarationEle); + List declarationTypeVars = declaration.getTypeArguments(); + + assert typeArgs.size() == declarationTypeVars.size(); + + final Iterator declTypeVarIterator = declarationTypeVars.iterator(); + final Iterator typeArgIterator = typeArgs.iterator(); + while (declTypeVarIterator.hasNext()) { + AnnotatedTypeMirror declTypeVar = declTypeVarIterator.next(); + AnnotatedTypeMirror typeArg = typeArgIterator.next(); + AnnotatedTypeMirror declUpperBound = ((AnnotatedTypeVariable) declTypeVar).getUpperBound(); + AnnotatedTypeMirror declLowerBound = ((AnnotatedTypeVariable) declTypeVar).getLowerBound(); + atypeFactory.getTypeHierarchy().isSubtype(declLowerBound, typeArg); + atypeFactory.getTypeHierarchy().isSubtype(typeArg, declUpperBound); + } + } + } + return super.validateTypeOf(tree) && res; + } } diff --git a/src/checkers/inference/VariableAnnotator.java b/src/checkers/inference/VariableAnnotator.java index 91becc7c..cbc8ef1c 100644 --- a/src/checkers/inference/VariableAnnotator.java +++ b/src/checkers/inference/VariableAnnotator.java @@ -541,18 +541,28 @@ private Slot addPrimaryVariable(AnnotatedTypeMirror atm, final Tree tree) { * We create a variable annotation for @1 and place it in the primary annotation position of * the type. */ - public SourceVariableSlot addImpliedPrimaryVariable(AnnotatedTypeMirror atm, final AnnotationLocation location) { - SourceVariableSlot variable = slotManager.createSourceVariableSlot(location, atm.getUnderlyingType()); - atm.addAnnotation(slotManager.getAnnotation(variable)); + public void annotateImpliedMethodReceiver(AnnotatedTypeMirror atm, final AnnotationLocation location) { + if (atm instanceof AnnotatedTypeVariable) { + // Create existential slots for type variables + AnnotatedTypeVariable typeVar = (AnnotatedTypeVariable) atm; - AnnotationMirror realAnno = atm.getAnnotationInHierarchy(realTop); - if (realAnno != null) { - constraintManager.addEqualityConstraint(slotManager.getSlot(realAnno), variable); + // Get bounds for the type variable. i.e. alternative slots + Element typeVarDeclElem = typeVar.getUnderlyingType().asElement(); + assert elementToAtm.containsKey(typeVarDeclElem); + AnnotatedTypeMirror typeVarDecl = elementToAtm.get(typeVarDeclElem); + + // Create the potential slot for the type variable + final Slot potentialVariable = createVariable(location, atm.getUnderlyingType()); + + existentialInserter.insert(potentialVariable, typeVar, typeVarDecl); + + } else { + // Create source variable slots for declared types + replaceOrCreateEquivalentVarAnno(atm, null, location); } logger.fine("Created implied variable for type:\n" + atm + " => " + location); - return variable; } /** @@ -1443,7 +1453,7 @@ private void handleReceiver(AnnotatedExecutableType methodType, final AnnotatedTypeMirror type = typeToPath.getKey(); final ASTRecord path = typeToPath.getValue(); - addImpliedPrimaryVariable(type, new AstPathLocation(path)); + annotateImpliedMethodReceiver(type, new AstPathLocation(path)); } receiverMissingTrees.put(methodElem, receiverType.deepCopy());