From a07290047e6b27638f491ee7ebb90e20fece2a79 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 7 May 2022 22:41:53 +0200 Subject: [PATCH 1/3] Compute lifetimes in scope at diagnostic time. --- compiler/rustc_ast_lowering/src/index.rs | 7 ++ compiler/rustc_hir/src/hir.rs | 2 + compiler/rustc_hir_pretty/src/lib.rs | 35 ++++---- compiler/rustc_middle/src/hir/map/mod.rs | 6 +- .../src/middle/resolve_lifetime.rs | 3 +- compiler/rustc_resolve/src/late/lifetimes.rs | 33 +++---- .../drop_ranges/cfg_build.rs | 1 + compiler/rustc_typeck/src/collect/type_of.rs | 19 +--- .../wrong_number_of_generic_args.rs | 89 +++++++++++-------- 9 files changed, 101 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index c506360aa8a13..4da09c4ef486e 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -313,6 +313,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) { + self.insert(type_binding.span, type_binding.hir_id, Node::TypeBinding(type_binding)); + self.with_parent(type_binding.hir_id, |this| { + intravisit::walk_assoc_type_binding(this, type_binding) + }) + } + fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) { // Do not visit the duplicate information in TraitItemRef. We want to // map the actual nodes, not the duplicate ones in the *Ref. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index cb2e66090e7c3..01cedccf997cd 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3302,6 +3302,7 @@ pub enum Node<'hir> { Stmt(&'hir Stmt<'hir>), PathSegment(&'hir PathSegment<'hir>), Ty(&'hir Ty<'hir>), + TypeBinding(&'hir TypeBinding<'hir>), TraitRef(&'hir TraitRef<'hir>), Binding(&'hir Pat<'hir>), Pat(&'hir Pat<'hir>), @@ -3347,6 +3348,7 @@ impl<'hir> Node<'hir> { | Node::PathSegment(PathSegment { ident, .. }) => Some(*ident), Node::Lifetime(lt) => Some(lt.name.ident()), Node::GenericParam(p) => Some(p.name.ident()), + Node::TypeBinding(b) => Some(b.ident), Node::Param(..) | Node::AnonConst(..) | Node::Expr(..) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 4558a3d10c4fb..fb40008d60b5d 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -85,6 +85,7 @@ impl<'a> State<'a> { Node::Stmt(a) => self.print_stmt(&a), Node::PathSegment(a) => self.print_path_segment(&a), Node::Ty(a) => self.print_type(&a), + Node::TypeBinding(a) => self.print_type_binding(&a), Node::TraitRef(a) => self.print_trait_ref(&a), Node::Binding(a) | Node::Pat(a) => self.print_pat(&a), Node::Arm(a) => self.print_arm(&a), @@ -1703,21 +1704,7 @@ impl<'a> State<'a> { for binding in generic_args.bindings.iter() { start_or_comma(self); - self.print_ident(binding.ident); - self.print_generic_args(binding.gen_args, false, false); - self.space(); - match generic_args.bindings[0].kind { - hir::TypeBindingKind::Equality { ref term } => { - self.word_space("="); - match term { - Term::Ty(ref ty) => self.print_type(ty), - Term::Const(ref c) => self.print_anon_const(c), - } - } - hir::TypeBindingKind::Constraint { bounds } => { - self.print_bounds(":", bounds); - } - } + self.print_type_binding(binding); } if !empty.get() { @@ -1726,6 +1713,24 @@ impl<'a> State<'a> { } } + pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) { + self.print_ident(binding.ident); + self.print_generic_args(binding.gen_args, false, false); + self.space(); + match binding.kind { + hir::TypeBindingKind::Equality { ref term } => { + self.word_space("="); + match term { + Term::Ty(ref ty) => self.print_type(ty), + Term::Const(ref c) => self.print_anon_const(c), + } + } + hir::TypeBindingKind::Constraint { bounds } => { + self.print_bounds(":", bounds); + } + } + } + pub fn print_pat(&mut self, pat: &hir::Pat<'_>) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 779af7a382765..ebda9f7588d5d 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -298,6 +298,7 @@ impl<'hir> Map<'hir> { Node::Stmt(_) | Node::PathSegment(_) | Node::Ty(_) + | Node::TypeBinding(_) | Node::Infer(_) | Node::TraitRef(_) | Node::Pat(_) @@ -323,7 +324,8 @@ impl<'hir> Map<'hir> { } pub fn get_parent_node(self, hir_id: HirId) -> HirId { - self.find_parent_node(hir_id).unwrap() + self.find_parent_node(hir_id) + .unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id))) } /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. @@ -973,6 +975,7 @@ impl<'hir> Map<'hir> { .with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi())) } Node::Ty(ty) => ty.span, + Node::TypeBinding(tb) => tb.span, Node::TraitRef(tr) => tr.path.span, Node::Binding(pat) => pat.span, Node::Pat(pat) => pat.span, @@ -1205,6 +1208,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { Some(Node::Stmt(_)) => node_str("stmt"), Some(Node::PathSegment(_)) => node_str("path segment"), Some(Node::Ty(_)) => node_str("type"), + Some(Node::TypeBinding(_)) => node_str("type binding"), Some(Node::TraitRef(_)) => node_str("trait ref"), Some(Node::Binding(_)) => node_str("local"), Some(Node::Pat(_)) => node_str("pat"), diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index cdc0d07680193..7d0b751d35abe 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -23,8 +23,7 @@ pub enum Region { pub enum LifetimeScopeForPath { /// Contains all lifetime names that are in scope and could possibly be used in generics /// arguments of path. - NonElided(Vec), - + NonElided, /// Information that allows us to suggest args of the form `<'_>` in case /// no generic arguments were provided for a path. Elided, diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 11f80b314d770..50e067e225f61 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -517,30 +517,16 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty:: #[tracing::instrument(level = "debug")] fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath { - let mut available_lifetimes = vec![]; loop { match scope { - Scope::Binder { lifetimes, s, .. } => { - available_lifetimes.extend(lifetimes.keys()); - scope = s; - } - Scope::Body { s, .. } => { - scope = s; - } - Scope::Elision { elide, s } => { - if let Elide::Exact(_) = elide { - return LifetimeScopeForPath::Elided; - } else { - scope = s; - } - } - Scope::ObjectLifetimeDefault { s, .. } => { - scope = s; - } - Scope::Root => { - return LifetimeScopeForPath::NonElided(available_lifetimes); - } - Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { + Scope::Elision { elide: Elide::Exact(_), .. } => return LifetimeScopeForPath::Elided, + Scope::Root => return LifetimeScopeForPath::NonElided, + Scope::Binder { s, .. } + | Scope::Body { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } + | Scope::Elision { s, .. } => { scope = s; } } @@ -2170,6 +2156,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None, + + Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None, + // Everything else (only closures?) doesn't // actually enjoy elision in return types. _ => { diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index 417778cc57d80..58b63804b4a4e 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -249,6 +249,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { | hir::Node::Stmt(..) | hir::Node::PathSegment(..) | hir::Node::Ty(..) + | hir::Node::TypeBinding(..) | hir::Node::TraitRef(..) | hir::Node::Binding(..) | hir::Node::Pat(..) diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 7e3fefe4502d2..2433401b7f0f5 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -450,21 +450,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { .discr_type() .to_ty(tcx), - Node::TraitRef(trait_ref @ &TraitRef { - path, .. - }) if let Some((binding, seg)) = - path - .segments - .iter() - .find_map(|seg| { - seg.args?.bindings - .iter() - .find_map(|binding| if binding.opt_const()?.hir_id == hir_id { - Some((binding, seg)) - } else { - None - }) - }) => + Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) + if let Node::TraitRef(trait_ref) = tcx.hir().get( + tcx.hir().get_parent_node(binding_id) + ) => { let Some(trait_def_id) = trait_ref.trait_def_id() else { return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"); diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index bc3a3db9fdadb..c433c5ebbd368 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -291,7 +291,52 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } // 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, + num_params_to_take: usize, + ) -> String { + debug!(?path_hir_id); + + if let Some(path_hir_id) = path_hir_id { + // We first try to get lifetime name suggestions from scope or elision information. + // If none is available we use the parameter definitions + if let Some(LifetimeScopeForPath::Elided) = self.tcx.lifetime_scope(path_hir_id) { + // Use suggestions of the form `<'_, '_>` in case lifetime can be elided + return ["'_"].repeat(num_params_to_take).join(","); + } + + 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()) + })); + 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 +546,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { 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::>() - .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 { From af8739b96efa97694526e478985960b4c9fc09f5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 4 Jun 2022 15:31:04 +0200 Subject: [PATCH 2/3] Completely remove LifetimeScopeForPath. --- .../src/middle/resolve_lifetime.rs | 13 --- compiler/rustc_middle/src/query/mod.rs | 5 -- compiler/rustc_middle/src/ty/context.rs | 6 +- compiler/rustc_middle/src/ty/query.rs | 4 +- compiler/rustc_resolve/src/late/lifetimes.rs | 88 ++----------------- .../wrong_number_of_generic_args.rs | 8 -- 6 files changed, 7 insertions(+), 117 deletions(-) diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 7d0b751d35abe..c71ba7b175313 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -16,19 +16,6 @@ pub enum Region { Free(DefId, /* lifetime decl */ DefId), } -/// This is used in diagnostics to improve suggestions for missing generic arguments. -/// It gives information on the type of lifetimes that are in scope for a particular `PathSegment`, -/// so that we can e.g. suggest elided-lifetimes-in-paths of the form <'_, '_> e.g. -#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] -pub enum LifetimeScopeForPath { - /// Contains all lifetime names that are in scope and could possibly be used in generics - /// arguments of path. - NonElided, - /// Information that allows us to suggest args of the form `<'_>` in case - /// no generic arguments were provided for a path. - Elided, -} - /// A set containing, at most, one known element. /// If two distinct values are inserted into a set, then it /// becomes `Many`, which can be used to detect ambiguities. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 899d6c7e490a6..ef23a182bf5e4 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1599,11 +1599,6 @@ rustc_queries! { desc { "looking up late bound vars" } } - query lifetime_scope_map(_: LocalDefId) -> Option> { - storage(ArenaCacheSelector<'tcx>) - desc { "finds the lifetime scope for an HirId of a PathSegment" } - } - query visibility(def_id: DefId) -> ty::Visibility { desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } separate_provide_extern diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 72e2beb372d3c..c23b97eba1e6d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -6,7 +6,7 @@ use crate::hir::place::Place as HirPlace; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath}; +use crate::middle::resolve_lifetime; use crate::middle::stability; use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar}; use crate::mir::{ @@ -2821,10 +2821,6 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn lifetime_scope(self, id: HirId) -> Option<&'tcx LifetimeScopeForPath> { - self.lifetime_scope_map(id.owner).as_ref().and_then(|map| map.get(&id.local_id)) - } - /// Whether the `def_id` counts as const fn in the current crate, considering all active /// feature gates pub fn is_const_fn(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 65f41c5266d17..db92ab0aa9a2c 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -6,9 +6,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::AccessLevels; -use crate::middle::resolve_lifetime::{ - LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes, -}; +use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes}; use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 50e067e225f61..359535951de99 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -8,12 +8,11 @@ use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc_ast::walk_list; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefIdMap, LocalDefId}; -use rustc_hir::hir_id::ItemLocalId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node}; use rustc_hir::{GenericParamKind, HirIdMap}; @@ -141,9 +140,6 @@ struct NamedRegionMap { // - trait refs // - bound types (like `T` in `for<'a> T<'a>: Foo`) late_bound_vars: HirIdMap>, - - // maps `PathSegment` `HirId`s to lifetime scopes. - scope_for_path: Option>>, } pub(crate) struct LifetimeContext<'a, 'tcx> { @@ -353,10 +349,6 @@ pub fn provide(providers: &mut ty::query::Providers) { _ => None, }, late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id), - lifetime_scope_map: |tcx, id| { - let item_id = item_for(tcx, id); - do_resolve(tcx, item_id, false, true).scope_for_path.unwrap().remove(&id) - }, ..*providers }; @@ -397,7 +389,7 @@ fn resolve_lifetimes_trait_definition( tcx: TyCtxt<'_>, local_def_id: LocalDefId, ) -> ResolveLifetimes { - convert_named_region_map(do_resolve(tcx, local_def_id, true, false)) + convert_named_region_map(do_resolve(tcx, local_def_id, true)) } /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`. @@ -405,21 +397,17 @@ fn resolve_lifetimes_trait_definition( /// `named_region_map`, `is_late_bound_map`, etc. #[tracing::instrument(level = "debug", skip(tcx))] fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { - convert_named_region_map(do_resolve(tcx, local_def_id, false, false)) + convert_named_region_map(do_resolve(tcx, local_def_id, false)) } fn do_resolve( tcx: TyCtxt<'_>, local_def_id: LocalDefId, trait_definition_only: bool, - with_scope_for_path: bool, ) -> NamedRegionMap { let item = tcx.hir().expect_item(local_def_id); - let mut named_region_map = NamedRegionMap { - defs: Default::default(), - late_bound_vars: Default::default(), - scope_for_path: with_scope_for_path.then(|| Default::default()), - }; + let mut named_region_map = + NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() }; let mut visitor = LifetimeContext { tcx, map: &mut named_region_map, @@ -515,24 +503,6 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty:: } } -#[tracing::instrument(level = "debug")] -fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath { - loop { - match scope { - Scope::Elision { elide: Elide::Exact(_), .. } => return LifetimeScopeForPath::Elided, - Scope::Root => return LifetimeScopeForPath::NonElided, - Scope::Binder { s, .. } - | Scope::Body { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } - | Scope::Elision { s, .. } => { - scope = s; - } - } - } -} - impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref. fn poly_trait_ref_binder_info(&mut self) -> (Vec, BinderScopeType) { @@ -1172,51 +1142,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) { - let scope = self.scope; - if let Some(scope_for_path) = self.map.scope_for_path.as_mut() { - // We add lifetime scope information for `Ident`s in associated type bindings and use - // the `HirId` of the type binding as the key in `LifetimeMap` - let lifetime_scope = get_lifetime_scopes_for_path(scope); - let map = scope_for_path.entry(type_binding.hir_id.owner).or_default(); - map.insert(type_binding.hir_id.local_id, lifetime_scope); - } - hir::intravisit::walk_assoc_type_binding(self, type_binding); - } - fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) { for (i, segment) in path.segments.iter().enumerate() { let depth = path.segments.len() - i - 1; if let Some(ref args) = segment.args { self.visit_segment_args(path.res, depth, args); } - - let scope = self.scope; - if let Some(scope_for_path) = self.map.scope_for_path.as_mut() { - // Add lifetime scope information to path segment. Note we cannot call `visit_path_segment` - // here because that call would yield to resolution problems due to `walk_path_segment` - // being called, which processes the path segments generic args, which we have already - // processed using `visit_segment_args`. - let lifetime_scope = get_lifetime_scopes_for_path(scope); - if let Some(hir_id) = segment.hir_id { - let map = scope_for_path.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, lifetime_scope); - } - } - } - } - - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx hir::PathSegment<'tcx>) { - let scope = self.scope; - if let Some(scope_for_path) = self.map.scope_for_path.as_mut() { - let lifetime_scope = get_lifetime_scopes_for_path(scope); - if let Some(hir_id) = path_segment.hir_id { - let map = scope_for_path.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, lifetime_scope); - } } - - intravisit::walk_path_segment(self, path_span, path_segment); } fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { @@ -2480,16 +2412,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } }; - // If we specifically need the `scope_for_path` map, then we're in the - // diagnostic pass and we don't want to emit more errors. - if self.map.scope_for_path.is_some() { - self.tcx.sess.delay_span_bug( - rustc_span::DUMMY_SP, - "Encountered unexpected errors during diagnostics related part", - ); - return; - } - let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); spans.sort(); let mut spans_dedup = spans.clone(); diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index c433c5ebbd368..edd2aedfe87e3 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -5,7 +5,6 @@ use rustc_errors::{ }; 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; @@ -299,13 +298,6 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { debug!(?path_hir_id); if let Some(path_hir_id) = path_hir_id { - // We first try to get lifetime name suggestions from scope or elision information. - // If none is available we use the parameter definitions - if let Some(LifetimeScopeForPath::Elided) = self.tcx.lifetime_scope(path_hir_id) { - // Use suggestions of the form `<'_, '_>` in case lifetime can be elided - return ["'_"].repeat(num_params_to_take).join(","); - } - let mut ret = Vec::new(); for (id, node) in self.tcx.hir().parent_iter(path_hir_id) { debug!(?id); From f71ad2f9920817b24a0253566f528bda845d9374 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jun 2022 09:59:26 +0200 Subject: [PATCH 3/3] Suggest 'static when in static/const items. --- .../wrong_number_of_generic_args.rs | 24 +++++++++++++++++++ .../elided-in-expr-position.stderr | 4 ++-- .../issue-81862.stderr | 2 +- .../missing-lifetime-specifier.stderr | 16 ++++++------- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index edd2aedfe87e3..c440e93fe0af1 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -317,6 +317,30 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { 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(", "); } diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr index 9263f3d67e3d2..b395a1cfd8a62 100644 --- a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr +++ b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr @@ -11,7 +11,7 @@ LL | type Assoc<'a> where Self: 'a; | ^^^^^ -- help: add missing lifetime argument | -LL | fn g(&self) -> Self::Assoc<'_>; +LL | fn g(&self) -> Self::Assoc<'a>; | ~~~~~~~~~ error[E0107]: missing generics for associated type `Trait::Assoc` @@ -27,7 +27,7 @@ LL | type Assoc<'a> where Self: 'a; | ^^^^^ -- help: add missing lifetime argument | -LL | fn g(&self) -> Self::Assoc<'_> { +LL | fn g(&self) -> Self::Assoc<'a> { | ~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/issue-81862.stderr b/src/test/ui/generic-associated-types/issue-81862.stderr index 024f8ad89f757..c664b3ee6683b 100644 --- a/src/test/ui/generic-associated-types/issue-81862.stderr +++ b/src/test/ui/generic-associated-types/issue-81862.stderr @@ -11,7 +11,7 @@ LL | type Item<'a>; | ^^^^ -- help: add missing lifetime argument | -LL | fn next(&mut self) -> Option>; +LL | fn next(&mut self) -> Option>; | ~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr index b04ea1c9158df..1498337549d81 100644 --- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr +++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr @@ -171,8 +171,8 @@ LL | pub union Qux<'t, 'k, I> { | ^^^ -- -- help: add missing lifetime argument | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | ++++ +LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); + | +++++++++ error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied --> $DIR/missing-lifetime-specifier.rs:43:44 @@ -243,8 +243,8 @@ LL | pub union Qux<'t, 'k, I> { | ^^^ -- -- help: add missing lifetime argument | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | ++++ +LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); + | +++++++++ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied --> $DIR/missing-lifetime-specifier.rs:51:45 @@ -261,8 +261,8 @@ LL | trait Tar<'t, 'k, I> {} | ^^^ -- -- help: add missing lifetime argument | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ++++ +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | +++++++++ error[E0106]: missing lifetime specifier --> $DIR/missing-lifetime-specifier.rs:51:44 @@ -360,8 +360,8 @@ LL | trait Tar<'t, 'k, I> {} | ^^^ -- -- help: add missing lifetime argument | -LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); - | ++++ +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | +++++++++ error: aborting due to 24 previous errors