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

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Dec 16 21:05:48 UTC 2019


On 16/12/2019 19:36, B. Blaser wrote:
> On 16/12/2019 16:40, Maurizio Cimadamore wrote:
>>> 6) "If m is a generic method and the method invocation does not
>>> provide explicit type arguments, then the applicability of the method
>>> is inferred as specified in §18.5.1."
>> Note that this applied also to 15.12.2.2 - all the paragraphs
>> 15.12.2.2/3/4 - are meant to be applied in sequence - they are literally
>> the same logic (esp. the first two), just with a different check context
>> (strict vs. loose vs. varargs). So I don't get why you believe that
>> 'pertinent to applicability' applies to 15.12.2.2 but not to 15.12.2.3 ?
> 'pertinent to applicability' applies to both, of course, but in
> different ways for method references; 'exact' is the condition
> expressed in §15.12.2.2 and 'inferrable' is the requirement for
> §15.12.2.3.
I really don't get where you get this interpretation for - where is it 
written that pertinent to applicability has a different definition in 
15.12.2.3?
>
> Interpreting the JLS otherwise would mean that the inexact method
> reference 'HashMap::new' is never pertinent to applicability and thus
> the assignment inference of 'broker' should fail too... but currently
> 'putAll()' is rejected while 'broker=' is still accepted.

The two processes are completely different. When you evaluate an 
assignment, you start by typing the LHS. In the case of broker= the LHS 
has type Map<? extends Integer, ? extends Integer>. But, and this is the 
crucial difference, this type is *not* used during overload selection. 
You basically perform selection _as if this type did not exist_. Which 
means that the inference variables are configured in this way:


M <: Map<K, U>
K <: Object
U <: Object

So, here, inferring Map<Object, Object> is fine, _for the purpose of 
overload resolution_.

You might ask , but Map<Object, Object> is not the type that comes out 
in the end - and that's true - the type computed at overload selection 
is _thrown away_ and a new process (invocation type inference, 18.5.2) 
kicks in. This process differs from overload inference in two main ways:

* it also throws the target type into the picture (Map<? extends 
Integer, ? extends Integer>)

* it keeps trying to 'unstuck' arguments that are stuck - that is, not 
only it evaluates constraints coming from arguments pertinent to 
applicability, but it used information from such constraint to unblock 
attribution of arguments that are _not_ pertinent to applicability.

By doing this, we can finally take full advantage of inference 
propagation - first the (implicit) parameter type of the first two 
lambdas is inferred to Map.Entry<Integer>. From there, both lambdas can 
finally be type checked, which produces constraints for both K and U - e.g.

Integer <: K
Integer <: U

At which point we no longer infer K=Object and U=Object like before, but 
we infer Integer instead, which makes the whole inference process to 
converge on the right solution.

So, this is the JLS explanation as to why things work in one case, but 
not in the other.

Maurizio

>
> The difference between them is that the target type constraint from
> 'Map<? extends Integer, ? extends Integer>' is added during the
> overload inference of 'putAll()' in which [1] applies whereas the same
> constraint is added during the assignment inference of 'broker=' for
> which [2] applies.
>
> On 16/12/2019 16:59, Maurizio Cimadamore wrote:
>> Now, the target type here is a wildcard-parameterized type (first
>> bullet), so eager instantiation should not happen - but I wonder what
>> happens inside javac.
> I'm not sure you're looking at the right place, recall that 'putAll()'
> works and 'broker=' doesn't with exactly the same argument
> 'HashMap::new' and the same target type 'Map<? extends Integer, ?
> extends Integer>'; the only difference being the overload [1] vs
> assignment inference [2] which don't seem to be distinct cases in the
> JLS, isn't it?
>
> On Mon, 16 Dec 2019 at 19:42, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> wrote:
>> So, this is not an issue, in the compiler sense (and should be closed).
>> Whether there's room to do better in the spec (esp. in terms of
>> incorporation) I'll leave that to Dan.
> I'm still not sure whether this is a spec or compiler issue (or
> nothing), so let's wait for Dan's feedback before closing it.
>
> Cheers,
> Bernard
>
> [1] http://hg.openjdk.java.net/jdk/jdk/file/cec148db7b55/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java#l1255
> [2] http://hg.openjdk.java.net/jdk/jdk/file/cec148db7b55/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java#l1145


More information about the compiler-dev mailing list