]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
Auto merge of #97081 - oli-obk:outlives_query_fast_path, r=jackh726
[rust.git] / compiler / rustc_typeck / src / structured_errors / wrong_number_of_generic_args.rs
index bc3a3db9fdadb3e7ce35a12f4d6c71f7fd39f738..c440e93fe0af1fdd3b516663b7faea8224113173 100644 (file)
@@ -5,7 +5,6 @@
 };
 use rustc_hir as hir;
 use rustc_middle::hir::map::fn_sig;
-use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
 use rustc_session::Session;
 use rustc_span::def_id::DefId;
@@ -291,7 +290,69 @@ fn get_quantifier_and_bound(&self) -> (&'static str, usize) {
     }
 
     // Creates lifetime name suggestions from the lifetime parameter names
-    fn get_lifetime_args_suggestions_from_param_names(&self, num_params_to_take: usize) -> String {
+    fn get_lifetime_args_suggestions_from_param_names(
+        &self,
+        path_hir_id: Option<hir::HirId>,
+        num_params_to_take: usize,
+    ) -> String {
+        debug!(?path_hir_id);
+
+        if let Some(path_hir_id) = path_hir_id {
+            let mut ret = Vec::new();
+            for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
+                debug!(?id);
+                let params = if let Some(generics) = node.generics() {
+                    generics.params
+                } else if let hir::Node::Ty(ty) = node
+                    && let hir::TyKind::BareFn(bare_fn) = ty.kind
+                {
+                    bare_fn.generic_params
+                } else {
+                    &[]
+                };
+                ret.extend(params.iter().filter_map(|p| {
+                    let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
+                        = p.kind
+                    else { return None };
+                    let hir::ParamName::Plain(name) = p.name else { return None };
+                    Some(name.to_string())
+                }));
+                // Suggest `'static` when in const/static item-like.
+                if let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::ImplItem(hir::ImplItem {
+                    kind: hir::ImplItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::ForeignItem(hir::ForeignItem {
+                    kind: hir::ForeignItemKind::Static { .. },
+                    ..
+                })
+                | hir::Node::AnonConst(..) = node
+                {
+                    ret.extend(
+                        std::iter::repeat("'static".to_owned())
+                            .take(num_params_to_take.saturating_sub(ret.len())),
+                    );
+                }
+                if ret.len() >= num_params_to_take {
+                    return ret[..num_params_to_take].join(", ");
+                }
+                // We cannot refer to lifetimes defined in an outer function.
+                if let hir::Node::Item(_) = node {
+                    break;
+                }
+            }
+        }
+
+        // We could not gather enough lifetime parameters in the scope.
+        // We use the parameter names from the target type's definition instead.
         self.gen_params
             .params
             .iter()
@@ -501,44 +562,10 @@ fn suggest_adding_lifetime_args(&self, err: &mut Diagnostic) {
         let num_params_to_take = num_missing_args;
         let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
 
-        // we first try to get lifetime name suggestions from scope or elision information. If none is
-        // available we use the parameter definitions
-        let suggested_args = if let Some(hir_id) = self.path_segment.hir_id {
-            if let Some(lifetimes_in_scope) = self.tcx.lifetime_scope(hir_id) {
-                match lifetimes_in_scope {
-                    LifetimeScopeForPath::NonElided(param_names) => {
-                        debug!("NonElided(param_names: {:?})", param_names);
-
-                        if param_names.len() >= num_params_to_take {
-                            // use lifetime parameters in scope for suggestions
-                            param_names
-                                .iter()
-                                .take(num_params_to_take)
-                                .map(|def_id| {
-                                    self.tcx.item_name(def_id.to_def_id()).to_ident_string()
-                                })
-                                .collect::<Vec<_>>()
-                                .join(", ")
-                        } else {
-                            // Not enough lifetime arguments in scope -> create suggestions from
-                            // lifetime parameter names in definition. An error for the incorrect
-                            // lifetime scope will be output later.
-                            self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-                        }
-                    }
-                    LifetimeScopeForPath::Elided => {
-                        debug!("Elided");
-                        // use suggestions of the form `<'_, '_>` in case lifetime can be elided
-                        ["'_"].repeat(num_params_to_take).join(",")
-                    }
-                }
-            } else {
-                self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-            }
-        } else {
-            self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-        };
-
+        let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
+            self.path_segment.hir_id,
+            num_params_to_take,
+        );
         debug!("suggested_args: {:?}", &suggested_args);
 
         match self.angle_brackets {