dart-lang / dart-lang/language

Proposal: add a context for RHS of equality operations.

Open
#3,653 1 comment 1 reaction 0 assignees View on GitHub
feature
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.