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

The "type_alias_impl_trait" feature has problems handling lifetime parameters. #69137

Open
steffahn opened this issue Feb 13, 2020 · 5 comments
Labels
A-closures Area: closures (`|args| { .. }`) A-lifetimes Area: lifetime related C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@steffahn
Copy link
Member

steffahn commented Feb 13, 2020

I was starting with this function (which does compile on nightly):

#![feature(unboxed_closures)]
#![feature(type_alias_impl_trait)]
fn curry<'a, A: 'a, B, C, F: Fn(A, B) -> C> (f: &'a F)
    -> impl Fn<(A,), Output = impl FnOnce(B) -> C + 'a> + 'a
{
    move |a| move |b| f(a,b)
}

and wanted to give a name to its return type.
The straightforward approach seems to be (please correct me if the "right" way to do this is different):

#![feature(unboxed_closures)]
#![feature(type_alias_impl_trait)]
type Curried<'a, A: 'a, B, C, F: Fn(A, B) -> C>
 = impl Fn<(A,), Output = impl FnOnce(B) -> C + 'a> + 'a;

fn curry<'a, A: 'a, B, C, F: Fn(A, B) -> C> (f: &'a F)
    -> Curried<'a, A, B, C, F>
{
    move |a| move |b| f(a,b)
}

But the compiler is currently unhappy with the lifetimes. I'm getting the following.

error: cannot infer an appropriate lifetime
  --> src/main.rs:11:5
   |
6  |  = impl Fn<(A,), Output = impl FnOnce(B) -> C + 'a> + 'a;
   |                           ------------------------ this return type evaluates to the `'static` lifetime...
...
11 |     move |a| move |b| f(a,b)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ ...but this borrow...
   |
note: ...can't outlive the lifetime `'a` as defined on the function body at 8:10
  --> src/main.rs:8:10
   |
8  | fn curry<'a, A: 'a, B, C, F: Fn(A, B) -> C> (f: &'a F)
   |          ^^
help: you can add a bound to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 8:10
   |
9  |     -> Curried<'a, A, B, C, F> + '_
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: cannot infer an appropriate lifetime
  --> src/main.rs:11:14
   |
6  |  = impl Fn<(A,), Output = impl FnOnce(B) -> C + 'a> + 'a;
   |                           ------------------------ this return type evaluates to the `'static` lifetime...
...
11 |     move |a| move |b| f(a,b)
   |              ^^^^^^^^^^^^^^^ ...but this borrow...
   |
note: ...can't outlive the lifetime `'a` as defined on the function body at 8:10
  --> src/main.rs:8:10
   |
8  | fn curry<'a, A: 'a, B, C, F: Fn(A, B) -> C> (f: &'a F)
   |          ^^
help: you can add a bound to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 8:10
   |
9  |     -> Curried<'a, A, B, C, F> + '_
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

It works without the lifetimes (i.e. after removing parametrization over 'a and replacing all occurrences of 'a with 'static), like this:

#![feature(unboxed_closures)]
#![feature(type_alias_impl_trait)]
type Curried<A: 'static, B, C, F: Fn(A, B) -> C>
 = impl Fn<(A,), Output = impl FnOnce(B) -> C + 'static> + 'static;

fn curry<A: 'static, B, C, F: Fn(A, B) -> C> (f: &'static F)
    -> Curried<A, B, C, F>
{
    move |a| move |b| f(a,b)
}

use std::ops::Add;
fn main() {
    let x = curry(&i32::add)(1)(2);
    println!("{}", x); // prints "3"
}

Meta

Current behavior only since #67844 was fixed (after nightly-2020-02-14). Before that, this code triggered an ICE.

@steffahn steffahn added the C-bug Category: This is a bug. label Feb 13, 2020
@steffahn steffahn changed the title The "type alias impl trait" feature has Problems handling lifetime parameters. The "type alias impl trait" feature has problems handling lifetime parameters. Feb 13, 2020
@steffahn steffahn changed the title The "type alias impl trait" feature has problems handling lifetime parameters. The "type_alias_impl_trait" feature has problems handling lifetime parameters. Feb 13, 2020
@jonas-schievink jonas-schievink added A-closures Area: closures (`|args| { .. }`) F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` A-lifetimes Area: lifetime related T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 13, 2020
@Aaron1011
Copy link
Member

When I wrote #69008, I assumed that the three types of generic substs (types, lifetimes, and consts) were all handled in the same way for opaque types. However, this is not the case: the handling of lifetimes is significantly more complicated than that of types or consts.

I still think that using the 'parent' opaque type as the 'parent' generics is the best approach. However, it's going to require several changes to how we process lifetimes. In particular, we'll need to ensure that simply using a lifetime (e.g. impl FnOnce(B) -> C + 'a) does not create a corresponding generic parameter when we're outside of a return-position-impl-trait context.

@jackh726
Copy link
Member

jackh726 commented Feb 4, 2021

Errors on master give correct suggestion

error[E0309]: the parameter type `F` may not live long enough
 --> src/main.rs:4:4
  |
4 |  = impl Fn<(A,), Output = impl FnOnce(B) -> C + 'a> + 'a;
  |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: consider adding an explicit lifetime bound `F: 'a`...
  = note: ...so that the type `[closure@src/main.rs:9:5: 9:29]` will meet its required lifetime bounds

error[E0309]: the parameter type `F` may not live long enough
 --> src/main.rs:4:27
  |
4 |  = impl Fn<(A,), Output = impl FnOnce(B) -> C + 'a> + 'a;
  |                           ^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: consider adding an explicit lifetime bound `F: 'a`...
  = note: ...so that the type `[closure@src/main.rs:9:14: 9:29]` will meet its required lifetime bounds

error: aborting due to 2 previous errors

Change Curried to be type Curried<'a, A: 'a, B, C, F: 'a + Fn(A, B) -> C> = ... compiles successfully.

This just needs to be added as a test.

@jackh726 jackh726 added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Feb 4, 2021
@steffahn
Copy link
Member Author

steffahn commented Feb 4, 2021

Seems like this works (with the additional F: 'a) since #72080 (nightly-2020-06-16).

@steffahn
Copy link
Member Author

steffahn commented Feb 4, 2021

Actually it used to work without the F: 'a for a while. From 2020-06-16 up to 2020-10-06 after which #73905 was merged. I feel like that it working without the 'a bound on F might potentially have been unsound, so I guess my original code stands corrected.

@nikomatsakis
Copy link
Contributor

For min_type_alias_impl_trait, this is #86731

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: closures (`|args| { .. }`) A-lifetimes Area: lifetime related C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
Status: Can do after stabilization
Development

No branches or pull requests

5 participants