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

impl Trait with associated type equality constraint fails to resolve when constraint contains associated type of non-parameter type #53984

Open
ytausky opened this Issue Sep 6, 2018 · 5 comments

Comments

Projects
None yet
5 participants
@ytausky
Copy link
Contributor

ytausky commented Sep 6, 2018

The following code fails to compile:

use std::iter::once;

trait TokenSpec {
    type Ident;
}

impl TokenSpec for String {
    type Ident = String;
}

struct Expr<I> {
    ident: I,
}

type Input = Expr<<String as TokenSpec>::Ident>;

fn foo() -> impl Iterator<Item = Input> {
    once(Expr { ident: "my_string".to_string() })
}

fn main() {
    let v: Vec<_> = foo().collect();
    println!("{:?}", v);
}

I get this error message:

error[E0271]: type mismatch resolving `<std::iter::Once<Expr<std::string::String>> as std::iter::Iterator>::Item == Expr<<std::string::String as TokenSpec>::Ident>`
  --> src/main.rs:17:13
   |
17 | fn foo() -> impl Iterator<Item = Input> {
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found associated type
   |
   = note: expected type `Expr<std::string::String>`
              found type `Expr<<std::string::String as TokenSpec>::Ident>`
   = note: the return type of a function must have a statically known size

I think this case should work, since <String as TokenSpec>::Ident can be resolved at type checking time.

@vitalyd

This comment has been minimized.

Copy link

vitalyd commented Sep 6, 2018

Worth mentioning that using a boxed (i.e. type erased) iterator as the return type works just fine, i.e.:

fn foo() -> Box<Iterator<Item = Input>> {
    Box::new(once(Expr { ident: "my_string".to_string() }))
}
@jonhoo

This comment has been minimized.

Copy link
Contributor

jonhoo commented Nov 19, 2018

Here's another instance of the same problem (playground):

trait Future {
    type Output;
}
impl<T> Future for T {
    type Output = T;
}

trait Service<Request> {
    type Error;
    type Future: Future<Output = Self::Error>;
    fn fail(&self, r: Request) -> Self::Future;
}

struct Foo;
struct A;

impl Service<A> for Foo {
    type Error = ();
    type Future = Self::Error;
    fn fail(&self, r: A) -> Self::Future {
        ()
    }
}

impl Foo {
    fn fail_fast(&self) -> impl Future<Output = <Self as Service<A>>::Error> {
        self.fail(A)
    }
}

And here too, boxing the return value instead of using impl Trait fixes the issue.

@MSleepyPanda

This comment has been minimized.

Copy link

MSleepyPanda commented Jan 17, 2019

I've hit this as well
This is rejected:

#![feature(impl_trait_in_bindings)]

trait Foo {
    type Arg;
    type Bar: Fn(&Self::Arg);

    fn bar(&self) -> Self::Bar;
}

struct X;

impl X {
    fn test<F>(this: F)
    where
        F: Foo<Arg = usize>,
    {
        let function: impl Fn(&F::Arg) = this.bar();
    }
}
error[E0277]: expected a `std::ops::Fn<(&usize,)>` closure, found `<F as Foo>::Bar`
  --> src/lib.rs:13:5
   |
13 | /     fn test<F>(this: F)
14 | |     where
15 | |         F: Foo<Arg = usize>,
16 | |     {
17 | |         let function: impl Fn(&F::Arg) = this.bar();
18 | |     }
   | |_____^ expected an `Fn<(&usize,)>` closure, found `<F as Foo>::Bar`

Playground

While this works as expected (missing the Foo<Arg=usize>)

#![feature(impl_trait_in_bindings)]

trait Foo {
    type Arg;
    type Bar: Fn(&Self::Arg);

    fn bar(&self) -> Self::Bar;
}

struct X;

impl X {
    fn test<F>(this: F)
    where
        F: Foo,
    {
        let function: impl Fn(&F::Arg) = this.bar();
    }
}

Playground

@MSleepyPanda

This comment has been minimized.

Copy link

MSleepyPanda commented Jan 30, 2019

I've hit this again, also on stable. I realize that sometimes, there is just not the manpower to tackle everyones issues, especially in OSS. Is there a way we could help with this?

@MSleepyPanda

This comment has been minimized.

Copy link

MSleepyPanda commented Feb 4, 2019

Further minimised on stable, playground:

trait Foo {
    type Arg;
    type Assoc: Fn(Self::Arg);

    fn assoc() -> Self::Assoc;
    fn baz(_: Self::Assoc);
}

fn test<F: Foo<Arg = usize>>(this: F) {
    F::baz(F::assoc());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment