Skip to content

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

New issue

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

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

Already on GitHub? # to your account

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
@fmease fmease added A-trait-system Area: Trait system and removed A-trait-system Area: Trait system labels Dec 21, 2024
# for free to join this conversation on GitHub. Already have an account? # 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

4 participants