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

Confusing error when impl is available only on RefCell contents #76095

Open
iximeow opened this issue Aug 30, 2020 · 2 comments
Open

Confusing error when impl is available only on RefCell contents #76095

iximeow opened this issue Aug 30, 2020 · 2 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints D-confusing Diagnostics: Confusing error or lint that should be reworked. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@iximeow
Copy link
Contributor

iximeow commented Aug 30, 2020

Some Rust (playground):

use std::cell::RefCell;

struct WorkDoer<'f, F> {
    f: &'f F,
}

impl<'f> WorkDoer<'f, i32> {
    fn do_work(&self) {}
}

fn main() {
    let f = RefCell::new(1i32);
    let work = WorkDoer { f: &f };
    work.do_work();
}

yields an error about no method do_work being found:

error[E0599]: no method named `do_work` found for struct `WorkDoer<'_, std::cell::RefCell<i32>>` in the current scope
  --> src/main.rs:14:10
   |
3  | struct WorkDoer<'f, F> {
   | ---------------------- method `do_work` not found for this
...
14 |     work.do_work();
   |          ^^^^^^^ method not found in `WorkDoer<'_, std::cell::RefCell<i32>>`

where do_work does exist, but on a different type. Specifically, WorkDoer<'_, i32>.

In the above example, WorkDoer should be made from a borrow of the RefCell, like WorkDoer { f: &*f.borrow() }, which rustc is entirely happy to build. It would be fantastic if rustc could suggest that the borrow would make a do_work available.

Related messages

There's (what I think to be) a similar variation of this with a more generic impl:

use std::cell::RefCell;

struct WorkDoer<'f, F> {
    f: &'f F,
}

impl<'f, I: std::ops::Add> WorkDoer<'f, I> {
    fn do_work(&self) {}
}

fn main() {
    let f = RefCell::new(1i32);
    let work = WorkDoer { f: &f };
    work.do_work();
}

yielding a more informative error:

error[E0599]: no method named `do_work` found for struct `WorkDoer<'_, std::cell::RefCell<i32>>` in the current scope
   --> src/main.rs:14:10
    |
3   |   struct WorkDoer<'f, F> {
    |   ---------------------- method `do_work` not found for this
...
14  |       work.do_work();
    |            ^^^^^^^ method not found in `WorkDoer<'_, std::cell::RefCell<i32>>`
    |
    = note: the method `do_work` exists but the following trait bounds were not satisfied:
            `std::cell::RefCell<i32>: std::ops::Add`

but if the constraints become much more complex than I: std::ops::Add it can be very confusing to read through mismatched types only to realize you've forgotten to borrow the RefCell.

If rustc could observe that the inner type satisfies the constraints and makes do_work available, then suggest that change, it'd be kind of incredibly good and cool.

(this is a minimization of https://twitter.com/iximeow/status/1297651292148359170 which @estebank also asked me to file an issue about :) the aforementioned "try borrowing the RefCell contents" suggestion would be very handy here.)

@estebank estebank added A-diagnostics Area: Messages for errors, warnings, and lints D-confusing Diagnostics: Confusing error or lint that should be reworked. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. labels Aug 30, 2020
@estebank
Copy link
Contributor

Current output:

error[E0599]: no method named `do_work` found for struct `WorkDoer<'_, RefCell<i32>>` in the current scope
  --> src/main.rs:14:10
   |
3  | struct WorkDoer<'f, F> {
   | ---------------------- method `do_work` not found for this struct
...
14 |     work.do_work();
   |          ^^^^^^^ method not found in `WorkDoer<'_, RefCell<i32>>`
   |
   = note: the method was found for
           - `WorkDoer<'f, i32>`
error[E0599]: the method `do_work` exists for struct `WorkDoer<'_, RefCell<i32>>`, but its trait bounds were not satisfied
  --> src/main.rs:14:10
   |
3  | struct WorkDoer<'f, F> {
   | ---------------------- method `do_work` not found for this struct
...
14 |     work.do_work();
   |          ^^^^^^^ method cannot be called on `WorkDoer<'_, RefCell<i32>>` due to unsatisfied trait bounds
  --> /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/cell.rs:678:1
   |
   = note: doesn't satisfy `RefCell<i32>: Add`
   |
note: trait bound `RefCell<i32>: Add` was not satisfied
  --> src/main.rs:7:13
   |
7  | impl<'f, I: std::ops::Add> WorkDoer<'f, I> {
   |             ^^^^^^^^^^^^^  ---------------
   |             |
   |             unsatisfied trait bound introduced here

@estebank
Copy link
Contributor

estebank commented Mar 7, 2025

CC #71505

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints D-confusing Diagnostics: Confusing error or lint that should be reworked. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. 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

2 participants