Skip to content

Trait bound on associated type causes confusing compilation error #58231

Open
@igowen

Description

@igowen

This code fails to compile:

pub trait Append<T> {
    type Appended;
}

pub trait Proc {
    type Item;
    type Tail;
    fn process_item<P>(&mut self, partial: P)
    where
        P: Append<Self::Item>,
        P::Appended: Append<Self::Tail>;
}

struct Read;

impl Proc for Read {
    type Item = i32;
    type Tail = i64;
    fn process_item<P>(&mut self, partial: P)
    where
        P: Append<Self::Item>,
        P::Appended: Append<Self::Tail>,
    {
        
    }
}
error[E0277]: the trait bound `P: Append<i32>` is not satisfied
  --> src/lib.rs:19:5
   |
19 | /     fn process_item<P>(&mut self, partial: P)
20 | |     where
21 | |         P: Append<Self::Item>,
22 | |         P::Appended: Append<Self::Tail>,
23 | |     {
24 | |         
25 | |     }
   | |_____^ the trait `Append<i32>` is not implemented for `P`
   |
   = help: consider adding a `where P: Append<i32>` bound

The error is confusing because Self::Item is i32. Furthermore, changing the bound on P to the suggested bound (setting aside the fact that this is a trait impl so imposing additional bounds isn't necessarily appropriate) yields an even more confusing error:

error[E0277]: the trait bound `P: Append<i32>` is not satisfied
  --> src/lib.rs:19:5
   |
19 | /     fn process_item<P>(&mut self, partial: P)
20 | |     where
21 | |         P: Append<i32>,
22 | |         P::Appended: Append<Self::Tail>,
23 | |     {
24 | |         
25 | |     }
   | |_____^ the trait `Append<i32>` is not implemented for `P`
   |
   = help: consider adding a `where P: Append<i32>` bound

error[E0276]: impl has stricter requirements than trait
  --> src/lib.rs:19:5
   |
8  | /     fn process_item<P>(&mut self, partial: P)
9  | |     where
10 | |         P: Append<Self::Item>,
11 | |         P::Appended: Append<Self::Tail>;
   | |________________________________________- definition of `process_item` from trait
...
19 | /     fn process_item<P>(&mut self, partial: P)
20 | |     where
21 | |         P: Append<i32>,
22 | |         P::Appended: Append<Self::Tail>,
23 | |     {
24 | |         
25 | |     }
   | |_____^ impl has extra requirement `P: Append<i32>`

error: aborting due to 2 previous errors

Adding an additional type parameter to the fn and using that as the bound on P::Appended appears to work fine, and i think it is semantically equivalent (although applying the bound directly to the associated type is cleaner IMO):

pub trait Append<T> {
    type Appended;
}

pub trait Proc {
    type Item;
    type Tail;
    fn process_item<P, T>(&mut self, partial: P)
    where
        P: Append<Self::Item, Appended = T>,
        T: Append<Self::Tail>;
}

struct Read;

impl Proc for Read {
    type Item = i32;
    type Tail = i64;
    fn process_item<P, T>(&mut self, partial: P)
    where
        P: Append<i32, Appended = T>,
        T: Append<Self::Tail>,
    {

    }
}

Should the original code compile? If not, the error message (and suggested fix) is monumentally unhelpful. Otherwise, if it should compile, this looks like a compiler bug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)A-diagnosticsArea: Messages for errors, warnings, and lintsC-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions