Possibly misleading compiler error

Upfront I just want to say that I don't know how to make minimal (non)compilable example out of this, but let me explain the situation (last two lines are important, other code is provided as a context):

pub struct Panel {
    tree_view_name: &'static str,
    list_view: gtk::ColumnView,
    bread_crumb: gtk::FlowBox,
    current_path: PathBuf,
    model: gtk::DirectoryList,
}
impl Panel {
    fn set_file_info(&mut self, file_info: &gio::FileInfo) {...}
}
...inside some fn:

 let mut rc_panel = Rc::new(RefCell::new(panel));
        let mut rc_panel_clone = rc_panel.clone();

        rc_panel
            .borrow()
            .list_view
            .connect_activate(move |col_view, inx| {
                println!("ColumnViewClicked:{},{}", col_view, inx);

                let selection_model: gtk::SingleSelection =
                    col_view.model().unwrap().downcast().unwrap();
                let sort_model = glib::object::Cast::dynamic_cast::<
                    gtk::SortListModel,
                >(selection_model.model())
                .unwrap();
                let directory_list =
                    glib::object::Cast::dynamic_cast::<gtk::DirectoryList>(
                        sort_model.model().unwrap(),
                    )
                    .unwrap();
                let file_info =
                    glib::object::Cast::dynamic_cast::<gio::FileInfo>(
                        selection_model.selected_item().unwrap(),
                    )
                    .unwrap();
                let file_name = file_info.name();
    
1)             let mut w = rc_panel_clone.borrow_mut();//If I only have this line I get proper error from compiler

   2)             w.set_file_info(&file_info);//if I add this line, I get incorrect error from compiler + the previous error disappears
            });
The error with line 1) only:
error[E0596]: cannot borrow `rc_panel_clone` as mutable, as it is a captured variable in a `Fn` closure
   --> src/main_application_window.rs:228:29
    |
228 |                 let mut w = rc_panel_clone.borrow_mut();
    |                             ^^^^^^^^^^^^^^ cannot borrow as mutable
The error with line 1) and 2):
w.set_file_info(&file_info);
    |                   ^^^^^^^^^^^^^ method not found in `&mut Rc<RefCell<Panel>>`

So basically what happens is this:
If the line marked 1) is present without the line marked 2) we get proper compiler error.
If we add line marked 2) the compiler error is misleading telling us that the method doesn't exist in a type (which is not true), and also we don't get error about line number one, which is doubly confusing, because we are being told by the compiler that everything is fine with line 1) only the line 2) is problematic.

Looks like it called <Rc<_> as BorrowMut>::borrow_mut instead of RefCell::borrow_mut. What are the full error messages (both with and without line 2)?

I've updated my OP, with errors for lines 1) and 2)

Ah ok. So when you have line 2, the compiler is trying to find the set_file_info method in the types that it has inferred. And it has inferred a &mut Rc<RefCell<_>>, and indeed that type does not have such a method. Because trait resolution (? -- this part of the compile pass anyway) has failed, the compiler never gets around to running the borrow checker. That's why you don't get the borrow error when line 2 is present. The compiler has errored out before it found it.


Here's a reduced example, minus the borrow checker violation. Because std::borrow::BorrowMut is in scope, method resolution finds that (trait) method on the Rc before applying deref coercion and finding the inherent borrow_mut method on the RefCell.

If I remove that import, the BorrowMut trait isn't considered, method resolution continues on to apply Deref coercion to the Rc, and the method is found on RefCell. And then the method can be found via DerefMut on the RefMut<'_, Foo>.

Alternatively, and more self-documenting-ly, you can call RefCell::borrow_mut while leaving the BorrowMut trait in scope.


These won't help with the borrow checker problem (the line-1-only error), but I hope it at least explains (a) why the compiler didn't continue on to the borrow checker phase when line 2 was present and (b) how to get the borrow that you intended.

2 Likes

Thanks, that is indeed great and helpful answer!

1 Like

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.