Rollup merge of #76468 - SNCPlay42:lifetime-names, r=Mark-Simulacrum

Improve lifetime name annotations for closures & async functions

* Don't refer to async functions as "generators" in error output
* Where possible, emit annotations pointing exactly at the `&` in the return type of closures (when they have explicit return types) and async functions, like we do for arguments.
Addresses #74072, but I wouldn't call that *closed* until annotations are identical for async and non-async functions.
* Emit a better annotation when the lifetime doesn't appear in the full name type, which currently happens for opaque types like `impl Future`. Addresses #74497, but further improves could probably be made (why *doesn't* it appear in the type as `impl Future + '1`?)
This is included in the same PR because the changes to `give_name_if_anonymous_region_appears_in_output` would introduce ICE otherwise (it would return `None` in cases where it didn't previously, which then gets `unwrap`ped)
This commit is contained in:
Dylan DPC 2020-11-09 19:06:39 +01:00 committed by GitHub
commit 99f16e637b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 282 additions and 46 deletions

View file

@ -0,0 +1,37 @@
// edition:2018
#![feature(async_closure)]
use std::future::Future;
// test the quality of annotations giving lifetimes names (`'1`) when async constructs are involved
pub async fn async_fn(x: &mut i32) -> &i32 {
let y = &*x;
*x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
y
}
pub fn async_closure(x: &mut i32) -> impl Future<Output=&i32> {
(async move || {
let y = &*x;
*x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
y
})()
}
pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future<Output=&i32> {
(async move || -> &i32 {
let y = &*x;
*x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
y
})()
}
pub fn async_block(x: &mut i32) -> impl Future<Output=&i32> {
async move {
let y = &*x;
*x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
y
}
}
fn main() {}

View file

@ -0,0 +1,51 @@
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/issue-74072-lifetime-name-annotations.rs:9:5
|
LL | pub async fn async_fn(x: &mut i32) -> &i32 {
| - let's call the lifetime of this reference `'1`
LL | let y = &*x;
| --- borrow of `*x` occurs here
LL | *x += 1;
| ^^^^^^^ assignment to borrowed `*x` occurs here
LL | y
| - returning this value requires that `*x` is borrowed for `'1`
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/issue-74072-lifetime-name-annotations.rs:16:9
|
LL | let y = &*x;
| --- borrow of `*x` occurs here
LL | *x += 1;
| ^^^^^^^ assignment to borrowed `*x` occurs here
LL | y
| - returning this value requires that `*x` is borrowed for `'1`
LL | })()
| - return type of async closure is &'1 i32
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/issue-74072-lifetime-name-annotations.rs:24:9
|
LL | (async move || -> &i32 {
| - let's call the lifetime of this reference `'1`
LL | let y = &*x;
| --- borrow of `*x` occurs here
LL | *x += 1;
| ^^^^^^^ assignment to borrowed `*x` occurs here
LL | y
| - returning this value requires that `*x` is borrowed for `'1`
error[E0506]: cannot assign to `*x` because it is borrowed
--> $DIR/issue-74072-lifetime-name-annotations.rs:32:9
|
LL | let y = &*x;
| --- borrow of `*x` occurs here
LL | *x += 1;
| ^^^^^^^ assignment to borrowed `*x` occurs here
LL | y
| - returning this value requires that `*x` is borrowed for `'1`
LL | }
| - return type of async block is &'1 i32
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0506`.

View file

@ -0,0 +1,19 @@
// edition:2018
// test that names give to anonymous lifetimes in opaque types like `impl Future` are correctly
// introduced in error messages
use std::future::Future;
pub async fn foo<F, T>(_: F)
where
F: Fn(&u8) -> T,
T: Future<Output = ()>,
{
}
pub async fn bar(_: &u8) {}
fn main() {
let _ = foo(|x| bar(x)); //~ ERROR lifetime may not live long enough
}

View file

@ -0,0 +1,11 @@
error: lifetime may not live long enough
--> $DIR/issue-74497-lifetime-in-opaque.rs:18:21
|
LL | let _ = foo(|x| bar(x));
| -- ^^^^^^ returning this value requires that `'1` must outlive `'2`
| ||
| |return type of closure `impl Future` contains a lifetime `'2`
| has type `&'1 u8`
error: aborting due to previous error

View file

@ -4,7 +4,7 @@ error: lifetime may not live long enough
LL | let _action = move || {
| -------
| | |
| | return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15]
| | return type of closure `[closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15]` contains a lifetime `'2`
| lifetime `'1` represents this closure's body
LL | || f() // The `nested` closure
| ^^^^^^ returning this value requires that `'1` must outlive `'2`

View file

@ -2,9 +2,9 @@ error: lifetime may not live long enough
--> $DIR/issue-58053.rs:6:33
|
LL | let f = |x: &i32| -> &i32 { x };
| - ---- ^ returning this value requires that `'1` must outlive `'2`
| - - ^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 i32
| | let's call the lifetime of this reference `'2`
| let's call the lifetime of this reference `'1`
error: lifetime may not live long enough