Skip to content

Trait with associated type bounds cannot be made into an object because it uses Self as a type parameter #80256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ldr709 opened this issue Dec 21, 2020 · 2 comments
Labels
A-associated-items Area: Associated items (types, constants & functions) A-dyn-compatibility Area: Dyn compatibility (formerly: object safety) A-dyn-trait Area: trait objects, vtable layout A-trait-system Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@ldr709
Copy link
Contributor

ldr709 commented Dec 21, 2020

A simplified example where this shows up is the following trait.

trait Conversion {
    type Source: Into<Self::Target>;
    type Target;
}

(Full code)

If you try to make a trait object, say &dyn Conversion<Source = String, Target = Box<str>>, then Rust errors:

error[E0038]: the trait `Conversion` cannot be made into an object
  --> src/main.rs:14:12
   |
1  | trait Conversion {
   |       ---------- this trait cannot be made into an object...
2  |     type Source: Into<Self::Target>;
   |                  ------------------ ...because it uses `Self` as a type parameter in this
...
14 |     let b: &dyn Conversion<Source = String, Target = Box<str>> = &a;
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Conversion` cannot be made into an object

If the bound was something like Source: Into<Self> this error would make sense, but instead the bound references another associated type, which all must be fully specified when making a trait object type anyway.

This problem does not seem to occur when associated types are used to define functions in the trait, as creating a &dyn Deref<Target = ...> trait object works.

@ldr709 ldr709 added the C-bug Category: This is a bug. label Dec 21, 2020
@camelid camelid added A-trait-system Area: Trait system A-DSTs Area: Dynamically-sized types (DSTs) labels Dec 21, 2020
@p-avital
Copy link

p-avital commented Mar 7, 2023

Hi,

I'm currently building stabby an alternative to abi_stable (with added values: use niches in sum types and stable multi-trait objects).

My proc-macro generates v-tables (with auto-generated identifiers) and makes them accessible through a trait which roughly looks like this:

impl<Assoc1> VtProvider for dyn MyTrait<Assoc=Assoc1> {
  type Vt = AutoGeneratedVtForMyTrait<Assoc1>;
}

allowing the user to refer to AutoGeneratedVtForMyTrait<Assoc1> by vtable!(MyTrait<Assoc=Assoc1>), which resolves to <dyn MyTrait<Assoc=Assoc1> as VtProvider>::Vt.

This bug prevents this trick from working when associated types are constrained.

Is anyone willing to look into it? Or provide mentoring so that I could try? (I don't have any experience working with the compiler)

I'll trade you a stable ABI that keeps enums small in stable Rust for fixing this bug :)

p-avital added a commit to ZettaScaleLabs/stabby that referenced this issue Mar 7, 2023
@Noratrieb Noratrieb added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. labels Apr 5, 2023
@Tamschi
Copy link

Tamschi commented Jul 23, 2024

Is this the same issue or should I file it separately?

use std::ops::Deref;
use std::borrow::Borrow;

trait Guard: Deref + Borrow<Self::Target> {}

fn foo(_: &dyn Guard<Target = i32>) {}
error[E0038]: the trait `Guard` cannot be made into an object
 --> src/main.rs:7:12
  |
7 | fn foo(_: &dyn Guard<Target = i32>) {}
  |            ^^^^^^^^^^^^^^^^^^^^^^^ `Guard` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/main.rs:5:22
  |
5 | trait Guard: Deref + Borrow<Self::Target> {}
  |       -----          ^^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
  |       |
  |       this trait cannot be made into an object...
help: consider using an opaque type instead
  |
7 | fn foo(_: &impl Guard<Target = i32>) {}
  |            ~~~~

For more information about this error, try `rustc --explain E0038`.

(Thanks to Helix in the Community Discord for constructing the example.)

I ran into both versions of this in a project of mine, and while it's easy to work around by making the trait generic, that doesn't seem ideal with my Guard example here, as it's implicitly exclusive.

Edit: This might be #65078 instead.

@fmease fmease added A-dyn-trait Area: trait objects, vtable layout A-associated-items Area: Associated items (types, constants & functions) A-dyn-compatibility Area: Dyn compatibility (formerly: object safety) and removed A-DSTs Area: Dynamically-sized types (DSTs) labels Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-associated-items Area: Associated items (types, constants & functions) A-dyn-compatibility Area: Dyn compatibility (formerly: object safety) A-dyn-trait Area: trait objects, vtable layout A-trait-system Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants