> On Mar 24, 2023, at 3:00 PM, Dan Smith <[email protected]> wrote:
>
> If I try to match the type Function<CAP1,CAP2> with a type like
> UnaryOperator, should that be an inference failure? The current rules say
> "yes": inference variable alpha=CAP1, and alpha=CAP2, a contradiction. But I
> don't think that's right. If the dynamic check for UnaryOperator succeeds,
> that means that this must actually be a Function in which the actual types
> represented by CAP1 and CAP2 are the same.
Followup: in fact, this is also true for type variables:
<S extends Foo, T extends Bar> void test(Function<S,T> f) {
if (f instanceof Mapper(var in, var out)) ...
}
It is certainly possible for this test to succeed—if, say, S and T are
instantiated to some subtype of Foo and Bar. (This is why it's perfectly legal
since Java 5 to cast from Function<S,T> to Mapper<?>.)
Unfortunately, if we were to give type variables the same treatment as
wildcards, what we'd end up inferring is Mapper<? extends Foo & Bar>, which is
not as useful as Mapper<S> or Mapper<T>.
And setting these complex use cases aside, it would be disappointing if, given
Collection<S> as a match input, we couldn't infer MyRecordList<S> as its
subtype and ended up with MyRecordList<? extends Foo> instead.
(It might also be useful to sometimes preserve capture variables in the
inferred type in simple cases, although there's some complexity there—compare
JDK-8170887.)
I'm unsure about the right way to resolve this tension. Best I can come up with
is a heuristic-based "try with the variables, then if that fails try turning
all variables into inference vars" strategy, but I don't love bringing yet more
of that kind of logic into type inference.