Skip to content

Commit 22c4f56

Browse files
committed
only do the elided-lifetimes-in-paths lint on type paths
Instead of linting for invisible lifetimes during (a callee of) `visit_path` (in the `LifetimeContext` visitor), we do it in the `hir::TyPath` branch of `visit_ty`. This fixes a false positive where we were suggesting `<'_>` on the struct name of a struct construction expression. (Applying the suggestion would result in a parse error.) Also, it seems better for the primary lint span (as distinguished from the zero-width suggestion span where we propose the insertion of anonymous lifetimes) to cover the entire path including any angle-bracketed type parameters, rather than just the last path-name segment. That is: we should highlight all of `Ref<T>` when we suggest replacing it with `Ref<'_, T>`, rather than just highlighting the `Ref`. (Interestingly, this false positive didn't happen for tuple structs like the one we already had in our UI test, probably because of something something value vs. type namespace &c. that the present author doesn't understand.) This is in the matter of issue no. 52041.
1 parent 7d03b39 commit 22c4f56

File tree

4 files changed

+55
-21
lines changed

4 files changed

+55
-21
lines changed

src/librustc/middle/resolve_lifetime.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
626626
self.with(scope, |_, this| this.visit_ty(&mt.ty));
627627
}
628628
hir::TyPath(hir::QPath::Resolved(None, ref path)) => {
629+
let segment = &path.segments[path.segments.len()-1];
630+
if let Some(ref args) = segment.args {
631+
self.lint_implicit_lifetimes_in_typath(path, args);
632+
}
629633
if let Def::Existential(exist_ty_did) = path.def {
630634
assert!(exist_ty_did.is_local());
631635
// Resolve the lifetimes that are applied to the existential type.
@@ -869,7 +873,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
869873
for (i, ref segment) in path.segments.iter().enumerate() {
870874
let depth = path.segments.len() - i - 1;
871875
if let Some(ref args) = segment.args {
872-
self.visit_segment_args(path.def, depth, segment.ident, args);
876+
self.visit_segment_args(path.def, depth, args);
873877
}
874878
}
875879
}
@@ -1667,7 +1671,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
16671671
&mut self,
16681672
def: Def,
16691673
depth: usize,
1670-
segment_ident: ast::Ident,
16711674
generic_args: &'tcx hir::GenericArgs,
16721675
) {
16731676
if generic_args.parenthesized {
@@ -1690,9 +1693,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
16901693
_ => None,
16911694
}).collect::<Vec<_>>();
16921695
if elide_lifetimes {
1693-
self.lint_implicit_lifetimes_in_segment(
1694-
segment_ident, generic_args, &lifetimes
1695-
);
16961696
self.resolve_elided_lifetimes(lifetimes);
16971697
} else {
16981698
lifetimes.iter().for_each(|lt| self.visit_lifetime(lt));
@@ -2070,30 +2070,38 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20702070
}
20712071
}
20722072

2073-
fn lint_implicit_lifetimes_in_segment(&mut self,
2074-
segment_ident: ast::Ident,
2075-
generic_args: &'tcx hir::GenericArgs,
2076-
lifetime_refs: &[&'tcx hir::Lifetime]) {
2077-
let num_implicit_lifetimes = lifetime_refs.iter()
2078-
.filter(|lt| lt.name.is_implicit()).count();
2079-
if num_implicit_lifetimes == 0 {
2073+
fn lint_implicit_lifetimes_in_typath(&mut self,
2074+
path: &hir::Path,
2075+
generic_args: &'tcx hir::GenericArgs) {
2076+
let implicit_lifetimes = generic_args.args.iter()
2077+
.filter_map(|arg| {
2078+
if let hir::GenericArg::Lifetime(lt) = arg {
2079+
if lt.name.is_implicit() {
2080+
return Some(lt)
2081+
}
2082+
}
2083+
None
2084+
}).collect::<Vec<_>>();
2085+
2086+
if implicit_lifetimes.len() == 0 {
20802087
return;
20812088
}
20822089

20832090
let mut err = self.tcx.struct_span_lint_node(
20842091
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
2085-
lifetime_refs[0].id, // FIXME: HirIdify #50928
2086-
segment_ident.span,
2092+
implicit_lifetimes[0].id, // FIXME: HirIdify #50928
2093+
path.span,
20872094
&format!("implicit lifetime parameters in types are deprecated"),
20882095
);
20892096

2090-
if num_implicit_lifetimes == 1 {
2097+
if implicit_lifetimes.len() == 1 {
2098+
let segment_span = &path.segments[path.segments.len()-1].ident.span;
20912099
let (replace_span,
2092-
suggestion) = if generic_args.args.len() == num_implicit_lifetimes &&
2100+
suggestion) = if generic_args.args.len() == implicit_lifetimes.len() &&
20932101
generic_args.bindings.is_empty() {
20942102
// If there are no (non-implicit) generic args or bindings, our
20952103
// suggestion includes the angle brackets
2096-
(segment_ident.span.shrink_to_hi(), "<'_>")
2104+
(segment_span.shrink_to_hi(), "<'_>")
20972105
} else {
20982106
// Otherwise—sorry, this is kind of gross—we need to infer the
20992107
// replacement point span from the generics that do exist

src/test/ui/in-band-lifetimes/elided-lifetimes.fixed

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,21 @@ fn bar(x: &Foo<'_>) {}
3030

3131
struct Wrapped<'a>(&'a str);
3232

33+
struct WrappedWithBow<'a> {
34+
gift: &'a str
35+
}
36+
3337
fn wrap_gift(gift: &str) -> Wrapped<'_> {
3438
//~^ ERROR implicit lifetime parameters in types are deprecated
3539
//~| HELP indicate the anonymous lifetime
3640
Wrapped(gift)
3741
}
3842

43+
fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> {
44+
//~^ ERROR implicit lifetime parameters in types are deprecated
45+
//~| HELP indicate the anonymous lifetime
46+
WrappedWithBow { gift }
47+
}
3948

4049
fn main() {
4150
let honesty = RefCell::new((4, 'e'));

src/test/ui/in-band-lifetimes/elided-lifetimes.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,21 @@ fn bar(x: &Foo<'_>) {}
3030

3131
struct Wrapped<'a>(&'a str);
3232

33+
struct WrappedWithBow<'a> {
34+
gift: &'a str
35+
}
36+
3337
fn wrap_gift(gift: &str) -> Wrapped {
3438
//~^ ERROR implicit lifetime parameters in types are deprecated
3539
//~| HELP indicate the anonymous lifetime
3640
Wrapped(gift)
3741
}
3842

43+
fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
44+
//~^ ERROR implicit lifetime parameters in types are deprecated
45+
//~| HELP indicate the anonymous lifetime
46+
WrappedWithBow { gift }
47+
}
3948

4049
fn main() {
4150
let honesty = RefCell::new((4, 'e'));

src/test/ui/in-band-lifetimes/elided-lifetimes.stderr

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,24 @@ LL | #![deny(elided_lifetimes_in_paths)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^
1212

1313
error: implicit lifetime parameters in types are deprecated
14-
--> $DIR/elided-lifetimes.rs:33:29
14+
--> $DIR/elided-lifetimes.rs:37:29
1515
|
1616
LL | fn wrap_gift(gift: &str) -> Wrapped {
1717
| ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
1818

1919
error: implicit lifetime parameters in types are deprecated
20-
--> $DIR/elided-lifetimes.rs:42:18
20+
--> $DIR/elided-lifetimes.rs:43:38
21+
|
22+
LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
23+
| ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
24+
25+
error: implicit lifetime parameters in types are deprecated
26+
--> $DIR/elided-lifetimes.rs:51:18
2127
|
2228
LL | let loyalty: Ref<(u32, char)> = honesty.borrow();
23-
| ^^^ - help: indicate the anonymous lifetime: `'_,`
29+
| ^^^^-^^^^^^^^^^^
30+
| |
31+
| help: indicate the anonymous lifetime: `'_,`
2432

25-
error: aborting due to 3 previous errors
33+
error: aborting due to 4 previous errors
2634

0 commit comments

Comments
 (0)