You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Implementation of traits on functions ignored after function call #31730
In this example, I implement a trait on generic functions. One with mutability and one without. When invoked manually, the proper trait gets called. Instead, if I try to peel off the function's unique tag using another function, the traits are no longer visible.
traitFooFn{fnfoo(&self);}impl<T:Sized>FooFnforfn(&mutT)-> T{fnfoo(&self){println!("Generic (with mutable) match!");}}impl<T:Sized>FooFnforfn(T)->T{fnfoo(&self){println!("Generic match!");}}fnsimple_fn(x:i32) -> i32{1}fnsimple_fn2(x:&muti32) -> i32{2}fnstrip<T,U>(x:fn(T)->U) -> fn(T)->U{ x }fnmain(){//Works&(simple_fn asfn(i32)->i32).foo();//Also works&(simple_fn2 asfn(&muti32)->i32).foo();//Worksstrip(simple_fn).foo();//Error: no method named `foo` found for type `fn(&mut i32) -> i32`strip(simple_fn2).foo();}
This is an unfortunate issue with late-bound regions.
Your impl is for the type for<'a> fn(&'a mut T) -> T, while strip forces T to be concrete, so you have fn(&'α mut T) -> T for some (specific) lifetime α.
@arielb1 Assuming I understand what you're saying, it seems like the more specific lifetime still inhabits the space of the more generic lifetimes that the impl covers. If that's true, I'd expect that functionality to still be available, even when it's concrete.
Or are you saying that mechanically the decision of whether the type has the impl available to it has to be made earlier than the nailing down of the lifetime?
The issue is fundamentally a type mismatch; there are two different kinds of "generic" lifetime. It tends to be a bit confusing, since the syntax is very similar, and there are implicit conversions in some cases, but the error is legitimate.
To illustrate:
traitFooFn{fnfoo(&self);}implFooFnforfor<'a> fn(&'amuti32)-> i32{fnfoo(&self){println!("Generic (with mutable) match!");}}impl<'a>FooFnforfn(&'amuti32)-> i32{fnfoo(&self){println!("Generic lifetime match!");}}implFooFnforfn(i32)->i32{fnfoo(&self){println!("Generic match!");}}fnsimple_fn(x:i32) -> i32{1}fnsimple_fn2(x:&muti32) -> i32{2}fnstrip(x:fn(i32)->i32) -> fn(i32)->i32{ x }fnstrip2(x:fn(&muti32)->i32) -> fn(&muti32)->i32{ x }fnstrip3<'a>(x:fn(&'amuti32)->i32) -> fn(&'amuti32)->i32{ x }fnstrip4(x:fn(&'staticmuti32)->i32) -> fn(&'staticmuti32)->i32{ x }fnmain(){&(simple_fn asfn(i32)->i32).foo();&(simple_fn2 asfn(&muti32)->i32).foo();strip(simple_fn).foo();strip2(simple_fn2).foo();strip3(simple_fn2).foo();strip4(simple_fn2).foo();}
cc @rust-lang/wg-diagnostics when reporting that a trait is not implemented for a type, we should also search for impls that only differ in lifetimes and explain why/how the lifetimes are different
error[E0599]: no method named `foo` found for fn pointer `fn(&mut i32) -> i32` in the current scope
--> f103.rs:33:23
|
33 | strip(simple_fn2).foo();
| ^^^ method not found in `fn(&mut i32) -> i32`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `FooFn` defines an item `foo`, perhaps you need to implement it
--> f103.rs:1:1
|
1 | trait FooFn {
| ^^^^^^^^^^^
We still don't do what oli suggested, and we should.
Activity
arielb1 commentedon Feb 17, 2016
This is an unfortunate issue with late-bound regions.
Your impl is for the type
for<'a> fn(&'a mut T) -> T, whilestripforcesTto be concrete, so you havefn(&'α mut T) -> Tfor some (specific) lifetimeα.I agree that the error message could be better.
sophiajt commentedon Feb 17, 2016
@arielb1 Assuming I understand what you're saying, it seems like the more specific lifetime still inhabits the space of the more generic lifetimes that the impl covers. If that's true, I'd expect that functionality to still be available, even when it's concrete.
Or are you saying that mechanically the decision of whether the type has the impl available to it has to be made earlier than the nailing down of the lifetime?
eefriedman commentedon Feb 17, 2016
The issue is fundamentally a type mismatch; there are two different kinds of "generic" lifetime. It tends to be a bit confusing, since the syntax is very similar, and there are implicit conversions in some cases, but the error is legitimate.
To illustrate:
oli-obk commentedon Jan 25, 2020
cc @rust-lang/wg-diagnostics when reporting that a trait is not implemented for a type, we should also search for impls that only differ in lifetimes and explain why/how the lifetimes are different
estebank commentedon Feb 21, 2024
Current output:
We still don't do what oli suggested, and we should.
estebank commentedon Nov 11, 2025
We already currently have logic to check for alternative impls:
rust/compiler/rustc_hir_typeck/src/method/suggest.rs
Lines 3543 to 3593 in 25d319a
that we could expand to account for alternative fn signatures.
oli-obk commentedon Nov 13, 2025
can also try to use selection to ask the trait solver to find all impls that match if all lifetimes are replaced by infer vars
Something I did with
in #148641