Stop resolving lifetime elision on HIR.
This commit is contained in:
parent
267d3620a5
commit
30565e5871
1 changed files with 52 additions and 425 deletions
|
@ -21,7 +21,7 @@ use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::middle::resolve_lifetime::*;
|
use rustc_middle::middle::resolve_lifetime::*;
|
||||||
use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
|
use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -215,9 +215,8 @@ enum Scope<'a> {
|
||||||
},
|
},
|
||||||
|
|
||||||
/// A scope which either determines unspecified lifetimes or errors
|
/// A scope which either determines unspecified lifetimes or errors
|
||||||
/// on them (e.g., due to ambiguity). For more details, see `Elide`.
|
/// on them (e.g., due to ambiguity).
|
||||||
Elision {
|
Elision {
|
||||||
elide: Elide,
|
|
||||||
s: ScopeRef<'a>,
|
s: ScopeRef<'a>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -290,9 +289,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
||||||
Scope::Body { id, s: _ } => {
|
Scope::Body { id, s: _ } => {
|
||||||
f.debug_struct("Body").field("id", id).field("s", &"..").finish()
|
f.debug_struct("Body").field("id", id).field("s", &"..").finish()
|
||||||
}
|
}
|
||||||
Scope::Elision { elide, s: _ } => {
|
Scope::Elision { s: _ } => f.debug_struct("Elision").field("s", &"..").finish(),
|
||||||
f.debug_struct("Elision").field("elide", elide).field("s", &"..").finish()
|
|
||||||
}
|
|
||||||
Scope::ObjectLifetimeDefault { lifetime, s: _ } => f
|
Scope::ObjectLifetimeDefault { lifetime, s: _ } => f
|
||||||
.debug_struct("ObjectLifetimeDefault")
|
.debug_struct("ObjectLifetimeDefault")
|
||||||
.field("lifetime", lifetime)
|
.field("lifetime", lifetime)
|
||||||
|
@ -309,21 +306,6 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum Elide {
|
|
||||||
/// Use a fresh anonymous late-bound lifetime each time, by
|
|
||||||
/// incrementing the counter to generate sequential indices. All
|
|
||||||
/// anonymous lifetimes must start *after* named bound vars.
|
|
||||||
FreshLateAnon(u32, Cell<u32>),
|
|
||||||
/// Always use this one lifetime.
|
|
||||||
Exact(Region),
|
|
||||||
/// Less or more than one lifetime were found, error on unspecified.
|
|
||||||
Error,
|
|
||||||
/// Forbid lifetime elision inside of a larger scope where it would be
|
|
||||||
/// permitted. For example, in let position impl trait.
|
|
||||||
Forbid,
|
|
||||||
}
|
|
||||||
|
|
||||||
type ScopeRef<'a> = &'a Scope<'a>;
|
type ScopeRef<'a> = &'a Scope<'a>;
|
||||||
|
|
||||||
const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
|
const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
|
||||||
|
@ -664,8 +646,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
|
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
|
||||||
// No lifetime parameters, but implied 'static.
|
// No lifetime parameters, but implied 'static.
|
||||||
let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE };
|
self.with(Scope::Elision { s: self.scope }, |this| {
|
||||||
self.with(scope, |this| intravisit::walk_item(this, item));
|
intravisit::walk_item(this, item)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
|
hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
|
||||||
// Opaque types are visited when we visit the
|
// Opaque types are visited when we visit the
|
||||||
|
@ -860,7 +843,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
// position impl Trait
|
// position impl Trait
|
||||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||||
self.with(scope, |this| {
|
self.with(scope, |this| {
|
||||||
let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope };
|
let scope = Scope::Elision { s: this.scope };
|
||||||
this.with(scope, |this| {
|
this.with(scope, |this| {
|
||||||
intravisit::walk_item(this, opaque_ty);
|
intravisit::walk_item(this, opaque_ty);
|
||||||
})
|
})
|
||||||
|
@ -936,7 +919,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
let mut index = self.next_early_index_for_opaque_type();
|
let mut index = self.next_early_index_for_opaque_type();
|
||||||
debug!(?index);
|
debug!(?index);
|
||||||
|
|
||||||
let mut elision = None;
|
|
||||||
let mut lifetimes = FxIndexMap::default();
|
let mut lifetimes = FxIndexMap::default();
|
||||||
let mut non_lifetime_count = 0;
|
let mut non_lifetime_count = 0;
|
||||||
debug!(?generics.params);
|
debug!(?generics.params);
|
||||||
|
@ -945,15 +927,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
GenericParamKind::Lifetime { .. } => {
|
GenericParamKind::Lifetime { .. } => {
|
||||||
let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m);
|
let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m);
|
||||||
lifetimes.insert(def_id, reg);
|
lifetimes.insert(def_id, reg);
|
||||||
if let hir::ParamName::Plain(Ident {
|
|
||||||
name: kw::UnderscoreLifetime,
|
|
||||||
..
|
|
||||||
}) = param.name
|
|
||||||
{
|
|
||||||
// Pick the elided lifetime "definition" if one exists
|
|
||||||
// and use it to make an elision scope.
|
|
||||||
elision = Some(reg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
||||||
non_lifetime_count += 1;
|
non_lifetime_count += 1;
|
||||||
|
@ -963,51 +936,25 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
let next_early_index = index + non_lifetime_count;
|
let next_early_index = index + non_lifetime_count;
|
||||||
self.map.late_bound_vars.insert(ty.hir_id, vec![]);
|
self.map.late_bound_vars.insert(ty.hir_id, vec![]);
|
||||||
|
|
||||||
if let Some(elision_region) = elision {
|
let scope = Scope::Binder {
|
||||||
let scope =
|
hir_id: ty.hir_id,
|
||||||
Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope };
|
lifetimes,
|
||||||
self.with(scope, |this| {
|
next_early_index,
|
||||||
let scope = Scope::Binder {
|
s: self.scope,
|
||||||
hir_id: ty.hir_id,
|
opaque_type_parent: false,
|
||||||
lifetimes,
|
scope_type: BinderScopeType::Normal,
|
||||||
next_early_index,
|
allow_late_bound: false,
|
||||||
s: this.scope,
|
where_bound_origin: None,
|
||||||
opaque_type_parent: false,
|
};
|
||||||
scope_type: BinderScopeType::Normal,
|
self.with(scope, |this| {
|
||||||
allow_late_bound: false,
|
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||||
where_bound_origin: None,
|
this.with(scope, |this| {
|
||||||
};
|
this.visit_generics(generics);
|
||||||
this.with(scope, |this| {
|
for bound in bounds {
|
||||||
this.visit_generics(generics);
|
this.visit_param_bound(bound);
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
}
|
||||||
this.with(scope, |this| {
|
})
|
||||||
for bound in bounds {
|
});
|
||||||
this.visit_param_bound(bound);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let scope = Scope::Binder {
|
|
||||||
hir_id: ty.hir_id,
|
|
||||||
lifetimes,
|
|
||||||
next_early_index,
|
|
||||||
s: self.scope,
|
|
||||||
opaque_type_parent: false,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
|
||||||
allow_late_bound: false,
|
|
||||||
where_bound_origin: None,
|
|
||||||
};
|
|
||||||
self.with(scope, |this| {
|
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
|
||||||
this.with(scope, |this| {
|
|
||||||
this.visit_generics(generics);
|
|
||||||
for bound in bounds {
|
|
||||||
this.visit_param_bound(bound);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => intravisit::walk_ty(self, ty),
|
_ => intravisit::walk_ty(self, ty),
|
||||||
}
|
}
|
||||||
|
@ -1156,12 +1103,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
|
fn visit_fn(
|
||||||
|
&mut self,
|
||||||
|
fk: intravisit::FnKind<'tcx>,
|
||||||
|
fd: &'tcx hir::FnDecl<'tcx>,
|
||||||
|
body_id: hir::BodyId,
|
||||||
|
_: Span,
|
||||||
|
_: hir::HirId,
|
||||||
|
) {
|
||||||
let output = match fd.output {
|
let output = match fd.output {
|
||||||
hir::FnRetTy::DefaultReturn(_) => None,
|
hir::FnRetTy::DefaultReturn(_) => None,
|
||||||
hir::FnRetTy::Return(ref ty) => Some(&**ty),
|
hir::FnRetTy::Return(ref ty) => Some(&**ty),
|
||||||
};
|
};
|
||||||
self.visit_fn_like_elision(&fd.inputs, output);
|
self.visit_fn_like_elision(&fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
|
||||||
|
intravisit::walk_fn_kind(self, fk);
|
||||||
|
self.visit_nested_body(body_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
|
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
|
||||||
|
@ -1773,7 +1729,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if generic_args.parenthesized {
|
if generic_args.parenthesized {
|
||||||
self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty()));
|
self.visit_fn_like_elision(
|
||||||
|
generic_args.inputs(),
|
||||||
|
Some(generic_args.bindings[0].ty()),
|
||||||
|
false,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2052,319 +2012,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
inputs: &'tcx [hir::Ty<'tcx>],
|
inputs: &'tcx [hir::Ty<'tcx>],
|
||||||
output: Option<&'tcx hir::Ty<'tcx>>,
|
output: Option<&'tcx hir::Ty<'tcx>>,
|
||||||
|
in_closure: bool,
|
||||||
) {
|
) {
|
||||||
debug!("visit_fn_like_elision: enter");
|
self.with(Scope::Elision { s: self.scope }, |this| {
|
||||||
let mut scope = &*self.scope;
|
|
||||||
let hir_id = loop {
|
|
||||||
match scope {
|
|
||||||
Scope::Binder { hir_id, allow_late_bound: true, .. } => {
|
|
||||||
break *hir_id;
|
|
||||||
}
|
|
||||||
Scope::ObjectLifetimeDefault { ref s, .. }
|
|
||||||
| Scope::Elision { ref s, .. }
|
|
||||||
| Scope::Supertrait { ref s, .. }
|
|
||||||
| Scope::TraitRefBoundary { ref s, .. } => {
|
|
||||||
scope = *s;
|
|
||||||
}
|
|
||||||
Scope::Root
|
|
||||||
| Scope::Body { .. }
|
|
||||||
| Scope::Binder { allow_late_bound: false, .. } => {
|
|
||||||
// See issues #83907 and #83693. Just bail out from looking inside.
|
|
||||||
// See the issue #95023 for not allowing late bound
|
|
||||||
self.tcx.sess.delay_span_bug(
|
|
||||||
rustc_span::DUMMY_SP,
|
|
||||||
"In fn_like_elision without appropriate scope above",
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// While not strictly necessary, we gather anon lifetimes *before* actually
|
|
||||||
// visiting the argument types.
|
|
||||||
let mut gather = GatherAnonLifetimes { anon_count: 0 };
|
|
||||||
for input in inputs {
|
|
||||||
gather.visit_ty(input);
|
|
||||||
}
|
|
||||||
trace!(?gather.anon_count);
|
|
||||||
let late_bound_vars = self.map.late_bound_vars.entry(hir_id).or_default();
|
|
||||||
let named_late_bound_vars = late_bound_vars.len() as u32;
|
|
||||||
late_bound_vars.extend(
|
|
||||||
(0..gather.anon_count).map(|var| ty::BoundVariableKind::Region(ty::BrAnon(var))),
|
|
||||||
);
|
|
||||||
let arg_scope = Scope::Elision {
|
|
||||||
elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)),
|
|
||||||
s: self.scope,
|
|
||||||
};
|
|
||||||
self.with(arg_scope, |this| {
|
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
this.visit_ty(input);
|
this.visit_ty(input);
|
||||||
}
|
}
|
||||||
|
if !in_closure && let Some(output) = output {
|
||||||
|
this.visit_ty(output);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
if in_closure && let Some(output) = output {
|
||||||
let Some(output) = output else { return };
|
self.visit_ty(output);
|
||||||
|
|
||||||
debug!("determine output");
|
|
||||||
|
|
||||||
// Figure out if there's a body we can get argument names from,
|
|
||||||
// and whether there's a `self` argument (treated specially).
|
|
||||||
let mut assoc_item_kind = None;
|
|
||||||
let mut impl_self = None;
|
|
||||||
let parent = self.tcx.hir().get_parent_node(output.hir_id);
|
|
||||||
match self.tcx.hir().get(parent) {
|
|
||||||
// `fn` definitions and methods.
|
|
||||||
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) => {}
|
|
||||||
|
|
||||||
Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
|
|
||||||
if let hir::ItemKind::Trait(.., ref trait_items) =
|
|
||||||
self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
|
|
||||||
{
|
|
||||||
assoc_item_kind =
|
|
||||||
trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, _), .. }) => {
|
|
||||||
if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
|
|
||||||
self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
|
|
||||||
{
|
|
||||||
impl_self = Some(self_ty);
|
|
||||||
assoc_item_kind =
|
|
||||||
items.iter().find(|ii| ii.id.hir_id() == parent).map(|ii| ii.kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
|
|
||||||
Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => {},
|
|
||||||
|
|
||||||
Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => {},
|
|
||||||
|
|
||||||
// Everything else (only closures?) doesn't
|
|
||||||
// actually enjoy elision in return types.
|
|
||||||
_ => {
|
|
||||||
self.visit_ty(output);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let has_self = match assoc_item_kind {
|
|
||||||
Some(hir::AssocItemKind::Fn { has_self }) => has_self,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// In accordance with the rules for lifetime elision, we can determine
|
|
||||||
// what region to use for elision in the output type in two ways.
|
|
||||||
// First (determined here), if `self` is by-reference, then the
|
|
||||||
// implied output region is the region of the self parameter.
|
|
||||||
if has_self {
|
|
||||||
struct SelfVisitor<'a> {
|
|
||||||
map: &'a NamedRegionMap,
|
|
||||||
impl_self: Option<&'a hir::TyKind<'a>>,
|
|
||||||
lifetime: Set1<Region>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SelfVisitor<'_> {
|
|
||||||
// Look for `self: &'a Self` - also desugared from `&'a self`,
|
|
||||||
// and if that matches, use it for elision and return early.
|
|
||||||
fn is_self_ty(&self, res: Res) -> bool {
|
|
||||||
if let Res::SelfTy { .. } = res {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't always rely on literal (or implied) `Self` due
|
|
||||||
// to the way elision rules were originally specified.
|
|
||||||
if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) =
|
|
||||||
self.impl_self
|
|
||||||
{
|
|
||||||
match path.res {
|
|
||||||
// Permit the types that unambiguously always
|
|
||||||
// result in the same type constructor being used
|
|
||||||
// (it can't differ between `Self` and `self`).
|
|
||||||
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _)
|
|
||||||
| Res::PrimTy(_) => return res == path.res,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for SelfVisitor<'a> {
|
|
||||||
fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) {
|
|
||||||
if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind {
|
|
||||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind
|
|
||||||
{
|
|
||||||
if self.is_self_ty(path.res) {
|
|
||||||
if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
|
|
||||||
self.lifetime.insert(*lifetime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
intravisit::walk_ty(self, ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visitor = SelfVisitor {
|
|
||||||
map: self.map,
|
|
||||||
impl_self: impl_self.map(|ty| &ty.kind),
|
|
||||||
lifetime: Set1::Empty,
|
|
||||||
};
|
|
||||||
visitor.visit_ty(&inputs[0]);
|
|
||||||
if let Set1::One(lifetime) = visitor.lifetime {
|
|
||||||
let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope };
|
|
||||||
self.with(scope, |this| this.visit_ty(output));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second, if there was exactly one lifetime (either a substitution or a
|
|
||||||
// reference) in the arguments, then any anonymous regions in the output
|
|
||||||
// have that lifetime.
|
|
||||||
let mut possible_implied_output_region = None;
|
|
||||||
let mut lifetime_count = 0;
|
|
||||||
for input in inputs.iter().skip(has_self as usize) {
|
|
||||||
let mut gather = GatherLifetimes {
|
|
||||||
map: self.map,
|
|
||||||
outer_index: ty::INNERMOST,
|
|
||||||
have_bound_regions: false,
|
|
||||||
lifetimes: Default::default(),
|
|
||||||
};
|
|
||||||
gather.visit_ty(input);
|
|
||||||
|
|
||||||
lifetime_count += gather.lifetimes.len();
|
|
||||||
|
|
||||||
if lifetime_count == 1 && gather.lifetimes.len() == 1 {
|
|
||||||
// there's a chance that the unique lifetime of this
|
|
||||||
// iteration will be the appropriate lifetime for output
|
|
||||||
// parameters, so lets store it.
|
|
||||||
possible_implied_output_region = gather.lifetimes.iter().cloned().next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let elide = if lifetime_count == 1 {
|
|
||||||
Elide::Exact(possible_implied_output_region.unwrap())
|
|
||||||
} else {
|
|
||||||
Elide::Error
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!(?elide);
|
|
||||||
|
|
||||||
let scope = Scope::Elision { elide, s: self.scope };
|
|
||||||
self.with(scope, |this| this.visit_ty(output));
|
|
||||||
|
|
||||||
struct GatherLifetimes<'a> {
|
|
||||||
map: &'a NamedRegionMap,
|
|
||||||
outer_index: ty::DebruijnIndex,
|
|
||||||
have_bound_regions: bool,
|
|
||||||
lifetimes: FxHashSet<Region>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> {
|
|
||||||
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
|
|
||||||
if let hir::TyKind::BareFn(_) = ty.kind {
|
|
||||||
self.outer_index.shift_in(1);
|
|
||||||
}
|
|
||||||
match ty.kind {
|
|
||||||
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
|
|
||||||
for bound in bounds {
|
|
||||||
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stay on the safe side and don't include the object
|
|
||||||
// lifetime default (which may not end up being used).
|
|
||||||
if !lifetime.is_elided() {
|
|
||||||
self.visit_lifetime(lifetime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
intravisit::walk_ty(self, ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let hir::TyKind::BareFn(_) = ty.kind {
|
|
||||||
self.outer_index.shift_out(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_generic_param(&mut self, param: &hir::GenericParam<'_>) {
|
|
||||||
if let hir::GenericParamKind::Lifetime { .. } = param.kind {
|
|
||||||
// FIXME(eddyb) Do we want this? It only makes a difference
|
|
||||||
// if this `for<'a>` lifetime parameter is never used.
|
|
||||||
self.have_bound_regions = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
intravisit::walk_generic_param(self, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_poly_trait_ref(
|
|
||||||
&mut self,
|
|
||||||
trait_ref: &hir::PolyTraitRef<'_>,
|
|
||||||
modifier: hir::TraitBoundModifier,
|
|
||||||
) {
|
|
||||||
self.outer_index.shift_in(1);
|
|
||||||
intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
|
|
||||||
self.outer_index.shift_out(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_param_bound(&mut self, bound: &hir::GenericBound<'_>) {
|
|
||||||
if let hir::GenericBound::LangItemTrait { .. } = bound {
|
|
||||||
self.outer_index.shift_in(1);
|
|
||||||
intravisit::walk_param_bound(self, bound);
|
|
||||||
self.outer_index.shift_out(1);
|
|
||||||
} else {
|
|
||||||
intravisit::walk_param_bound(self, bound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
|
|
||||||
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
|
|
||||||
match lifetime {
|
|
||||||
Region::LateBound(debruijn, _, _)
|
|
||||||
| Region::LateBoundAnon(debruijn, _, _)
|
|
||||||
if debruijn < self.outer_index =>
|
|
||||||
{
|
|
||||||
self.have_bound_regions = true;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// FIXME(jackh726): nested trait refs?
|
|
||||||
self.lifetimes.insert(lifetime.shifted_out_to_binder(self.outer_index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GatherAnonLifetimes {
|
|
||||||
anon_count: u32,
|
|
||||||
}
|
|
||||||
impl<'v> Visitor<'v> for GatherAnonLifetimes {
|
|
||||||
#[instrument(skip(self), level = "trace")]
|
|
||||||
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
|
|
||||||
// If we enter a `BareFn`, then we enter a *new* binding scope
|
|
||||||
if let hir::TyKind::BareFn(_) = ty.kind {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
intravisit::walk_ty(self, ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_generic_args(
|
|
||||||
&mut self,
|
|
||||||
path_span: Span,
|
|
||||||
generic_args: &'v hir::GenericArgs<'v>,
|
|
||||||
) {
|
|
||||||
// parenthesized args enter a new elision scope
|
|
||||||
if generic_args.parenthesized {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
intravisit::walk_generic_args(self, path_span, generic_args)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self), level = "trace")]
|
|
||||||
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
|
|
||||||
if lifetime_ref.is_elided() {
|
|
||||||
self.anon_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2375,48 +2034,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut late_depth = 0;
|
|
||||||
let mut scope = self.scope;
|
let mut scope = self.scope;
|
||||||
loop {
|
loop {
|
||||||
match *scope {
|
match *scope {
|
||||||
// Do not assign any resolution, it will be inferred.
|
// Do not assign any resolution, it will be inferred.
|
||||||
Scope::Body { .. } => return,
|
Scope::Body { .. } => return,
|
||||||
|
|
||||||
Scope::Root => break,
|
Scope::Root | Scope::Elision { .. } => break,
|
||||||
|
|
||||||
Scope::Binder { s, scope_type, .. } => {
|
Scope::Binder { s, .. }
|
||||||
match scope_type {
|
| Scope::ObjectLifetimeDefault { s, .. }
|
||||||
BinderScopeType::Normal => late_depth += 1,
|
|
||||||
BinderScopeType::Concatenating => {}
|
|
||||||
}
|
|
||||||
scope = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scope::Elision {
|
|
||||||
elide: Elide::FreshLateAnon(named_late_bound_vars, ref counter),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
for lifetime_ref in lifetime_refs {
|
|
||||||
let lifetime =
|
|
||||||
Region::late_anon(named_late_bound_vars, counter).shifted(late_depth);
|
|
||||||
|
|
||||||
self.insert_lifetime(lifetime_ref, lifetime);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scope::Elision { elide: Elide::Exact(l), .. } => {
|
|
||||||
let lifetime = l.shifted(late_depth);
|
|
||||||
for lifetime_ref in lifetime_refs {
|
|
||||||
self.insert_lifetime(lifetime_ref, lifetime);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scope::Elision { elide: Elide::Error, .. }
|
|
||||||
| Scope::Elision { elide: Elide::Forbid, .. } => break,
|
|
||||||
|
|
||||||
Scope::ObjectLifetimeDefault { s, .. }
|
|
||||||
| Scope::Supertrait { s, .. }
|
| Scope::Supertrait { s, .. }
|
||||||
| Scope::TraitRefBoundary { s, .. } => {
|
| Scope::TraitRefBoundary { s, .. } => {
|
||||||
scope = s;
|
scope = s;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue