Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow autoderef and autoref in operators #2147

Closed
wants to merge 12 commits into from
14 changes: 6 additions & 8 deletions text/0000-eye-of-sauron.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,35 +74,33 @@ Like methods, operators and indexing support automatic referencing and dereferen

Operator type-checking behaves similarly to method type-checking. It works as follows:

## S1. Subexpression checking
## Step 1 - Subexpression checking

Both the LHS and the RHS (if binary) of the operator are first type-checked with no expected type.

This differs from rustc 1.20, in which an expected type was sometimes propagated from the LHS into the RHS, potentially triggering coercions within the RHS. I should probably come up with an example in which this matters.
Copy link
Contributor

@oli-obk oli-obk Sep 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one's probably a crazy example, but the RHS is definitely dependent on the LHS and the case is rather horrible:

    let byte = 0u8;
    let word = 1u16;

    let x = word + &byte.into();
    println!("{}", x);

This needs the & for $reasons

Found in rust-lang/rust-clippy#2042

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one's probably a crazy example, but the RHS is definitely dependent on the LHS and the case is rather degenerate:

That's a trait-system issue. Operator overloading does succeed in this case. Without the autoref, you get these trait bounds:

u16: Add<$0>
u8: Into<$0>

Because the compiler only considers each trait bound alone, it can't see that the only solution is $0 = u16.

If you add a reference, instead yoou get

u16: Add<&'a $0>
u8: Into<$0>

And on the first bound, only the impl Add<&u16> for u16 impl matches, which allows a solution.

Copy link

@leoyvens leoyvens Sep 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also won't coerce: &1 + &mut 1. As soon as you have two different implementations for the RHS it stops working. That coercion only fires in such rare situations that I wonder if it's existence is by design or an accident of implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In any case it's orthogonal to this RFC.


## S2. Adjustment selection
## Step 2 - Adjustment selection

Afterwards, an adjustment list is selected for both operands as follows:

Adjustment lists for the LHS of an indexing operation are selected from these matching the following regular expression:
Adjustment lists for the LHS of an indexing operator (the `X` in `X[Y]`) are selected from these matching the following regular expression:
```
"Deref"* "Autoref(Immutable)" "ConvertArrayToSlice"?
```

Adjustment lists for all other operands (including the RHS of indexing operations) are selected from these matching the following regular expression
Adjustment lists for all other operands (including the RHS of indexing operator, as well as all operands of all other operators) are selected from these matching the following regular expression
```
"Deref"* ( "Autoref(Immutable)" "ConvertArrayToSlice"? )?
```

The adjustment lists selected are the lexicographically first pair of adjustment lists `(lhs_adjust, rhs_adjust)` (or with an unary op, just the `lhs_adjust`) such that
A1. Both adjustment lists match the relevant regular expressions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw this list does not render well in markdown. Perhaps add some bullets?

A2. Both adjustment lists must be valid to apply to their operand types.
A2. Both adjustment lists must be valid to apply to their operand types. If, due to the presence of inference variables, it can't be determined whether these adjustment lists would be valid to apply, and we didn't find a smaller adjustment list that would apply, that is a compilation error (this is the "can't autoderef because of inference variables" case).
A3. After applying both adjustment lists, the adjusted operand types are a potential match for the operator trait (if there is an ambiguity because of inference variables, it is counted as a match).
A3.1. NOTE: the operator trait for overloaded indexing is `Index`, not `IndexMut`, even if indexing is done in a mutable context. rustc 1.20 is inconsistent in that regard.

If the smallest adjustment can't be determined because of the presence of inference variables (because it is not obvious whether an adjustment list would be valid to apply), this is a compilation error.

## S3. Fixups
## Step 3 - Fixups

After adjustments are selected, the following fixups are made. They do not affect adjustment selection.

Expand Down