-
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
Analyzer regression around diagnostics when imported files are not generated #42832
Comments
Can you point me at a document that specifies the required behavior? What I see implemented, and what I vaguely remember hearing when this feature was discussed, is that we ignore errors reported on identifiers that are either (1) imported with a prefix; (2) imported without a prefix but with an explicit The example provided in the first comment does not satisfy these conditions, so we report multiple errors. import 'doesNotExist.g.dart' show A;
void f(A a) {
A.b;
} or import 'doesNotExist.g.dart' as p;
void f(p.A a) {
p.A.b;
} In both cases we get We have a disjoined check for reporting a special error for a missing file when it looks like it might be generated. |
Unfortunately, no. I don't believe that we documented the desired behavior.
I don't remember those restrictions, but it's quite possible that we decided to do that in order to reduce the number of false negatives. If that's the case, there is no regression. But I think we should consider broadening the support because using |
OK, then this is not a bug, but an enhancement. Without additional information we cannot distinguish an identifier that should come from an imported library, and identifier that should come from a part. But I can imagine that there might be a correspondence between a generated part name, and the pattern of names of generated entities in the part. Do you have examples of such parts and generated identifiers? |
Related: #42977 (see note at the bottom of the issue)
I have some examples here for over_react, if they're worth considering 🙂:
(There are other examples under example/builder/src) as well. (Note that in this repo the generated files use a build-to-source builder and are checked in, but all consumer repos use build-to-cache.) To summarize:
|
Hey @greglittlefield-wf - to follow up on your last comment (and, cc'ing in @robbecker-wf): We're looking at expanding the file name patterns for what we consider probably generated code, and, how we then identify the following undefined symbols in that file, to know which missing symbol errors to ignore. We currently support two patterns for this - For the imports of the form One possible solution to this would be to use One follow-on concern we have here is that this could unintentionally catch user code which is not using codegen. |
If you allowed user to specify the form of generated symbols, would that help with the concern for false negatives. |
Yes, that would help. It would be better if users didn't need to repeat that pattern in every library with a generated part, so we could consider adding a list of |
@devoncarew Yes, I believe that would work for our use-case! We currently have a subset of boilerplate that references generated |
If it only applies when there's a missing generated file then it will still cause errors while people are editing a file that uses a code generator. |
Do you mean: in the case where the file was generated but the generated file is not out of date? |
Is not up to date, yes. |
How important is it to support that use case (not reporting diagnostics when a generated file is out of date)? |
Hard to say. It depends a lot on how much the code generator is doing. If, as soon as you touch anything in the file, it fills up with false errors, that seems bad - makes analysis useless for that file. But I think a lot of generators try to minimize how much of the original file is affected. Is it difficult to detect when the generated file is older than the current file and treat that the same as if it was missing? |
If the content was this unstable I would expect that the The only new errors that should surface here would be, I think, the same places you'd need to add a new |
No, but that means that any change to the current file, such as adding a space, would block analysis support until the generated file is regenerated. I don't think that's a good UX either. |
At least for the over_react use-case, the majority of the time, the code that references generated members isn't often edited after it's introduced. Usually, it's one UI component per file of the same name. For example, this isn't very common: part 'foo.over_react.g.dart';
-UiFactory<FooProps> Foo = _$Foo;
+UiFactory<BarProps> Bar = _$Bar; ...and in those cases the solution from that CL would work well. However, there's a newer case that isn't very common yet, but I suspect could become more common, where you have multiple, smaller UI components per file. This means new code can be added to existing files that references new generated members. For example: part 'foo.over_react.g.dart';
UiFactory<FooProps> Foo = _$Foo;
...
+UiFactory<BarProps> Bar = _$Bar; ...and that would be an issue, both when users are adding that new code themselves, or when switching to branches that contain added code. As a middle ground between only ignoring errors when the generated files are missing vs. only erroring when the source file hasn't been modified, could we update the error messages for undefined members that match that Since the situation is less common, my main concern would be more around users being confused about how to resolve the issue, as opposed to being around them having to rerun a build to resolve it. For example, instead of just saying
...it also said something like:
|
@scheglov @bwilkerson I tried out that CL locally and it works great except for one thing: I'm seeing that errors related to disabled implicit casts aren't ignored. For example: part 'foo.g.dart';
class Foo {}
methodCall(Foo foo) {}
// error: A value of type 'dynamic' can't be assigned to a variable of type 'Foo'. (invalid_assignment)
Foo foo = _$foo;
// error: The argument type 'dynamic' can't be assigned to the parameter type 'Foo'. (argument_type_not_assignable)
var result = methodCall(_$foo); Are there plans to silence |
Well, that's a complication. |
Change-Id: I5a103cd362318b4db292b5f41da9e56a60f6431d Bug: #42832 Bug: #42977 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166820 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
At one point we had an "undefined" type that was distinct from |
So, I assume re-implementing a distinction between the two cases is out of the question? That aside, just to make sure I have a correct understanding of what the path forward for us currently looks like... We'd be going from what we have now: UiFactory<FooProps> Foo = _$Foo; // ignore: undefined_identifier, invalid_assignment ...to utilizing the latest implementation added in that commit and either: // A: Adding an implicit cast.
UiFactory<FooProps> Foo = _$Foo as UiFactory<FooProps>;
// B: Adding an implicit cast and removing the LHS typing to avoid
// having to repeat the type.
final Foo = _$Foo as UiFactory<FooProps>;
// C: Using a helper method that performs a cast without having to repeat the type.
T cast<T>(dynamic value) => value as T;
UiFactory<FooProps> Foo = cast(_$Foo); old incorrect option B for posterity// B: Adding an implicit cast and removing the LHS typing to avoid
// having to repeating the type.
// But, this would conflict with the type_annotate_public_apis Effective Dart lint,
// so we probably wouldn't pick it.
var Foo = _$Foo as UiFactory<FooProps>; (It might be worth noting that having the cast isn't ideal because it prevents static type-checking from occurring once the generated field is present.) While having to perform that explicit cast isn't ideal, if we can eventually replace them with external variables like what was proposed in this comment #42977 (comment), then having to live with this until then seems acceptable. And sorry for bringing up the |
Are you sure about *B:* ?
For top-level final fields, I believe this is fixed!
…On Thu, Oct 15, 2020 at 4:39 PM Greg Littlefield ***@***.***> wrote:
So, I assume re-implementing a distinction between the two cases is out of
the question?
That aside, just to make sure I have a correct understanding of what the
path forward for us currently looks like...
We'd be going from what we have now:
UiFactory<FooProps> Foo = _$Foo; // ignore: undefined_identifier, invalid_assignment
...to utilizing the latest implementation added in that commit and either:
// A: Adding an implicit cast.
UiFactory<FooProps> Foo = _$Foo as UiFactory<FooProps>;
// B: Adding an implicit cast and removing the LHS typing to avoid
// having to repeating the type.
// But, this would conflict with the type_annotate_public_apis Effective Dart lint,
// so we probably wouldn't pick it.
var Foo = _$Foo as UiFactory<FooProps>;
// C: Using a helper method that performs a cast without having to repeat the type.
T cast<T>(dynamic value) => value as T;
UiFactory<FooProps> Foo = cast(_$Foo);
(It might be worth noting that having the cast isn't ideal because it
prevents static type-checking from occurring once the generated field is
present.)
While having to perform that explicit cast isn't ideal, if we can
eventually replace them with external variables like what was proposed in
this comment #42977 (comment)
<#42977 (comment)>,
then having to live with this until then seems acceptable.
And sorry for bringing up the invalid_assignment issue last-minute! We
haven't turned off implicit casts in most of our repos, so it wasn't top of
mind 😓 .
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#42832 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAEFCW2RBN6CIKN7DRE5P3SK6B4ZANCNFSM4PHCHT6A>
.
|
Oh you're right: making it final gets rid of the type_annotate_public_apis lint! Nice!! I'll update that example -var Foo = _$Foo as UiFactory<FooProps>;
+final Foo = _$Foo as UiFactory<FooProps>; |
The analyzer used to notice when an
import
,export
orpart
directive referenced a generate file that does not exist and silenced follow-on diagnostics. That behavior appears to have been broken. For example, a file containing the following:Now produces 3 diagnostics when it ought to produce a single "generated file does not exist" diagnostic.
This has serious implications for internal users.
The text was updated successfully, but these errors were encountered: