Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit d1d585d

Browse files
committed
Account for owning item lifetimes in suggestion and annotate tests as run-rustfix
``` error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:12:9 | LL | fn ref_self(&self, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` | | | let's call the lifetime of this reference `'2` LL | f | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` | help: consider introducing a named lifetime parameter and update trait if needed | LL | fn ref_self<'b>(&'b self, f: &'b u32) -> &'b u32 { | ++++ ++ ++ ++ ```
1 parent 120049f commit d1d585d

27 files changed

+404
-59
lines changed

compiler/rustc_infer/src/errors/mod.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use hir::GenericParamKind;
2+
use rustc_data_structures::fx::FxHashSet;
23
use rustc_errors::{
34
codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg,
45
MultiSpan, SubdiagMessageOp, Subdiagnostic,
@@ -362,13 +363,27 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
362363

363364
let node = self.tcx.hir_node_by_def_id(anon_reg.def_id);
364365
let is_impl = matches!(&node, hir::Node::ImplItem(_));
365-
let generics = match node {
366+
let (generics, parent_generics) = match node {
366367
hir::Node::Item(&hir::Item {
367368
kind: hir::ItemKind::Fn(_, ref generics, ..),
368369
..
369370
})
370371
| hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
371-
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
372+
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
373+
generics,
374+
match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id))
375+
{
376+
hir::Node::Item(hir::Item {
377+
kind: hir::ItemKind::Trait(_, _, ref generics, ..),
378+
..
379+
})
380+
| hir::Node::Item(hir::Item {
381+
kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
382+
..
383+
}) => Some(generics),
384+
_ => None,
385+
},
386+
),
372387
_ => return false,
373388
};
374389

@@ -379,8 +394,29 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
379394
.map(|p| p.name.ident().name)
380395
.find(|i| *i != kw::UnderscoreLifetime);
381396
let introduce_new = suggestion_param_name.is_none();
397+
398+
let mut default = "'a".to_string();
399+
if let Some(parent_generics) = parent_generics {
400+
let used: FxHashSet<_> = parent_generics
401+
.params
402+
.iter()
403+
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
404+
.map(|p| p.name.ident().name)
405+
.filter(|i| *i != kw::UnderscoreLifetime)
406+
.map(|l| l.to_string())
407+
.collect();
408+
if let Some(lt) =
409+
('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
410+
{
411+
// We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
412+
// `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
413+
// likely to be an over-constraining lifetime requirement, so we always add a
414+
// lifetime to the `fn`.
415+
default = lt;
416+
}
417+
}
382418
let suggestion_param_name =
383-
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
419+
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
384420

385421
struct ImplicitLifetimeFinder {
386422
suggestions: Vec<(Span, String)>,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
struct Foo {
4+
field: i32,
5+
}
6+
7+
impl Foo {
8+
fn foo<'a>(&'a self, x: &'a i32) -> &'a i32 {
9+
10+
x
11+
//~^ ERROR lifetime may not live long enough
12+
13+
}
14+
15+
}
16+
17+
fn main() {}

tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
13
struct Foo {
2-
field: i32
4+
field: i32,
35
}
46

57
impl Foo {
@@ -12,4 +14,4 @@ impl Foo {
1214

1315
}
1416

15-
fn main() { }
17+
fn main() {}

tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: lifetime may not live long enough
2-
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:8:5
2+
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:10:5
33
|
44
LL | fn foo<'a>(&self, x: &'a i32) -> &i32 {
55
| -- - let's call the lifetime of this reference `'1`
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
struct Foo {
4+
field: i32,
5+
}
6+
7+
impl Foo {
8+
fn foo<'a>(&'a self, x: &'a i32) -> &'a i32 {
9+
x
10+
//~^ ERROR lifetime may not live long enough
11+
}
12+
}
13+
14+
fn main() { }

tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
13
struct Foo {
2-
field: i32
4+
field: i32,
35
}
46

57
impl Foo {

tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: lifetime may not live long enough
2-
--> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:7:5
2+
--> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:9:5
33
|
44
LL | fn foo<'a>(&self, x: &i32) -> &i32 {
55
| - - let's call the lifetime of this reference `'1`

tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ impl Foo {
66
fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
77
//~^ lifetime may not live long enough
88

9+
// For this suggestion to be right, we'd need to also suggest `self: Pin<&'a Self>`, which we
10+
// don't, but we provide a follow up suggestion to do so, so I condider that good at least for
11+
// now.
912
fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
1013
//~^ lifetime may not live long enough
1114
}

tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ LL | fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &'a Foo { f }
1313
| ++++ ++ ++ ++
1414

1515
error: lifetime may not live long enough
16-
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:9:69
16+
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:12:69
1717
|
1818
LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
1919
| - - ^^^^^^^^^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
@@ -27,7 +27,7 @@ LL | fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&'a Foo>, &'
2727
| ++++ ++ ++ ++ ++
2828

2929
error: lifetime may not live long enough
30-
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58
30+
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:18:58
3131
|
3232
LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
3333
| -- ---- has type `Pin<&'1 Foo>` ^^^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//@ edition:2018
2+
//@ run-rustfix
3+
#![allow(non_snake_case, dead_code)]
4+
5+
use std::pin::Pin;
6+
7+
struct Struct<'a> { data: &'a u32 }
8+
9+
impl<'a> Struct<'a> {
10+
// Test using `&self` sugar:
11+
12+
async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 {
13+
f
14+
//~^ ERROR lifetime may not live long enough
15+
}
16+
17+
// Test using `&Self` explicitly:
18+
19+
async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 {
20+
f
21+
//~^ ERROR lifetime may not live long enough
22+
}
23+
24+
async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 {
25+
f
26+
//~^ ERROR lifetime may not live long enough
27+
}
28+
29+
async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 {
30+
f
31+
//~^ ERROR lifetime may not live long enough
32+
}
33+
34+
async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 {
35+
f
36+
//~^ ERROR lifetime may not live long enough
37+
}
38+
39+
async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 {
40+
f
41+
//~^ ERROR lifetime may not live long enough
42+
}
43+
}
44+
45+
fn main() { }

tests/ui/self/elision/lt-ref-self-async.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ edition:2018
2-
3-
#![allow(non_snake_case)]
2+
//@ run-rustfix
3+
#![allow(non_snake_case, dead_code)]
44

55
use std::pin::Pin;
66

tests/ui/self/elision/lt-ref-self-async.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ LL | f
1010
|
1111
help: consider introducing a named lifetime parameter and update trait if needed
1212
|
13-
LL | async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
13+
LL | async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 {
1414
| ++++ ++ ++
1515

1616
error: lifetime may not live long enough
@@ -25,7 +25,7 @@ LL | f
2525
|
2626
help: consider introducing a named lifetime parameter and update trait if needed
2727
|
28-
LL | async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
28+
LL | async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 {
2929
| ++++ ++ ++
3030

3131
error: lifetime may not live long enough
@@ -40,7 +40,7 @@ LL | f
4040
|
4141
help: consider introducing a named lifetime parameter and update trait if needed
4242
|
43-
LL | async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
43+
LL | async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 {
4444
| ++++ ++ ++
4545

4646
error: lifetime may not live long enough
@@ -55,7 +55,7 @@ LL | f
5555
|
5656
help: consider introducing a named lifetime parameter and update trait if needed
5757
|
58-
LL | async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
58+
LL | async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 {
5959
| ++++ ++ ++
6060

6161
error: lifetime may not live long enough
@@ -70,7 +70,7 @@ LL | f
7070
|
7171
help: consider introducing a named lifetime parameter and update trait if needed
7272
|
73-
LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
73+
LL | async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 {
7474
| ++++ ++ ++
7575

7676
error: lifetime may not live long enough
@@ -85,7 +85,7 @@ LL | f
8585
|
8686
help: consider introducing a named lifetime parameter and update trait if needed
8787
|
88-
LL | async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
88+
LL | async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 {
8989
| ++++ ++ ++
9090

9191
error: aborting due to 6 previous errors
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//@ run-rustfix
2+
#![allow(non_snake_case, dead_code)]
3+
4+
use std::pin::Pin;
5+
6+
struct Struct<'a> { data: &'a u32 }
7+
8+
impl<'a> Struct<'a> {
9+
// Test using `&self` sugar:
10+
11+
fn ref_self<'b>(&'b self, f: &'b u32) -> &'b u32 {
12+
f
13+
//~^ ERROR lifetime may not live long enough
14+
}
15+
16+
// Test using `&Self` explicitly:
17+
18+
fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &'b u32 {
19+
f
20+
//~^ ERROR lifetime may not live long enough
21+
}
22+
23+
fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &'b u32 {
24+
f
25+
//~^ ERROR lifetime may not live long enough
26+
}
27+
28+
fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &'b u32 {
29+
f
30+
//~^ ERROR lifetime may not live long enough
31+
}
32+
33+
fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &'b u32 {
34+
f
35+
//~^ ERROR lifetime may not live long enough
36+
}
37+
38+
fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &'b u32 {
39+
f
40+
//~^ ERROR lifetime may not live long enough
41+
}
42+
}
43+
44+
fn main() { }

tests/ui/self/elision/lt-ref-self.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
#![allow(non_snake_case)]
1+
//@ run-rustfix
2+
#![allow(non_snake_case, dead_code)]
23

34
use std::pin::Pin;
45

0 commit comments

Comments
 (0)