Struct and variant constructors are not generic over lifetimes like regular functions.

2c47dd4
Opened by Eduard-Mihai Burtescu at 2019-11-13 23:10:06

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

  1. 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

  2. @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

  3. Submitted ICE separately as #30906.

    Eduard-Mihai Burtescu at 2016-01-14 16:25:34

  4. 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 errors
    

    Steve Klabnik at 2019-09-22 14:54:46

  5. @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