Record pattern inference & capture

Dan Smith daniel.smith at oracle.com
Thu May 4 21:43:20 UTC 2023


> On Mar 24, 2023, at 3:00 PM, Dan Smith <daniel.smith at oracle.com> 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.


More information about the amber-spec-observers mailing list