Why non-reference parameter accepts references?

I have this code example:

use std::path::{Path, PathBuf};

fn test1(p1: impl AsRef<Path>) {
}

fn test2(p1: &impl AsRef<Path>) {
}

fn test3(p1: PathBuf) {
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let p1: PathBuf = PathBuf::from("/home/path");
    test1(&p1); // OK (Why?)
    test1(p1);  // OK
    test2(&p1); // OK
    test2(p1);  // expected reference
    test3(&p1); // expected struct `PathBuf`, found `&PathBuf`
    test3(p1);  // OK
    Ok(())
}

I understand why there are errors on calling test2 and test3.
But why test1 accepts parameter by reference? Where is this behavior documented?

AsRef is automatically implemented for &T if it is implemented for T:
(std::convert::AsRef - Rust)

1 Like

Thanks @tczajka
Unfortunately I don't understand how this stuff helps here:

impl<'_, T, U> AsRef<U> for &'_ T
where
    T: AsRef<U> + ?Sized,
    U: ?Sized, 

but that is another question.

Well let

T = PathBuf
U = Path

Then since the standard library contains impl AsRef<Path> for PathBuf, it is indeed the case that T: AsRef<U>, hence the impl applies, implementing AsRef<Path> for &PathBuf.

thanks @alice

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.