1

I'm trying to wrap a DST around a Rc with the aim of cloning it and accessing it from various parts of the code but the following error appears on compilation.

Here is a minimal reproducible example of the error (playground):

use std::rc::Rc;

trait Trait<'a> {
    fn return_hello(&self) -> &'a str;
}

impl<'a, F> Trait<'a> for F
where
    F: Fn() -> &'a str
{
    fn return_hello(&self) -> &'a str {
        self()
    }
}

impl<'a, T> Trait<'a> for Rc<T> 
where
    T: Trait<'a>
{
    fn return_hello(&self) -> &'a str {
        (**self).return_hello()
    } 
}

fn caller<'a, T>(t: T) 
where
    T: Trait<'a>
{
    print!("{}\n", t.return_hello());
}

fn main() {
    fn test1<'a>() -> &'a str {
        "Hello from function"
    }
    let test2 = move || "hello from closure";
    
    fn f<'a>() -> &'a str {
        "Hello from Rc"
    }
    let test3: Rc<dyn Trait<'_>> = Rc::new(f);

    caller(test1);
    caller(test2);
    caller(test3);
}

Gives:

error[E0277]: the trait bound `Rc<dyn Trait<'_>>: Trait<'_>` is not satisfied
  --> src/main.rs:45:12
   |
25 | fn caller<'a, T>(t: T) 
   |    ------ required by a bound in this
26 | where
27 |     T: Trait<'a>
   |        --------- required by this bound in `caller`
...
45 |     caller(test3);
   |            ^^^^^ the trait `Trait<'_>` is not implemented for `Rc<dyn Trait<'_>>`
   |
   = help: the following implementations were found:
             <Rc<T> as Trait<'a>>
Jmb
  • 18,893
  • 2
  • 28
  • 55
cdecompilador
  • 178
  • 2
  • 9

2 Answers2

4

Your impl for Rc<T> has an implicit requirement that T: Sized, as if you wrote:

impl<'a, T> Trait<'a> for Rc<T> 
where
    T: Trait<'a> + Sized //The latter is implicit

But when you want to apply it to a Rc<dyn Trait<'a>> then the type T is dyn Trait<'a>, that is not Sized, so it does not apply.

The solution is to add + ?Sized to relax that requirement (playground):

impl<'a, T> Trait<'a> for Rc<T> 
where
    T: Trait<'a> + ?Sized

And now that you are into it you can add it to the other impl too:

impl<'a, F> Trait<'a> for F
where
    F: Fn() -> &'a str + ?Sized

so that it applies to dyn Fn() -> &'a str, too.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • 1
    Cleaner way ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=cd5311a7869017521b67920fe7d7f9d2)): `impl<'a> Trait<'a> for Rc> { ... }` – dvec Jul 27 '21 at 16:29
  • @dvec But that's constrained to DSTs only, I want it to allow the `Rc` to hold `Sized` and `?Sized` types, but thanks for the help. – cdecompilador Jul 27 '21 at 16:31
  • @dvec: But that `impl` only applies to that particular type, not to any other `Rc` where `T: Trait<'a>` but it is different from `dyn Trait<'a>`. For example `struct S {}; impl<'a> Trait<'a> for S { ... }`. Does `Rc` implement `Trait<'a>`? – rodrigo Jul 27 '21 at 16:32
1

In the implementation of Rc<T> for Trait, T have an implicit bound of Sized (source) because of that, the implementations of Rc<T> will only resolve to Sized types. Simply telling that T "may not be sized" will solve the problem, so add a ?Sized.

impl<'a, T> Trait<'a> for Rc<T> 
where
    T: ?Sized + Trait<'a>
{
    fn return_hello(&self) -> &'a str {
        (**self).return_hello()
    } 
}