-
Notifications
You must be signed in to change notification settings - Fork 213
Better inference of conditional expressions. #1877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Interesting! However, in that case we probably want to ensure that a non-informative context type (with notation There is also a circularity issue: If the type of the conditional expression will be used to select an implicitly induced declared type for a variable, or a function return type, etc., then it doesn't make sense to rely on that not-yet-inferred declared type during inference of the type of the conditional. bool b = true;
void main() {
var x = b ? 'true' : false; // Give `x` the type `Object` because that's the type of the conditional, because ...? ;-)
} When this comes up I usually recommend that we compute the LUB as we do currently, but we start flagging that LUB (in conditional expressions, possibly in collection literals, maybe in a few other places) in the case where it produces Perhaps it should only be when the LUB produces This would probably make it an analyzer hint. |
Using the context type as static type should probably only be done when necessary. If we have a more precise upper bound, it may lose information to just use the context type. num x = (test ? 0 : -1)..toRadixString(16).log(); // <- `log` is extension method on string. If we promote the static type of So, proposal: When inferring the type of `e` of the form `e1 ? e2 : e3`, with context type `C`, proceed as follows:
* Infer the type of `e1` to `T1` with context type `bool`. It's a compile-time error if the static type of `e1` is not assignable to `bool.`
* Infer the type of `e2` to `T2` with context type `C`.
* Infer the type of `e3` to `T2` with context type `C`.
* Let `S` be **UP**(`T1`, `T2`).
* If `C` is `_`, the static type of `e` is `S`.
* Otherwise, if `S` \< `C` (least /greatest closure of?), the static type of `e` is `S`
* Otherwise, if `T2` is assignable to (the ... closure of?) `C` and `T3` is assignable to (ditto) `C`, the static type of `e` is `C`.
* Otherwise the static type of `e` is `S`. |
Closing: The original example here is accepted today by
|
To be precise: We still use LUB even if there is a context type. We just discard the LUB result and use the context type, if the LUB result doesn't satisfy the context type requirement. The result can be better then the context type (for some definition of "better"), but not worse in a way that won't compile, which was the real surprise. The difference matters for something (very hypothetical) like |
Currently:
fails to compile because the static type of
someTest ? B() : C()
isObject
. It'sObject
because the LUB computation of the language spec is not particularly clever. That is what it is, but here it feels particularly disingenuous when we have an available context type which is also a valid upper bound (A<Object?>
in this case).So, could we say that the static type of
e1 ? e2 : e3
with context typeC
isC
ifC
is a supertype of the static types ofe2
ande3
, and only use LUB if there is no context type, or if the context type is not a supertype of the types ofe2
ande3
(and then we'll likely have other issues too eventually).See this StackOverflow question for context.
The text was updated successfully, but these errors were encountered: