Skip to content

Commit

Permalink
Substitute type parameters from super types of enclosing classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
smillst committed Aug 12, 2021
1 parent c56cdb2 commit 99bc4d9
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 10 deletions.
18 changes: 18 additions & 0 deletions checker/tests/nullness/Issue4853Nullness.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import org.checkerframework.checker.nullness.qual.Nullable;

public class Issue4853Nullness {
interface Interface<Q> {}

static class MyClass<T> {
class InnerMyClass implements Interface<T> {}
}

abstract static class SubMyClass extends MyClass<@Nullable String> {
protected void f() {
// :: error: (argument)
method(new InnerMyClass());
}

abstract void method(Interface<String> callback);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -193,29 +193,51 @@ public List<AnnotatedDeclaredType> visitDeclared(AnnotatedDeclaredType type, Voi
supertypes.add(jlaAnnotation);
}

Map<TypeVariable, AnnotatedTypeMirror> typeVarToTypeArg = getTypeVarToTypeArg(type);

List<AnnotatedDeclaredType> superTypesNew = new ArrayList<>();
for (AnnotatedDeclaredType dt : supertypes) {
type.atypeFactory.initializeAtm(dt);
superTypesNew.add(
(AnnotatedDeclaredType)
atypeFactory.getTypeVarSubstitutor().substitute(typeVarToTypeArg, dt));
}

return superTypesNew;
}

/**
* Creates a mapping from a type parameter to its corresponding annotated type argument for all
* type parameters of {@code type}, its enclosing types, and all super types of all {@code
* type}'s enclosing types.
*
* @param type a type
* @return a mapping from each type parameter to its corresponding annotated type argument
*/
private Map<TypeVariable, AnnotatedTypeMirror> getTypeVarToTypeArg(AnnotatedDeclaredType type) {
Map<TypeVariable, AnnotatedTypeMirror> mapping = new HashMap<>();
AnnotatedDeclaredType enclosing = type;
while (enclosing != null) {
TypeElement enclosingTypeElement = (TypeElement) enclosing.getUnderlyingType().asElement();
List<AnnotatedTypeMirror> typeArgs = enclosing.getTypeArguments();
List<? extends TypeParameterElement> typeParams = enclosingTypeElement.getTypeParameters();
List<AnnotatedTypeMirror> 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);
}

enclosing = enclosing.getEnclosingType();
}
@SuppressWarnings("interning:not.interned") // First time through type == enclosing.
boolean notType = enclosing != type;
if (notType) {
for (AnnotatedDeclaredType enclSuper : directSupertypes(enclosing)) {
mapping.putAll(getTypeVarToTypeArg(enclSuper));
}
}

List<AnnotatedDeclaredType> superTypesNew = new ArrayList<>();
for (AnnotatedDeclaredType dt : supertypes) {
type.atypeFactory.initializeAtm(dt);
superTypesNew.add(
(AnnotatedDeclaredType) atypeFactory.getTypeVarSubstitutor().substitute(mapping, dt));
enclosing = enclosing.getEnclosingType();
}

return superTypesNew;
return mapping;
}

private List<AnnotatedDeclaredType> supertypesFromElement(
Expand Down
16 changes: 16 additions & 0 deletions framework/tests/all-systems/Issue4853.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@SuppressWarnings("all") // Just check for crashes.
public class Issue4853 {
interface Interface<T> {}

static class MyClass<T> {
class InnerMyClass implements Interface<T> {}
}

abstract static class SubMyClass extends MyClass<Void> {
protected void f() {
method(new InnerMyClass());
}

abstract void method(Interface<Void> callback);
}
}

0 comments on commit 99bc4d9

Please sign in to comment.