JDK-8219318 (???): inferred type does not conform to upper bound(s) when collecting to a HashMap

B. Blaser bsrbnd at gmail.com
Thu Dec 19 15:23:23 UTC 2019


On Wed, 18 Dec 2019 at 16:46, Maurizio Cimadamore
<maurizio.cimadamore at oracle.com> wrote:
>
> On 18/12/2019 15:35, B. Blaser wrote:
> > Another possibility would be to reduce the fix to 'inexact method
> > references with *a unique potential target* and no stuck variables
> > would be pertinent to applicability'?
>
> I honestly believe you are looking in the wrong place. I think there's a
> reason (as I explained) as to why pertinent to applicability was defined
> the way it was. If there's a spec problem here, it seems like it lies in
> how incorporation fails to generate constraints for the underconstrained
> vars because of the presence of wildcards. That's a much more direct
> problem to fix, which doesn't involve re-architecting how overload
> selection is structured (which is not gonna happen).

I guess you're right, the method reference is probably shadowing the problem.

Take the following simpler example:

class Test3 {
    interface I<V> {}

    <W, X extends I<W>> X m() { return null; }

    void n(I<Integer> p) {}
    void o(I<? extends Integer> p) {}

    void run() {
        n(m());
        o(this.<Integer, I<Integer>>m());
        o(m()); // KO!
    }
}

$ javac Test3.java
Test3.java:12: error: incompatible types: inferred type does not
conform to upper bound(s)
        o(m()); // KO!
        ^
    inferred: I<Object>
    upper bound(s): I<Object>,I<? extends Integer>
Note: Some messages have been simplified; recompile with
-Xdiags:verbose to get full output
1 error

The problem is that when inferring 'n(m())' the bounds 'X <: I(W),
I(Integer)' implies 'W=Integer' per §18.3.1 but with 'o(m())' the
bounds 'X <: I(W), I(? extends Integer)' should probably imply 'W <:
Integer' instead of inferring 'W=Object'.

So, I did a voodoo cult devoted to inference which ended up with some
black magic on our good old friend 'Types::isSameType', see below.

While this experiment is somewhat incomplete, both examples 'putAll()'
and 'o(m())' are now working without any 'langtools:tier1' failure.

What do you think?
Bernard

diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
@@ -1376,6 +1376,10 @@
             @Override
             public Boolean visitWildcardType(WildcardType t, Type s) {
                 if (!s.hasTag(WILDCARD)) {
+                    if (!t.isUnbound() && t.isExtendsBound() &&
s.hasTag(UNDETVAR)) {
+                        ((UndetVar)s).addBound(InferenceBound.UPPER,
t.type, Types.this);
+                        return true;
+                    }
                     return false;
                 } else {
                     WildcardType t2 = (WildcardType)s;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java
@@ -944,6 +944,10 @@
                         List<Type> allParamsSuperBound1 =
commonSupers.fst.allparams();
                         List<Type> allParamsSuperBound2 =
commonSupers.snd.allparams();
                         while (allParamsSuperBound1.nonEmpty() &&
allParamsSuperBound2.nonEmpty()) {
+                            if
(allParamsSuperBound1.head.hasTag(WILDCARD) &&
!allParamsSuperBound2.head.hasTag(WILDCARD)) {
+                                //try to match wildcard and undet var bounds
+                                isSameType(allParamsSuperBound1.head,
inferenceContext.asUndetVar(allParamsSuperBound2.head));
+                            }
                             //traverse the list of all params comparing them
                             if (!allParamsSuperBound1.head.hasTag(WILDCARD) &&

!allParamsSuperBound2.head.hasTag(WILDCARD)) {


More information about the compiler-dev mailing list