Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Substitute type parameters from super types of enclosing classes. #4866

Merged
merged 4 commits into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}