JDK-8177520 : Type inference "varargs mismatch; inference variable R has incompatible bounds"
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 9
  • Priority: P3
  • Status: Resolved
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2017-03-23
  • Updated: 2018-11-27
  • Resolved: 2017-03-29
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbd_majorResolved
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+161)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+161, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
not OS specific (currently reproducing on Darwin syrah 16.4.0 Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64 x86_64)

A DESCRIPTION OF THE PROBLEM :
See the code, compiles with JDK8 alright, fails with latest JDK9 161.

/Users/rhusar/wildfly/clustering/jgroups/extension/src/main/java/org/jboss/as/clustering/jgroups/JChannelFactory.java:[68,13] error: no suitable method found for addProtocols(List<Object>)
    method ProtocolStack.addProtocols(Protocol...) is not applicable
      (varargs mismatch; inference variable R has incompatible bounds
          equality constraints: List<T#2>
          upper bounds: Protocol,Object)
    method ProtocolStack.addProtocols(List<Protocol>) is not applicable
      (argument mismatch; inference variable T#2 has incompatible bounds
          equality constraints: Protocol
          lower bounds: Object)
  where R,A,T#1,T#2 are type-variables:
    R extends Object declared in method <R,A>collect(Collector<? super T#1,A,R>)
    A extends Object declared in method <R,A>collect(Collector<? super T#1,A,R>)
    T#1 extends Object declared in interface Stream
    T#2 extends Object declared in method <T#2>toList()
[ERROR] /Users/rhusar/wildfly/clustering/jgroups/extension/src/main/java/org/jboss/as/clustering/jgroups/JChannelFactory.java:[72,76] error: cannot find symbol
  symbol:   method createProtocol(ProtocolStackConfiguration)
  location: variable pc of type Object

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
see code

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the test attached compiles OK like jdk9
ACTUAL -
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /Users/rhusar/git/jdk9typebug/src/main/java/JChannelFactory.java:[14,14] no suitable method found for addProtocols(java.util.List<java.lang.Object>)
    method JChannelFactory.ProtocolStack.addProtocols(JChannelFactory.Protocol...) is not applicable
      (varargs mismatch; inference variable R has incompatible bounds
          equality constraints: java.util.List<T>
          upper bounds: JChannelFactory.Protocol,java.lang.Object)
    method JChannelFactory.ProtocolStack.addProtocols(java.util.List<JChannelFactory.Protocol>) is not applicable
      (argument mismatch; inference variable T has incompatible bounds
          equality constraints: JChannelFactory.Protocol
          lower bounds: java.lang.Object)
[ERROR] /Users/rhusar/git/jdk9typebug/src/main/java/JChannelFactory.java:[17,77] cannot find symbol
  symbol:   method createProtocol(JChannelFactory.ProtocolStackConfiguration)
  location: variable pc of type java.lang.Object
[INFO] 2 errors

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Radoslav Husar
 */
public class JChannelFactory {
    void createChannel() {
        ProtocolStackConfiguration configuration = new ProtocolStackConfiguration();
        ProtocolStack stack = new ProtocolStack();
        stack.addProtocols(Stream.of(
                Stream.of(configuration.getTransport()),
                configuration.getProtocols().stream()
        ).flatMap(Function.identity()).filter(Objects::nonNull).map(pc -> pc.createProtocol(configuration)).collect(Collectors.toList()));
    }

    public abstract static class Protocol {
    }

    public interface ProtocolConfiguration<P extends Protocol> {
        P createProtocol(ProtocolStackConfiguration stackConfiguration);
    }

    static class ProtocolStackConfiguration {

        ProtocolConfiguration<? extends TP> getTransport() {
            return null;
        }

        List<ProtocolConfiguration<? extends Protocol>> getProtocols() {
            return null;
        }
    }

    static class TP extends Protocol {
    }

    public static class ProtocolStack {

        public ProtocolStack addProtocols(Protocol... prots) {
            return this;
        }

        public ProtocolStack addProtocols(List<Protocol> prots) {
            return this;
        }

    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
explicitly cast:

.map(pc -> ((ProtocolConfiguration)pc).createProtocol(configuration))


Comments
Keeping this bug priority is same as its duplicate bug JDK-8160244
30-05-2017

Digging deeper, this is ultimately the same problem as JDK-8160244. The additional report is helpful; we'll pursue a fix via that entry.
29-03-2017

The introduction of a new capture variable during inference is probably a bug. But the spec is unclear: see JDK-8016196.
27-03-2017

Here is the feedback from WildFly: > > we currently are blocked by compiler bug, that we reported https://bugs.openjdk.java.net/browse/JDK-8177520 > > We are still testing most of the components with latest jdk9 builds, but WildFly build itself is currently broken. > > --
27-03-2017

I believe the incorporation fix in JDK-8067767 just uncovered an existing bug - the compiler appears to do the right thing. More specifically - the flatMap signature is instantiated as follows: <R> Function<? super Stream<? extends Foo<? extends String>>, ? extends Stream<? extends R>> mapper) Then it has to establish as to whether the return type of Function.identity() is compatible with the expected type of 'mapper': Function<T, T> <: Function<? super Stream<? extends Foo<? extends String>>, ? extends Stream<? extends R>> This generates the following constraints: Stream<? extends Foo<? extends String> <: T T <: Stream<? extends R> Which can be incorporated as follows: Stream<? extends Foo<? extends String>> <: Stream<? extends R> Stream<#CAP> <: Stream<? extends R>, where #CAP <: Foo<? extends String> #CAP <: R When javac attempts to resolve R = #CAP, incorporation fails, because the above check would be instantiated as follows: Stream<? extends Foo<? extends String>> <: Stream<? extends #CAP> Which leads to an errors: Stream<#CAP2> <: Stream<? extends #CAP>, where #CAP2 <: Foo<? extends String> #CAP2 <: #CAP -> false Ultimately, this seems related to JDK-8016196.
24-03-2017

This started to fail, in its current form in b94. It's either JDK-8067767 or JDK-8046685 - probably more the former, as disabling the optimization introduced by the latter doesn't help.
24-03-2017

This is an regression introduced in 9 ea b22 9 ea b21 - Pass 9 ea b22 - fail
24-03-2017

Issue is reproducible on 9, test case passes on 8u121. == jdk/9/ea/161/binaries/linux-x64/bin/javac JChannelFactory.java JChannelFactory.java:14: error: no suitable method found for addProtocols(List<Object>) stack.addProtocols(Stream.of( ^ method ProtocolStack.addProtocols(Protocol...) is not applicable (varargs mismatch; inference variable R has incompatible bounds equality constraints: List<T#2> upper bounds: Protocol,Object) method ProtocolStack.addProtocols(List<Protocol>) is not applicable (argument mismatch; inference variable T#2 has incompatible bounds equality constraints: Protocol lower bounds: Object) where R,A,T#1,T#2 are type-variables: R extends Object declared in method <R,A>collect(Collector<? super T#1,A,R>) A extends Object declared in method <R,A>collect(Collector<? super T#1,A,R>) T#1 extends Object declared in interface Stream T#2 extends Object declared in method <T#2>toList() JChannelFactory.java:17: error: cannot find symbol ).flatMap(Function.identity()).filter(Objects::nonNull).map(pc -> pc.createProtocol(configuration)).collect(Collectors.toList())); ^ symbol: method createProtocol(ProtocolStackConfiguration) location: variable pc of type Object 2 errors == 8u121 - Pass 8u131 b04 - Pass 9 ea b161 - Fail
24-03-2017

For completeness, this started to fail in b22, and then started to work again from b62 to b94. I believe what made this temporarily work was the fix for JDK-8078024, which also caused other programs that were previously illegal to be accepted. In JDK 8 (and very early JDK 9) there is no issue, as captured variables are mapped to their bounds during a containment test - which means no capture variable would have been generated for this case.
24-03-2017

The following, minimal test, is sufficient to reproduce the problem: import java.util.List; import java.util.function.Function; import java.util.stream.Stream; class Foo<X> { } class Test { void test() { Stream<Stream<? extends Foo<? extends String>>> ss = null; ss.flatMap(Function.identity()).nonExistent(); //return type of flatMap is Stream<Object> ??? ss.flatMap(s -> s).nonExistent(); //return type of flatMap is Stream<#CAP>, where #CAP <: Foo<? extends String> } } This generates the following errors: Main.java:75: error: cannot find symbol ss.flatMap(Function.identity()).nonExistent(); ^ symbol: method nonExistent() location: interface Stream<Object> Main.java:76: error: cannot find symbol ss.flatMap(s -> s).nonExistent(); ^ symbol: method nonExistent() location: interface Stream<CAP#1> where CAP#1 is a fresh type-variable: CAP#1 extends Foo<? extends String> from capture of ? extends Foo<? extends String> 2 errors Note how in the first call, the inferred type for flatMap is just Stream<Object> - such a type is too weak and prevents further inference to take place.
24-03-2017