Why does `AsRef<Path>` not accept `PathBuf`?

Having some trouble understanding how to use AsRef<Path>. This code does not compile:

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

fn main() {
    let p = PathBuf::from("foo");
    let p2 = PathBuf::from("bar");
    bar(&p, &p2);
    foo(p);
}

fn foo<P: AsRef<Path> + fmt::Debug>(p: P) {
    let _p2 = PathBuf::from("/test");
    println!("foo with {:?}", p);
    bar(p, _p2);
}
fn bar<P: AsRef<Path> + fmt::Debug>(p: P, p2: P) {
    println!("bar with {:?}, {:?}", p, p2);
}

gives this error message:

  --> src/main.rs:15:12
   |
12 | fn foo<P: AsRef<Path> + fmt::Debug>(p: P) {
   |        - this type parameter
...
15 |     bar(p, _p2);
   |            ^^^ expected type parameter `P`, found struct `std::path::PathBuf`
   |

while this compiles just fine:

fn foo<P: AsRef<Path> + fmt::Debug>(p: P) {
    let _p2 = PathBuf::from("/test");
    println!("foo with {:?}", p);
    //bar(p, _p2);
}

playground example is here

It is because you are reusing the generic parameter for both arguments, which means that they must both be the same concrete type. Since the P supplied to foo might not be a PathBuf, there is a type mismatch. To fix this, use two generic parameters.

Thanks @alice, you are most helpful!
the version that works looks like this:

fn bar<P: AsRef<Path> + fmt::Debug, P2: AsRef<Path> + fmt::Debug>(p: P, p2: P2) {
    println!("bar with {:?}, {:?}", p, p2);
}

or rewritten a little nicer:

fn bar(p: impl AsRef<Path> + Debug, p2: impl AsRef<Path> + Debug) {
    println!("bar with {:?}, {:?}", p, p2);
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.