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

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 · 10 comments

Comments

@ytausky
Copy link
Contributor

@ytausky 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
Copy link

@vitalyd 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
Copy link
Contributor

@jonhoo 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.

@matprec
Copy link
Contributor

@matprec matprec 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

@matprec
Copy link
Contributor

@matprec matprec 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?

@matprec
Copy link
Contributor

@matprec matprec 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());
}
@matprec

This comment has been hidden.

@rustbot rustbot added the C-bug label Aug 12, 2019
@matprec
Copy link
Contributor

@matprec matprec commented Dec 18, 2019

The above minimzation compiles when using chalk with rustc foo.rs -Z chalk

@matprec
Copy link
Contributor

@matprec matprec commented Jul 9, 2020

With the somewhat recent update of chalk, it doesn't compile anymore and the issue is still present.

@matprec
Copy link
Contributor

@matprec matprec commented Jul 18, 2020

The above minimization can be made to compile on stable when fully spelling out the bound:

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

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

fn test<C: Fn(usize), F: Foo<Arg = usize, Assoc = C>>(this: F) {
    F::baz(F::assoc());
}
@matprec
Copy link
Contributor

@matprec matprec commented Mar 9, 2021

#55697 being closed made me re-check the status of this issue and now all of the above minimal examples now compile since Rust 1.49, so this issue can be closed i think :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants