Skip to content

Commit e706438

Browse files
authored
Rollup merge of rust-lang#62453 - zackmdavis:single_path, r=estebank
in which we suggest anonymizing single-use lifetimes in paths Following @nikomatsakis's [October 2017 comment](rust-lang#44752 (comment)). ![path_anon_suggest](https://user-images.githubusercontent.com/1076988/60761598-e2619180-a000-11e9-9144-1bdf8eb848e3.png) r? @estebank cc @eddyb (you were saying something about running single-use-lifetimes against the tree the other week?)
2 parents f169b15 + acc4e56 commit e706438

File tree

3 files changed

+99
-26
lines changed

3 files changed

+99
-26
lines changed

src/librustc/middle/resolve_lifetime.rs

+56-25
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::hir::def::{Res, DefKind};
99
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
1010
use crate::hir::map::Map;
1111
use crate::hir::ptr::P;
12-
use crate::hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, Node, ParamName};
12+
use crate::hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, Node, ParamName, QPath};
1313
use crate::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
1414

1515
use crate::rustc::lint;
@@ -1458,10 +1458,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
14581458
}
14591459

14601460
// helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)`
1461+
// or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)`
14611462
fn suggest_eliding_single_use_lifetime(
14621463
&self, err: &mut DiagnosticBuilder<'_>, def_id: DefId, lifetime: &hir::Lifetime
14631464
) {
1464-
// FIXME: future work: also suggest `impl Foo<'_>` for `impl<'a> Foo<'a>`
14651465
let name = lifetime.name.ident();
14661466
let mut remove_decl = None;
14671467
if let Some(parent_def_id) = self.tcx.parent(def_id) {
@@ -1471,18 +1471,38 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
14711471
}
14721472

14731473
let mut remove_use = None;
1474+
let mut elide_use = None;
14741475
let mut find_arg_use_span = |inputs: &hir::HirVec<hir::Ty>| {
14751476
for input in inputs {
1476-
if let hir::TyKind::Rptr(lt, _) = input.node {
1477-
if lt.name.ident() == name {
1478-
// include the trailing whitespace between the ampersand and the type name
1479-
let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi());
1480-
remove_use = Some(
1481-
self.tcx.sess.source_map()
1482-
.span_until_non_whitespace(lt_through_ty_span)
1483-
);
1484-
break;
1477+
match input.node {
1478+
hir::TyKind::Rptr(lt, _) => {
1479+
if lt.name.ident() == name {
1480+
// include the trailing whitespace between the lifetime and type names
1481+
let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi());
1482+
remove_use = Some(
1483+
self.tcx.sess.source_map()
1484+
.span_until_non_whitespace(lt_through_ty_span)
1485+
);
1486+
break;
1487+
}
14851488
}
1489+
hir::TyKind::Path(ref qpath) => {
1490+
if let QPath::Resolved(_, path) = qpath {
1491+
1492+
let last_segment = &path.segments[path.segments.len()-1];
1493+
let generics = last_segment.generic_args();
1494+
for arg in generics.args.iter() {
1495+
if let GenericArg::Lifetime(lt) = arg {
1496+
if lt.name.ident() == name {
1497+
elide_use = Some(lt.span);
1498+
break;
1499+
}
1500+
}
1501+
}
1502+
break;
1503+
}
1504+
},
1505+
_ => {}
14861506
}
14871507
}
14881508
};
@@ -1506,24 +1526,35 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
15061526
}
15071527
}
15081528

1509-
if let (Some(decl_span), Some(use_span)) = (remove_decl, remove_use) {
1510-
// if both declaration and use deletion spans start at the same
1511-
// place ("start at" because the latter includes trailing
1512-
// whitespace), then this is an in-band lifetime
1513-
if decl_span.shrink_to_lo() == use_span.shrink_to_lo() {
1514-
err.span_suggestion(
1515-
use_span,
1516-
"elide the single-use lifetime",
1517-
String::new(),
1518-
Applicability::MachineApplicable,
1519-
);
1520-
} else {
1529+
let msg = "elide the single-use lifetime";
1530+
match (remove_decl, remove_use, elide_use) {
1531+
(Some(decl_span), Some(use_span), None) => {
1532+
// if both declaration and use deletion spans start at the same
1533+
// place ("start at" because the latter includes trailing
1534+
// whitespace), then this is an in-band lifetime
1535+
if decl_span.shrink_to_lo() == use_span.shrink_to_lo() {
1536+
err.span_suggestion(
1537+
use_span,
1538+
msg,
1539+
String::new(),
1540+
Applicability::MachineApplicable,
1541+
);
1542+
} else {
1543+
err.multipart_suggestion(
1544+
msg,
1545+
vec![(decl_span, String::new()), (use_span, String::new())],
1546+
Applicability::MachineApplicable,
1547+
);
1548+
}
1549+
}
1550+
(Some(decl_span), None, Some(use_span)) => {
15211551
err.multipart_suggestion(
1522-
"elide the single-use lifetime",
1523-
vec![(decl_span, String::new()), (use_span, String::new())],
1552+
msg,
1553+
vec![(decl_span, String::new()), (use_span, "'_".to_owned())],
15241554
Applicability::MachineApplicable,
15251555
);
15261556
}
1557+
_ => {}
15271558
}
15281559
}
15291560

src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs

+10
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,14 @@ fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
99
//~^ HELP elide the single-use lifetime
1010
}
1111

12+
struct Single<'a> { x: &'a u32 }
13+
struct Double<'a, 'b> { f: &'a &'b u32 }
14+
15+
fn center<'m>(_: Single<'m>) {} //~ ERROR `'m` only used once
16+
//~^ HELP elide the single-use lifetime
17+
fn left<'x, 'y>(foo: Double<'x, 'y>) -> &'x u32 { foo.f } //~ ERROR `'y` only used once
18+
//~^ HELP elide the single-use lifetime
19+
fn right<'x, 'y>(foo: Double<'x, 'y>) -> &'y u32 { foo.f } //~ ERROR `'x` only used once
20+
//~^ HELP elide the single-use lifetime
21+
1222
fn main() { }

src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr

+33-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,37 @@ help: elide the single-use lifetime
1616
LL | fn a(x: &u32) {
1717
| -- --
1818

19-
error: aborting due to previous error
19+
error: lifetime parameter `'m` only used once
20+
--> $DIR/one-use-in-fn-argument.rs:15:11
21+
|
22+
LL | fn center<'m>(_: Single<'m>) {}
23+
| ^^ -- ...is used only here
24+
| |
25+
| this lifetime...
26+
help: elide the single-use lifetime
27+
|
28+
LL | fn center(_: Single<'_>) {}
29+
| -- ^^
30+
31+
error: lifetime parameter `'y` only used once
32+
--> $DIR/one-use-in-fn-argument.rs:17:13
33+
|
34+
LL | fn left<'x, 'y>(foo: Double<'x, 'y>) -> &'x u32 { foo.f }
35+
| ^^ this lifetime... -- ...is used only here
36+
help: elide the single-use lifetime
37+
|
38+
LL | fn left<'x>(foo: Double<'x, '_>) -> &'x u32 { foo.f }
39+
| -- ^^
40+
41+
error: lifetime parameter `'x` only used once
42+
--> $DIR/one-use-in-fn-argument.rs:19:10
43+
|
44+
LL | fn right<'x, 'y>(foo: Double<'x, 'y>) -> &'y u32 { foo.f }
45+
| ^^ this lifetime... -- ...is used only here
46+
help: elide the single-use lifetime
47+
|
48+
LL | fn right<'y>(foo: Double<'_, 'y>) -> &'y u32 { foo.f }
49+
| -- ^^
50+
51+
error: aborting due to 4 previous errors
2052

0 commit comments

Comments
 (0)