Open mkustermann opened 1 year ago
T
is Never
according to normalization rules, but type literal Never
is actually Never*
in non-sound mode (due to constant erasure), so they are not identical.
Kernel AST:
static method foo<T extends Never>() → dynamic {
core::print(foo::foo::T);
core::print(#C1);
if(!core::identical(foo::foo::T, #C1))
throw "bar";
}
static method main() → dynamic {
foo::foo<Never>();
}
#C1 = TypeLiteralConstant(Never*)
Either this test is incorrect (cc @leafpetersen) or this is a front-end bug (cc @johnniwinther).
I think we specified this identity to hold: https://github.com/dart-lang/language/blob/main/accepted/2.12/nnbd/feature-specification.md#type-literals . @eernstg might check me there.
That said, I'm not sure this corner of weak mode semantics is a high priority to fix at this point.
Right, the priority is a bit low for tests that are going to go away soon.
However, I'm actually arriving at a more vague conclusion: identical
can return true or false in this case.
foo<T extends Never>() {
if (!identical(T, Never)) throw 'bar';
}
main() {
foo();
}
The library is null safe (at least, this test has no @dart = ...
specifier), so Never
means Never
, not Null
.
Never
is a constant expression. It should be canonicalized, but it is unspecified which canonical representation is chosen for the set of reified types that are equal according to the type equality operation.
So it could evaluate to the Type
that reifies Never
or Never*
, none of those is a violation of the specified behavior.
The invocation foo()
in main
would be inferred as foo<Never>()
.
This is then the run-time value of T
when foo
is executed. T
is not a constant expression, and hence there is no normalization step when T
is evaluated to a reified type, which would then be the Type
for Never
.
So, as far as I can see, both true and false are acceptable results from identical(T, Never)
. On the other hand, T == Never
should evaluate to true (and presumably it does not matter which value is passed to T
at the call site, because T
is normalized to Never
no matter what).
Perhaps the test should simply be adjusted to test if (T != Never) throw 'bar';
.
See log:
It seems this is due to weak mode, as:
Passes by-default
Fails in non sound null safety
/cc @alexmarkov