Skip to content

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() { }

0 commit comments

Comments
 (0)