Null<T> should not satisfy type constraint T
This compiles fine and leads to a null access error:
function getLength<T:String>(v:T) {
return v.length;
}
function main() {
final nullable:Null<String> = null;
trace(getLength(nullable));
}
That would likely break a lot of things.. 🤔 However I do think this shouldn't be allowed with null safety enabled
A similar example where at least this should not trigger double Null<> wrapping:
function main() {
var x:Null<String> = "";
var zz = testfn(x);
$type(zz); // Null<Null<String>>
}
function testfn<T>(x:T) {
var arr = [x];
return arr.pop();
}
(I thought we already did some things to avoid Null<Null<T>>, but that one might be due to this issue)
That would likely break a lot of things.. 🤔 However I do think this shouldn't be allowed with null safety enabled
Could we make it so that Null<String> never satisfies String, but with null safety disabled we can automatically convert Null<String> to String and instantiate T as String instead of Null<String>? This is consistent with how the type hierarchy should work (Null<String> is not a subtype of String), but still allows the current flexibility if null safety is not desired.
function wrap<T:String>(v:T) {
return v;
}
function main() {
final nullable:Null<String> = null;
$type(wrap(nullable)); // currently Null<String>, would be String
}
This solution would also solve our problem at #12019.
A similar example where at least this should not trigger double Null<> wrapping:
Also, your sample does not require the testfn function to reproduce:
function main() {
var x:Null<String> = "";
var arr = [x];
$type(arr.pop());
}
(I also don't think it's related to this problem, since the T in testfn<T> and Array<T> is unconstrained.)
I've come across something similar related to the nullability of basic types:
function f<T:Int>(a:T) {
trace(a);
}
@:nullSafety(Strict)
@:debug.mono
function main() {
var x = null;
f(x);
}
This doesn't complain at all and traces 0. The mono debug shows us that we have a 0: Null<Unknown<0> : Int> (8:2), which means it's a monomorph constrained to be nullable and to be Int, which in my mind is a conflict on static targets.
This is also very likely the root problem of #6762.
Edit: Maybe it actually isn't a conflict because Null<Int> satisfies both constraints...