Skip to content

Undetailed diagnostics for object safety of supertraits defined in dependencies #87014

@lf-

Description

@lf-

Currently, the diagnostics for object safety are not very good if the object safety issue is caused by a trait defined outside the current crate, as it just points that some supertrait is not object safe and doesn't explain why from there. It's possible to argue that the current way this works is correct and that exposing implementation details of your libraries is a bad idea, but it's not necessarily good for teaching the user that object safety is not some magic.

Given the following code: also at https://github.com/lf-/object-safety-issue

cargo new --lib v
v/src/lib.rs:

pub trait T0: Clone {}
pub trait T1: T0 {}

Cargo.toml:

[package]
name = "play-si1zd_4v"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
v = {path = "./v"}

src/main.rs:

trait T2: v::T1 {
    fn a(self) -> u32;
}

#[derive(Clone)]
struct S;

impl v::T0 for S {}
impl v::T1 for S {}
impl T2 for S {
    fn a(self) -> u32 {
        4
    }
}

fn f(a: Box<dyn T2>) {}
fn main() {}

The current output is:

error[E0038]: the trait `T2` cannot be made into an object
  --> src/main.rs:16:9
   |
16 | fn f(a: Box<dyn T2>) {}
   |         ^^^^^^^^^^^ `T2` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the c
all to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/
reference/items/traits.html#object-safety>
  --> src/main.rs:1:11
   |
1  | trait T2: v::T1 {
   |       --  ^^^^^ ...because it requires `Self: Sized`
   |       |
   |       this trait cannot be made into an object...

error: aborting due to previous error

For more information about this error, try `rustc --explain E0038`.
error: could not compile `play-si1zd_4v`

Ideally the output should look like:

error[E0038]: the trait `T2` cannot be made into an object
  --> src/main.rs:16:9
   |
16 | fn f(a: Box<dyn T2>) {}
   |         ^^^^^^^^^^^ `T2` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the c
all to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/
reference/items/traits.html#object-safety>
note: because of requirement `T2: T1`
note: because of requirement `T1: T0`
note: because of requirement `T0: Clone`
note: because of requirement `Clone: Sized`
  --> src/main.rs:1:11
   |
1  | trait T2: v::T1 {
   |       --  ^^^^^ ...because it requires `Self: Sized`
   |       |
   |       this trait cannot be made into an object...

error: aborting due to previous error

For more information about this error, try `rustc --explain E0038`.
error: could not compile `play-si1zd_4v`

Filed based on nightly 2021-07-08.

If the traits are all declared in the same crate, the error is much better and points further along to the cause, although it still does not say that Clone: Sized, so you'd have to read the rustdocs or source to figure that out.

src/main.rs

mod v {
    pub trait T0: Clone {}
    pub trait T1: T0 {}
}

trait T2: v::T1 {
    fn a(self) -> u32;
}

#[derive(Clone)]
struct S;

impl v::T0 for S {}
impl v::T1 for S {}
impl T2 for S {
    fn a(self) -> u32 {
        4
    }
}

fn f(a: Box<dyn T2>) {}
error[E0038]: the trait `T2` cannot be made into an object
  --> src/main.rs:21:9
   |
21 | fn f(a: Box<dyn T2>) {}
   |         ^^^^^^^^^^^ `T2` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the c
all to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/
reference/items/traits.html#object-safety>
  --> src/main.rs:2:19
   |
2  |     pub trait T0: Clone {}
   |                   ^^^^^ ...because it requires `Self: Sized`
3  |     pub trait T1: T0 {}
   |                   ^^ ...because it requires `Self: Sized`
...
6  | trait T2: v::T1 {
   |       --  ^^^^^ ...because it requires `Self: Sized`
   |       |
   |       this trait cannot be made into an object...

error: aborting due to previous error

For more information about this error, try `rustc --explain E0038`.
error: could not compile `play-si1zd_4v`

To learn more, run the command again with --verbose.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-trait-systemArea: Trait systemD-terseDiagnostics: 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.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions