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
Analyzer is satisfied as soon as one sub-expression of a ternary-if yields the right type #22750
Comments
Thanks. Added Area-Analyzer, Triaged labels. |
While I agree that this is confusing, I believe that it is the behavior required by the Dart Language Specification. You should get a warning if the static type of the initialization expression is not assignment compatible with the declared type. The static type of a ternary expression is the least upper bound of the types of the second (then) and third (else) operands. The least upper bound of 'int' and 'double' is 'num'. But in Dart, one type T1 is assignable to another T2 if either T1 is a subtype of T2 or if T2 is a subtype of T1. That means that 'num' is assignable to both 'int' and 'double'. The reason you get the warning you expect in the first case (rd1) is because the type of the expression is 'int' and 'int' is not assignable to 'double'. The inverse is true for the second case (d) because the type of the expression is 'double' and 'double' is not assignable to 'int'. cc @gbracha. |
This comment was originally written by googlegroups...@kaioa.com The analyzer thinks this is okay: main(){ Checked mode disagrees (and so do I): Breaking on exception: object of type _TypeError: If an "if" is used instead: main(){ The analyzer will spot the mistake: A value of type 'double' cannot be assigned to a variable of type 'int' I really think the analyzer should flag something like "int b = a ? 1.2 : 3", because it's obviously wrong. When I ported some code yesterday, I had a handful of these mistakes. I had to "abuse" checked mode, because the analyzer failed to spot them. Also note that the types don't have to be compatible. If one matches, the other one is completely ignored. The analyzer also thinks that this one is okay: main(){ |
The reason it doesn't produce a warning is because the least upper bound of 'String' and 'int' is 'Object', and 'Object' is assignable to 'int'. The warnings that are specified are not intended to cover all possible runtime errors, they are intended to catch cases that can never be right. There is intentionally no warning in these cases because the code might be written in such a way that it could work without error. But, yes, that does mean that sometimes helpful warnings are not produced, such as in the cases you've given or even in the worse case of: f(bool b) { which can never be valid in checked mode (although it will execute fine in production mode). |
This comment was originally written by googlegroups...@kaioa.com How is this any different from if-else? If the wrong branch isn't executed it will also work "without error". Is there any use case where this behavior is desirable? If I put the type annotation there, I do apparently intend/assume that both sub-expressions return the specified type. Not flagging this means that you need two unit tests for each "?:". You need to execute both branches in checked mode to identify the problem. This isn't desirable nor reasonable. For what it's worth, TypeScript does this right: var a:boolean = true; The second line is flagged with: Type 'string | number' is not assignable to type 'number'. |
This issue was originally filed by googlegroups...@kaioa.com
Example #1:
double rd1(bool a) => a ? 1 : 0;
double rd2(bool a) => a ? 1.0 : 0;
double rd3(bool a) => a ? 0 : 0.0;
"rd1" is correctly flagged. "rd2" and "rd3", however, are not. In checked mode, it bombs when you hit the wrong branch.
Example #2:
var a = true;
int b = a ? 1.2 : 3;
int c = a ? 1 : 3.4;
int d = a ? 1.2 : 3.4;
Only the last line is flagged.
The analyzer should ensure that both sub-expressions of a ternary-if yield the specified type.
The text was updated successfully, but these errors were encountered: