-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
[June 2024: This issue has been clarified by revisiting the specification. The analyzer should report a compile-time error like the one that the CFE currently reports, as summarized here.]
Cf. #52077 for a situation where this question came up. Cf. #52077 (comment) where @lrhn first clarified the situation.
Consider the following program:
class Filterable {}
class Filter<T extends Filterable?> {
void test(T t) {
if (t is! Filterable) return; // Should promote `t` to `T & Filterable`.
t.when(); // Accepted by analyzer. Error from CFE.
}
}
extension When<T extends Filterable> on T {
T? when() => null;
}
void main() {}
The type of t
at the method invocation t.when()
is T & Filterable
. In order to invoke the extension method when
, the extension needs to receive a type argument, which implies that T & Filterable
must be erased to a type which is representable at run time.
If it is erased to T
(which is typical for intersection types when reified), the extension does not match, and we should get a compile time error. This appears to be the approach taken in the CFE.
If it is erased to Filterable
(possibly after trying T
and failing), the invocation can resolve to When.when
, and there are no errors. This may be the approach taken by the analyzer—at least, it does not report any errors for this program.
Pragmatically, it seems desirable to try each of the two operands of the intersection type. However, it might create difficulties (say, in terms of an exponential time/space usage) because it is a deviation from the one-pass strategies that we are otherwise using.
So what is the desired approach? @dart-lang/language-team, WDYT?