error[E0277]: the size for values of type `dyn BaseObject` cannot be known at compilation time
--> src/main.rs:38:5
|
38 | try_new_cyclic_rc(|weak| {
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn BaseObject`
note: required by a bound in `try_new_cyclic_rc`
--> src/main.rs:4:26
|
4 | pub fn try_new_cyclic_rc<T: Sized>(f: impl FnOnce(&Weak<T>) -> Result<T, String>) -> Result<Rc<T>, String> {
| ^ required by this bound in `try_new_cyclic_rc`
error[E0277]: the size for values of type `dyn BaseObject` cannot be known at compilation time
--> src/main.rs:42:54
|
42 | let child = create_child_object(weak.clone())?;
| ^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn BaseObject`
= help: the following other types implement trait `FromResidual<R>`:
<Result<T, F> as FromResidual<Result<Infallible, E>>>
<Result<T, F> as FromResidual<Yeet<E>>>
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, String>>` for `Result<dyn BaseObject, String>`
So the question is why? Why does it try to return dyn BaseObject when it should be bound by both create_container_object function return type and Ok(ViewObject {...}) result?
I found a "solution" by explicitly specifying T try_new_cyclic_rc<Rc<ViewObject>, _>(...) but because of this usability is awful...
The thing that seems to be misguiding the compiler here is
create_child_object(weak.clone())
Where it sees create_child_object takes a Weak<dyn BaseObject> and concludes that's what weak is, versus something that could coerce to Weak<dyn BaseObject>. It's not the ? specifically; you can replace it with .unwrap() and get the same errors.
With this change, the compiler gets the message that weak might not be Weak<dyn BaseObject> exactly, and apparently that's enough for it to take the result type of the function into consideration, causing everything to resolve correctly.
try_new_cyclic_rc(|weak| {
- let child = create_child_object(weak.clone())?;
+ let child = create_child_object(weak.clone() as _)?;
Ok(ViewObject { parent, child: Some(child) })
})
Another alternative is annotating the closure header:
try_new_cyclic_rc(|weak: &Weak<ViewObject>| {
// or
try_new_cyclic_rc(|weak| -> Result<ViewObject, String> {
This general case (where the return value would guide inference correctly, but the type resolver wants to find something before considering that context) reminds me of an existing issue, but I've failed to track it down so far; if I find it I'll add a link.
? has a ton of flexibility. That's not a problem when you're in function scope, since the return type must always be fully annotated, but when you're in a closure like this -- where the return type also gets inferred -- it's much easier for the compiler to have too many options to be willing to pick one.
So basically I have no way around but to add type annotation at least somewhere (closure arg, closure return, T in try_new_cyclic_rc).
In my case this doesn't really help either, as I have many create_xxx_object methods.
From what I've tested it seams that compiler just takes first available line with the type in question to test inference. Just as an example if I add one unreachable statement everything seams to work (but it must be added at the beginning):
Frankly I hoped that compiler will compute all possible scenarios and select the one to fit, or at the very least scan whole closure instead of just first mention. Sadly, this is not the case
PS: I've actually reproduced the same issue with Rc:new_cyclic, so "?" is really not to blame but rather weak.clone().