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

Rustc fails to infer appropriately general Fn* trait implementation in the face of complex HRTBs with GATs #99991

Open
Aiden2207 opened this issue Jul 31, 2022 · 3 comments
Labels
A-closures Area: Closures (`|…| { … }`) A-GATs Area: Generic associated types (GATs) A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-lifetimes Area: Lifetimes / regions C-bug Category: This is a bug. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@Aiden2207
Copy link

I tried this code:

#![feature(generic_associated_types)]
pub trait Func<'a, T> {
    type Output;
    fn invoke(&mut self, x: T) -> Self::Output;
}
impl<'a, T, U, F> Func<'a, T> for &'a mut F
where
    F: FnMut(T) -> U,
{
    type Output = U;
    fn invoke(&mut self, x: T) -> Self::Output {
        self(x)
    }
}
trait Foo {
    type Bar<'a>
    where
        Self: 'a;
    fn test<F>(f: F)
    where
        for<'a> &'a mut F: Func<'a, Self::Bar<'a>>;
}

impl Foo for () {
    type Bar<'a> = &'a ();
    fn test<F>(mut f: F)
    where
        for<'a> &'a mut F: Func<'a, Self::Bar<'a>>,
    {
        (&mut f).invoke(&());
    }
}
fn main() {
    let f: fn(&()) -> &() = |t| t;
    <()>::test(f); //works
    <()>::test(|t| t); //error
}

I expected to see this happen: Code compiles without errors.

Instead, this happened:

   Compiling playground v0.0.1 (/playground)
error: implementation of `FnOnce` is not general enough
  --> src/main.rs:33:5
   |
33 |     <()>::test(|t|t);  //error
   |     ^^^^^^^^^^ implementation of `FnOnce` is not general enough
   |
   = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
   = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`

error: could not compile `playground` due to previous error

Playground

The compiler needs closures to be explicitly coerced into a general enough type for the provided trait bounds to work. It's not the end of the world, because I can always use trait objects, but it's definitely an ergonomic issue. Also, it works just fine if you use a non-generic associated type.

Meta

Playground version:

1.64.0-nightly

(2022-07-30 0f4bcadb46006bc484da)
@Aiden2207 Aiden2207 added the C-bug Category: This is a bug. label Jul 31, 2022
@compiler-errors
Copy link
Member

compiler-errors commented Jul 31, 2022

This doesn't have to do with GATs really. If you replace Self::Bar<'a> with &'a () (i.e. inlining the GAT) then you get the same issue:

pub trait Func<'a, T> {
    type Output;
    fn invoke(&mut self, x: T) -> Self::Output;
}

impl<'a, T, U, F> Func<'a, T> for &'a mut F
where
    F: FnMut(T) -> U,
{
    type Output = U;
    fn invoke(&mut self, x: T) -> Self::Output {
        self(x)
    }
}
trait Foo {
    fn test<F>(f: F)
    where
        for<'a> &'a mut F: Func<'a, &'a ()>;
}

impl Foo for () {
    fn test<F>(mut f: F)
    where
        for<'a> &'a mut F: Func<'a, &'a ()>,
    {
        (&mut f).invoke(&());
    }
}

fn main() {
    <()>::test(|t| { t }); //error
}

@aliemjay
Copy link
Member

This is a known bug with closures where we fail to infer if the lifetime in an argument type is higher-ranked.

Minmized further to make it independent of GAT:

trait Func<T> {}
impl<T, F> Func<T> for F where F: Fn(T) {}

fn test<F>(_: F)
where
    for<'a> F: Func<&'a ()>,
{
}

fn main() {
    let f: fn(&()) = |t| {};
    test(f); //works
    test(|t| {}); //error
}

@rustbot label T-types A-closures A-lifetimes

@rustbot rustbot added A-closures Area: Closures (`|…| { … }`) A-lifetimes Area: Lifetimes / regions T-types Relevant to the types team, which will review and decide on the PR/issue. labels Jul 31, 2022
@fmease fmease added A-GATs Area: Generic associated types (GATs) A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) labels Sep 24, 2024
@grindvoll
Copy link

I just came across a version of this issue; the compiler refuses to accept a closure with an anonymous parameter (my example is very similar to the simplified code example posted on July 31. 2022). Are there any short term plans to fix this issue?

I did search for HRTB issues, and there are numerous open issues related to this. Wonder if there is a prioritized HRTB issue list in progress?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`) A-GATs Area: Generic associated types (GATs) A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-lifetimes Area: Lifetimes / regions C-bug Category: This is a bug. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants