-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Unpredictable missing strong mode errors when analyzing across files. #26265
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
I suspect that this is related to strong mode instantiating to the bounds of the generic, rather than to dynamic. That is, in standard dart, the When I reproduce this in Intellij, what I see is that the initial analysis does not report the expected error, but if I edit the body of the |
Originally reproduced in 1.16.0-dev.4.0 , but reproduces in 1.16.0-dev.5.0 . |
When Actually we don't even need to have multiple files. main() {
Local a;
List l = [];
a.listOfS.addAll(l); // should be warning
}
class S<T> {}
class Local<T extends S> {
List<T> get listOfS => null;
} Or, in general case, types depend on the order of their declarations. class A {}
class B<T extends A> {}
class C<T extends B> {}
class R<T extends C> {
List<T> get listOfS => null;
}
main() {
R a;
List l = [];
a.listOfS.addAll(l); // should be warning
} Gives But if we move class A {}
class C<T extends B> {}
class R<T extends C> {
List<T> get listOfS => null;
}
main() {
R a;
List l = [];
a.listOfS.addAll(l); // should be warning
}
class B<T extends A> {} Gives @bwilkerson |
Yep. I discovered that yesterday while looking at #26310, which has the same underlying cause. It (only) happens in strong mode because we're using the bounds for inference. I was thinking that you were right, that it will be somewhat expensive to fix because it would means that we would have to resolve the type bounds in dependency order. But then I thought of an interesting case that might make even that insufficient. Consider the following:
What is the inferred type for
If we infer the bounds of But assuming that we define reasonable behavior for this case, we might be able to simplify the implementation by delaying the inference of type arguments until after all the bounds (for every imported unit and the transitive closure of their exports) have been computed. |
Oh, that's a fun one! I think it would possible to make it an error and detect it - it would look something like typedef cycle detection. So when you get to An alternative would be to say that in bounds, Yet another alternative would be to forbid implicit instantiation in bounds for things with a non-default bound. I'd suggest filing a separate bug for the language issue, and in the meantime seeing if there's something pragmatic we can do to fix the immediate issue. For example, if it would be possible to implement a version which does the right thing for top level uses, and instantiates all uses in bounds to dynamic, then this would at least put us in a stable position. If doing this is pretty straightforward, I'd suggest doing this for now. If doing even this much requires substantial changes that might have to be backed out if we do something else, then perhaps we should discuss more first. |
@scheglov @bwilkerson Can one of you take this and get it to a state that at least unblocks @ochafik ? I suspect that as long as we get top level uses correct, corner cases like uses of implicitly instantiated parameterized types as upper bounds can be left open for now. Let's be sure and keep a tracking bug open for any missing functionality though. |
I'm working on it. |
Per offline discussion, we are going to look into fixing this for occurrences outside of bounds now, while making uses inside of bounds be errors. We will look into how to handle the case for things inside of bounds later. class C<T extends num> {...}
// the bound in the extends clause here will be treated as C<dynamic>, and hence
// the bound will be treated as erroneous.
class D<T extends C> {
}
void main() {
C c; // this will be reliably interpreted as C<num>
} @ochafik If you need to make progress in the meantime, you can explicitly instantiate instead of relying on strong mode to fill it in: // strong and regular mode
Rectangle<num>
// strong mode only
Rectangle<dynamic /*=num*/>
// I think this syntax works as well for strong mode only?
Rectangle/*<num>*/ |
…o their bounds. [email protected], [email protected] BUG= #26265 Review URL: https://codereview.chromium.org/1927323002 .
@scheglov is this resolved? Can I close this? |
The problem in analysis is resolved. |
With the following three files:
// tobounds_a.dart
//tobounds.dart
//tobounds_client.dart
Analyzing tobounds.dart directly in strong mode yields three of the four expected errors:
Analyzing tobounds_client.dart in strong mode yields all four of the expected errors:
Removing the unused import in tobounds_client.dart causes the fourth expected error not to be reported again.
The text was updated successfully, but these errors were encountered: