Skip to content

Using GATs with other associated types sometimes claims those types don't satisfy their supertraits #88405

Closed
@kahomayo

Description

@kahomayo

Using an associated type as an argument to a GAT will sometimes fail with an incorrect [E0277] "trait bound is not satisfied" error, when that type is used to constrain an associated type of another trait.

#![feature(generic_associated_types)]

trait SomeTrait {}
trait OtherTrait { type Item; }

trait ErrorSimpleExample {
    type AssociatedType: SomeTrait;
    type GatBounded<T: SomeTrait>;
    type ErrorMinimal: OtherTrait<Item = Self::GatBounded<Self::AssociatedType>>;
}

Playground link including the other examples in this issue

This code should compile fine. In particular, Self::GatBounded<Self::AssociatedType> should be valid because Self::AssociatedType is constrained to implement SomeTrait.

However, the compilation fails with the following error:

error[E0277]: the trait bound `<Self as ErrorSimpleExample>::AssociatedType: SomeTrait` is not satisfied
 --> src/lib.rs:9:35
  |
9 |     type ErrorMinimal: OtherTrait<Item = Self::GatBounded<Self::AssociatedType>>;
  |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait` is not implemented for `<Self as ErrorSimpleExample>::AssociatedType`
  |
note: required by a bound in `ErrorSimpleExample::GatBounded`
 --> src/lib.rs:8:24
  |
8 |     type GatBounded<T: SomeTrait>;
  |                        ^^^^^^^^^ required by this bound in `ErrorSimpleExample::GatBounded`
help: consider further restricting the associated type
  |
6 | trait ErrorSimpleExample where <Self as ErrorSimpleExample>::AssociatedType: SomeTrait {
  |                          +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

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

The trait bound Self::AssociatedType: SomeTrait is obviously satisfied, so something is wrong here. The suggested where clause does not fix the error, instead the compiler will suggest you add another one.

Adding the same bound again and again

#![feature(generic_associated_types)]

trait SomeTrait {}
trait OtherTrait {
    type Item;
}

trait ErrorSimpleExample
where
    <Self as ErrorSimpleExample>::AssociatedType: SomeTrait,
    <Self as ErrorSimpleExample>::AssociatedType: SomeTrait,
    <Self as ErrorSimpleExample>::AssociatedType: SomeTrait,
    <Self as ErrorSimpleExample>::AssociatedType: SomeTrait,
    <Self as ErrorSimpleExample>::AssociatedType: SomeTrait,
    <Self as ErrorSimpleExample>::AssociatedType: SomeTrait,
{
    type AssociatedType: SomeTrait;
    type GatBounded<T: SomeTrait>;
    type ErrorMinimal: OtherTrait<Item = Self::GatBounded<Self::AssociatedType>>;
}
help: consider further restricting the associated type
   |
15 |     <Self as ErrorSimpleExample>::AssociatedType: SomeTrait, <Self as ErrorSimpleExample>::AssociatedType: SomeTrait
   |    

Further observations

Spreading types over several traits causes the same issue

This error occurs even if the first two types, AssociatedType and GatBounded, are part of other traits (implemented either by Self or some generic type arguments).

trait ExampleSetup {
    type AssociatedTypeOfSomeTrait: SomeTrait;
    type GatBoundedOnSomeTrait<T: SomeTrait>;
}

trait ErrorUsingSupertrait: ExampleSetup {
    type ErrorSupertrait: OtherTrait<Item = Self::GatBoundedOnSomeTrait<Self::AssociatedTypeOfSomeTrait>>;
}

Error also happens in generic argument

trait ErrorInTraitArgument: ExampleSetup {
    type ErrorTraitArg: From<Self::GatBoundedOnSomeTrait<Self::AssociatedTypeOfSomeTrait>>;
}

Error affected by other items in trait

The error seems to be affected by the presence and ordering of other items in the trait. This code happily compiles:

trait OkInReturnBefore: ExampleSetup {
    fn ok_before_type() -> Self::GatBoundedOnSomeTrait<Self::AssociatedTypeOfSomeTrait>;
    type OkAfterFn: OtherTrait<Item = Self::GatBoundedOnSomeTrait<Self::AssociatedTypeOfSomeTrait>>;
}

But swapping the two items causes the above error:

trait ErrorInReturnAfter: ExampleSetup {
    type ErrorBeforeFn: OtherTrait<Item = Self::GatBoundedOnSomeTrait<Self::AssociatedTypeOfSomeTrait>>;
    fn error_after_type() -> Self::GatBoundedOnSomeTrait<Self::AssociatedTypeOfSomeTrait>;
}

Make sure to write each test in a separate trait to avoid other items messing with your testing. I initially thought the ErrorTraitArg example did not produce an error because I had put it into the same trait as other working examples.

Potentially related issue

I found another issue, #88287, that produces the same error message. However, I'm not sure if that is the same bug because I could not get Self::GatBounded<Self::AssociatedType> to error in only the return type position. That issue's example also uses the TAIT feature (which I'm unfamiliar with) so I was unable to reduce it enough to see similarities to my example.

Meta

rustc --version --verbose:

rustc 1.56.0-nightly (0afc20860 2021-08-25)
binary: rustc
commit-hash: 0afc20860eb98a29d9bbeea80f2acc5be38c6bf3
commit-date: 2021-08-25
host: x86_64-pc-windows-msvc
release: 1.56.0-nightly
LLVM version: 13.0.0

As well as rust playground 1.56.0-nightly (2021-08-25 0afc20860eb98a29d9bb)

@rustbot label +T-compiler +F-generic_associated_types +A-Traits +requires-nightly

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-GATsArea: Generic associated types (GATs)A-trait-systemArea: Trait systemC-bugCategory: This is a bug.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.F-generic_associated_types`#![feature(generic_associated_types)]` a.k.a. GATsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions