From cea25a86bd75f86a69a4e88fa895ad024255c32b Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Thu, 19 Dec 2024 13:01:18 +0000 Subject: [PATCH 1/4] Arbitrary self types v2: update reference. --- src/expressions/method-call-expr.md | 22 +++++++++++++++++++++- src/items/associated-items.md | 13 +++++-------- src/special-types-and-traits.md | 12 +++++++++++- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/expressions/method-call-expr.md b/src/expressions/method-call-expr.md index 9535cd207..19a25bd91 100644 --- a/src/expressions/method-call-expr.md +++ b/src/expressions/method-call-expr.md @@ -23,7 +23,18 @@ Then, for each candidate `T`, add `&T` and `&mut T` to the list immediately afte 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]`. -Then, for each candidate type `T`, search for a [visible] method with a receiver of that type in the following places: +A second - possible more expansive - list is then made of types where we might +find [visible] methods with a receiver of that type, called the list of +contributing types. To make this list, follow the exact same process, +but this time use the `Receiver` trait +instead of the `Deref` trait for any non-built-in derefences. + +There is a blanket implementation of `Receiver` for all `T: Deref`, so in many +cases the lists are identical, but there are rare smart pointers which +may implement `Receiver` without implementing `Deref`, so this second list of +types may be longer than the list of candidate 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 +77,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..773f44cf3 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. @@ -564,6 +560,7 @@ fn main() { [`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/special-types-and-traits.md b/src/special-types-and-traits.md index dc34dffae..517ec51fd 100644 --- a/src/special-types-and-traits.md +++ b/src/special-types-and-traits.md @@ -73,7 +73,16 @@ 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`. r[lang-types.drop] ## `Drop` @@ -218,6 +227,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 From 0ecbbf81891407e9e1f9a7a12334f99013efd74a Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Tue, 28 Jan 2025 09:02:31 +0000 Subject: [PATCH 2/4] Review comment regarding Rc/etc. --- src/special-types-and-traits.md | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/special-types-and-traits.md b/src/special-types-and-traits.md index 517ec51fd..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` @@ -83,6 +61,9 @@ 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` From e138cf700c7372f7b3ea066f6c74f35e5e6838b5 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Tue, 28 Jan 2025 11:30:01 +0000 Subject: [PATCH 3/4] Rewrite list creation bit --- src/expressions/method-call-expr.md | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/expressions/method-call-expr.md b/src/expressions/method-call-expr.md index 19a25bd91..8f71bccfc 100644 --- a/src/expressions/method-call-expr.md +++ b/src/expressions/method-call-expr.md @@ -17,24 +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]`. -A second - possible more expansive - list is then made of types where we might -find [visible] methods with a receiver of that type, called the list of -contributing types. To make this list, follow the exact same process, -but this time use the `Receiver` trait -instead of the `Deref` trait for any non-built-in derefences. +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`. -There is a blanket implementation of `Receiver` for all `T: Deref`, so in many -cases the lists are identical, but there are rare smart pointers which -may implement `Receiver` without implementing `Deref`, so this second list of -types may be longer than the list of candidate types. +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: +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`. From 84f896f6300cb2a7efc132301683db1dff32fa78 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Tue, 28 Jan 2025 11:42:48 +0000 Subject: [PATCH 4/4] Fix broken links. --- src/items/associated-items.md | 3 +-- src/items/traits.md | 12 +++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/items/associated-items.md b/src/items/associated-items.md index 773f44cf3..33f1126bf 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -113,7 +113,7 @@ If the type of the `self` parameter is specified, it is limited to types resolvi 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`]). +or `Arc`). This can also include the contextual type alias `Self`, other type aliases, or associated type projections resolving to the implementing type. @@ -555,7 +555,6 @@ 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 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