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

Inconsistency regarding inferring trait bounds of an associated type: this causes paradox when trying to generically implement the trait #116200

Open
BaxHugh opened this issue Sep 27, 2023 · 1 comment
Labels
A-associated-items Area: Associated items (types, constants & functions) 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.

Comments

@BaxHugh
Copy link

BaxHugh commented Sep 27, 2023

This issue relates to implied trait bounds in trait definitions / impls. There maybe a wider issue / tracker issue this relates to. I've looked and don't think I can find a duplicate.

This probably falls somewhere under the tracker issue Extended Implied Trait Bounds.

I tried this code:

trait StoresItem {
    type Item: Clone;
    fn bar(&self) {}
}

// #region Implement on structs
struct MyBar<T> {
    t: T,
}
impl<T> StoresItem for MyBar<T>
where
    T: Clone,
{
    type Item = T;
}

struct MyFoo0 {}
struct MyFoo1 {}

// #endregion

mod try_use_implied_trait_bounds {

    use super::*;

    trait Foo {
        // trait StoresItem specifies that StoresItem::Item: Clone
        // so there's no need for Foo to specify that
        // and this is one of the few places where the compiler can infer that trait bound.
        // so the compiler doesn't complain here.
        type Bar<T>: StoresItem<Item = T>;
    }

    // But if we try and implement Foo, we can't because of the paradox in trait bounds.
    // Therefore, for consistency, without the support of implied trait bounds, the above should not compile.
    // The non erroring of the above gave us false hope that trait bounds are implied, but alas, currently they are not.

    impl Foo for MyFoo0 {
        // What if we assume the compiler can again imply that T: Clone?
        //
        // Error: 'the trait bound `T: Clone` is not satisfied
        //         required for `MyBar<T>` to implement `StoresItem`
        //         required by a bound in `Foo::Bar`'
        type Bar<T> = MyBar<T>;
    }
    impl Foo for MyFoo1 {
        // Ok, what if we appease the compiler and specify that T: Clone so that Foo::Bar<T> is satisfied?
        //
        // Error: 'impl has stricter requirements than trait
        //         impl has extra requirement `T: Clone`'
        type Bar<T> = MyBar<T> where T: Clone;
    }
}

mod use_specified_trait_bounds {

    use super::*;

    trait Foo {
        // Let's specify that T: Clone within Foo, even though this is implied by StoresItem, and the compiler appears to know this as seen above.
        type Bar<T>: StoresItem<Item = T>
        where
            T: Clone;
    }

    impl Foo for MyFoo0 {
        // The compiler can't see here that MyBar<T> implies T: Clone within this context.
        // Error: 'the trait bound `T: Clone` is not satisfied...'
        type Bar<T> = MyBar<T>;
    }

    impl Foo for MyFoo1 {
        // This works
        type Bar<T> = MyBar<T> where T: Clone;
    }
}

I expected the compiler to be consistent at all stages of the definition / use of the trait Foo (Ideally the compiler would imply trait bounds more globally here anyway)

  • i.e. either that first definition of trait try_use_implied_trait_bounds::Foo { type Bar<T>: StoresItem<Item = T>} which does not specify T: Clone would not compile / should be flagged as invalid by the compiler, because, as explained above, it cannot be implemented generically.

  • or that, the impls of try_use_implied_trait_bounds::Foo on MyFoo* should imply T: Clone in some way or another.

See the comments in the code for details / explanation.

Meta

rustc --version --verbose:

rustc 1.72.0 (5680fa18f 2023-08-23)
binary: rustc
commit-hash: 5680fa18feaa87f3ff04063800aec256c3d4b4be
commit-date: 2023-08-23
host: x86_64-unknown-linux-gnu
release: 1.72.0
LLVM version: 16.0.5
rustc 1.74.0-nightly (5ae769f06 2023-09-26)
binary: rustc
commit-hash: 5ae769f06bbe2afc50cde219757a5915e61ba365
commit-date: 2023-09-26
host: x86_64-unknown-linux-gnu
release: 1.74.0-nightly
LLVM version: 17.0.0
rustc 1.73.0-beta.7 (7c76587ed 2023-09-22)
binary: rustc
commit-hash: 7c76587edc7f5edb73cb8a1c45faa352cd036c62
commit-date: 2023-09-22
host: x86_64-unknown-linux-gnu
release: 1.73.0-beta.7
LLVM version: 17.0.0
@BaxHugh BaxHugh added the C-bug Category: This is a bug. label Sep 27, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Sep 27, 2023
@BaxHugh
Copy link
Author

BaxHugh commented Sep 27, 2023

This could be similar to #41118

@jieyouxu jieyouxu added A-trait-system Area: Trait system A-associated-items Area: Associated items (types, constants & functions) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Feb 18, 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-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.
Projects
None yet
Development

No branches or pull requests

3 participants