blob: 8257c083e4054bedc81ba8b66b9f3cb2fd953978 [file] [log] [blame] [view]
r[expr.method]
# Method-call expressions
r[expr.method.syntax]
```grammar,expressions
MethodCallExpression -> Expression `.` PathExprSegment `(`CallParams? `)`
```
r[expr.method.intro]
A _method call_ consists of an expression (the *receiver*) followed by a single dot, an expression path segment, and a parenthesized expression-list.
r[expr.method.target]
Method calls are resolved to associated [methods] on specific traits, either statically dispatching to a method if the exact `self`-type of the left-hand-side is known, or dynamically dispatching if the left-hand-side expression is an indirect [trait object](../types/trait-object.md).
```rust
let pi: Result<f32, _> = "3.14".parse();
let log_pi = pi.unwrap_or(1.0).log(2.72);
# assert!(1.14 < log_pi && log_pi < 1.15)
```
r[expr.method.autoref-deref]
When looking up a method call, the receiver may be automatically dereferenced or borrowed in order to call a method.
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:
r[expr.method.candidate-receivers]
The first step is to build a list of candidate receiver types.
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.
r[expr.method.candidate-receivers-refs]
Then, for each candidate `T`, add `&T` and `&mut T` to the list immediately after `T`.
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]`.
r[expr.method.candidate-search]
Then, for each candidate type `T`, search for a [visible] method with a receiver of that 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`.
If `T` is a type parameter, methods provided by trait bounds on `T` are looked up first.
Then all remaining methods in scope are looked up.
> [!NOTE]
> The lookup is done for each type in order, which can occasionally lead to surprising results. The below code will print "In trait impl!", because `&self` methods are looked up first, the trait method is found before the struct's `&mut self` method is found.
>
> ```rust
> struct Foo {}
>
> trait Bar {
> fn bar(&self);
> }
>
> impl Foo {
> fn bar(&mut self) {
> println!("In struct impl!")
> }
> }
>
> impl Bar for Foo {
> fn bar(&self) {
> println!("In trait impl!")
> }
> }
>
> fn main() {
> let mut f = Foo{};
> f.bar();
> }
> ```
r[expr.method.ambiguous-target]
If this results in multiple possible candidates, then it is an error, and the receiver must be [converted][disambiguate call] to an appropriate receiver type to make the method call.
r[expr.method.receiver-constraints]
This process does not take into account the mutability or lifetime of the receiver, or whether a method is `unsafe`.
Once a method is looked up, if it can't be called for one (or more) of those reasons, the result is a compiler error.
r[expr.method.ambiguous-search]
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.
r[expr.method.edition2021]
> [!EDITION-2021]
> 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.
>
> This special case may be removed in the future.
> [!WARNING]
> For [trait objects], if there is an inherent method of the same name as a trait method, it will give a compiler error when trying to call the method in a method call expression.
> Instead, you can call the method using [disambiguating function call syntax], in which case it calls the trait method, not the inherent method.
> There is no way to call the inherent method.
> Just don't define inherent methods on trait objects with the same name as a trait method and you'll be fine.
[visible]: ../visibility-and-privacy.md
[array type]: ../types/array.md
[trait objects]: ../types/trait-object.md
[disambiguate call]: call-expr.md#disambiguating-function-calls
[disambiguating function call syntax]: call-expr.md#disambiguating-function-calls
[dereference]: operator-expr.md#the-dereference-operator
[methods]: ../items/associated-items.md#methods
[unsized coercion]: ../type-coercions.md#unsized-coercions
[`IntoIterator`]: std::iter::IntoIterator