-
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
[Extension type] linter support #58838
Comments
avoid_logic_in_view_classes |
@IvanDembicki Could you provide more information about what the proposed lint would actually do (either here or in a separate issue, the latter being my personal preference). |
@eernstg: in the spec you write:
Could you provide a bit of detail on the lints you had imagined? |
Perhaps one lint ( |
Proposed elsewhere:
Could someone (with more context) provide some context/examples? |
@pq wrote:
Sure! Ideally, they would flag any construct that performs a dynamic type test on an expression We need to consider types where extension types occur as subterms as well. For instance, if So let's spell out this concept in more detail: We say that a type We say that the transition from a source type
Note that an upcast never introduces an extension type, even in cases like the transition from With that, we can list cases that are candidates to be linted:
Finally, the lint message should be omitted in the case where the extension type which was introduced has a direct or indirect superinterface which is a non-extension type. For example, You could say that [Edit Oct 1 2023: The example about going from |
@scheglov, do you think it would be appropriate for the analyzer to have a variant of isSubTypeOf which would return true if called with Perhaps it could be implemented by giving This task is non-trivial, but it seems to be very similar to the computation of the subtype relationship, which means that it would be a very helpful method to have for the implementation of the "don't skip the constructor" lint which is outlined here. |
Regarding enforcing (CamelCase) naming, I'd love not to add another lint but would love to get people's 2 cents. How do folks feel about extending /cc @munificent @natebosch @eernstg @lrhn @bwilkerson @srawlins @jakemac53 |
I see no reason to not add it to an existing lint, at least if the lint is updated before extension types land in stable. It seems it (and |
Thanks @parlough! I agree we may have been too conservative w/ |
Now, if you had to choose which lint to extend? |
Unless that potential added context changes something, I would say |
An extension type defined a type; an extension does not. I don't remember why we created |
Regarding the possible constness of the primary constructor (spec), I wonder if That is: BAD extension type E(int i) { } GOOD extension type const E(int i) { } (See also the conversation about immutability and extension types as it pertains to linting in #59275 and #59276.) |
As mentioned above, a primary constructor of an extension type can always be constant, because it has no initializer list, and the extension type has no non-final instance variables. However, this nudge may be considered spammy if the advice is given for every extension type declaration, especially in cases where the static type of the parameter does not have any constant constructors (we generally can't know: except for a So it's probably good to have the lint (and have it flag all extension type constructors which can be constant, not just the primary one), but it is probably also useful to make sure that it is a separate lint for extension types, not an extension of the applicability of the corresponding lint for classes. |
A few more lint rules that need changes:
|
Fantastic. Thanks @srawlins! |
A few more lint rules that need changes:
|
These are really interesting edge cases. It has taken me a minute to wrap my head around them. The
Turns out this one is already fragile with respect to regular Dart classes. Probably a P3 bug to make it less fragile in general. class DummyFile implements File {
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
void main() async {
DummyFile file = DummyFile();
await file.exists(); does not trigger the lint but File file = DummyFile();
await file.exists(); So the existing behavior sometimes triggers on subclasses of File but sometimes doesn't.
This lint has an existing similar issue for implementing classes. Arguably the lint should still fire for this case of a class implementing HeadingElement but it doesn't. import 'dart:html';
class ET implements HeadingElement {
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
void f(ET heading) {
heading.setInnerHtml('<script>');
} |
A few more lint rules that need changes:
|
This is interesting. The
which could also be catching The question about If we want to go that direction, I'd want to understand better when we should use the runtime type rather than the static type so that we can be more consistent about where that technique is applied. |
Here is one way to think about the representation type of an extension type that might be useful when deciding on things like "should Check whether the associated semantics includes a dynamic type test or an upcast to a top type or The point is that if the semantics of a construct discards the extension type then there is no way we can restore it (there is no evidence whatsoever for the extension type at run time). In that case it makes sense to treat the expression as if it had had the representation type as its static type (and it should be the recursively erased type that we sometimes call the 'ultimate' representation type). We're trying to take certain scenarios into account, and they may depend on the run-time type, and the ultimate representation type is our best compile-time approximation of that run-time type, but the scenarios certainly won't depend on the extension type. For example, evaluation of Now what if we have the property mentioned above (i.e., the extension type is unavoidably discarded), but the most useful choice is to allow an extension type to hide the underlying representation type? For example, what if we're creating Perhaps we can come up with a scenario like this, but I tend to think that we should ignore it (and just rely on the representation type when the extension type is guaranteed to be forgotten anyway). An interesting case is It is actually a compile-time error if we encounter So there's no need to decide on what to do in the lint if this situation arises. If On the other hand, Again, the point is that we'd want to detect situations where an unexpected run-time error occurs because a future was left unawaited (and nobody was around to receive an exception), plus situations where a program has execution ordering bugs because some operations aren't awaiting the completion of other operations. In both cases, the undesirable outcome depends on the given object being a future, not on its static type. Again, we could come up with a scenario where we want to use the extension type to hide that a certain future is a future (because we know that all these futures do not need to be awaited). However, in that case it's probably possible to avoid returning that future in the first place, or it could have the type Otherwise, I think an extension type should probably always be preserved with respect to lints and similar checks. This supports the ability of extension types to arrange for a different treatment of the underlying object than that which is given to the representation type, and that's the main point of having extension types in the first place. |
Thanks, that's helpful. I mentioned this elsewhere, but just to capture it somewhere more permanent: In order to reduce user confusion, I think it's important that we document whenever a lint will use the representation type rather than the extension type. |
unreachable_from_main needs some changes to support extension types:
|
The description of |
Good catch. I think we didn't implement for instance members to avoid complexity with inheritance. I agree with your assessment and suggestion. |
Work towards https://github.com/dart-lang/linter/issues/3625 Change-Id: I41a28795f16eb19b41f864ef512cf10936c2e11f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327713 Commit-Queue: Samuel Rawlins <srawlins@google.com> Auto-Submit: Samuel Rawlins <srawlins@google.com> Reviewed-by: Phil Quitslund <pquitslund@google.com>
@pq Should I add checklist items to the tippy top of this issue for the rules that I think need updating, which I commented on above? |
Thanks for bumping this, Sam. I've been meaning to! Please add items. My sense is that a bunch of the ones above are WAI as of my last conversations with @bwilkerson where I thought there was a general consensus that we did not want to lint based on runtime/representation type but I do see a few that don't fit that pattern. Thanks! |
OK, they're added. Some need work and some can probably just be checked because we decided above that I was wrong in the repro case I had written down. |
Ok, cool. Thanks, Sam! |
A meta-issue to discuss and track work on linter support for extension types.
Feature Spec
Existing Lints
Some existing lints will need tests (minimally) and possibly enhanced implementations.
annotate_overrides
support for extension types #59263avoid_catching_errors
, see [Extension type] linter support #58838avoid_setters_without_getters
support for extension types #59264avoid_shadowing_type_parameters
support for extension types #59253avoid_slow_async_io
, see [Extension type] linter support #58838avoid_types_as_parameter_types
, see [Extension type] linter support #58838avoid_type_to_string
support for extension types #59326avoid_types_as_parameter_names
support for extension types #59294await_only_futures
support for extension types #59252cancel_subscriptions
, see [Extension type] linter support #58838camel_case_types
support for extension types #59272collection_methods_unrelated_type
, see [Extension type] linter support #58838close_sinks
, see [Extension type] linter support #58838deprecated_member_use_from_same_package
support for extension types #59271diagnostic_describe_all_properties
support for extension typesdiscarded_futures
, see [Extension type] linter support #58838hash_and_equals
support for extension types #59247library_private_types_in_public_api
support for extension types #59242non_constant_identifier_names
support for extension types #59254only_throw_errors
, see [Extension type] linter support #58838overridden_fields
support for extension typespackage_api_docs
support for extension typesprefer_asserts_in_initializer_lists
support for extension types #59324prefer_const_constructors
support for extension types #59274prefer_const_constructors_in_immutables
support for extension types #59275prefer_const_declarations
support for extension typesprefer_const_literals_to_create_immutables
support for extension types #59276prefer_constructors_over_static_methods
support for extension types #59250prefer_final_fields
support for extension types #59243prefer_void_to_null
false positive for extension types #59308public_member_api_docs
support for extension types #59239sort_constructors_first
support for extension types #59245sort_unnamed_constructors_first
support for extension types #59246type_annotate_public_apis
support for extension types #59270unnecessary_constructor_name
support for extension types #59249unnecessary_getters_setters
support for extension types #59266unnecessary_overrides
support for extension typesunnecessary_this
support for extension types #59248unreachable_from_main
, see [Extension type] linter support #58838unrelated_type_equality_checks
, see [Extension type] linter support #58838unsafe_html
, see [Extension type] linter support #58838use_key_in_widget_constructors
support for extension typesuse_late_for_private_fields_and_variables
support for extension types #59251🚧 Incomplete list: feedback welcome! 🚧
New Lints
Users of extension types might benefit from some new lints.
annotate_redeclares
#59297See also: #53121
...
The text was updated successfully, but these errors were encountered: