Wow, nice one! It took me a few minutes thinking to understand what is going on here. So, as I guess you know, this:
max {}
Is supposed to be, in theory, the same thing as these:
max({})
max { values={}; }
Now, if you write either of those permutations, you will get the correct return type Null
inferred for max()
. And, indeed, if you execute either example, the result is, correctly, null
.
Indeed, even if I run the following program:
void run() => print( max{} );
It prints <null>
, as we would expect.
So what's going on here is that I have a bug in my type argument inference algorithm, where it fails to take into account the "implicit" empty iterable argument, a {Nothing*}
, when inferring type args. Therefore, you're getting the inferred type Nothing
for both type parameters of max()
, because the type parameters are treated as unconstrained. Then, since Nothing
is a subtype of Integer
, the typechecker lets you assign the result to Integer
. Of course the null value that is actually returned by the function is not assignable to Integer
, so you get an NPE that of course should never happen.
The solution is I need to fix the bug. It will be a tiny one liner.
If you don't mind, would you submit a bug report to ceylon-spec please, and I will fix it tomorrow.
Thanks!