-
-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Description
The trait std::borrow::Borrow and type std::rc::RefCell both have a method borrow(). This leads to ambiguity, possibly hard-to-understand errors and most importantly breaking unrelated code by adding use std::borrow::Borrow;.
Consider the following code:
use std::rc::Rc;
use std::cell::RefCell;
// Uncommenting causes compile error
//use std::borrow::Borrow;
pub struct S {
flag : bool
}
type SCell = Rc<RefCell<S>>;
fn main() {
// Type annotations just for clarity
let s : SCell = Rc::new(RefCell::new(S {flag: false}));
let sb : &S = &s.borrow();
println!("{:?}", sb.flag);
}This code compiles and works as intended. But when you add use std::borrow::Borrow;, the compiler complains:
rustc 1.17.0 (56124baa9 2017-04-24)
error[E0277]: the trait bound `std::rc::Rc<std::cell::RefCell<S>>: std::borrow::Borrow<S>` is not satisfied
--> <anon>:13:21
|
13 | let sb: &S = &s.borrow();
| ^^^^^^ the trait `std::borrow::Borrow<S>` is not implemented for `std::rc::Rc<std::cell::RefCell<S>>`
|
= help: the following implementations were found:
<std::rc::Rc<T> as std::borrow::Borrow<T>>
The problem is that the method call s.borrow() is applied to Rc which is an instance of Borrow rather than to the contained RefCell as intended (and as working in the example above), and the error just complains that this borrow is not possible (which is fine).
This is mentioned by @spirali in related #41865, but this issue deals with a different part of the problem. (Namely that if you remove the type annotation from let sb : &S = ..., the error message will complain about ambiguity of the Borrow::borrow() return type in a confusing way.)
I would propose to change the method name for RefCell::borrow to something else (a painful change, but leaving such bugs around things implementing the Deref trait might be even worse for the language long-term) and avoid this naming collisions whenever possible (is there a guideline for that?). Any other solutions?