Rollup merge of #97312 - cjgillot:no-path-in-scope, r=compiler-errors
Compute lifetimes in scope at diagnostic time The set of available lifetimes is currently computed during lifetime resolution on HIR. It is only used for one diagnostic. In this PR, HIR lifetime resolution just reports whether elided lifetimes are well-defined at the place of use. The diagnostic code is responsible for building a list of lifetime names if elision is not allowed. This will allow to remove lifetime resolution on HIR eventually.
This commit is contained in:
commit
a736acc804
15 changed files with 127 additions and 206 deletions
|
@ -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) {
|
fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
|
||||||
// Do not visit the duplicate information in TraitItemRef. We want to
|
// Do not visit the duplicate information in TraitItemRef. We want to
|
||||||
// map the actual nodes, not the duplicate ones in the *Ref.
|
// map the actual nodes, not the duplicate ones in the *Ref.
|
||||||
|
|
|
@ -3302,6 +3302,7 @@ pub enum Node<'hir> {
|
||||||
Stmt(&'hir Stmt<'hir>),
|
Stmt(&'hir Stmt<'hir>),
|
||||||
PathSegment(&'hir PathSegment<'hir>),
|
PathSegment(&'hir PathSegment<'hir>),
|
||||||
Ty(&'hir Ty<'hir>),
|
Ty(&'hir Ty<'hir>),
|
||||||
|
TypeBinding(&'hir TypeBinding<'hir>),
|
||||||
TraitRef(&'hir TraitRef<'hir>),
|
TraitRef(&'hir TraitRef<'hir>),
|
||||||
Binding(&'hir Pat<'hir>),
|
Binding(&'hir Pat<'hir>),
|
||||||
Pat(&'hir Pat<'hir>),
|
Pat(&'hir Pat<'hir>),
|
||||||
|
@ -3347,6 +3348,7 @@ impl<'hir> Node<'hir> {
|
||||||
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
|
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
|
||||||
Node::Lifetime(lt) => Some(lt.name.ident()),
|
Node::Lifetime(lt) => Some(lt.name.ident()),
|
||||||
Node::GenericParam(p) => Some(p.name.ident()),
|
Node::GenericParam(p) => Some(p.name.ident()),
|
||||||
|
Node::TypeBinding(b) => Some(b.ident),
|
||||||
Node::Param(..)
|
Node::Param(..)
|
||||||
| Node::AnonConst(..)
|
| Node::AnonConst(..)
|
||||||
| Node::Expr(..)
|
| Node::Expr(..)
|
||||||
|
|
|
@ -85,6 +85,7 @@ impl<'a> State<'a> {
|
||||||
Node::Stmt(a) => self.print_stmt(&a),
|
Node::Stmt(a) => self.print_stmt(&a),
|
||||||
Node::PathSegment(a) => self.print_path_segment(&a),
|
Node::PathSegment(a) => self.print_path_segment(&a),
|
||||||
Node::Ty(a) => self.print_type(&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::TraitRef(a) => self.print_trait_ref(&a),
|
||||||
Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
|
Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
|
||||||
Node::Arm(a) => self.print_arm(&a),
|
Node::Arm(a) => self.print_arm(&a),
|
||||||
|
@ -1703,10 +1704,20 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
for binding in generic_args.bindings.iter() {
|
for binding in generic_args.bindings.iter() {
|
||||||
start_or_comma(self);
|
start_or_comma(self);
|
||||||
|
self.print_type_binding(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !empty.get() {
|
||||||
|
self.word(">")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
|
||||||
self.print_ident(binding.ident);
|
self.print_ident(binding.ident);
|
||||||
self.print_generic_args(binding.gen_args, false, false);
|
self.print_generic_args(binding.gen_args, false, false);
|
||||||
self.space();
|
self.space();
|
||||||
match generic_args.bindings[0].kind {
|
match binding.kind {
|
||||||
hir::TypeBindingKind::Equality { ref term } => {
|
hir::TypeBindingKind::Equality { ref term } => {
|
||||||
self.word_space("=");
|
self.word_space("=");
|
||||||
match term {
|
match term {
|
||||||
|
@ -1720,12 +1731,6 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !empty.get() {
|
|
||||||
self.word(">")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
|
pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
|
||||||
self.maybe_print_comment(pat.span.lo());
|
self.maybe_print_comment(pat.span.lo());
|
||||||
self.ann.pre(self, AnnNode::Pat(pat));
|
self.ann.pre(self, AnnNode::Pat(pat));
|
||||||
|
|
|
@ -298,6 +298,7 @@ impl<'hir> Map<'hir> {
|
||||||
Node::Stmt(_)
|
Node::Stmt(_)
|
||||||
| Node::PathSegment(_)
|
| Node::PathSegment(_)
|
||||||
| Node::Ty(_)
|
| Node::Ty(_)
|
||||||
|
| Node::TypeBinding(_)
|
||||||
| Node::Infer(_)
|
| Node::Infer(_)
|
||||||
| Node::TraitRef(_)
|
| Node::TraitRef(_)
|
||||||
| Node::Pat(_)
|
| Node::Pat(_)
|
||||||
|
@ -323,7 +324,8 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_parent_node(self, hir_id: HirId) -> HirId {
|
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.
|
/// 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()))
|
.with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
|
||||||
}
|
}
|
||||||
Node::Ty(ty) => ty.span,
|
Node::Ty(ty) => ty.span,
|
||||||
|
Node::TypeBinding(tb) => tb.span,
|
||||||
Node::TraitRef(tr) => tr.path.span,
|
Node::TraitRef(tr) => tr.path.span,
|
||||||
Node::Binding(pat) => pat.span,
|
Node::Binding(pat) => pat.span,
|
||||||
Node::Pat(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::Stmt(_)) => node_str("stmt"),
|
||||||
Some(Node::PathSegment(_)) => node_str("path segment"),
|
Some(Node::PathSegment(_)) => node_str("path segment"),
|
||||||
Some(Node::Ty(_)) => node_str("type"),
|
Some(Node::Ty(_)) => node_str("type"),
|
||||||
|
Some(Node::TypeBinding(_)) => node_str("type binding"),
|
||||||
Some(Node::TraitRef(_)) => node_str("trait ref"),
|
Some(Node::TraitRef(_)) => node_str("trait ref"),
|
||||||
Some(Node::Binding(_)) => node_str("local"),
|
Some(Node::Binding(_)) => node_str("local"),
|
||||||
Some(Node::Pat(_)) => node_str("pat"),
|
Some(Node::Pat(_)) => node_str("pat"),
|
||||||
|
|
|
@ -16,20 +16,6 @@ pub enum Region {
|
||||||
Free(DefId, /* lifetime decl */ DefId),
|
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(Vec<LocalDefId>),
|
|
||||||
|
|
||||||
/// 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.
|
/// A set containing, at most, one known element.
|
||||||
/// If two distinct values are inserted into a set, then it
|
/// If two distinct values are inserted into a set, then it
|
||||||
/// becomes `Many`, which can be used to detect ambiguities.
|
/// becomes `Many`, which can be used to detect ambiguities.
|
||||||
|
|
|
@ -1599,11 +1599,6 @@ rustc_queries! {
|
||||||
desc { "looking up late bound vars" }
|
desc { "looking up late bound vars" }
|
||||||
}
|
}
|
||||||
|
|
||||||
query lifetime_scope_map(_: LocalDefId) -> Option<FxHashMap<ItemLocalId, LifetimeScopeForPath>> {
|
|
||||||
storage(ArenaCacheSelector<'tcx>)
|
|
||||||
desc { "finds the lifetime scope for an HirId of a PathSegment" }
|
|
||||||
}
|
|
||||||
|
|
||||||
query visibility(def_id: DefId) -> ty::Visibility {
|
query visibility(def_id: DefId) -> ty::Visibility {
|
||||||
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::hir::place::Place as HirPlace;
|
||||||
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
|
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
|
||||||
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
|
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
|
||||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
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::middle::stability;
|
||||||
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
|
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
|
||||||
use crate::mir::{
|
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
|
/// Whether the `def_id` counts as const fn in the current crate, considering all active
|
||||||
/// feature gates
|
/// feature gates
|
||||||
pub fn is_const_fn(self, def_id: DefId) -> bool {
|
pub fn is_const_fn(self, def_id: DefId) -> bool {
|
||||||
|
|
|
@ -6,9 +6,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||||
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||||
use crate::middle::lib_features::LibFeatures;
|
use crate::middle::lib_features::LibFeatures;
|
||||||
use crate::middle::privacy::AccessLevels;
|
use crate::middle::privacy::AccessLevels;
|
||||||
use crate::middle::resolve_lifetime::{
|
use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes};
|
||||||
LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes,
|
|
||||||
};
|
|
||||||
use crate::middle::stability::{self, DeprecationEntry};
|
use crate::middle::stability::{self, DeprecationEntry};
|
||||||
use crate::mir;
|
use crate::mir;
|
||||||
use crate::mir::interpret::GlobalId;
|
use crate::mir::interpret::GlobalId;
|
||||||
|
|
|
@ -8,12 +8,11 @@
|
||||||
|
|
||||||
use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
|
use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
|
||||||
use rustc_ast::walk_list;
|
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_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefIdMap, LocalDefId};
|
use rustc_hir::def_id::{DefIdMap, LocalDefId};
|
||||||
use rustc_hir::hir_id::ItemLocalId;
|
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
|
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
|
||||||
use rustc_hir::{GenericParamKind, HirIdMap};
|
use rustc_hir::{GenericParamKind, HirIdMap};
|
||||||
|
@ -141,9 +140,6 @@ struct NamedRegionMap {
|
||||||
// - trait refs
|
// - trait refs
|
||||||
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
|
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
|
||||||
late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
|
late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
|
||||||
|
|
||||||
// maps `PathSegment` `HirId`s to lifetime scopes.
|
|
||||||
scope_for_path: Option<FxHashMap<LocalDefId, FxHashMap<ItemLocalId, LifetimeScopeForPath>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct LifetimeContext<'a, 'tcx> {
|
pub(crate) struct LifetimeContext<'a, 'tcx> {
|
||||||
|
@ -362,10 +358,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
|
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
|
..*providers
|
||||||
};
|
};
|
||||||
|
@ -406,7 +398,7 @@ fn resolve_lifetimes_trait_definition(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
local_def_id: LocalDefId,
|
local_def_id: LocalDefId,
|
||||||
) -> ResolveLifetimes {
|
) -> 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`.
|
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
|
||||||
|
@ -414,21 +406,17 @@ fn resolve_lifetimes_trait_definition(
|
||||||
/// `named_region_map`, `is_late_bound_map`, etc.
|
/// `named_region_map`, `is_late_bound_map`, etc.
|
||||||
#[tracing::instrument(level = "debug", skip(tcx))]
|
#[tracing::instrument(level = "debug", skip(tcx))]
|
||||||
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
|
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(
|
fn do_resolve(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
local_def_id: LocalDefId,
|
local_def_id: LocalDefId,
|
||||||
trait_definition_only: bool,
|
trait_definition_only: bool,
|
||||||
with_scope_for_path: bool,
|
|
||||||
) -> NamedRegionMap {
|
) -> NamedRegionMap {
|
||||||
let item = tcx.hir().expect_item(local_def_id);
|
let item = tcx.hir().expect_item(local_def_id);
|
||||||
let mut named_region_map = NamedRegionMap {
|
let mut named_region_map =
|
||||||
defs: Default::default(),
|
NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
|
||||||
late_bound_vars: Default::default(),
|
|
||||||
scope_for_path: with_scope_for_path.then(|| Default::default()),
|
|
||||||
};
|
|
||||||
let mut visitor = LifetimeContext {
|
let mut visitor = LifetimeContext {
|
||||||
tcx,
|
tcx,
|
||||||
map: &mut named_region_map,
|
map: &mut named_region_map,
|
||||||
|
@ -524,38 +512,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 {
|
|
||||||
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 = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
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.
|
/// 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<ty::BoundVariableKind>, BinderScopeType) {
|
fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) {
|
||||||
|
@ -1202,52 +1158,14 @@ 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) {
|
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
|
||||||
for (i, segment) in path.segments.iter().enumerate() {
|
for (i, segment) in path.segments.iter().enumerate() {
|
||||||
let depth = path.segments.len() - i - 1;
|
let depth = path.segments.len() - i - 1;
|
||||||
if let Some(ref args) = segment.args {
|
if let Some(ref args) = segment.args {
|
||||||
self.visit_segment_args(path.res, depth, 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>) {
|
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
|
||||||
let output = match fd.output {
|
let output = match fd.output {
|
||||||
|
@ -2227,6 +2145,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
|
|
||||||
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
|
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
|
||||||
Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
|
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
|
// Everything else (only closures?) doesn't
|
||||||
// actually enjoy elision in return types.
|
// actually enjoy elision in return types.
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -2548,16 +2469,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();
|
let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
|
||||||
spans.sort();
|
spans.sort();
|
||||||
let mut spans_dedup = spans.clone();
|
let mut spans_dedup = spans.clone();
|
||||||
|
|
|
@ -249,6 +249,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
||||||
| hir::Node::Stmt(..)
|
| hir::Node::Stmt(..)
|
||||||
| hir::Node::PathSegment(..)
|
| hir::Node::PathSegment(..)
|
||||||
| hir::Node::Ty(..)
|
| hir::Node::Ty(..)
|
||||||
|
| hir::Node::TypeBinding(..)
|
||||||
| hir::Node::TraitRef(..)
|
| hir::Node::TraitRef(..)
|
||||||
| hir::Node::Binding(..)
|
| hir::Node::Binding(..)
|
||||||
| hir::Node::Pat(..)
|
| hir::Node::Pat(..)
|
||||||
|
|
|
@ -450,21 +450,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
||||||
.discr_type()
|
.discr_type()
|
||||||
.to_ty(tcx),
|
.to_ty(tcx),
|
||||||
|
|
||||||
Node::TraitRef(trait_ref @ &TraitRef {
|
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
|
||||||
path, ..
|
if let Node::TraitRef(trait_ref) = tcx.hir().get(
|
||||||
}) if let Some((binding, seg)) =
|
tcx.hir().get_parent_node(binding_id)
|
||||||
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
|
|
||||||
})
|
|
||||||
}) =>
|
|
||||||
{
|
{
|
||||||
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
||||||
return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
|
return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
|
||||||
|
|
|
@ -5,7 +5,6 @@ use rustc_errors::{
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_middle::hir::map::fn_sig;
|
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_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
|
@ -291,7 +290,69 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates lifetime name suggestions from the lifetime parameter names
|
// 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
|
self.gen_params
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -501,44 +562,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||||
let num_params_to_take = num_missing_args;
|
let num_params_to_take = num_missing_args;
|
||||||
let msg = format!("add missing {} argument{}", self.kind(), pluralize!(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
|
let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
|
||||||
// available we use the parameter definitions
|
self.path_segment.hir_id,
|
||||||
let suggested_args = if let Some(hir_id) = self.path_segment.hir_id {
|
num_params_to_take,
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("suggested_args: {:?}", &suggested_args);
|
debug!("suggested_args: {:?}", &suggested_args);
|
||||||
|
|
||||||
match self.angle_brackets {
|
match self.angle_brackets {
|
||||||
|
|
|
@ -11,7 +11,7 @@ LL | type Assoc<'a> where Self: 'a;
|
||||||
| ^^^^^ --
|
| ^^^^^ --
|
||||||
help: add missing lifetime argument
|
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`
|
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
|
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
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -11,7 +11,7 @@ LL | type Item<'a>;
|
||||||
| ^^^^ --
|
| ^^^^ --
|
||||||
help: add missing lifetime argument
|
help: add missing lifetime argument
|
||||||
|
|
|
|
||||||
LL | fn next(&mut self) -> Option<Self::Item<'_>>;
|
LL | fn next(&mut self) -> Option<Self::Item<'a>>;
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
|
@ -171,8 +171,8 @@ LL | pub union Qux<'t, 'k, I> {
|
||||||
| ^^^ -- --
|
| ^^^ -- --
|
||||||
help: add missing lifetime argument
|
help: add missing lifetime argument
|
||||||
|
|
|
|
||||||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||||
| ++++
|
| +++++++++
|
||||||
|
|
||||||
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||||
--> $DIR/missing-lifetime-specifier.rs:43:44
|
--> $DIR/missing-lifetime-specifier.rs:43:44
|
||||||
|
@ -243,8 +243,8 @@ LL | pub union Qux<'t, 'k, I> {
|
||||||
| ^^^ -- --
|
| ^^^ -- --
|
||||||
help: add missing lifetime argument
|
help: add missing lifetime argument
|
||||||
|
|
|
|
||||||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||||
| ++++
|
| +++++++++
|
||||||
|
|
||||||
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||||
--> $DIR/missing-lifetime-specifier.rs:51:45
|
--> $DIR/missing-lifetime-specifier.rs:51:45
|
||||||
|
@ -261,8 +261,8 @@ LL | trait Tar<'t, 'k, I> {}
|
||||||
| ^^^ -- --
|
| ^^^ -- --
|
||||||
help: add missing lifetime argument
|
help: add missing lifetime argument
|
||||||
|
|
|
|
||||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||||
| ++++
|
| +++++++++
|
||||||
|
|
||||||
error[E0106]: missing lifetime specifier
|
error[E0106]: missing lifetime specifier
|
||||||
--> $DIR/missing-lifetime-specifier.rs:51:44
|
--> $DIR/missing-lifetime-specifier.rs:51:44
|
||||||
|
@ -360,8 +360,8 @@ LL | trait Tar<'t, 'k, I> {}
|
||||||
| ^^^ -- --
|
| ^^^ -- --
|
||||||
help: add missing lifetime argument
|
help: add missing lifetime argument
|
||||||
|
|
|
|
||||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||||
| ++++
|
| +++++++++
|
||||||
|
|
||||||
error: aborting due to 24 previous errors
|
error: aborting due to 24 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue