Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Method Resolution & Operator Overload

Method calls are the expressions that look like $receiver.method($args..). Method calls in Rust involve a fair bit of implicit magic: the receiver expression may be referenced and/or dereferenced to get to the right type, and figuring out which methods are available requires trait solving.

Explaining how that works is out of scope for this guide (see [expr.method]); whatever the exact process, the result is that we replace each method call with a full-unambiguous function call expression and some expression adjustments:

#![allow(unused)]
fn main() {
let opt = Some(42);
let x: &i32 = opt.as_ref().clone().unwrap();
// desugars to:
let x: &i32 = Option::unwrap(<Option<&i32> as Clone>::clone(&Option::as_ref(&opt)));
}

The <Type as Trait>::method(self, args..) syntax is called UFCS (Uniform Function Call Syntax) [expr.call.desugar] and allows specifying exactly what trait method is getting called. Note also how opt got borrowed into &opt in order to match the type required for Option::as_ref.

Aside postfix method calls, a number of operations can be overridden using traits. We desugar such overridden operations into the appropriate method call:

  • a + b -> Add::add(a, b)
  • a += b -> AddAssign::add_assign(&mut a, b)
  • a - b -> Sub::sub(a, b)
  • -a -> Neg::neg(a)
  • a[b] -> Index::index(&a, b)/IndexMut::index_mut(&mut a, b)
  • f(args...) -> Fn::call/FnMut::call_mut/FnOnce::call_once(f, (args...))
  • etc

The non-overriden versions of these operations stay unchanged. For example + on integers is built-in, but on integer references is defined by a trait:

#![allow(unused)]
fn main() {
let x = 1 + 2 + &3;
// becomes
let x = 1 + <i32 as Add<&i32>>::add(2, &3);
}

Note that we don’t handle the * operator (overrideable with Deref/DerefMut) here, we’ll do it in Deref/DerefMut Desugarings.

At the end of this step every method call and overridden operator use has been turned into a plain function call.