Why this code compiles? Is this expected?

use std::ops::Deref;

pub struct B;

impl B {
    fn foo(&self) -> &Self {
        &*self
    }
}

impl Deref for B {
    type Target = i32;

    fn deref(&self) -> &Self::Target {
        &1
    }
}

pub fn bar(b: &B) {
    let c: &i32 = b.foo(); // I expect this an error (type mismatch).
    let d: &B = b.foo();
}

What you are seeing here is deref coercion. Because of the Deref implementation, any &B can be converted to a &i32. The foo() function is something of a red herring, since it isn't directly interacting with the coercion, and a similar effect can be seen with the following code:

let a: &i32 = &B;

All that is happening in your example is that the coercion above is being applied to the return value of foo().

3 Likes

Note that if you don't want deref coercion then a trait like AsRef might be more appropriate, or even just a normal function if it's not meaningful to use it generically.

2 Likes