Poor error message for attempt to make doubly-fat pointers

b4641b6
Opened by Jim Blandy at 2025-03-22 18:51:36

Compiling the following code yields the given error:

#![allow(unused_variables)]

trait T1 { fn f(&self); }
trait T2 { fn g(&self); }

struct S;

impl T1 for S {
    fn f(&self) {
        println!("<S as T1>::f");
    }
}

impl T2 for T1 {
    fn g(&self) {
        println!("<T1 as T2>::g");
        self.f();
    }
}

fn main() {
    let s: S = S;
    let bs: Box<S> = Box::new(s);

    let t1_object: Box<T1> = bs;
    let t2_object: Box<T2> = t1_object;
}
error[E0308]: mismatched types
  --> src/main.rs:26:30
   |
26 |     let t2_object: Box<T2> = t1_object;
   |                              ^^^^^^^^^ expected trait `T2`, found trait `T1`
   |
   = note: expected type `std::boxed::Box<T2>`
              found type `std::boxed::Box<T1>`

This is confusing when the intent is to create a trait object. I think it's common to internalize the rule that one can coerce Box<T> to Box<Trait> if T: Trait, without noticing the side requirement that Box<T> must not be a fat pointer, lest we create a doubly-fat pointer.

I would speculate that what's going on in the compiler is that the coercion code declines to perform any coercion, leaving Rust to report the mismatch. It would be helpful to issue a note to the effect that trait object creation was considered, but rejected because the incoming pointer was already fat.

  1. Triage: no change.

    Esteban Kuber at 2019-09-26 18:23:06

  2. Current output, little change:

    error[E0308]: mismatched types
      --> file.rs:26:30
       |
    26 |     let t2_object: Box<T2> = t1_object;
       |                    -------   ^^^^^^^^^ expected trait `T2`, found trait `T1`
       |                    |
       |                    expected due to this
       |
       = note: expected struct `std::boxed::Box<dyn T2>`
                  found struct `std::boxed::Box<dyn T1>`
    

    Esteban Kuber at 2020-02-01 20:53:52

  3. Using:

    % caro -v -V
    zsh: command not found: caro
    rod@Mac fatptr % cargo -v -V
    cargo 1.85.1 (d73d2caf9 2024-12-31)
    release: 1.85.1
    commit-hash: d73d2caf9e41a39daf2a8d6ce60ec80bf354d2a7
    commit-date: 2024-12-31
    host: aarch64-apple-darwin
    libgit2: 1.8.1 (sys:0.19.0 vendored)
    libcurl: 8.7.1 (sys:0.4.74+curl-8.9.0 system ssl:(SecureTransport) LibreSSL/3.3.6)
    ssl: OpenSSL 1.1.1w  11 Sep 2023
    os: Mac OS 15.3.2 [64-bit]
    

    yields:

     % cargo build
       Compiling fatptr v0.1.0 (/Users/rod/code/rust/triage/fatptr)
    error[E0782]: expected a type, found a trait
      --> src/main.rs:14:13
       |
    14 | impl T2 for T1 {
       |             ^^
       |
    help: you can add the `dyn` keyword if you want a trait object
       |
    14 | impl T2 for dyn T1 {
       |             +++
    help: alternatively use a blanket implementation to implement `T2` for all types that also implement `T1`
       |
    14 | impl<T: T1> T2 for T {
       |     +++++++        ~
    
    error[E0782]: expected a type, found a trait
      --> src/main.rs:25:24
       |
    25 |     let t1_object: Box<T1> = bs;
       |                        ^^
       |
    help: you can add the `dyn` keyword if you want a trait object
       |
    25 |     let t1_object: Box<dyn T1> = bs;
       |                        +++
    
    error[E0782]: expected a type, found a trait
      --> src/main.rs:26:24
       |
    26 |     let t2_object: Box<T2> = t1_object;
       |                        ^^
       |
    help: you can add the `dyn` keyword if you want a trait object
       |
    26 |     let t2_object: Box<dyn T2> = t1_object;
       |                        +++
    
    For more information about this error, try `rustc --explain E0782`.
    error: could not compile `fatptr` (bin "fatptr") due to 3 previous errors
    

    which is a totally different set of error messages. However after following the recommended fixes to give:

    #![allow(unused_variables)]
    
    trait T1 { fn f(&self); }
    trait T2 { fn g(&self); }
    
    struct S;
    
    impl T1 for S { 
        fn f(&self) {
            println!("<S as T1>::f");
        }   
    }
    
    // impl T2 for dyn T1    -- gives same error
    impl<T: T1> T2 for T { 
        fn g(&self) {
            println!("<T1 as T2>::g");
            self.f();
        }   
    }
    
    fn main() {
        let s: S = S;
        let bs: Box<S> = Box::new(s);
    
        let t1_object: Box<dyn T1> = bs; 
        let t2_object: Box<dyn T2> = t1_object;
    }
    

    Produces:

    cargo build   
       Compiling fatptr v0.1.0 (/Users/rod/code/rust/triage/fatptr)
    error[E0308]: mismatched types
      --> src/main.rs:26:34
       |
    26 |     let t2_object: Box<dyn T2> = t1_object;
       |                    -----------   ^^^^^^^^^ expected trait `T2`, found trait `T1`
       |                    |
       |                    expected due to this
       |
       = note: expected struct `Box<dyn T2>`
                  found struct `Box<dyn T1>`
    
    For more information about this error, try `rustc --explain E0308`.
    error: could not compile `fatptr` (bin "fatptr") due to 1 previous error
    

    which is essentially the same as in the issue.

    Rod at 2025-03-22 18:51:36