Skip to content

Commit 416796f

Browse files
committed
Preserve casts pinning generic-method return type in lambdas
Without the cast, calls like `<T extends SourceFile> T withSourcePath(Path)` inside a lambda lose `T` to its bound during outer inference (e.g. `Optional.map(...).ifPresent(generated::add)`), causing compilation errors. Fixes #871
1 parent 9f02852 commit 416796f

2 files changed

Lines changed: 44 additions & 0 deletions

File tree

src/main/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCast.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,23 @@ public J visitTypeCast(J.TypeCast typeCast, ExecutionContext ctx) {
131131
}
132132
}
133133

134+
// A cast inside a lambda body may pin the inferred return type of a generic method call
135+
// so outer inference (e.g. Optional.map -> ifPresent) doesn't lose it to the type bound.
136+
if (parentValue instanceof J.Lambda && typeCast.getExpression() instanceof J.MethodInvocation) {
137+
JavaType.Method invokedMethod = ((J.MethodInvocation) typeCast.getExpression()).getMethodType();
138+
if (invokedMethod != null && invokedMethod.getDeclaringType() != null) {
139+
for (JavaType.Method declared : invokedMethod.getDeclaringType().getMethods()) {
140+
if (declared.getName().equals(invokedMethod.getName()) &&
141+
declared.getParameterTypes().size() == invokedMethod.getParameterTypes().size() &&
142+
declared.getReturnType() instanceof JavaType.GenericTypeVariable &&
143+
declared.getDeclaredFormalTypeNames().contains(
144+
((JavaType.GenericTypeVariable) declared.getReturnType()).getName())) {
145+
return visitedTypeCast;
146+
}
147+
}
148+
}
149+
}
150+
134151
if (!(targetType instanceof JavaType.Array) && TypeUtils.isOfClassType(targetType, "java.lang.Object") ||
135152
TypeUtils.isOfType(targetType, expressionType) ||
136153
TypeUtils.isAssignableTo(targetType, expressionType)) {

src/test/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCastTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,33 @@ private ChildBar getChildBar() {
612612
);
613613
}
614614

615+
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/871")
616+
@Test
617+
void doNotRemoveCastNeededForGenericMethodInferenceInLambda() {
618+
rewriteRun(
619+
//language=java
620+
java(
621+
"""
622+
import java.nio.file.Path;
623+
import java.util.List;
624+
import java.util.Optional;
625+
626+
interface SourceFile {
627+
<T extends SourceFile> T withSourcePath(Path path);
628+
}
629+
630+
class Test {
631+
void foo(Optional<? extends SourceFile> opt, Path targetPath, List<SourceFile> generated) {
632+
opt
633+
.map(sourceFile -> (SourceFile) sourceFile.withSourcePath(targetPath))
634+
.ifPresent(generated::add);
635+
}
636+
}
637+
"""
638+
)
639+
);
640+
}
641+
615642
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/221")
616643
@Test
617644
void doNotRemoveCharacterCastInGenericContext() {

0 commit comments

Comments
 (0)