Struct and variant constructors are not generic over lifetimes like regular functions.
The following testcase produces the errors noted in comments and the last one is an ICE (run on playpen):
#![feature(fn_traits, unboxed_closures)]
fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {}
struct Compose<F,G>(F,G);
impl<T,F,G> FnOnce<(T,)> for Compose<F,G>
where F: FnOnce<(T,)>, G: FnOnce<(F::Output,)> {
type Output = G::Output;
extern "rust-call" fn call_once(self, (x,): (T,)) -> G::Output {
(self.1)((self.0)(x))
}
}
struct Str<'a>(&'a str);
fn mk_str<'a>(s: &'a str) -> Str<'a> { Str(s) }
fn main() {
let _: for<'a> fn(&'a str) -> Str<'a> = mk_str;
// expected concrete lifetime, found bound lifetime parameter 'a
let _: for<'a> fn(&'a str) -> Str<'a> = Str;
test(|_: &str| {});
test(mk_str);
// expected concrete lifetime, found bound lifetime parameter 'x
test(Str);
test(Compose(|_: &str| {}, |_| {}));
test(Compose(mk_str, |_| {}));
// internal compiler error: cannot relate bound region:
// ReLateBound(DebruijnIndex { depth: 2 },
// BrNamed(DefId { krate: 0, node: DefIndex(6) => test::'x }, 'x(65)))
//<= ReSkolemized(0,
// BrNamed(DefId { krate: 0, node: DefIndex(6) => test::'x }, 'x(65)))
test(Compose(Str, |_| {}));
}
The same errors occur if an enum Foo<'a> { Str(&'a str) } is used.
Usage of FnOnce<(T,)> is to avoid proving an explicit type parameter for the Output associated type, as an workaround for #30867.
Originally found in @asajeffrey's wasm repo (see my comment on asajeffrey/wasm#1). cc @nikomatsakis @arielb1
It's not as simple as making all regions late-bound; we'd have to use similar logic to what we use for fns I guess, where we distinguish the early-vs-late based on whether they are in use by where clauses. I imagine we don't do so because, when the struct or enum is used as a type, all the regions are always early bound.
Niko Matsakis at 2016-01-14 16:21:18
@nikomatsakis I wouldn't expect anything less (than having the same logic for both constructors and free functions).
Eduard-Mihai Burtescu at 2016-01-14 16:22:58
Submitted ICE separately as #30906.
Eduard-Mihai Burtescu at 2016-01-14 16:25:34
Triage: The ICE has been fixed, and the error message is now:
error[E0308]: mismatched types --> src/main.rs:20:45 | 20 | let _: for<'a> fn(&'a str) -> Str<'a> = Str; | ^^^ expected concrete lifetime, found bound lifetime parameter 'a | = note: expected type `for<'a> fn(&'a str) -> Str<'a>` found type `fn(&str) -> Str<'_> {Str::<'_>}` error[E0631]: type mismatch in function arguments --> src/main.rs:25:10 | 3 | fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {} | -------------------------------------------- required by `test` ... 14 | struct Str<'a>(&'a str); | ------------------------ found signature of `fn(&str) -> _` ... 25 | test(Str); | ^^^ expected signature of `for<'x> fn(&'x str) -> _` error: aborting due to 2 previous errorsSteve Klabnik at 2019-09-22 14:54:46
@steveklabnik Oops, I missed your comment - the ICE is #30906, not this issue. This issue is about the example erroring (which is IMO a bug).
Eduard-Mihai Burtescu at 2019-11-13 23:09:43