Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trait bounds that would be satisfied if autoderef was applied are not considered for function calls but are considered when using methods via the dot-operator #102839

Open
sdroege opened this issue Oct 9, 2022 · 4 comments
Labels
A-traits Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@sdroege
Copy link
Contributor

sdroege commented Oct 9, 2022

I tried this code (playground link):

struct D(String);

impl std::ops::Deref for D {
    type Target = str;
    
    fn deref(&self) -> &str {
        &self.0
    }
}

fn print(val: &(impl std::fmt::Debug + ?Sized)) {
    println!("{:?}", val);
}

trait T {
    fn print(&self);
}

impl T for str {
    fn print(&self) {
        println!("{}", self);
    }
}

fn main() {
    print("123");
    print(&String::from("123"));
    // XXX: Doesn't compile but probably should via autoderef
    print(&D(String::from("123")));
    // because the below compiles
    print(&*D(String::from("123")));
    
    "123".print();
    // and because it works via the dot operator just fine
    D(String::from("123")).print();
}

I expected to see this happen: The above code compiles

Instead, this happened:

error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): `D` doesn't implement `Debug`
  --> src/main.rs:29:14
   |
29 |        print(&D(String::from("123")));
   |        ----- ^^^^^^^^^^^^^^^^^^^^^^^ `D` cannot be formatted using `{:?}`
   |        |
   |        required by a bound introduced by this call
   |
   = help: the trait `Debug` is not implemented for `D`
   = note: add `#[derive(Debug)]` to `D` or manually `impl Debug for D`
note: required by a bound in `print`
  --> src/main.rs:11:22
   |
11 | fn print(val: &(impl std::fmt::Debug + ?Sized)) {
   |                      ^^^^^^^^^^^^^^^ required by this bound in `print`
help: consider annotating `D` with `#[derive(Debug)]`
   |
1  | #[derive(Debug)]
   |

Note that it works fine via the dot-operator and autoderef.

Meta

rustc --version --verbose:

rustc 1.64.0 (a55dd71d5 2022-09-19)
binary: rustc
commit-hash: a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52
commit-date: 2022-09-19
host: x86_64-unknown-linux-gnu
release: 1.64.0
LLVM version: 14.0.6
@sdroege sdroege added the C-bug Category: This is a bug. label Oct 9, 2022
@sdroege
Copy link
Contributor Author

sdroege commented Oct 9, 2022

Updated to make it clear that the very same currently works fine via autoderef and the dot-operator.

@sdroege sdroege changed the title Trait bounds that would be satisfied if autoderef was applied are not considered Trait bounds that would be satisfied if autoderef was applied are not considered for function calls but are considered when using methods via the dot-operator Oct 9, 2022
@sdroege
Copy link
Contributor Author

sdroege commented Oct 23, 2022

This is also a problem with impl Into<Option<&str>> in a much simpler scenario playground link:

fn print_a<'a>(s: impl Into<Option<&'a str>>) {
    match s.into() {
        None => println!("none"),
        Some(s) => println!("{}", s),
    }
}

fn print_b(s: Option<&str>) {
    match s {
        None => println!("none"),
        Some(s) => println!("{}", s),
    }
}

fn main() {
    print_a("123");
    print_a(None);
    // Doesn't compile:
    print_a(&String::from("123"));
    print_a(&*String::from("123"));
    print_b(Some("123"));
    print_b(None);
    print_b(Some(&String::from("123")));
    print_b(Some(&*String::from("123")));
}

This gives the following error:

error[[E0277]](https://doc.rust-lang.org/stable/error-index.html#E0277): the trait bound `Option<&str>: From<&String>` is not satisfied
  --> src/main.rs:19:13
   |
19 |     print_a(&String::from("123"));
   |     ------- ^^^^^^^^^^^^^^^^^^^^
   |     |       |
   |     |       the trait `From<&String>` is not implemented for `Option<&str>`
   |     |       help: consider dereferencing here: `&*String::from("123")`
   |     required by a bound introduced by this call
   |
   = note: required because of the requirements on the impl of `Into<Option<&str>>` for `&String`
note: required by a bound in `print_a`
  --> src/main.rs:1:24
   |
1  | fn print_a<'a>(s: impl Into<Option<&'a str>>) {
   |                        ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `print_a`

CC @fengalin

@ChrisDenton ChrisDenton added the needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. label Jul 16, 2023
@Enselic
Copy link
Member

Enselic commented Jul 30, 2024

Triage: I'm a bit confused, because the code you posted fails to compile because of a missing #[derive(Debug)]. This compiles:

#[derive(Debug)]
struct D(String);

impl std::ops::Deref for D {
    type Target = str;
    
    fn deref(&self) -> &str {
        &self.0
    }
}

fn print(val: &(impl std::fmt::Debug + ?Sized)) {
    println!("{:?}", val);
}

trait T {
    fn print(&self);
}

impl T for str {
    fn print(&self) {
        println!("{}", self);
    }
}

fn main() {
    print("123");
    print(&String::from("123"));
    // XXX: Doesn't compile but probably should via autoderef
    print(&D(String::from("123")));
    // because the below compiles
    print(&*D(String::from("123")));
    
    "123".print();
    D(String::from("123")).print();
}

Your second examples does not compile though. So maybe it would be good to edit the original issue and change it to the second example.

@sdroege
Copy link
Contributor Author

sdroege commented Aug 6, 2024

That's the whole point. The Debug impl shouldn't be necessary

@Enselic Enselic added A-traits Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. labels Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-traits Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants