1
Fork 0

Compute is_late_bound in a separate query.

The computation is actually much simpler, and can be done by directly
fetching the HIR for the `FnDecl` and its generics.
This commit is contained in:
Camille GILLOT 2022-05-26 08:59:15 +02:00
parent b1294e86bb
commit ba40fe99c3
6 changed files with 47 additions and 99 deletions

View file

@ -830,11 +830,11 @@ fn for_each_late_bound_region_defined_on<'tcx>(
fn_def_id: DefId, fn_def_id: DefId,
mut f: impl FnMut(ty::Region<'tcx>), mut f: impl FnMut(ty::Region<'tcx>),
) { ) {
if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) { if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
for &region_def_id in late_bounds.iter() { for &region_def_id in late_bounds.iter() {
let name = tcx.item_name(region_def_id.to_def_id()); let name = tcx.item_name(region_def_id.to_def_id());
let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: owner.to_def_id(), scope: fn_def_id,
bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name), bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
})); }));
f(liberated_region); f(liberated_region);

View file

@ -364,7 +364,11 @@ impl<'hir> Map<'hir> {
match node.node { match node.node {
OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics), OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics), OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
OwnerNode::Item(Item { OwnerNode::ForeignItem(ForeignItem {
kind: ForeignItemKind::Fn(_, _, generics),
..
})
| OwnerNode::Item(Item {
kind: kind:
ItemKind::Fn(_, generics, _) ItemKind::Fn(_, generics, _)
| ItemKind::TyAlias(_, generics) | ItemKind::TyAlias(_, generics)

View file

@ -1584,7 +1584,7 @@ rustc_queries! {
Option<&'tcx FxHashMap<ItemLocalId, Region>> { Option<&'tcx FxHashMap<ItemLocalId, Region>> {
desc { "looking up a named region" } desc { "looking up a named region" }
} }
query is_late_bound_map(_: LocalDefId) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> { query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxHashSet<LocalDefId>> {
desc { "testing if a region is late bound" } desc { "testing if a region is late bound" }
} }
/// For a given item (like a struct), gets the default lifetimes to be used /// For a given item (like a struct), gets the default lifetimes to be used

View file

@ -2803,6 +2803,13 @@ impl<'tcx> TyCtxt<'tcx> {
self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned()) self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
} }
pub fn is_late_bound(self, id: HirId) -> bool {
self.is_late_bound_map(id.owner).map_or(false, |set| {
let def_id = self.hir().local_def_id(id);
set.contains(&def_id)
})
}
pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> { pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
self.mk_bound_variable_kinds( self.mk_bound_variable_kinds(
self.late_bound_vars_map(id.owner) self.late_bound_vars_map(id.owner)

View file

@ -16,11 +16,11 @@ use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::hir_id::ItemLocalId; 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, HirIdSet}; use rustc_hir::{GenericParamKind, HirIdMap};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*; use rustc_middle::middle::resolve_lifetime::*;
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
@ -134,11 +134,6 @@ struct NamedRegionMap {
// `Region` describing how that region is bound // `Region` describing how that region is bound
defs: HirIdMap<Region>, defs: HirIdMap<Region>,
// the set of lifetime def ids that are late-bound; a region can
// be late-bound if (a) it does NOT appear in a where-clause and
// (b) it DOES appear in the arguments.
late_bound: HirIdSet,
// Maps relevant hir items to the bound vars on them. These include: // Maps relevant hir items to the bound vars on them. These include:
// - function defs // - function defs
// - function pointers // - function pointers
@ -402,7 +397,7 @@ fn resolve_lifetimes_trait_definition(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
local_def_id: LocalDefId, local_def_id: LocalDefId,
) -> ResolveLifetimes { ) -> ResolveLifetimes {
convert_named_region_map(tcx, do_resolve(tcx, local_def_id, true, false)) convert_named_region_map(do_resolve(tcx, local_def_id, true, false))
} }
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`. /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
@ -410,7 +405,7 @@ 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(tcx, do_resolve(tcx, local_def_id, false, false)) convert_named_region_map(do_resolve(tcx, local_def_id, false, false))
} }
fn do_resolve( fn do_resolve(
@ -422,7 +417,6 @@ fn do_resolve(
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 = NamedRegionMap {
defs: Default::default(), defs: Default::default(),
late_bound: Default::default(),
late_bound_vars: Default::default(), late_bound_vars: Default::default(),
scope_for_path: with_scope_for_path.then(|| Default::default()), scope_for_path: with_scope_for_path.then(|| Default::default()),
}; };
@ -439,18 +433,13 @@ fn do_resolve(
named_region_map named_region_map
} }
fn convert_named_region_map(tcx: TyCtxt<'_>, named_region_map: NamedRegionMap) -> ResolveLifetimes { fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
let mut rl = ResolveLifetimes::default(); let mut rl = ResolveLifetimes::default();
for (hir_id, v) in named_region_map.defs { for (hir_id, v) in named_region_map.defs {
let map = rl.defs.entry(hir_id.owner).or_default(); let map = rl.defs.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v); map.insert(hir_id.local_id, v);
} }
for hir_id in named_region_map.late_bound {
let map = rl.late_bound.entry(hir_id.owner).or_default();
let def_id = tcx.hir().local_def_id(hir_id);
map.insert(def_id);
}
for (hir_id, v) in named_region_map.late_bound_vars { for (hir_id, v) in named_region_map.late_bound_vars {
let map = rl.late_bound_vars.entry(hir_id.owner).or_default(); let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v); map.insert(hir_id.local_id, v);
@ -506,28 +495,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
item item
} }
fn is_late_bound_map<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
match tcx.def_kind(def_id) {
DefKind::AnonConst | DefKind::InlineConst => {
let mut def_id = tcx.local_parent(def_id);
// We search for the next outer anon const or fn here
// while skipping closures.
//
// Note that for `AnonConst` we still just recurse until we
// find a function body, but who cares :shrug:
while tcx.is_closure(def_id.to_def_id()) {
def_id = tcx.local_parent(def_id);
}
tcx.is_late_bound_map(def_id)
}
_ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)),
}
}
/// In traits, there is an implicit `Self` type parameter which comes before the generics. /// In traits, there is an implicit `Self` type parameter which comes before the generics.
/// We have to account for this when computing the index of the other generic parameters. /// We have to account for this when computing the index of the other generic parameters.
/// This function returns whether there is such an implicit parameter defined on the given item. /// This function returns whether there is such an implicit parameter defined on the given item.
@ -687,9 +654,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
_ => {} _ => {}
} }
match item.kind { match item.kind {
hir::ItemKind::Fn(ref sig, ref generics, _) => { hir::ItemKind::Fn(_, ref generics, _) => {
self.missing_named_lifetime_spots.push(generics.into()); self.missing_named_lifetime_spots.push(generics.into());
self.visit_early_late(None, item.hir_id(), &sig.decl, generics, |this| { self.visit_early_late(None, item.hir_id(), generics, |this| {
intravisit::walk_item(this, item); intravisit::walk_item(this, item);
}); });
self.missing_named_lifetime_spots.pop(); self.missing_named_lifetime_spots.pop();
@ -731,13 +698,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
self.map.defs.insert(hir::HirId { owner, local_id }, *region); self.map.defs.insert(hir::HirId { owner, local_id }, *region);
}); });
} }
for (&owner, late_bound) in resolved_lifetimes.late_bound.iter() {
late_bound.iter().for_each(|&id| {
let hir_id = self.tcx.local_def_id_to_hir_id(id);
debug_assert_eq!(owner, hir_id.owner);
self.map.late_bound.insert(hir_id);
});
}
for (&owner, late_bound_vars) in for (&owner, late_bound_vars) in
resolved_lifetimes.late_bound_vars.iter() resolved_lifetimes.late_bound_vars.iter()
{ {
@ -807,8 +767,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
match item.kind { match item.kind {
hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { hir::ForeignItemKind::Fn(_, _, ref generics) => {
self.visit_early_late(None, item.hir_id(), decl, generics, |this| { self.visit_early_late(None, item.hir_id(), generics, |this| {
intravisit::walk_foreign_item(this, item); intravisit::walk_foreign_item(this, item);
}) })
} }
@ -1085,13 +1045,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
use self::hir::TraitItemKind::*; use self::hir::TraitItemKind::*;
match trait_item.kind { match trait_item.kind {
Fn(ref sig, _) => { Fn(_, _) => {
self.missing_named_lifetime_spots.push((&trait_item.generics).into()); self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let tcx = self.tcx; let tcx = self.tcx;
self.visit_early_late( self.visit_early_late(
Some(tcx.hir().get_parent_item(trait_item.hir_id())), Some(tcx.hir().get_parent_item(trait_item.hir_id())),
trait_item.hir_id(), trait_item.hir_id(),
&sig.decl,
&trait_item.generics, &trait_item.generics,
|this| intravisit::walk_trait_item(this, trait_item), |this| intravisit::walk_trait_item(this, trait_item),
); );
@ -1153,13 +1112,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
use self::hir::ImplItemKind::*; use self::hir::ImplItemKind::*;
match impl_item.kind { match impl_item.kind {
Fn(ref sig, _) => { Fn(..) => {
self.missing_named_lifetime_spots.push((&impl_item.generics).into()); self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx; let tcx = self.tcx;
self.visit_early_late( self.visit_early_late(
Some(tcx.hir().get_parent_item(impl_item.hir_id())), Some(tcx.hir().get_parent_item(impl_item.hir_id())),
impl_item.hir_id(), impl_item.hir_id(),
&sig.decl,
&impl_item.generics, &impl_item.generics,
|this| intravisit::walk_impl_item(this, impl_item), |this| intravisit::walk_impl_item(this, impl_item),
); );
@ -1656,14 +1614,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
&mut self, &mut self,
parent_id: Option<LocalDefId>, parent_id: Option<LocalDefId>,
hir_id: hir::HirId, hir_id: hir::HirId,
decl: &'tcx hir::FnDecl<'tcx>,
generics: &'tcx hir::Generics<'tcx>, generics: &'tcx hir::Generics<'tcx>,
walk: F, walk: F,
) where ) where
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
{ {
insert_late_bound_lifetimes(self.tcx, self.map, decl, generics);
// Find the start of nested early scopes, e.g., in methods. // Find the start of nested early scopes, e.g., in methods.
let mut next_early_index = 0; let mut next_early_index = 0;
if let Some(parent_id) = parent_id { if let Some(parent_id) = parent_id {
@ -1687,7 +1642,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => { GenericParamKind::Lifetime { .. } => {
if self.map.late_bound.contains(&param.hir_id) { if self.tcx.is_late_bound(param.hir_id) {
let late_bound_idx = named_late_bound_vars; let late_bound_idx = named_late_bound_vars;
named_late_bound_vars += 1; named_late_bound_vars += 1;
Some(Region::late(late_bound_idx, self.tcx.hir(), param)) Some(Region::late(late_bound_idx, self.tcx.hir(), param))
@ -1708,7 +1663,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
.iter() .iter()
.filter(|param| { .filter(|param| {
matches!(param.kind, GenericParamKind::Lifetime { .. }) matches!(param.kind, GenericParamKind::Lifetime { .. })
&& self.map.late_bound.contains(&param.hir_id) && self.tcx.is_late_bound(param.hir_id)
}) })
.enumerate() .enumerate()
.map(|(late_bound_idx, param)| { .map(|(late_bound_idx, param)| {
@ -2613,7 +2568,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} }
/// Detects late-bound lifetimes and inserts them into /// Detects late-bound lifetimes and inserts them into
/// `map.late_bound`. /// `late_bound`.
/// ///
/// A region declared on a fn is **late-bound** if: /// A region declared on a fn is **late-bound** if:
/// - it is constrained by an argument type; /// - it is constrained by an argument type;
@ -2622,13 +2577,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// "Constrained" basically means that it appears in any type but /// "Constrained" basically means that it appears in any type but
/// not amongst the inputs to a projection. In other words, `<&'a /// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
#[tracing::instrument(level = "debug", skip(tcx, map))] fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxHashSet<LocalDefId>> {
fn insert_late_bound_lifetimes( let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx: TyCtxt<'_>, let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
map: &mut NamedRegionMap, let generics = tcx.hir().get_generics(def_id)?;
decl: &hir::FnDecl<'_>,
generics: &hir::Generics<'_>, let mut late_bound = FxHashSet::default();
) {
let mut constrained_by_input = ConstrainedCollector::default(); let mut constrained_by_input = ConstrainedCollector::default();
for arg_ty in decl.inputs { for arg_ty in decl.inputs {
constrained_by_input.visit_ty(arg_ty); constrained_by_input.visit_ty(arg_ty);
@ -2675,11 +2630,12 @@ fn insert_late_bound_lifetimes(
debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id); debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
let inserted = map.late_bound.insert(param.hir_id); let inserted = late_bound.insert(param_def_id);
assert!(inserted, "visited lifetime {:?} twice", param.hir_id); assert!(inserted, "visited lifetime {:?} twice", param.hir_id);
} }
return; debug!(?late_bound);
return Some(tcx.arena.alloc(late_bound));
#[derive(Default)] #[derive(Default)]
struct ConstrainedCollector { struct ConstrainedCollector {

View file

@ -1364,7 +1364,6 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
fn has_late_bound_regions<'tcx>( fn has_late_bound_regions<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
generics: &'tcx hir::Generics<'tcx>, generics: &'tcx hir::Generics<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>, decl: &'tcx hir::FnDecl<'tcx>,
) -> Option<Span> { ) -> Option<Span> {
@ -1373,14 +1372,9 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
outer_index: ty::INNERMOST, outer_index: ty::INNERMOST,
has_late_bound_regions: None, has_late_bound_regions: None,
}; };
let late_bound_map = tcx.is_late_bound_map(def_id);
let is_late_bound = |id| {
let id = tcx.hir().local_def_id(id);
late_bound_map.map_or(false, |(_, set)| set.contains(&id))
};
for param in generics.params { for param in generics.params {
if let GenericParamKind::Lifetime { .. } = param.kind { if let GenericParamKind::Lifetime { .. } = param.kind {
if is_late_bound(param.hir_id) { if tcx.is_late_bound(param.hir_id) {
return Some(param.span); return Some(param.span);
} }
} }
@ -1392,25 +1386,25 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
match node { match node {
Node::TraitItem(item) => match item.kind { Node::TraitItem(item) => match item.kind {
hir::TraitItemKind::Fn(ref sig, _) => { hir::TraitItemKind::Fn(ref sig, _) => {
has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl) has_late_bound_regions(tcx, &item.generics, sig.decl)
} }
_ => None, _ => None,
}, },
Node::ImplItem(item) => match item.kind { Node::ImplItem(item) => match item.kind {
hir::ImplItemKind::Fn(ref sig, _) => { hir::ImplItemKind::Fn(ref sig, _) => {
has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl) has_late_bound_regions(tcx, &item.generics, sig.decl)
} }
_ => None, _ => None,
}, },
Node::ForeignItem(item) => match item.kind { Node::ForeignItem(item) => match item.kind {
hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => { hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
has_late_bound_regions(tcx, item.def_id, generics, fn_decl) has_late_bound_regions(tcx, generics, fn_decl)
} }
_ => None, _ => None,
}, },
Node::Item(item) => match item.kind { Node::Item(item) => match item.kind {
hir::ItemKind::Fn(ref sig, .., ref generics, _) => { hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
has_late_bound_regions(tcx, item.def_id, generics, sig.decl) has_late_bound_regions(tcx, generics, sig.decl)
} }
_ => None, _ => None,
}, },
@ -1671,7 +1665,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
params.push(opt_self); params.push(opt_self);
} }
let early_lifetimes = early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics); let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef { params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
name: param.name.ident().name, name: param.name.ident().name,
index: own_start + i as u32, index: own_start + i as u32,
@ -2054,23 +2048,10 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
/// `resolve_lifetime::early_bound_lifetimes`. /// `resolve_lifetime::early_bound_lifetimes`.
fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>( fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
generics: &'a hir::Generics<'a>, generics: &'a hir::Generics<'a>,
) -> impl Iterator<Item = &'a hir::GenericParam<'a>> + Captures<'tcx> { ) -> impl Iterator<Item = &'a hir::GenericParam<'a>> + Captures<'tcx> {
let late_bound_map = if generics.params.is_empty() {
// This function may be called on `def_id == CRATE_DEF_ID`,
// which makes `is_late_bound_map` ICE. Don't even try if there
// is no generic parameter.
None
} else {
tcx.is_late_bound_map(def_id)
};
let is_late_bound = move |hir_id| {
let id = tcx.hir().local_def_id(hir_id);
late_bound_map.map_or(false, |(_, set)| set.contains(&id))
};
generics.params.iter().filter(move |param| match param.kind { generics.params.iter().filter(move |param| match param.kind {
GenericParamKind::Lifetime { .. } => !is_late_bound(param.hir_id), GenericParamKind::Lifetime { .. } => !tcx.is_late_bound(param.hir_id),
_ => false, _ => false,
}) })
} }
@ -2255,7 +2236,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
// have to be careful to only iterate over early-bound regions. // have to be careful to only iterate over early-bound regions.
let mut index = parent_count let mut index = parent_count
+ has_own_self as u32 + has_own_self as u32
+ early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32; + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
// Collect the predicates that were written inline by the user on each // Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`). // type parameter (e.g., `<T: Foo>`).