Box is special. It is a lang item, and the compiler knows to deref it without help. So:
self - &Box.
*self - Box, builtin deref of shared reference.
**self - T, builtin deref of Box.
&**self - &T.
Similar things happen for all builtin operations. For example, this is the Add impl for integers (inside a macro):
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Add for $t {
type Output = $t;
#[inline]
#[rustc_inherit_overflow_checks]
fn add(self, other: $t) -> $t { self + other }
}
Again, the compiler knows to add integers. It is a builtin operation.
The reason we need the impl is for generics. Code like 0i32 + 0i32 translates to the builtin addition, but in a generic function:
fn add<T: Add>(a: T, b: T) -> T::Output { a + b }
If integers wouldn't implement Add, this function wouldn't accept them. The same happens for Box and Deref.
You can see that by inspecting the MIR. For example, the following function:
pub fn deref(b: &Box<i32>) -> &i32 {
&**b
}
Generates the following MIR:
fn deref(_1: &Box<i32>) -> &i32 {
let mut _0: &i32;
bb0: {
_0 = &(*(*_1));
return;
}
}
However, the following function:
pub fn deref<T: std::ops::Deref<Target = i32>>(b: &T) -> &i32 {
&**b
}
Generates the following MIR, that calls deref():
fn deref(_1: &T) -> &i32 {
let mut _0: &i32;
let _2: &i32;
let mut _3: &T;
bb0: {
_3 = _1;
_2 = <T as Deref>::deref(move _3) -> bb1;
}
bb1: {
_0 = _2;
return;
}
}
The same happens for other Deref implementors, e.g. Rc:
pub fn deref(b: &std::rc::Rc<i32>) -> &i32 {
&**b
}
fn deref(_1: &Rc<i32>) -> &i32 {
let mut _0: &i32;
let _2: &i32;
let mut _3: &std::rc::Rc<i32>;
bb0: {
_3 = _1;
_2 = <Rc<i32> as Deref>::deref(move _3) -> bb1;
}
bb1: {
_0 = _2;
return;
}
}