-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Unexpected unnecessary_cast reported when variable is reassigned later #48984
Comments
I guess the topic here is that the cast isn't actually unnecessary, because it's needed in order to guide the inference of the declared type of However, it could be claimed that the direct solution ( Using So perhaps it's not a problem that |
Perhaps my interpretation of "unnecessary" is not what was meant by the message. To me, it seemed to suggest "this cast can be removed and everything will work the same". Even if the warning is correct though, it feels odd to me that the code has a quick-fix (which removes the cast) that results in code with an error. After doing that, it's perhaps not very clear what the correct action is that avoids bringing back the warning. If the suggestion is to move the type to the left, it might be nice if the fix could do that instead of only removing the cast. Whether that's feasible (or even worthwhile), I'm not sure. |
@bwilkerson, what do you think? First, it looks like a false positive to me, too, when Could |
The We could certainly add a lint that would catch this case and recommend using the style of adding an explicit type annotation rather than using the cast to influence inference. I personally think that's a better style because it's more explicit and it avoids an unnecessary run-time check (assuming the compiler doesn't optimize the check away), but it's a question of stylistic preference so it should be opt-in. |
I've seen this come up more w.r.t. null safety code. I think perhaps because the migration tool sometimes adds casts. Anyway the only way I can see keeping this Hint "false positive"-free, is to stop reporting upcasts. See #49550, #49269, and #44411 for more examples. I think the general idea is that it would be great to report an upcast as unnecessary if that type does not result in a change to an inferred type or a promoted type (beyond the left side of the as-expression and beyond the type of the as-expression itself). This is complicated to know; we don't track provenance of types which bubble up from inference. I like @eernstg 's idea (which @bwilkerson also approved of, above) of a second rule, a lint, which would catch unnecessary upcasts in some declarations with initializers. We would still not catch all technically unnecessary casts, like class A {}
class B extends A {}
void f() {
var x = [B() as A];
x.add(B());
// There was no reason to cast.
} but I think that's a very pragmatic approach. I don't think we can catch all assignment expression cases: var x = [
if (foo)
...[
// Perhaps all of the other elements are `List<String>`, so this one cast changes the type
// of `x`. It would be great to track that this cast could be replaced by a type annotation
// on `x`, but difficult.
if (bar) a as Iterable<String>,
// ...
],
// ...
]; But the common seem to be: assigning a ConditionalExpression where one branch is an AsExpression, assigning an AsExpression, and assigning an if-null expression where one branch is an AsExpression. |
I requested said lint rule here: #58903 |
Would those cases be sufficient to cover the false positives, or are they merely representative? If they are sufficient, then perhaps the cases we allow should be limited to those. As I said elsewhere, my concern is that we could be too aggressive and stop reporting places where the cast is clearly not necessary in our attempt to eliminate all false positives. |
We already allow unnecessary casts in a conditional operation. See the test cases here: https://github.com/dart-lang/sdk/blob/main/pkg/analyzer/test/src/diagnostics/unnecessary_cast_test.dart#L22 Allowing unnecessary casts in conditional operations has not fixed this issue, #49269, #44411, or #49550. Removing the |
Would it be possible to go in the other direction, and have the quick fix put in the type information that would be inferred due to the cast? I don't know if we've had a wide discussion about it, but I do think that adding explicit types is preferred over nudging inference with casts. |
Yes, the fix can definitely add explicit types (in all the cases that I can think of). |
Apologies for the late reply. I don't think we can simply follow what inferred types are influenced by an as-cast. Consider the example above, slightly modified here: var /* COULD ADD Set<Iterable<String>> */ x = /* COULD ADD <Iterable<String>> */{
if (foo)
.../* COULD ADD <Iterable<String>> */[
// Perhaps all of the other elements are `List<String>`, so this one cast changes the type
// of `x`. It would be great to track that this cast could be replaced by a type annotation
// on `x`, but difficult.
if (bar) a as Iterable<String>,
// ...
},
// ...
]; It would be a complex mechanism, which would use heuristics to decide where to annotate, for little payoff. And it would be enforcing one style.
Whether or not we are, that is an opinion about style. For this static warning (not lint, not opt-in), we should not be requiring users to change their code from one style to another, to avoid a default-enabled static warning. I am fully in favor of re-implementing that behavior in the requested lint rule, #58903. @jamesderlin gives an example where using a full record type at variable declaration becomes "awkward, tedious, and potentially error-prone," with: (int, num, int) record = (1, 2, 3); (obviously, imagine types with more than 3 letters, and records with more than 3 fields.) |
This code reports
unnecessary_cast
on casting aList
toIterable
, but without it you can't re-assign the variable if you want to append some filters.Writing
Iterable<Strings> strings = <String>[];
to avoid writing the cast works fine.The text was updated successfully, but these errors were encountered: