Skip to content

"Unused" associated type bounds in dyn no longer parameterize the type #140645

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
QuineDot opened this issue May 4, 2025 · 4 comments · May be fixed by #140684
Open

"Unused" associated type bounds in dyn no longer parameterize the type #140645

QuineDot opened this issue May 4, 2025 · 4 comments · May be fixed by #140684
Labels
A-dyn-trait Area: trait objects, vtable layout C-bug Category: This is a bug. I-prioritize Issue: Indicates that prioritization has been requested for this issue. L-unused_associated_type_bounds Lint: unused_associated_type_bounds regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@QuineDot
Copy link

QuineDot commented May 4, 2025

Code

I tried this code:

#![allow(unused_associated_type_bounds)]

pub trait Other {}
pub trait Trait {
    type Assoc where Self: Sized;
}

impl Other for dyn Trait {}
impl Other for dyn Trait<Assoc = ()> {}
impl<T> dyn Trait<Assoc = T> {}

I expected to see this happen: successful compilation.

Instead, this happened:

error[E0119]: conflicting implementations of trait `Other` for type `(dyn Trait + 'static)`
 --> src/lib.rs:9:1
  |
8 | impl Other for dyn Trait {}
  | ------------------------ first implementation here
9 | impl Other for dyn Trait<Assoc = ()> {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Trait + 'static)`

error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
  --> src/lib.rs:10:6
   |
10 | impl<T> dyn Trait<Assoc = T> {}
   |      ^ unconstrained type parameter

Some errors have detailed explanations: E0119, E0207.
For more information about an error, try `rustc --explain E0119`.

Version it worked on

It most recently worked on: Rust 1.86.0

Version with regression

Playground: Beta version: 1.87.0-beta.8 (2025-05-03 973ec11)

More notes

CC #125560

Before Beta, dyn Trait and dyn Trait<Assoc = ()> were different types. Now they are the same type.

Here's a more complete example that makes practical (albeit contrived) use of distinct dyn Trait<Assoc = ...> types.

Considering the release notes, #136458 may be the cause (but there's no discussion about this change in particular). Assuming this is the case and the use case that broke is considered unimportant, this aspect of the change could at least be mentioned in the release notes.

Incidentally, this also means dyn Trait<Assoc = &'can_be_non_static str> meets a 'static bound now. Hopefully irrelevant, but it does seem like an exception to outlive bounds being syntactical.

@rustbot modify labels: +regression-from-stable-to-beta, -regression-untriaged

@QuineDot QuineDot added C-bug Category: This is a bug. regression-untriaged Untriaged performance or correctness regression. labels May 4, 2025
@rustbot rustbot added I-prioritize Issue: Indicates that prioritization has been requested for this issue. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. regression-from-stable-to-beta Performance or correctness regression from stable to beta. and removed regression-untriaged Untriaged performance or correctness regression. labels May 4, 2025
@fmease fmease added T-types Relevant to the types team, which will review and decide on the PR/issue. A-dyn-trait Area: trait objects, vtable layout labels May 4, 2025
@compiler-errors
Copy link
Member

I don't believe that this behavioral change is worth concern. I'll discuss this with @lcnr tomorrow since we worked together on these dyn issues, b/c we have several options here:

  1. Do nothing.
  2. Bump unused_associated_type_bounds up to a future-compat warning.
  3. Adjust the assoc-type-bound lowering algorithm in Do not deduplicate list of associated types provided by dyn principal #136458 to start lowering impossible associated type bounds again.
  4. Fully revert Do not deduplicate list of associated types provided by dyn principal #136458 -- this would be the worst option since Do not deduplicate list of associated types provided by dyn principal #136458 fixes a much more legitimate class of issues with dyn types than this IMO.

I kinda prefer (0.) or (1.) here, personally. I don't see any problem with writing these bounds, but we could probably be clearer in explaining to users that we now don't consider dyn Trait<NeedsSized = T> and dyn Trait<NeedsSized = U> as distinct types if T != U. (2.) would be annoying but doable.


Incidentally, this also means dyn Trait<Assoc = &'can_be_non_static str> meets a 'static bound now. [...] Hopefully irrelevant, but it does seem like an exception to outlive bounds being syntactical.

Side-note, it's not exactly true to say that dyn Trait<Assoc = T> now implies that T satisfies the item bounds of Assoc due to this change; we're simply not enforcing the item bounds since we ignore the user-written associated type bound since dyn Trait is definitely unsized.

This is IMO irrelevant because that bound is never relevant for a dyn type. It's as if we were saying "if dyn Sized: Sized, then require &'a str: 'static". It's got a false premise.

@compiler-errors
Copy link
Member

The fact that impossible associated type bounds used to constrain type parameters to me is interesting at best, but is technically an observable change. I think this warrants an FCP, and I'll open up one tomorrow when I can write up some coherent justification for why this behavioral change is at best desirable and at worst worth ignoring.

@QuineDot
Copy link
Author

QuineDot commented May 5, 2025

Let me call out one particular part of my more complete playground:

        // SAFETY:
        // - `BaseType: Use<Assoc = Assoc>` is guaranteed by unsizing coercion

Or in other words: "Box<T> coerces to Box<dyn Use<Assoc = Assoc> + 't>" no longer implies T: Use<Assoc = Assoc> + 't, because now sometimes Box<dyn Use<Assoc = Assoc> + 't> is synonymous with Box<dyn Use + 't>.

With that in mind, here's a version of the playground where code that used to be sound by relying on that implication is no longer sound, but still compiles on Beta. Even ignoring soundness, the code suddenly becomes very misleading IMO. I think assuming the implication holds is reasonable, but on Beta it's no longer always true.

Even if (2) and (3) won't happen, perhaps this is relevant re: unused_associated_type_bounds becoming a FCW.

If do-nothing bounds are eventually disallowed, the implication that "what you can (syntactically) coerce to reflects the capability of the coercee" will become true again.

Side-note, it's not exactly true to say that dyn Trait<Assoc = T> now implies that T satisfies the item bounds of Assoc due to this change; we're simply not enforcing the item bounds since we ignore the user-written associated type bound since dyn Trait is definitely unsized.

Under a mental model of "dyn Trait<..> + 'a means ErasedType: Trait<..> + 'a", the item bound is a restriction on the erased type, which was not unsized. That take correlates to the now-violated assumption above.

Anyway, I don't care strongly enough to argue hard for (2) or (3), and I'm not trying to do that. The lost ability is neat but I also recognize the change is cleaner. The code I wrote using the lost ability were POCs, not load bearing. And I only pointed out the 'static thing in case there was some soundness consideration I didn't know about.

But I do think "do-nothing item bounds" are quite misleading without the invariant, and should be loud about it. I think one can see how previously_sound_crate could be convincing in a code review, say.

@jieyouxu jieyouxu added L-unused_associated_type_bounds Lint: unused_associated_type_bounds and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels May 5, 2025
@compiler-errors
Copy link
Member

I changed my mind and implemented #140684.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-dyn-trait Area: trait objects, vtable layout C-bug Category: This is a bug. I-prioritize Issue: Indicates that prioritization has been requested for this issue. L-unused_associated_type_bounds Lint: unused_associated_type_bounds regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
5 participants