dart-lang / dart-lang/language
Proposal: add a context for RHS of equality operations.
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
The analyzer and front end currently use the following rules to perform type inference for equality expressions (expressions of the form `e1 op e2`, where `op` is either `==` or `!=`):
- First, `e1` is type inferred in context `_`, producing `m1` with static type `T1`.
- Let `K` be static type of the single argument accepted by `T1.operator==`.
- Then, `e2` is type inferred in context `_`, producing `m2` with static type `T2`.
- Define `m` as follows:
- If `T2 <: K?`, let `m` be `m1 op m2`.
- Otherwise, if a coercion `C` exists that coerces type `T2` to `T2'`, and `T2' <: K?`, then let `m` be `m1 op C(m2)`.
- Otherwise, it is a compile-time error.
- Then, the result of type inferring `e1 op e2` is `m`, with static type `bool`.
It seems odd to me that the type `K?` is used for coercions but not to supply a context when type inferring `e2`. This matters if a user decides to declare an `operator==` with a covariant argument type. For example:
```dart
class ComparableList {
final List _values;
ComparableList(this._values);
bool operator==(covariant ComparableList other) {
if (_values.length != other._values.length) return false;
for (var i = 0; i < _values.length; i++) {
if (_values[i] != other._values[i]) return false;
}
return true;
}
}
f(ComparableList doubles) => doubles == ComparableList([0]);
main() {}
```
This code is rejected by both the analyzer and front end, with the error message:
```
The argument type 'ComparableList' can't be assigned to the parameter type 'ComparableList?'.
```
However, if `C.operator==` is replaced with any other user definable operator, then the code is accepted:
```dart
class ComparableList {
final List _values;
ComparableList(this._values);
bool operator+(covariant ComparableList other) {
if (_values.length != other._values.length) return false;
for (var i = 0; i < _values.length; i++) {
if (_values[i] != other._values[i]) return false;
}
return true;
}
}
f(ComparableList doubles) => doubles + ComparableList([0]);
main() {}
```
This seems unnecessarily inconsistent. I think we should change the third bullet in the type inference rules to be:
- Then, `e2` is type inferred in context `K?`, producing `m2` with static type `T2`.
This would make type inference for `operator ==` more consistent with other operators.
Contributor guide
Research direction
Start with the equality-expression type-inference rules described in the issue and compare them with inference for other user-definable operators. The change is complete when the specification infers the RHS in context K? and the analyzer and front end consistently accept the demonstrated covariant equality example.
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
- 25/100