Open lrhn opened 2 years ago
@lrhn : didn't this issue rather intend to be filed on https://github.com/dart-lang/linter ?
I don't have an objection to this being implemented as a lint, but it might make more sense for it to be implemented as a language option, along the same lines as strict-casts
, strict-inference
, and strict-raw-types
, possibly called strict-void
.
@leafpetersen @srawlins
I'm not sure what a "language option" really is. Couldn't it just be a named set of lints? I don't see any need for more categories of user-enabled/configured source analyses.
@a14n Absolutely should be in linter repo. My bad. (So that's why I couldn't find it!)
I'm not sure what a "language option" really is.
As I understand it, the notion of a language option was originally designed to be a way for users to further tighten the semantics of the language. It was motivated by a desire to clean up the strong_mode
option that we had before we had introduced the notion of experiments.
In the analysis options file it looks something like the following:
analyzer:
language:
strict-casts: true
Couldn't it just be a named set of lints?
Yes, I believe that we could replace each of the current language options with a warning that is disabled by default. Whether there's a compelling reason to support a different way of enabling these warnings, especially in light of the proposed simplification of errors and warnings, is definitely something we should consider. I hadn't really thought about that question, I was merely pointing out that this is very similar to what we now call language options.
Is this issue a duplicate (or a further development) of #1830?
I think this goes too far and throws out some good things with the bad. Chaining explicit-void-to-explicit-void is a nice language feature.
Writing methods that delegate with =>
without worrying about the 'type' is a nice affordance, allowing the delegating pattern be shorter and have visual uniformity between void and non-void methods. It is make-work, i.e. an impediment to coding velocity, to have to flip between a method definition that has an expression body vs a full body, and having to avoid =>
is especially ugly in closures used as arguments.
The current rules allow annotations of expression-statements by annotating a variable.
@pragma('dart2js:disable-inlining')
void _ = print('hello');
If the above becomes illegal then we will need another way of annotating an expression-statement. (The pattern is not yet in common usage but dart2js is heading towards finely scoped annotations to restrict the scope of non-spec behaviour (https://github.com/dart-lang/sdk/issues/49475). As the different annotations become more finely scoped, using this pattern would become the recommended practice.)
A
void
expression should be treated as not having a value. The language is permissive for backwards compatibility reasons, and allow you to assignvoid
tovoid
anddynamic
, and assignvoid
,dynamic
andnull
tovoid
.I'd like to restrict doing so as much as possible. With a
strict_void
lint (or possible multiple separate lints, if that makes more sense), it would be an error to:void?
. (You can't directly, but can through a type alias expansion. It's an error if type alias expansion yieldsvoid?
as a part of the type.)void
. Noe as void
(which isn't allowed grammatically, but again check after type alias expansion).void
. Noe is void
(after alias expansion).return e;
in a function body in, or use=> e;
as a function body, of a function declaration with declared return typevoid
. (Only static types count, notT foo<T>() => e
which might get a type argument ofvoid
.)async
function with static future-return-typevoid
.return e;
or=> e
in a non-async
function with declared return typeFutureOr<void>
unlesse
has a static type which is a subtype ofFuture<void>
(not allowingdynamic
because there is no implicit downcast toFuture<void>
).void
orvoid?
.void
orvoid?
. (Can happen for, say,foo<T>({T? bar}) => ...
withfoo<void>()
.)null
as argument (or operator operand) to a required parameter of typevoid
orvoid?
.FutureOr<void>
orFutureOr<void?>
which does not have a static type which is a subtype ofFuture<void>
.FutureOr<void>
orFutureOr<void?>
which does not have a static type which is a subtype ofFuture<void>
, or is the expressionnull
.void
in any place where it's value is used. That's probably anywhere but:for(*here*;...;...)
statement. (When it's not a declaration).for(...;...;*here*, *or here*, ...)
statement.Use an expression of type
FutureOr<void>
orFutureOr<void?>
as operand of anis
check oras
cast with a type which is not a subtype ofFuture<void>
.That is, not in a context with context type
void
. You neednull
there.Which might be summarized as:
void
as not having a value. Only use it in contexts where a value is immediately discarded. No casting, no assigning to dynamic, no checking its runtime type. There is no value. We currently allow casts and type checks to any type.null
. No casting to, implicitly by upcast to context type or explicitly byas
. Possibly already covered byvoid_checks
.void
, which should only and always usereturn;
or body fall-through to return. Also somewhat covered byvoid_checks
, but that allows=> x as dynamic;
or=> x as Void;
(withVoid
an alias forvoid
). No arrow body exception here.FutureOr<void>
is special. You may assign aFuture
to it (any future), and you may check whether it is aFuture
, but never look at the non-future part.