about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorZack M. Davis <code@zackmdavis.net>2019-07-06 15:02:27 -0700
committerZack M. Davis <code@zackmdavis.net>2019-07-06 15:04:18 -0700
commitacc4e564feb5151ca02070e0890e428d7967b8b4 (patch)
treef26f265ffba5e6aecef81427acac7a78f469e949 /src
parente12d682dde0adbbde3d49dd202b223deb1ceec89 (diff)
downloadrust-acc4e564feb5151ca02070e0890e428d7967b8b4.tar.gz
rust-acc4e564feb5151ca02070e0890e428d7967b8b4.zip
in which we suggest anonymizing single-use lifetimes in paths
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/resolve_lifetime.rs81
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs3
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr16
3 files changed, 73 insertions, 27 deletions
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 3221b41ee1d..beb8061842d 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -9,7 +9,7 @@ use crate::hir::def::{Res, DefKind};
 use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use crate::hir::map::Map;
 use crate::hir::ptr::P;
-use crate::hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, Node, ParamName};
+use crate::hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, Node, ParamName, QPath};
 use crate::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
 
 use crate::rustc::lint;
@@ -1458,10 +1458,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     }
 
     // helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)`
+    // or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)`
     fn suggest_eliding_single_use_lifetime(
         &self, err: &mut DiagnosticBuilder<'_>, def_id: DefId, lifetime: &hir::Lifetime
     ) {
-        // FIXME: future work: also suggest `impl Foo<'_>` for `impl<'a> Foo<'a>`
         let name = lifetime.name.ident();
         let mut remove_decl = None;
         if let Some(parent_def_id) = self.tcx.parent(def_id) {
@@ -1471,18 +1471,38 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         }
 
         let mut remove_use = None;
+        let mut elide_use = None;
         let mut find_arg_use_span = |inputs: &hir::HirVec<hir::Ty>| {
             for input in inputs {
-                if let hir::TyKind::Rptr(lt, _) = input.node {
-                    if lt.name.ident() == name {
-                        // include the trailing whitespace between the ampersand and the type name
-                        let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi());
-                        remove_use = Some(
-                            self.tcx.sess.source_map()
-                                .span_until_non_whitespace(lt_through_ty_span)
-                        );
-                        break;
+                match input.node {
+                    hir::TyKind::Rptr(lt, _) => {
+                        if lt.name.ident() == name {
+                            // include the trailing whitespace between the lifetime and type names
+                            let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi());
+                            remove_use = Some(
+                                self.tcx.sess.source_map()
+                                    .span_until_non_whitespace(lt_through_ty_span)
+                            );
+                            break;
+                        }
                     }
+                    hir::TyKind::Path(ref qpath) => {
+                        if let QPath::Resolved(_, path) = qpath {
+
+                            let last_segment = &path.segments[path.segments.len()-1];
+                            let generics = last_segment.generic_args();
+                            for arg in generics.args.iter() {
+                                if let GenericArg::Lifetime(lt) = arg {
+                                    if lt.name.ident() == name {
+                                        elide_use = Some(lt.span);
+                                        break;
+                                    }
+                                }
+                            }
+                            break;
+                        }
+                    },
+                    _ => {}
                 }
             }
         };
@@ -1506,24 +1526,35 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         }
 
-        if let (Some(decl_span), Some(use_span)) = (remove_decl, remove_use) {
-            // if both declaration and use deletion spans start at the same
-            // place ("start at" because the latter includes trailing
-            // whitespace), then this is an in-band lifetime
-            if decl_span.shrink_to_lo() == use_span.shrink_to_lo() {
-                err.span_suggestion(
-                    use_span,
-                    "elide the single-use lifetime",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                );
-            } else {
+        let msg = "elide the single-use lifetime";
+        match (remove_decl, remove_use, elide_use) {
+            (Some(decl_span), Some(use_span), None) => {
+                // if both declaration and use deletion spans start at the same
+                // place ("start at" because the latter includes trailing
+                // whitespace), then this is an in-band lifetime
+                if decl_span.shrink_to_lo() == use_span.shrink_to_lo() {
+                    err.span_suggestion(
+                        use_span,
+                        msg,
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.multipart_suggestion(
+                        msg,
+                        vec![(decl_span, String::new()), (use_span, String::new())],
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+            (Some(decl_span), None, Some(use_span)) => {
                 err.multipart_suggestion(
-                    "elide the single-use lifetime",
-                    vec![(decl_span, String::new()), (use_span, String::new())],
+                    msg,
+                    vec![(decl_span, String::new()), (use_span, "'_".to_owned())],
                     Applicability::MachineApplicable,
                 );
             }
+            _ => {}
         }
     }
 
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs
index 60435c4ad24..ff9d6bd01c6 100644
--- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.rs
@@ -13,7 +13,10 @@ struct Single<'a> { x: &'a u32 }
 struct Double<'a, 'b> { f: &'a &'b u32 }
 
 fn center<'m>(_: Single<'m>) {} //~ ERROR `'m` only used once
+//~^ HELP elide the single-use lifetime
 fn left<'x, 'y>(foo: Double<'x, 'y>) -> &'x u32 { foo.f } //~ ERROR `'y` only used once
+//~^ HELP elide the single-use lifetime
 fn right<'x, 'y>(foo: Double<'x, 'y>) -> &'y u32 { foo.f } //~ ERROR `'x` only used once
+//~^ HELP elide the single-use lifetime
 
 fn main() { }
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr
index e8513e6647a..faaa7e2f1b0 100644
--- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument.stderr
@@ -23,18 +23,30 @@ LL | fn center<'m>(_: Single<'m>) {}
    |           ^^            -- ...is used only here
    |           |
    |           this lifetime...
+help: elide the single-use lifetime
+   |
+LL | fn center(_: Single<'_>) {}
+   |         --          ^^
 
 error: lifetime parameter `'y` only used once
-  --> $DIR/one-use-in-fn-argument.rs:16:13
+  --> $DIR/one-use-in-fn-argument.rs:17:13
    |
 LL | fn left<'x, 'y>(foo: Double<'x, 'y>) -> &'x u32 { foo.f }
    |             ^^ this lifetime... -- ...is used only here
+help: elide the single-use lifetime
+   |
+LL | fn left<'x>(foo: Double<'x, '_>) -> &'x u32 { foo.f }
+   |          --                 ^^
 
 error: lifetime parameter `'x` only used once
-  --> $DIR/one-use-in-fn-argument.rs:17:10
+  --> $DIR/one-use-in-fn-argument.rs:19:10
    |
 LL | fn right<'x, 'y>(foo: Double<'x, 'y>) -> &'y u32 { foo.f }
    |          ^^ this lifetime... -- ...is used only here
+help: elide the single-use lifetime
+   |
+LL | fn right<'y>(foo: Double<'_, 'y>) -> &'y u32 { foo.f }
+   |         --               ^^
 
 error: aborting due to 4 previous errors