diff --git a/src/expressions/method-call-expr.md b/src/expressions/method-call-expr.md index 9535cd207..8f71bccfc 100644 --- a/src/expressions/method-call-expr.md +++ b/src/expressions/method-call-expr.md @@ -17,13 +17,17 @@ When looking up a method call, the receiver may be automatically dereferenced or This requires a more complex lookup process than for other functions, since there may be a number of possible methods to call. The following procedure is used: -The first step is to build a list of candidate receiver types. +The first step is to build a list of types where we might find methods. Obtain these by repeatedly [dereferencing][dereference] the receiver expression's type, adding each type encountered to the list, then finally attempting an [unsized coercion] at the end, and adding the result type if that is successful. -Then, for each candidate `T`, add `&T` and `&mut T` to the list immediately after `T`. +Then, for each candidate `T`, add `&T` and `&mut T` to the list immediately after `T`. While dereferencing, we don't use the normal `Deref` trait, but instead the `Receiver` trait: there is a blanket implementation of `Receiver` for all `T: Deref` so in practice this is often the same. -For instance, if the receiver has type `Box<[i32;2]>`, then the candidate types will be `Box<[i32;2]>`, `&Box<[i32;2]>`, `&mut Box<[i32;2]>`, `[i32; 2]` (by dereferencing), `&[i32; 2]`, `&mut [i32; 2]`, `[i32]` (by unsized coercion), `&[i32]`, and finally `&mut [i32]`. +For instance, if the receiver has type `Box<[i32;2]>`, then the contributing types will be `Box<[i32;2]>`, `&Box<[i32;2]>`, `&mut Box<[i32;2]>`, `[i32; 2]` (by dereferencing), `&[i32; 2]`, `&mut [i32; 2]`, `[i32]` (by unsized coercion), `&[i32]`, and finally `&mut [i32]`. -Then, for each candidate type `T`, search for a [visible] method with a receiver of that type in the following places: +Some custom smart pointers may implement `Receiver` but not `Deref`. Imagine `MySmartPtr: Receiver`: if the receiver type has `Box>` the contributing types will be `Box>`, `MySmartPtr` and `SomeStruct`. + +Even though we assemble this list by following the chain of `Receiver` implementations, we keep a note of which steps can be reached by following the regular `Deref` chain. In the above example, that would be all but the last step. The items in the list reachable by the `Deref` chain are termed the "candidate types"; the full list reachable by the `Receiver` chain is called the "contributing types". + +Then, for each _contributing_ type `T`, search for a [visible] method with a receiver of any _candidate_ type in the following places: 1. `T`'s inherent methods (methods implemented directly on `T`). 1. Any of the methods provided by a [visible] trait implemented by `T`. @@ -66,6 +70,15 @@ Once a method is looked up, if it can't be called for one (or more) of those rea If a step is reached where there is more than one possible method, such as where generic methods or traits are considered the same, then it is a compiler error. These cases require a [disambiguating function call syntax] for method and function invocation. +As well as emitting methods for multiple candidates within a given step, +an additional search may be performed to look for specific cases where an outer +(smart pointer) type may have a method that shadows or overrides a method +on its referent. This process is performed if we are about to return a method +identified by a by-value step; a search is then performed for a matching by-reference +methods deeper along the chain of contributing types with an identical `self` type. +This extra search is also performed if we are about to return a method from +a `&T` pick; error are emitted if a `&mut T` method would be shadowed. + > **Edition differences**: Before the 2021 edition, during the search for visible methods, if the candidate receiver type is an [array type], methods provided by the standard library [`IntoIterator`] trait are ignored. > > The edition used for this purpose is determined by the token representing the method name. diff --git a/src/items/associated-items.md b/src/items/associated-items.md index ea95c1890..33f1126bf 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -110,15 +110,11 @@ well as the usual function call notation. r[items.associated.fn.method.self-ty] If the type of the `self` parameter is specified, it is limited to types resolving -to one generated by the following grammar (where `'lt` denotes some arbitrary -lifetime): +to a type implementing the [`Receiver`] trait with a `Target` associated type +matching the implementing type. Typically, this means the type itself, a +reference to it, or a smart pointer referring to it (such as [`Box`] +or `Arc`). -```text -P = &'lt S | &'lt mut S | Box | Rc | Arc | Pin

-S = Self | P -``` - -The `Self` terminal in this grammar denotes a type resolving to the implementing type. This can also include the contextual type alias `Self`, other type aliases, or associated type projections resolving to the implementing type. @@ -559,11 +555,11 @@ fn main() { [_OuterAttribute_]: ../attributes.md [_TypeAlias_]: type-aliases.md [_Visibility_]: ../visibility-and-privacy.md -[`Arc`]: ../special-types-and-traits.md#arct [`Box`]: ../special-types-and-traits.md#boxt [`Pin

`]: ../special-types-and-traits.md#pinp [`Rc`]: ../special-types-and-traits.md#rct [`Sized`]: ../special-types-and-traits.md#sized +[`Receiver`]: ../special-types-and-traits.md#receiver [traits]: traits.md [type aliases]: type-aliases.md [inherent implementations]: implementations.md#inherent-implementations diff --git a/src/items/traits.md b/src/items/traits.md index 00cdd885f..89fec7221 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -102,13 +102,13 @@ r[items.traits.dyn-compatible.associated-functions] * Dispatchable functions must: * Not have any type parameters (although lifetime parameters are allowed). * Be a [method] that does not use `Self` except in the type of the receiver. - * Have a receiver with one of the following types: + * Have a receiver implementing [`Receiver`], for example one of the following types: * `&Self` (i.e. `&self`) * `&mut Self` (i.e `&mut self`) * [`Box`] - * [`Rc`] - * [`Arc`] - * [`Pin

`] where `P` is one of the types above + * `Rc` + * `Arc` + * `Pin

` where `P` is one of the types above * Not have an opaque return type; that is, * Not be an `async fn` (which has a hidden `Future` type). * Not have a return position `impl Trait` type (`fn example(&self) -> impl Trait`). @@ -383,10 +383,8 @@ fn main() { [trait implementation]: implementations.md#trait-implementations [`Send`]: ../special-types-and-traits.md#send [`Sync`]: ../special-types-and-traits.md#sync -[`Arc`]: ../special-types-and-traits.md#arct [`Box`]: ../special-types-and-traits.md#boxt -[`Pin

`]: ../special-types-and-traits.md#pinp -[`Rc`]: ../special-types-and-traits.md#rct +[`Receiver`]: ../special-types-and-traits.md#receiver [`async`]: functions.md#async-functions [`const`]: functions.md#const-functions [type namespace]: ../names/namespaces.md diff --git a/src/special-types-and-traits.md b/src/special-types-and-traits.md index dc34dffae..9cb4294b3 100644 --- a/src/special-types-and-traits.md +++ b/src/special-types-and-traits.md @@ -17,34 +17,12 @@ r[lang-types.box.deref] * The [dereference operator] for `Box` produces a place which can be moved from. This means that the `*` operator and the destructor of `Box` are built-in to the language. - -r[lang-types.box.receiver] -* [Methods] can take `Box` as a receiver. - r[lang-types.box.fundamental] * A trait may be implemented for `Box` in the same crate as `T`, which the [orphan rules] prevent for other generic types. -r[lang-types.rc] -## `Rc` - -r[lang-types.rc.receiver] -[Methods] can take [`Rc`] as a receiver. - -r[lang-types.arc] -## `Arc` - -r[lang-types.arc.receiver] -[Methods] can take [`Arc`] as a receiver. - -r[lang-types.pin] -## `Pin

` - -r[lang-types.pin.receiver] -[Methods] can take [`Pin

`] as a receiver. - r[lang-types.unsafe-cell] ## `UnsafeCell` @@ -73,7 +51,19 @@ r[lang-types.deref] ## `Deref` and `DerefMut` As well as overloading the unary `*` operator, [`Deref`] and [`DerefMut`] are -also used in [method resolution] and [deref coercions]. +also used in [deref coercions]; see also [`Receiver`] below. + +r[lang-types.receiver] +## `Receiver` + +[`Receiver`] is used in [method resolution]. It indicates that a type may be +used as a method receiver; that is, the type of a `self` parameter for a +method. There is a blanket implementation of `Receiver` for all `T: Deref`, +so it's rare to implement `Receiver` directly: you'd only normally do this +for smart pointer types which for some reason can't implement `Deref`. +Built-in types which implement `Receiver` (via `Deref`) and are commonly +used as method receivers include `Rc`, `Arc`, `Box`, and `Pin

` +where `P: Deref`. r[lang-types.drop] ## `Drop` @@ -218,6 +208,7 @@ These implicit `Sized` bounds may be relaxed by using the special `?Sized` bound [`DerefMut`]: std::ops::DerefMut [`Pin

`]: std::pin::Pin [`Rc`]: std::rc::Rc +[`Receiver`]: std::ops::Receiver [`RefUnwindSafe`]: std::panic::RefUnwindSafe [`Termination`]: std::process::Termination [`UnwindSafe`]: std::panic::UnwindSafe