[lworld] RFR: Make "PrimitiveParameterizedClass.default" a poly expression.

Jesper Steen Møller jesper at selskabet.org
Fri Mar 19 15:35:27 UTC 2021


On 19 Mar 2021, at 13.28, Maurizio Cimadamore <mcimadamore at openjdk.java.net> wrote:
> 
> On Fri, 19 Mar 2021 10:57:22 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org <mailto:mcimadamore at openjdk.org>> wrote:
> 
>> One possibility would be to push this change as is - as the refactoring part is really good - and maybe issue raw type warning when generic types are involved, or when default expressions are used in method context. And then in another, separate PR we can refine what happens in truly poly cases.
> 

Yes, that might make sense. I’ll split the PR up into the two cases.

> So, I debugged what happens in case where we have
> 
> `List<String> ls = List.default`
> 
> What I missed is that we create a variable symbol for `default` which has the right type (from the expected type) - so the expression is correctly typed as `List<String>`. But this seems to happen "just because" the compiler detects that the expected type has same base class as the default expression type. Then, the check performed by `checkId` is always vacuously satisfied, given that we're passing in a synthetic variable whose type is the same as the expected one.
> 
> Counter example:
> 
> interface Foo<X extends Number> extends List<X> { }
> ...
> List<String> ls = Foo.default; // still ok, type is `Foo`
> 
> This example is more complex, for two reasons:
> 
> * in this case, Foo is a sub-interface, so the trick of saying "if base class is the same just use the expected type" doesn't work. In fact the compiler types this with `Foo` - which is a raw type
> * in this particular instance, the code should not even be allowed - because the constraint on the `Foo` type parameter are incompatible with those of the expected type List<String> (X must extend Number).
> 
> All this stuff needs to work correctly if we want to claim that default expressions are true poly expressions.
> 

I get it; this needs to be checked before blindly promoting to the expected type.
Thank you for the good counter example.

As for method overload, I’ve come up with this example, which seems to demonstrate the need for the "full poly treatment" using deferred types.

class Whatever {

	static int foo(Consumer<Integer> c) { return 1; }
	static String foo(BiConsumer<Integer, Integer> c) { return "x"; }

	static primitive class Quux<T extends Number> implements Consumer<Integer>, BiConsumer<T, T> {
		public void accept(T t, T u) { }
		public void accept(Integer t) { }
	}
	
	public static void ambiguous() {
		var result = foo(Quux.default); // foo here is ambiguous, just like non-primitive new Quux<>() is
	}
}

-Jesper




More information about the valhalla-dev mailing list