Bug 521765 - [Compiler] Type inference failure with Generics and Optional leads to unnecessary explicit typing
Summary: [Compiler] Type inference failure with Generics and Optional leads to unneces...
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.7   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2017-09-01 12:10 EDT by Sebastian Millies CLA
Modified: 2022-06-08 12:54 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastian Millies CLA 2017-09-01 12:10:45 EDT
Eclipse Java Development Tools 3.13.0.v20170612-0950

While playing around with mimicking some functional programming standards in Java, I have stumbled on a strange corner case where type inference in the Eclipse Java compiler breaks down.

In the following program, Eclipse requires explicit typing of the lambda parameter "idx" as int[], where javac (jdk1.8.0_121) accepts an implicitly typed lambda expression.

I cannot tell if Eclipse does less than the JLS mandates, or if javac does more.

public abstract class Bug {

    List<int[]> example(String s) {
        return Stream.of(new int[] { 0 })
                .flatMap(startIdx -> unfold(
                            (int[] idx) -> Optional.of(pair(idx, idx)),  // explicitly typed lambda parameter!
                            startIdx)
                        .stream())
                .collect(toList());
    }
    
    abstract <T, R> List<R> unfold(Function<T, Optional<Pair<R, T>>> f, T x);
    
    abstract <F, S> Pair<F, S> pair(F first, S second);
 
    class Pair<F, S> { }
}

The problem goes away when I remove the Optional around the Pair in the marked line and in the type signature of unfold. Strangely, it also goes away when I replace the first argument of the call to pair() with a String constant (and change the return type of example() to List<String>).

It does not go away when I stream a list of Integer arrays instead of primitive int arrays. I am then required to explicitly type the lambda parameter as Integer[].
Comment 1 Stephan Herrmann CLA 2017-09-01 16:43:33 EDT
Here's the full version demonstrating the error (imports *are* relevant):

//---
import java.util.*;
import java.util.stream.*;
import java.util.function.*;
import static java.util.stream.Collectors.*;

public abstract class Bug {

    List<int[]> example(String s) {
        return Stream.of(new int[] { 0 })
                .flatMap(startIdx -> unfold(
                            (idx) -> Optional.of(pair(idx, idx)),  // explicitly typed lambda parameter!
                            startIdx)
                        .stream())
                .collect(toList());
    }

    abstract <T, R> List<R> unfold(Function<T, Optional<Pair<R, T>>> f, T x);

    abstract <F, S> Pair<F, S> pair(F first, S second);

    class Pair<F, S> { }
}
//---

ecj reports:

  Type mismatch: cannot convert from List<Object> to List<int[]>

At this point I can't tell either, whether that's the correct answer or not.

Hope to find the time between Java 9 GA (current priority) and Photon release.

BTW, I didn't succeed to construct the mentioned variant using Integer[]. Could you please show what you had there?
Comment 2 Sebastian Millies CLA 2017-09-02 05:01:56 EDT
Something like this:

    List<Integer[]> example2(String s) {
        return Arrays.asList(new Integer[] { 0 }, new Integer[] { 1 }).stream()
                .flatMap(startIdx -> unfold(
                            (Integer[] idx) -> Optional.of(pair(idx, idx)),
                            startIdx)
                        .stream())
                .collect(toList());
    }
Comment 3 Stephan Herrmann CLA 2017-09-02 08:23:24 EDT
(In reply to Sebastian Millies from comment #2)
> Something like this:
> 
>     List<Integer[]> example2(String s) {
>         return Arrays.asList(new Integer[] { 0 }, new Integer[] { 1
> }).stream()
>                 .flatMap(startIdx -> unfold(
>                             (Integer[] idx) -> Optional.of(pair(idx, idx)),
>                             startIdx)
>                         .stream())
>                 .collect(toList());
>     }

Thanks, so we know it's an issue of arrays, not of primitives.
Comment 4 Manoj N Palat CLA 2018-05-17 03:25:59 EDT
bulk move out of 4.8
Comment 5 Eclipse Genie CLA 2022-06-08 12:54:47 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.