-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Open
Labels
A-closuresArea: Closures (`|…| { … }`)Area: Closures (`|…| { … }`)A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`Area: Suggestions generated by the compiler applied by `cargo fix`D-lack-of-suggestionDiagnostics: Adding a (structured) suggestion would increase the quality of the diagnostic.Diagnostics: Adding a (structured) suggestion would increase the quality of the diagnostic.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.Diagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
In this code:
pub struct Shared {}
pub trait State {
fn new(shared: Rc<RefCell<Shared>>) -> Self where Self: Sized;
}
pub struct StateManager {
factories: HashMap<String, Box<dyn Fn() -> Box<dyn State>>>,
shared: Rc<RefCell<Shared>>
}
impl StateManager {
pub fn new() -> Self {
Self {
factories: HashMap::new(),
shared: Rc::new(RefCell::new(Shared {}))
}
}
pub fn register_state<S: State + 'static>(&mut self, name: String) {
let shared = self.shared.clone();
self.factories.insert(name, Box::new(move || {
// uncomment this to make it compile:
// let shared = shared.clone();
Box::new(S::new(shared)) as Box<dyn State>
}) as Box<dyn Fn() -> Box<dyn State>>);
}
}
I expected to see this happen: An error that explains that the closure is FnOnce
due to giving shared
away.
Instead, this happened: An error that says the closure is not dyn Fn()
, which appears to be talking about its return value. Note in particular the help
note about wrapping it in a closure with no arguments.
The error is:
error[E0277]: expected a `std::ops::Fn<()>` closure, found `[closure@src/lib.rs:25:46: 29:10 shared:std::rc::Rc<std::cell::RefCell<Shared>>]`
--> src/lib.rs:25:37
|
25 | self.factories.insert(name, Box::new(move || {
| _____________________________________^
26 | | // uncomment this to make it compile:
27 | | // let shared = shared.clone();
28 | | Box::new(S::new(shared)) as Box<dyn State>
29 | | }) as Box<dyn Fn() -> Box<dyn State>>);
| |__________^ expected an `Fn<()>` closure, found `[closure@src/lib.rs:25:46: 29:10 shared:std::rc::Rc<std::cell::RefCell<Shared>>]`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `[closure@src/lib.rs:25:46: 29:10 shared:std::rc::Rc<std::cell::RefCell<Shared>>]`
= note: wrap the `[closure@src/lib.rs:25:46: 29:10 shared:std::rc::Rc<std::cell::RefCell<Shared>>]` in a closure with no arguments: `|| { /* code */ }
= note: required for the cast to the object type `dyn std::ops::Fn() -> std::boxed::Box<dyn State>`
By moving things around a little bit, you get the expected error message:
pub fn register_state<S: State + 'static>(&mut self, name: String) {
let shared = self.shared.clone();
let closure: Box<dyn Fn() -> Box<dyn State>> = Box::new(move || {
// uncomment this to make it compile:
// let shared = shared.clone();
Box::new(S::new(shared)) as Box<dyn State>
});
self.factories.insert(name, closure);
}
error[E0507]: cannot move out of `shared`, a captured variable in an `Fn` closure
--> src/lib.rs:29:29
|
24 | let shared = self.shared.clone();
| ------ captured outer variable
...
29 | Box::new(S::new(shared)) as Box<dyn State>
| ^^^^^^ move occurs because `shared` has type `std::rc::Rc<std::cell::RefCell<Shared>>`, which does not implement the `Copy` trait
Metadata
Metadata
Assignees
Labels
A-closuresArea: Closures (`|…| { … }`)Area: Closures (`|…| { … }`)A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`Area: Suggestions generated by the compiler applied by `cargo fix`D-lack-of-suggestionDiagnostics: Adding a (structured) suggestion would increase the quality of the diagnostic.Diagnostics: Adding a (structured) suggestion would increase the quality of the diagnostic.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.Diagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.