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

Trait implementation solving fails for a closure #138805

Closed
akatsukilelouch opened this issue Mar 21, 2025 · 0 comments
Closed

Trait implementation solving fails for a closure #138805

akatsukilelouch opened this issue Mar 21, 2025 · 0 comments
Labels
C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.

Comments

@akatsukilelouch
Copy link

akatsukilelouch commented Mar 21, 2025

I tried this code:

struct Foo<A, B>(A, B);

#[allow(non_camel_case_types, dead_code)]
trait Fn_require_outlives_in_method<A, B> {
    // a for<'a> alternative that is type checked
    // at the call site
    fn call<'a>(self, value: &'a A) -> &'a B;
}

// impl the trait for FnOnce(&A) -> &B
impl<A, B, F: for<'a> FnOnce(&'a A) -> &'a B /* where A: 'a, B: 'a (trivial bounds) */>
Fn_require_outlives_in_method<A, B> for F {
    #[inline(always)]
    fn call<'a>(self, value: &'a A) -> &'a B {
        self(value)
    }
}

impl<A, B> Foo<A, B> {
    fn new(_value: A, _callback: impl Fn_require_outlives_in_method<A, B>) -> Self {
        todo!()
    }
}

fn check_fn_once_impl_universal_over_lifetime_a(_: impl for<'a> FnOnce(&'a i32) -> &'a i32) {}

fn main() {
    Foo::new(0, |e| e);
}

I expected to see this happen: compiles

Instead, this happened:

error: implementation of `FnOnce` is not general enough
  --> src/main.rs:28:5
   |
28 |     Foo::new(0, |e| e);
   |     ^^^^^^^^ implementation of `FnOnce` is not general enough
   |
   = note: closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`...
   = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2`

Other examples with comments:

fn check_fn_once_impl_universal_over_lifetime_a(_: impl for<'a> FnOnce(&'a i32) -> &'a i32) {}

fn main() {
    fn test(e: &i32) -> &i32 { e }

    // Foo::new(0, |e| e); // fails to compile (not general enough)
    // Foo::<i32, i32>::new(0, |e| e); // fails to compile (not general enough)

    check_fn_once_impl_universal_over_lifetime_a(|e| e); // ok

    Foo::new(0, for<'a> |e: &'a i32| -> &'a i32 { e }); // ok (experimental)
    Foo::new(0, test); // ok
}

Meta

rustc --version --verbose:

rustc 1.87.0-nightly (75530e9f7 2025-03-18)
binary: rustc
commit-hash: 75530e9f72a1990ed2305e16fd51d02f47048f12
commit-date: 2025-03-18
host: aarch64-apple-darwin
release: 1.87.0-nightly
LLVM version: 20.1.0
Backtrace


@akatsukilelouch akatsukilelouch added the C-bug Category: This is a bug. label Mar 21, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Mar 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged.
Projects
None yet
Development

No branches or pull requests

2 participants