dart-lang / dart-lang/language
Where is `void` allowed in pattern matching?
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
We currently do not allow a `void`-typed expression to be used in a context where its value is used (only a context of type `void` or `dynamic`, and `dynamic` was only allowed to not have to rewrite legacy code).
We should consider whether `void` is allowed to flow into pattern matches.
We are already doing something on some platforms, but we should be consistent and deliberate about it.
I'd say "hard no", and disallow (aka. make compile-time error):
* Any `switch` expression with static type `void`.
* Any `if`-`case` matched value expression with static type `void`.
* Any pattern being type-checked with matched value type `void`, unless the pattern is `_` (or any other non-checking, non-binding pattern which also wouldn't need to look up the value of a list or map at all). _That's needed for `var (x, _, z) = o as (int, void, int);`._
The first two are really just expressions-in-position-where-value-is-used, and could be covered by current behavior.
The last one is new, because there is no *expression* the original program which has static type `void`. It only exists in the desugared version. Still, the is a *value* with static type `void` which is pushed into a pattern match, and that pattern match actually looks at the value (it binds it to a new variable, one not typed as `void`).
We an allow a pattern to bind a `void` value to another variable of type `void` or `dynamic`, but you *really shouldn't*.
I'd prefer to make the `void` protection stronger here, since it's new syntax that doesn't have to accommodate existing code.
* Also disallow using `void` as the type of a binding pattern, `void v`, to introduce a `void`-typed variable. Just use `_`, because you are not supposed to look at the value later anyway.
And
* Disallow `void` as the static type of an object pattern. (Also if doing so through a type alias, but `T(:var hashCode)` is OK, even if `T` ends up bound to `void` at runtime. This is just static checking.)
Even though the object pattern `void()` is technically not looking at the object, it's also not useful, and you should just use `_`.
Doing `void(:var runtimeType)` is just plain wrong, you're invoking members on a `void` typed value. So
(Now that we have `_`, we no longer need to allow you to assign `void` values to anything. Or at least, we won't when we allow `_` as a parameter name.)
Example code:
```dart
typedef OQ = Object?;
void main() {
void v;
switch (v) {
// Error: This expression has type 'void' and can't be used.
// switch (v) {
// ^
case OQ(:var hashCode): print(hashCode);
}
if (v case Object? o) print(o.hashCode);
// Error: This expression has type 'void' and can't be used.
// if (v case Object? o) print(o.hashCode);
// ^
if ((1, v) case (int _, Object? o)) { // No error
print(o.hashCode);
}
if (null case void v) { // Safe, but unnecessary
print(v as dynamic);
}
if (null case Void(:var hashCode)) { // Reads `.hashCode` of `void`
print(hashCode);
}
}
```
This was run in dartpad.dev on master branch.
Dart2js rejects two of the cases, but not the third.
The analyzer gives no warnings whatsoever. (Should probably be considered a bug.)
@dart-lang/language-team
Contributor guide
Research direction
Start by running the example from the issue on dartpad.dev with the master branch, then compare dart2js and analyzer diagnostics for each void pattern case. Read the existing language and pattern-matching rules before deciding how the behavior should be specified. Done means the listed void uses have deliberate, consistent compile-time behavior across the affected tools.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100