Open alexmarkov opened 3 years ago
@alexmarkov what check are you looking for? Given:
class A {}
class B {}
...
B f(A a) => a as B;
There can be classes which extend both A and B.
Are you just thinking of the un-extendable classes (int
, double
, num
, String
, bool
, Future
, FutureOr
, void
, Never
, or something like this)? Given the prevalence of int, double, String, etc, I think this could be useful.
The real code was converting double
to int via as int
, so we can at least cover sealed built-in classes.
In general, we can conclude that the cast will always fail if we know all possible subtypes of static type of an operand (A
) or all possible subtypes of a target type (B
). That may happen for sealed built-in classes, library-private classes which don't have public subtypes or if we're analyzing the whole program and see all classes (but I'm not sure if analyzer can ever make closed-world assumptions). In certain cases it is also possible to infer actual runtime type of an operand from a generative constructor invocation / constant.
Yeah, whole program will be a neat feature in the future. Analyzer does not do it today.
I think sealed built-in classes will be most useful. Private classes with no public subtypes is not as useful.
For example:
With null safety this code always throws an error and dartanalyzer can figure this out using static types and issue a hint or lint. Such type checks happened in practice in package:flutter_quill (fix: https://github.com/singerdmx/flutter-quill/pull/239/files).