Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
return m;
}
} else {
// This invocation is an argument of the enclosing invocation.
if (shouldRetainOnStaticMethod(methodType)) {
// As above, retain unless inferable from this call's own arguments (static or not).
if (!canInferTypeArgumentsFromArguments(methodType)) {
return m;
}
// Cannot remove type parameters if it would introduce ambiguity about which method should be called
Expand Down Expand Up @@ -153,13 +153,6 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu
return samReturn;
}

private boolean shouldRetainOnStaticMethod(JavaType.Method methodType) {
// Without a target type, removing the explicit type arguments of a static method can break
// overload resolution in the enclosing call when the type variables are not inferable from
// the call's own arguments.
return methodType.hasFlags(Flag.Static) && !canInferTypeArgumentsFromArguments(methodType);
}

private boolean canInferTypeArgumentsFromArguments(JavaType.Method methodType) {
// Without arguments, the type parameters cannot be inferred from call-site arguments.
if (methodType.getParameterTypes().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,75 @@ String test(Cursor c) {
);
}

@Test
void retainsWitnessOnInstanceMethodPassedAsArgumentToGenericMethod() {
// STATE_VALUE isn't inferable from source()'s (zero) args or from of()'s target type.
rewriteRun(
//language=java
java(
"""
interface Transition {
<STATE_VALUE> STATE_VALUE source();
}

class Pair<STATE_VALUE extends Enum<STATE_VALUE>> {
static <STATE_VALUE extends Enum<STATE_VALUE>> Pair<STATE_VALUE> of(STATE_VALUE a, STATE_VALUE b) {
return new Pair<>();
}
}

class Test<STATE_VALUE extends Enum<STATE_VALUE>> {
Pair<STATE_VALUE> test(Transition t, STATE_VALUE b) {
return Pair.of(t.<STATE_VALUE>source(), b);
}
}
"""
)
);
}

@Test
void removesWitnessOnInstanceMethodArgumentWhenInferableFromOwnArguments() {
// Unlike above, T is inferable from identity()'s own argument, so it's still removable.
rewriteRun(
//language=java
java(
"""
class Holder {
<T> T identity(T value) {
return value;
}
}

class Test {
void accept(Object o) {
}

void test(Holder h) {
accept(h.<String>identity("x"));
}
}
""",
"""
class Holder {
<T> T identity(T value) {
return value;
}
}

class Test {
void accept(Object o) {
}

void test(Holder h) {
accept(h.identity("x"));
}
}
"""
)
);
}

@Nested
class StaticMethods {
static final SourceSpecs GENERIC_CLASS_SOURCE = java(
Expand Down
Loading