dart-lang / dart-lang/language

Allow any assignable expression in assignment patterns

Open
#2,855 0 comments 1 reaction 0 assignees View on GitHub
feature patterns
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

A pattern assignment, like `(a, b) = (b, a);`, allows destructuring and assigning to existing variables.

It does not allow refutable patterns, and it does not allow variable patterns, so all that's left is (irrefutable) destructuring, type assertions (`!` and `as T` which count as irrefutable), and-patterns and assigning to existing variables.

Since you can only assign to existing variables (or *identifiers*, really), it's not possible to do things like:
```dart
extension on List {
void swap(int i, int j) {
(list[i], list[j]) = (list[j], list[i]);
}
}
```
or even
```dart
(prefix.x, y) = values;
```

_We should consider whether it's possible to allow more (all) assignable expressions as leaves of a destructuring assignment, not just plain identifiers._

Assignable expressions have the forms:
```ebnf
identifier
primary selector* '.' identifier -- includes qualified identifiers
primary selector* '[' expression ']'
primary selector* ' ?.' identifier
primary selector* '?[' expression ']'
```
_(Did I miss any?)_

Parsing those in a position where a destructuring pattern is also allowed, may cause some initial conflicts, but it should be unambiguously parsable with sufficient look-ahead.

The allowed composite patterns are:
```ebnf
pattern && pattern -- and pattern.
pattern '!' -- null assertion pattern
pattern 'as' type -- type assertion pattern
typeArgs? '[' pattern*{,} ']' -- list destructuring pattern
typeArgs? '{' (key ':' pattern) *{,} '}' -- map destructuring pattern
'(' ((identifier ':')? pattern)*{,} ')' -- record destructuring pattern
(identifier|qualifiedIdentifier) typeArgs? '(' (identifier ':' pattern)*{,} ')' -- object destructuring pattern
```
_(Did I miss anything allowed in destructuring assignments?)_

The destructuring patterns all end in either `)`, `]` or `}`, and of those only `]` can also end an assignable expression, but they must be preceded by different things - `primary selector*` for the assignable expression and *not* an expression for the list pattern. (That's how we usually distinguish list literals from index operators.)

The assertion patterns also end in something not allowed to end an assignable pattern, so if a sub-pattern ends in one of those, it's a composite pattern, not part of the assignable expression leaf pattern.

The and-pattern cannot be contained inside at top-level of an assignable expression, the `primary selector*` does not allow binary operators.

All in all, I don't think there is any ambiguity in:
```ebnf
assignableExpression ::=
identifier
| primary selector* '.' identifier -- includes qualified identifiers
| primary selector* '[' expression ']'
| primary selector* ' ?.' identifier
| primary selector* '?[' expression ']'

assignmentPattern ::=
'_' -- non-binding pattern allowed.
| assignableExpression
| destructuringAssignable
| assignmentPattern && assignmentPattern
| assignmentPattern '!'
| assignmentPattern 'as' type

destructuringAssignable ::=
typeArgs? '[' assignmentPattern *{,} ']'
| typeArgs? '{' (constantExpression ':' assignmentPattern ) *{,} '}'
| '(' ((identifier ':')? assignmentPattern )*{,} ')'
| (identifier|qualifiedIdentifier) typeArgs? '(' (identifier ':' assignmentPattern )*{,} ')'

assignment ::=
assignableExpression '=' expression
| destructuringAssignable '=' expression
```

(Which might mean that we can just change `assignableExpression` to include `destructuringAssignable`.)

I think it can work. I think it might be worth allowing. (Caveat for unforeseen complications.)

Contributor guide

Open the contributing guide

Research direction

Start with the assignableExpression, assignmentPattern, and assignment grammar in the issue, then locate their corresponding language-specification entry points; no implementation files or tests are named. Done means the proposed assignable-expression leaves and destructuring forms are accepted without ambiguity, including the listed list-index and property-assignment examples.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.