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

Trait bounds on associated types of subtraits don't work correctly #54149

Closed
sicking opened this issue Sep 12, 2018 · 5 comments
Closed

Trait bounds on associated types of subtraits don't work correctly #54149

sicking opened this issue Sep 12, 2018 · 5 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system C-enhancement Category: An issue proposing an enhancement or a PR with one. D-confusing Diagnostics: Confusing error or lint that should be reworked. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@sicking
Copy link

sicking commented Sep 12, 2018

The following code does not compile:

trait MyTrait1 {
    type X;
    fn get_val(&self) -> Self::X;
}

trait MyTrait2: MyTrait1 where <Self as MyTrait1>::X: Into<u32> {}

struct MyStruct(u32);

impl MyTrait1 for MyStruct {
    type X = u32;
    fn get_val(&self) -> Self::X { self.0 }
}
impl MyTrait2 for MyStruct {}

fn myfunc<T: MyTrait2>(v: &T) {
    println!("{}", Into::<u32>::into(v.get_val()));
}

fn main() {
    let s = MyStruct(10);
    myfunc(&s);
}

It fails with

error[E0277]: the trait bound `u32: std::convert::From<<T as MyTrait1>::X>` is not satisfied
  --> src/main.rs:16:1
   |
16 | / fn myfunc<T: MyTrait2>(v: &T) {
17 | |     println!("{}", Into::<u32>::into(v.get_val()));
18 | | }
   | |_^ the trait `std::convert::From<<T as MyTrait1>::X>` is not implemented for `u32`
   |
   = help: consider adding a `where u32: std::convert::From<<T as MyTrait1>::X>` bound
   = note: required because of the requirements on the impl of `std::convert::Into<u32>` for `<T as MyTrait1>::X`
note: required by `MyTrait2`
  --> src/main.rs:6:1
   |
6  | trait MyTrait2: MyTrait1 where <Self as MyTrait1>::X: Into<u32> {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In fact, I haven't been able to come up with any syntax for myfunc which uses a trait bound using MyTrait2 that will compile once the trait bound X exists.

Changing the declaration of MyTrait2 to trait MyTrait2: MyTrait1<X=u32> {} does work, so it's clearly possible for super traits to put constraints on the associated types of subtraits. However I've only been able to create constraints that require the associated types to be of a particular type, not to require that they implement particular traits. I also tried trait MyTrait2: MyTrait1<X: Into<u32>> {}, however that just yielded a syntax error.

It's quite possible that I'm misunderstanding the meaning of the syntax in the original example above, and that I should create an RFC for supporting what I'm trying to accomplish above.

@rkarp
Copy link
Contributor

rkarp commented Oct 14, 2018

This is another issue with probably the same underlying cause as #24159. Here's how to fix your code:

trait MyTrait1 {
    type X;
    fn get_val(&self) -> Self::X;
}

trait MyTrait2: MyTrait1 where <Self as MyTrait1>::X: Into<u32> {}

struct MyStruct(u32);

impl MyTrait1 for MyStruct {
    type X = u32;
    fn get_val(&self) -> Self::X { self.0 }
}
impl MyTrait2 for MyStruct {}


fn myfunc<T>(v: &T)
where T: MyTrait2,
      <T as MyTrait1>::X: Into<u32>,
{
    println!("{}", Into::<u32>::into(v.get_val()));
}

fn main() {
    let s = MyStruct(10);
    myfunc(&s);
}

Funnily enough there is no error when you remove myfunc altogether. I guess rustc believes it's fine to declare Mytrait2 as long as you never actually use it.

@estebank estebank added A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 5, 2019
@estebank estebank added the D-confusing Diagnostics: Confusing error or lint that should be reworked. label Oct 8, 2019
@crlf0710 crlf0710 added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jun 11, 2020
@estebank
Copy link
Contributor

Current output:

error[E0277]: the trait bound `u32: std::convert::From<<T as MyTrait1>::X>` is not satisfied
  --> src/main.rs:16:14
   |
6  | trait MyTrait2: MyTrait1 where <Self as MyTrait1>::X: Into<u32> {}
   |                                                       --------- required by this bound in `MyTrait2`
...
16 | fn myfunc<T: MyTrait2>(v: &T) {
   |              ^^^^^^^^ the trait `std::convert::From<<T as MyTrait1>::X>` is not implemented for `u32`
   |
   = note: required because of the requirements on the impl of `std::convert::Into<u32>` for `<T as MyTrait1>::X`

A possible solution is to incorporate a new type param to restrict MyTrait2::X with:

fn myfunc<I: Into<u32>, T: MyTrait2<X = I>>(v: &T) {
    println!("{}", Into::<u32>::into(v.get_val()));
}

@estebank
Copy link
Contributor

estebank commented Feb 2, 2021

Triage: no change.

@estebank
Copy link
Contributor

estebank commented Aug 3, 2023

Current output suggests a fix:

error[E0277]: the trait bound `u32: From<<T as MyTrait1>::X>` is not satisfied
  --> src/main.rs:16:14
   |
16 | fn myfunc<T: MyTrait2>(v: &T) {
   |              ^^^^^^^^ the trait `From<<T as MyTrait1>::X>` is not implemented for `u32`
   |
   = note: required for `<T as MyTrait1>::X` to implement `Into<u32>`
note: required by a bound in `MyTrait2`
  --> src/main.rs:6:55
   |
6  | trait MyTrait2: MyTrait1 where <Self as MyTrait1>::X: Into<u32> {}
   |                                                       ^^^^^^^^^ required by this bound in `MyTrait2`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
   |
16 | fn myfunc<T: MyTrait2>(v: &T) where u32: From<<T as MyTrait1>::X> {
   |                               +++++++++++++++++++++++++++++++++++

@estebank estebank closed this as completed Aug 3, 2023
@robertbastian
Copy link
Contributor

Why does myfunc need the <T as MyTrait1>::X: Into<u32> bound? It already has T: MyTrait2, which implies <T as MyTrait1>::X: Into<u32>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system C-enhancement Category: An issue proposing an enhancement or a PR with one. D-confusing Diagnostics: Confusing error or lint that should be reworked. 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

5 participants