diff --git a/framework/src/main/java/org/checkerframework/framework/type/SupertypeFinder.java b/framework/src/main/java/org/checkerframework/framework/type/SupertypeFinder.java index b5c73e76dd2..2fe2af1542b 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/SupertypeFinder.java +++ b/framework/src/main/java/org/checkerframework/framework/type/SupertypeFinder.java @@ -211,33 +211,58 @@ public List visitDeclared(AnnotatedDeclaredType type, Voi * type parameters of {@code type}, its enclosing types, and all super types of all {@code * type}'s enclosing types. * + *

It does not get the type parameters of the supertypes of {@code type} because the result + * of this method is used to substitute the type arguments of the supertypes of {@code type}. + * * @param type a type * @return a mapping from each type parameter to its corresponding annotated type argument */ private Map getTypeVarToTypeArg(AnnotatedDeclaredType type) { Map mapping = new HashMap<>(); - AnnotatedDeclaredType enclosing = type; - while (enclosing != null) { - TypeElement enclosingTypeElement = (TypeElement) enclosing.getUnderlyingType().asElement(); - List typeParams = enclosingTypeElement.getTypeParameters(); - List typeArgs = enclosing.getTypeArguments(); - for (int i = 0; i < enclosing.getTypeArguments().size(); ++i) { - AnnotatedTypeMirror typArg = typeArgs.get(i); - TypeParameterElement ele = typeParams.get(i); - mapping.put((TypeVariable) ele.asType(), typArg); - } + // addTypeVarsFromEnclosingTypes can't be called with `type` because it calls + // `directSupertypes(types)`, which then calls this method. Add the type variables from `type` + // and then call addTypeVarsFromEnclosingTypes on the enclosing type. + addTypeVariablesToMapping(type, mapping); + addTypeVarsFromEnclosingTypes(type.getEnclosingType(), mapping); + return mapping; + } - @SuppressWarnings("interning:not.interned") // First time through type == enclosing. - boolean notType = enclosing != type; - if (notType) { - for (AnnotatedDeclaredType enclSuper : directSupertypes(enclosing)) { - mapping.putAll(getTypeVarToTypeArg(enclSuper)); - } - } + /** + * Adds a mapping from a type parameter to its corresponding annotated type argument for all + * type parameters of {@code type}. + * + * @param type a type + * @param mapping type variable to type argument map; side-effected by this method + */ + private void addTypeVariablesToMapping( + AnnotatedDeclaredType type, Map mapping) { + TypeElement enclosingTypeElement = (TypeElement) type.getUnderlyingType().asElement(); + List typeParams = enclosingTypeElement.getTypeParameters(); + List typeArgs = type.getTypeArguments(); + for (int i = 0; i < type.getTypeArguments().size(); ++i) { + AnnotatedTypeMirror typArg = typeArgs.get(i); + TypeParameterElement ele = typeParams.get(i); + mapping.put((TypeVariable) ele.asType(), typArg); + } + } + /** + * Adds a mapping from a type parameter to its corresponding annotated type argument for all + * type parameters of {@code enclosing} and its enclosing types. This method recurs on all the + * super types of {@code enclosing}. + * + * @param mapping type variable to type argument map; side-effected by this method + * @param enclosing a type + */ + private void addTypeVarsFromEnclosingTypes( + AnnotatedDeclaredType enclosing, Map mapping) { + while (enclosing != null) { + addTypeVariablesToMapping(enclosing, mapping); + for (AnnotatedDeclaredType enclSuper : directSupertypes(enclosing)) { + addTypeVarsFromEnclosingTypes(enclSuper, mapping); + } enclosing = enclosing.getEnclosingType(); } - return mapping; } private List supertypesFromElement( diff --git a/framework/tests/all-systems/Issue4924.java b/framework/tests/all-systems/Issue4924.java new file mode 100644 index 00000000000..d6391c30dd8 --- /dev/null +++ b/framework/tests/all-systems/Issue4924.java @@ -0,0 +1,15 @@ +public class Issue4924 { + interface Callback {} + + static class Template { + class Adapter implements Callback {} + } + + static class Super extends Template {} + + static class Issue extends Super { + void foo() { + Callback f = new Adapter(); + } + } +}