Intersection type and method ref bug ?
B. Blaser
bsrbnd at gmail.com
Thu Oct 15 14:56:18 UTC 2020
Hi,
Resurrecting this old thread as the following expression:
Stream.of(new A(), new B()).map(Test::f).forEach(System.out::println);
still throws a LCE at runtime: "Type mismatch for lambda argument 0:
class Test$C is not convertible to interface Test$I".
>From 'Stream::of' we have 'Stream<C & I>' and then:
<R> Stream<R> map(Function<? super C & I, ? extends R> mapper);
Further, wildcards are removed per JLS15 §9.9 resulting to the
functional descriptor 'apply(C & I)' finally erased to 'apply(C)'
which isn't convertible to 'lambda$main$0(Test$I)' that javac
currently generates, failing to detect the intersection type 'C & I'.
The following patch adds the missing lines to 'LambdaToMethod' on
jdk14u (langtools:tier1 is OK).
What do you think?
Bernard
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
@@ -968,6 +968,10 @@
// If the unerased parameter type is a type variable whose
// bound is an intersection (eg. <T extends A & B>) then
// use the SAM parameter type
+ if (checkForIntersection && descPTypes.head.getKind()
== TypeKind.INTERSECTION) {
+ parmType = samPTypes.head;
+ }
+
if (checkForIntersection && descPTypes.head.getKind()
== TypeKind.TYPEVAR) {
TypeVar tv = (TypeVar) descPTypes.head;
if (tv.getUpperBound().getKind() ==
TypeKind.INTERSECTION) {
On Fri, 26 Oct 2018 at 15:21, Vicente Romero <vicente.romero at oracle.com> wrote:
>
> Hi Remi, Francois,
>
> Thanks for reporting this. I have created [1] to track this issue,
>
> Vicente
>
> [1] https://bugs.openjdk.java.net/browse/JDK-8213032
>
> On 10/24/18 6:05 AM, Remi Forax wrote:
> > This bug was discovered by Francois Green when testing records, but the bug is independent of the record,
> > method reference and intersection type doesn't mix well.
> >
> > public class RecordBadType {
> > interface I {}
> > static abstract class C { }
> > static class A extends C implements I { }
> > static class B extends C implements I { }
> >
> > static String f(I i) { return null; }
> >
> > public static void main(String[] args) {
> > Stream.of(new A(), new B())
> > .map(RecordBadType::f) // here the compiler should generate a bridge method no ?
> > .forEach(System.out::println);
> > }
> > }
> >
> > this code compiles but you get a LambdaConversionException at runtime.
> >
> > Rémi
>
More information about the compiler-dev
mailing list