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

Unrecognized associated type bound on another associated type #24159

Open
kvark opened this Issue Apr 7, 2015 · 8 comments

Comments

Projects
None yet
@kvark
Copy link
Contributor

kvark commented Apr 7, 2015

trait Bar<T> { fn dummy(&self); }
trait Car<T> { fn dummy(&self); }

trait Foo {
    type A;
    type B: Bar<Self::A>;
    type C: Car<Self::A>;

    fn get_b(&self) -> &Self::B;
}

fn test_bar<A, B: Bar<A>>(_: &B) {}

fn test<A, F: Foo<A=A>>(f: &F) {
    test_bar(f.get_b());
}

Gives me:

<anon>:15:16: 15:23 error: the trait `Bar<A>` is not implemented for the type `<F as Foo>::B` [E0277]
<anon>:15     test_bar(f.get_b());
                         ^~~~~~~
<anon>:15:16: 15:23 error: the trait `Car<A>` is not implemented for the type `<F as Foo>::C` [E0277]
<anon>:15     test_bar(f.get_b());
                         ^~~~~~~
error: aborting due to 2 previous errors
playpen: application terminated with error code 101

There is a workaround:

fn test<A, B: Bar<A>, C: Car<A>, F: Foo<A=A, B=B, C=C>>(f: &F) {
    test_bar(f.get_b());
}

But it's ugly and should not be necessary.

We hit this problem a lot with gfx::Device, and I'd like to see cleaner use of it without explicit CommandBuffer bounds that we use as a workaround.

@apasel422

This comment has been minimized.

Copy link
Member

apasel422 commented Apr 7, 2015

This may be related to #23481.

@Mark-Simulacrum

This comment has been minimized.

Copy link
Member

Mark-Simulacrum commented May 16, 2017

Edited original post to remove PhantomFn bounds, they're no longer needed. Issue still reproduces:

error[E0277]: the trait bound `<F as Foo>::B: Bar<A>` is not satisfied
  --> test.rs:14:1
   |
14 | / fn test<A, F: Foo<A=A>>(f: &F) {
15 | |     test_bar(f.get_b());
16 | | }
   | |_^ the trait `Bar<A>` is not implemented for `<F as Foo>::B`
   |
   = help: consider adding a `where <F as Foo>::B: Bar<A>` bound
   = note: required by `Foo`

error[E0277]: the trait bound `<F as Foo>::C: Car<A>` is not satisfied
  --> test.rs:14:1
   |
14 | / fn test<A, F: Foo<A=A>>(f: &F) {
15 | |     test_bar(f.get_b());
16 | | }
   | |_^ the trait `Car<A>` is not implemented for `<F as Foo>::C`
   |
   = help: consider adding a `where <F as Foo>::C: Car<A>` bound
   = note: required by `Foo`

error: aborting due to 2 previous errors
@rkarp

This comment has been minimized.

Copy link
Contributor

rkarp commented Dec 10, 2017

A lot of related issues for this have been opened over time.

Duplicates: #37808, #39532, #40093, #48674, #54375, #54844

Probably same underlying cause: #32722, #37883, #38917, #43475, #47897, #54149

There's also a related discussion on the Rust forums: https://users.rust-lang.org/t/bounds-on-associated-types-enforced-too-soon/12948

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Mar 13, 2018

Mildly simplified:

trait Bar<T> { fn dummy(&self); }

trait Foo {
    type A;
    type B: Bar<Self::A>;

    fn get_b(&self) -> &Self::B;
}

fn test_bar<A, B: Bar<A>>(_: &B) {}

fn test<A, F: Foo<A=A>>(f: &F) {
    test_bar(f.get_b());
}

fn main() { }

So, probably the fix is "just" that we need to do some normalization somewhere or other. My preference is to fix this by moving over to lazy normalization and chalk, which will do away with these sorts of shortcomings for good. But it's probably worth looking to see if this can be fixed a touch more rapidly by adding a normalization in the right place. I'll try to do that in a bit and mentor/open a fix if it seems reasonable.

@malbarbo

This comment has been minimized.

Copy link
Contributor

malbarbo commented Jun 20, 2018

Any progress here @nikomatsakis?

@ZerothLaw

This comment has been minimized.

Copy link

ZerothLaw commented Aug 17, 2018

Looks like the issue is known and mentioned at this line: https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/check/compare_method.rs#L252

This indicates this may be the area to check in when working on this? Still working on understanding a lot of this code, so I'm not sure.

@daboross

This comment has been minimized.

Copy link
Contributor

daboross commented Aug 26, 2018

Ran into this as well. Here's my minimal test case:

trait Bar<T> {}
trait Caz {
    type A;
    type B: Bar<Self::A>;
}

fn test<T, U>() where T: Caz, U: Caz<A = T::A> {}
error[E0277]: the trait bound `<U as Caz>::B: Bar<<T as Caz>::A>` is not satisfied
 --> src/main.rs:7:1
  |
7 | fn test<T, U>() where T: Caz, U: Caz<A = T::A> {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar<<T as Caz>::A>` is not implemented for `<U as Caz>::B`
  |
  = help: consider adding a `where <U as Caz>::B: Bar<<T as Caz>::A>` bound
note: required by `Caz`
 --> src/main.rs:2:1
  |
2 | trait Caz {
  | ^^^^^^^^^
@elidupree

This comment has been minimized.

Copy link

elidupree commented Mar 26, 2019

I've just run into this issue in one of my own projects, and reduced it to a test case that's even simpler than the last one:

trait Bar<T> {}
trait Caz {
    type A;
    type B: Bar<Self::A>;
}
fn test<T: Caz<A = ()>>() {}

Although it compiles successfully if you add the bizarrely-tautological-looking where T::B: Bar<T::A>.

For now, I'm stuck with adding the where clause, but that's putting a LOT of boilerplate in my code (the actual where clause is 71 characters long and appears in dozens of places, including being de-facto required in code that uses my library, not just inside the library itself). Is there any progress on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.