Javac type inference issue
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Aug 28 10:59:02 UTC 2023
This does seem like an issue.
Note that similar code, w/o a method call works:
|List<List<? super T1>> res = Arrays.asList(args); |
I did some manual calculation of the bounds involved and I got to:
|List<? super T1> <: #A = List<? super #T2> |
Which seems solvable for:
|A = List<? super T2> T2 = T1 |
But the javac error message reveals a capture conversion is being
applied somewhere:
|error: method listMethod in class Test cannot be applied to given
types; List<List<? super T2>> res = listMethod(Arrays.asList(args)); ^
required: List<List<? super T2>> found: List<List<? super T1>> reason:
inference variable T has incompatible bounds equality constraints:
List<? super CAP#1> // <-------------------------- lower bounds: List<?
super T1> |
Which seems odd - I would have understod if javac tried to capture
“args” before passing to Arrays::asList - but that’s not what is
happening here.
My feeling (confirmed by looking at the internals of the compiler) is
that javac is applying incorporation to the above set of bounds - and
running the following check:
|List<? super T1> <: List<? super #T2> |
The JLS here says that when running the this incorporation step, since
both types are |? super X| wildcards we should just derive:
|#T2 <: T1 |
(e.g. no capture conversion applied).
But that’s not what happens in the compiler implementation (which does a
straight subtyping check with capture conversion), hence the issue.
Maurizio
On 27/08/2023 15:06, Attila Kelemen wrote:
>
> In case of a capture, the inference does not try to replace the
> capture by its bound. It's a limitation of the inference which
> tend to choose the most speciifc type where here, it has to use a
> less specific type.
>
>
> I don't quite understand the step by step "reasoning" of the type
> inferer here, because naively this is what I would do if I was
> employed as a full time type inferer :). (I'm copying here my code
> again with some variable renaming for easier reference) Suppose I'm a
> compiler, and I see this:
>
> ```
> <T1> void arrayMethod(List<? super T1>[] args) {
> listMethod(Arrays.asList(args));
> }
> <T2> void listMethod(List<List<? super T2>> list) { }
> ```
>
> 1. I look at `arrayMethod` and see 2 type variables to infer. One for
> `listMethod` (let's call it #L), and one for `Arrays.asList` (let's
> call it #A).
> 2. The first thing I see is that `Arrays.asList` returns `List<#A>`,
> and it is assigned to `List<List<? super #L>>`. This is easy to
> satisfy with #A = List<? super #L> (and this is actually the only
> possibility).
> 3. Then I go the next part, and see that args is of course `List<?
> super T1>[]` which must be assigned to `#A[]`, which is again easy to
> satisfy with #A = List<? super T1> (which is the only possibility again).
> 4. So, now I have to satisfy all equalities `#A = List<? super #L>`
> and `#A = List<? super T1>`, which implies that `List<? super #L> =
> List<? super T1>`, which is easy to satisfy by the choice #L = T1
> (again, this is the only choice).
> 5. So, now I have resolved both variables:` #L = T1`, and `#A = List<?
> super T1>`, and indeed I can validate that this choice will satisfy
> every constraint.
>
> I'm just puzzled here, because sometimes the type inferer can solve
> much more difficult problems, and this seems trivial compared to those.
>
> My bad, I should have written List<? super List<? super T>>.
>
>
> Surprisingly (to me), that would compile without explicitly specifying
> the type arguments (though of course that is not a type declaration
> that is acceptable for me). What surprises me here is that I would
> think that this would make the job of the type inferer harder, since
> now it is more difficult to find the correct types, since there are
> more options. Without the outer "? super" the inferer would be forced
> to make the correct type assignment (since there is always only one
> possibility). That is, when you write `List<? super List<? super T>`,
> now you get another fresh type variable to satisfy. Namely, you have
> to pick a type of `? super List<? super T>`. While in the other case
> your only option for this was `List<? super T>` (which is the only
> correct choice even in the `? super` variant.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20230828/33b1a160/attachment-0001.htm>
More information about the compiler-dev
mailing list