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

Closed
ytausky opened this issue Sep 6, 2018 · 11 comments
Labels
A-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. A-traits Area: Trait system A-typesystem Area: The type system C-bug Category: This is a bug. WG-traits Working group: Traits, https://internals.rust-lang.org/t/announcing-traits-working-group/6804

Comments

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

@Centril Centril added A-typesystem Area: The type system A-traits Area: Trait system A-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. WG-traits Working group: Traits, https://internals.rust-lang.org/t/announcing-traits-working-group/6804 labels Sep 7, 2018
@jonhoo
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.

@matprec
Copy link
Contributor

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 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 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 minimized.

@rustbot rustbot added the C-bug Category: This is a bug. label Aug 12, 2019
@matprec
Copy link
Contributor

matprec commented Dec 18, 2019

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

@matprec
Copy link
Contributor

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 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 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 :)

@jackh726
Copy link
Member

Closing since fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: impl Trait. Universally / existentially quantified anonymous types with static dispatch. A-traits Area: Trait system A-typesystem Area: The type system C-bug Category: This is a bug. WG-traits Working group: Traits, https://internals.rust-lang.org/t/announcing-traits-working-group/6804
Projects
None yet
Development

No branches or pull requests

7 participants