about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2022-06-30 13:06:19 +0400
committerMaybe Waffle <waffle.lapkin@gmail.com>2022-07-12 21:00:13 +0400
commit0c284843ba23482a2263e1e60b595ead154baae1 (patch)
tree36f544973905aabab11afbfdc6d91d9b9ced53cf
parentc2dbd62c7c60cd4017c9d499101e40c129e4bc61 (diff)
downloadrust-0c284843ba23482a2263e1e60b595ead154baae1.tar.gz
rust-0c284843ba23482a2263e1e60b595ead154baae1.zip
make for<> in closures a possible place to suggest adding named lifetime
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs34
2 files changed, 36 insertions, 4 deletions
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 03cb1cfcfc9..d46f0319f2c 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -70,6 +70,8 @@ pub(crate) enum ForLifetimeSpanType {
     BoundTail,
     TypeEmpty,
     TypeTail,
+    ClosureEmpty,
+    ClosureTail,
 }
 
 impl ForLifetimeSpanType {
@@ -77,13 +79,15 @@ impl ForLifetimeSpanType {
         match self {
             Self::BoundEmpty | Self::BoundTail => "bound",
             Self::TypeEmpty | Self::TypeTail => "type",
+            Self::ClosureEmpty | Self::ClosureTail => "closure",
         }
     }
 
     pub(crate) fn suggestion(&self, sugg: &str) -> String {
         match self {
             Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
-            Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
+            Self::ClosureEmpty => format!("for<{}>", sugg),
+            Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg),
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 547255498a0..8763279a668 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
-use rustc_hir::{GenericParamKind, HirIdMap};
+use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
@@ -629,8 +629,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     })
                     .unzip();
 
-            // FIXME: missing_named_lifetime_spots
-
             self.map.late_bound_vars.insert(e.hir_id, binders);
             let scope = Scope::Binder {
                 hir_id: e.hir_id,
@@ -642,11 +640,41 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 allow_late_bound: true,
                 where_bound_origin: None,
             };
+
+            if let &hir::ClosureBinder::For { span, .. } = binder {
+                let last_lt = bound_generic_params
+                    .iter()
+                    .filter(|p| {
+                        matches!(
+                            p,
+                            GenericParam {
+                                kind: GenericParamKind::Lifetime {
+                                    kind: LifetimeParamKind::Explicit
+                                },
+                                ..
+                            }
+                        )
+                    })
+                    .last();
+                let (span, span_type) = match last_lt {
+                    Some(GenericParam { span: last_sp, .. }) => {
+                        (last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail)
+                    }
+                    None => (span, ForLifetimeSpanType::ClosureEmpty),
+                };
+                self.missing_named_lifetime_spots
+                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
+            }
+
             self.with(scope, |this| {
                 // a closure has no bounds, so everything
                 // contained within is scoped within its binder.
                 intravisit::walk_expr(this, e)
             });
+
+            if let hir::ClosureBinder::For { .. } = binder {
+                self.missing_named_lifetime_spots.pop();
+            }
         } else {
             intravisit::walk_expr(self, e)
         }