From a0c735810c8d25cbf676a6db788359bff2eed6a9 Mon Sep 17 00:00:00 2001 From: d367wang Date: Thu, 24 Jun 2021 23:48:06 -0400 Subject: [PATCH 1/2] validate method receiver --- src/checkers/inference/InferenceVisitor.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/checkers/inference/InferenceVisitor.java b/src/checkers/inference/InferenceVisitor.java index 459c1d75..6fcb4ff3 100644 --- a/src/checkers/inference/InferenceVisitor.java +++ b/src/checkers/inference/InferenceVisitor.java @@ -47,6 +47,8 @@ import com.sun.source.tree.Tree.Kind; import com.sun.source.tree.VariableTree; +import static com.sun.source.tree.Tree.Kind.METHOD; + /** * InferenceVisitor visits trees in each compilation unit both in typecheck/inference mode. @@ -793,4 +795,16 @@ protected void checkConstructorResult( } } + @Override + public boolean validateTypeOf(Tree tree) { + boolean res = true; + if (tree.getKind() == METHOD) { + AnnotatedExecutableType methodType = (AnnotatedExecutableType) atypeFactory.getAnnotatedType(tree); + AnnotatedTypeMirror type = methodType.getReceiverType(); + if (!validateType(tree, type)) { + res = false; + } + } + return super.validateTypeOf(tree) && res; + } } From a549e43f36bf788713b9545791c47172fe164982 Mon Sep 17 00:00:00 2001 From: d367wang Date: Tue, 29 Jun 2021 09:30:27 -0400 Subject: [PATCH 2/2] create existential var for receiver type arg and wellformedness constraints --- src/checkers/inference/InferenceVisitor.java | 31 ++++++++++++++++--- src/checkers/inference/VariableAnnotator.java | 26 +++++++++++----- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/checkers/inference/InferenceVisitor.java b/src/checkers/inference/InferenceVisitor.java index 6fcb4ff3..2784e647 100644 --- a/src/checkers/inference/InferenceVisitor.java +++ b/src/checkers/inference/InferenceVisitor.java @@ -26,6 +26,7 @@ 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; @@ -798,11 +799,33 @@ protected void checkConstructorResult( @Override public boolean validateTypeOf(Tree tree) { boolean res = true; - if (tree.getKind() == METHOD) { + if (infer && tree.getKind() == METHOD) { + // Validate implicit receiver parameters separately, while explicit receivers are validated + // in the super.validateTypeOf() AnnotatedExecutableType methodType = (AnnotatedExecutableType) atypeFactory.getAnnotatedType(tree); - AnnotatedTypeMirror type = methodType.getReceiverType(); - if (!validateType(tree, type)) { - res = false; + 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 c2f675e4..2bc260a6 100644 --- a/src/checkers/inference/VariableAnnotator.java +++ b/src/checkers/inference/VariableAnnotator.java @@ -539,18 +539,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());