Skip to content
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

Adding trait bound causes unrelated trait resolution to fail #115080

Open
joshlf opened this issue Aug 21, 2023 · 6 comments
Open

Adding trait bound causes unrelated trait resolution to fail #115080

joshlf opened this issue Aug 21, 2023 · 6 comments
Labels
A-trait-system Area: Trait system C-bug Category: This is a bug. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@joshlf
Copy link
Contributor

joshlf commented Aug 21, 2023

This example is minimized from this code. Also discussed on URLO.

I have the following code:

pub trait HasAssocType {
    type Assoc;
}

pub trait Foo {}

impl<T: Foo> HasAssocType for T {
    type Assoc = ();
}

trait Bar {
    fn bar()
    where
        Self: Foo + Sized,
    {
        fn bar_inner<T: HasAssocType<Assoc = ()>>() {}

        bar_inner::<Self>();
    }
}

This code compiles fine. However, when I modify the definition of Bar to trait Bar: HasAssocType, it fails:

error[E0271]: type mismatch resolving `<Self as HasAssocType>::Assoc == ()`
  --> src/lib.rs:18:21
   |
18 |         bar_inner::<Self>();
   |                     ^^^^ type mismatch resolving `<Self as HasAssocType>::Assoc == ()`
   |
note: expected this to be `()`
  --> src/lib.rs:8:18
   |
8  |     type Assoc = ();
   |                  ^^
   = note:    expected unit type `()`
           found associated type `<Self as HasAssocType>::Assoc`
   = help: consider constraining the associated type `<Self as HasAssocType>::Assoc` to `()`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `bar_inner`
  --> src/lib.rs:16:38
   |
16 |         fn bar_inner<T: HasAssocType<Assoc = ()>>() {}
   |                                      ^^^^^^^^^^ required by this bound in `bar_inner`

I'm surprised by this - the existing Self: Foo bound on fn bar was previously sufficient to constrain <Self as HasAssocType>::Assoc == (), so I don't understand why further constraining Self: HasAssocType would somehow cause that to no longer hold.

cc @CAD97

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 21, 2023
@compiler-errors
Copy link
Member

This is a somewhat known bug, where a where clause will shadow a blanket impl. For the record, this is ~approximately impossible to solve with the old trait solver, but should be fixed by (or at least we're aware of it in) the new solver (rust-lang/trait-system-refactor-initiative#12).

@joshlf
Copy link
Contributor Author

joshlf commented Aug 21, 2023

I ended up figuring out how to work around the issue thankfully:

fn try_read_from(bytes: &[u8]) -> Option<Self>
where
    Self: Sized,
{
    // TODO(https://github.com/rust-lang/rust/issues/115080): Inline this
    // function once #115080 is resolved.
    #[inline(always)]
    fn try_read_from_inner<T: Sized, F: FnOnce(&MaybeValid<T>) -> bool>(
        bytes: &[u8],
        is_bit_valid: F,
    ) -> Option<T> {
        let maybe_valid = MaybeValid::<T>::read_from(bytes)?;

        if is_bit_valid(&maybe_valid) {
            Some(unsafe { maybe_valid.assume_valid() })
        } else {
            None
        }
    }

    try_read_from_inner(bytes, Self::is_bit_valid)
}

The idea is that I actually remove trait information from T in try_read_from_inner, and that seems to get the trait solver unstuck.

(This fix doesn't really have an analogue in the minimized example that I provided in the original issue description, so I'm just pasting the actual fix, not a minimized version of it.)

@compiler-errors
Copy link
Member

Yes, the "fix" is to remove any redundant where clauses that conflict with blanket impls that are known to hold, or to explicitly annotate those where clauses with the associated type bounds that would be inferred from that where clause.

@joshlf
Copy link
Contributor Author

joshlf commented Aug 21, 2023

Mmmk well thanks for the background! The fix unblocks me for now.

@Cerber-Ursi
Copy link
Contributor

For the record, this sounds close (if not duplicating) to #24066.

@Noratrieb Noratrieb added A-trait-system Area: Trait system T-types Relevant to the types team, which will review and decide on the PR/issue. C-bug Category: This is a bug. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Aug 22, 2023
@joshlf
Copy link
Contributor Author

joshlf commented Sep 4, 2023

I ran into this issue again, but now in a more fundamental way because it appears in the definition of a trait impl rather than in a method body that I can refactor.

This works fine:

unsafe impl<T: Sized> TryFromBytes for MaybeUninit<T> {
    fn is_bit_valid(_c: &MaybeValid<MaybeUninit<T>>) -> bool {
        true
    }
}

However, when I add a T: TryFromBytes bound (which I need to for the impl to be sound), I get this error:

error[E0277]: the size for values of type `<T as AsMaybeUninit>::MaybeUninit` cannot be known at compilation time
    --> src/lib.rs:1873:38
     |
1873 | unsafe impl<T: TryFromBytes + Sized> TryFromBytes for MaybeUninit<T> {
     |                                      ^^^^^^^^^^^^ doesn't have a size known at compile-time
     |
     = help: within `MaybeUninit<T>`, the trait `Sized` is not implemented for `<T as AsMaybeUninit>::MaybeUninit`
note: required because it appears within the type `MaybeUninit<T>`
    --> src/lib.rs:1507:12
     |
1507 | pub struct MaybeUninit<T: AsMaybeUninit + ?Sized> {
     |            ^^^^^^^^^^^
note: required for `MaybeUninit<T>` to implement `AsMaybeUninit`
    --> src/lib.rs:1703:23
     |
1703 | unsafe impl<T: Sized> AsMaybeUninit for T {
     |                       ^^^^^^^^^^^^^     ^
note: required by a bound in `TryFromBytes`
    --> src/lib.rs:599:32
     |
599  | pub unsafe trait TryFromBytes: AsMaybeUninit {
     |                                ^^^^^^^^^^^^^ required by this bound in `TryFromBytes`
help: consider further restricting the associated type
     |
1873 | unsafe impl<T: TryFromBytes + Sized> TryFromBytes for MaybeUninit<T> where <T as AsMaybeUninit>::MaybeUninit: Sized {

I haven't found a good way to minimize this, but the code is available here; just git clone and then cargo check (don't run cargo check --tests; the tests are broken for other reasons because I came across this bug while in the middle of implementing something else). If you're going to poke at this, also note that MaybeUninit here is our own locally-defined type, not the one from the standard library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-trait-system Area: Trait system C-bug Category: This is a bug. 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

5 participants