What are the rules for coercing values to Trait Objects?

Consider the following Rust code:

#[derive(Debug, Clone, Copy)]
struct Struct;
trait Trait {}
impl Trait for Struct {}

fn f() {
    // Why does this coerce to the target type (Result<Box<dyn Trait>, ()>)
    let rbdt: Result<Box<dyn Trait>, ()> = Ok(Box::new(Struct));

    // And this coerces to the target type...
    let bs = Box::new(Struct);
    let rbdt: Result<Box<dyn Trait>, ()> = Ok(bs);

    // But this does not:
    let rbs = Ok(Box::new(Struct));
    let rbdt: Result<Box<dyn Trait>, ()> = rbs; // Error: mismatched types
}

Why do the first two assignments to rbdt work correctly, coercing the value into the target type (Result<Box<dyn Trait>, ()>), but the 3rd one does not? It seems to me that in all three cases the type of the RHS of the assignment is Result<Box<Struct>, ()>, so it's perplexing that some forms work while other cause a mismatched types error.

What are the rules governing when types containing trait objects can be assigned to? Are these documented anywhere?

Coarsely speaking, you can't be in a nested context, unless a recursive CoerceUnsized implementor is involved.

You can do this to clue the compiler in that a coercion needs to take place when you create the Result.

-    let rbs = Ok(Box::new(Struct));
+    let rbs = Ok(Box::new(Struct) as _);
3 Likes

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.