Skip to content

Generic bounds are used overzealously #82170

@RustyYato

Description

@RustyYato

I tried this code:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d10a2b403aee136b0426cc7f602d51ef

pub trait Callable<A> {
    type Output;
}

pub struct Call<A>(A);

impl<F: FnOnce(A) -> B, A, B> Callable<F> for Call<A> {
    type Output = B;
}

impl<A> Call<A> {
    fn build<F>(f: F) -> impl FnOnce(A) -> <Self as Callable<F>>::Output
    where
        Self: Callable<F>
    {
        move |a| todo!()
    }
}

fn foo<F>(f: F)
where
    Call<()>: Callable<F>
{
    Call::build(Call::build(f));
}

fn bar() {
    Call::build(Call::build(|()| 0));
}

I expected it to compile, but it doesn't. Instead, I get the following compile error:

error[E0308]: mismatched types
  --> src/lib.rs:25:17
   |
13 |     fn build<F>(f: F) -> impl FnOnce(A) -> <Self as Callable<F>>::Output
   |                          ----------------------------------------------- the found opaque type
...
21 | fn foo<F>(f: F)
   |        - this type parameter
...
25 |     Call::build(Call::build(f));
   |                 ^^^^^^^^^^^^^^ expected type parameter `F`, found opaque type
   |
   = note: expected type parameter `F`
                 found opaque type `impl FnOnce<((),)>`
   = help: type parameters must be constrained to match other types
   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

This is unusual because Call::build is implemented for all types F: FnOnce(A) -> _ (through the Callable trait), and since Call::build returns a type that implements FnOnce(A) -> _, it should be possible to recursively call Call::bulid if the first one succeeds. However, Rust overzelously assumes that Call::build can only be called with F (the concrete type parameter) instead of any type that implements FnOnce(A) -> _. (I'm trying to abstract over Fn* traits for a single argument, so this is road bump is annoying to work around, it requires duplicating all applicable functions).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-inferenceArea: Type inferenceA-trait-systemArea: Trait systemC-bugCategory: This is a bug.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions