Skip to content

Commit

Permalink
Rollup merge of rust-lang#97415 - cjgillot:is-late-bound-solo, r=este…
Browse files Browse the repository at this point in the history
…bank

Compute `is_late_bound_map` query separately from lifetime resolution

This query is actually very simple, and is only useful for functions and method.  It can be computed directly by fetching the HIR, with no need to embed it within the lifetime resolution visitor.

Based on rust-lang#96296
  • Loading branch information
Dylan-DPC committed Jun 3, 2022
2 parents 72f7e31 + ba40fe9 commit 76340ce
Show file tree
Hide file tree
Showing 17 changed files with 205 additions and 266 deletions.
41 changes: 17 additions & 24 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,9 +672,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
LifetimeRes::Param { .. } => {
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
}
LifetimeRes::Fresh { param, .. } => {
(hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided)
}
LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided),
LifetimeRes::Static | LifetimeRes::Error => return None,
res => panic!(
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
Expand Down Expand Up @@ -1576,10 +1574,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
}
// Input lifetime like `'1`:
LifetimeRes::Fresh { param, .. } => (
hir::ParamName::Fresh(outer_def_id),
LifetimeRes::Fresh { param, binder: fn_node_id },
),
LifetimeRes::Fresh { param, .. } => {
(hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
}
LifetimeRes::Static | LifetimeRes::Error => continue,
res => {
panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
Expand Down Expand Up @@ -1749,18 +1746,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::Lifetime {
debug!(?self.captured_lifetimes);
let name = match res {
LifetimeRes::Param { param, binder } => {
LifetimeRes::Param { mut param, binder } => {
debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
let p_name = ParamName::Plain(ident);
if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
&mut self.captured_lifetimes
&& !binders_to_ignore.contains(&binder)
{
match captures.entry(param) {
Entry::Occupied(_) => {}
Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1),
Entry::Vacant(v) => {
let p_id = self.resolver.next_node_id();
self.resolver.create_def(
let p_def_id = self.resolver.create_def(
*parent_def_id,
p_id,
DefPathData::LifetimeNs(p_name.ident().name),
Expand All @@ -1769,10 +1766,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);

v.insert((span, p_id, p_name, res));
param = p_def_id;
}
}
}
hir::LifetimeName::Param(p_name)
hir::LifetimeName::Param(param, p_name)
}
LifetimeRes::Fresh { mut param, binder } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
Expand All @@ -1792,21 +1790,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span.with_parent(None),
);

let p_name = ParamName::Fresh(param);
v.insert((span, p_id, p_name, res));
v.insert((span, p_id, ParamName::Fresh, res));
param = p_def_id;
}
}
}
let p_name = ParamName::Fresh(param);
hir::LifetimeName::Param(p_name)
hir::LifetimeName::Param(param, ParamName::Fresh)
}
LifetimeRes::Anonymous { binder, elided } => {
let l_name = if elided {
hir::LifetimeName::Implicit
} else {
hir::LifetimeName::Underscore
};
if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
&mut self.captured_lifetimes
&& !binders_to_ignore.contains(&binder)
Expand All @@ -1819,18 +1810,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ExpnId::root(),
span.with_parent(None),
);
let p_name = ParamName::Fresh(p_def_id);
captures.insert(p_def_id, (span, p_id, p_name, res));
hir::LifetimeName::Param(p_name)
captures.insert(p_def_id, (span, p_id, ParamName::Fresh, res));
hir::LifetimeName::Param(p_def_id, ParamName::Fresh)
} else if elided {
hir::LifetimeName::Implicit
} else {
l_name
hir::LifetimeName::Underscore
}
}
LifetimeRes::Static => hir::LifetimeName::Static,
LifetimeRes::Error => hir::LifetimeName::Error,
res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
};
debug!(?self.captured_lifetimes);
debug!(?name);
hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,14 +567,14 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let lifetime =
self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
match lifetime.name {
hir::LifetimeName::Param(hir::ParamName::Plain(_) | hir::ParamName::Error)
hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error)
| hir::LifetimeName::Error
| hir::LifetimeName::Static => {
let lifetime_span = lifetime.span;
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
}

hir::LifetimeName::Param(hir::ParamName::Fresh(_))
hir::LifetimeName::Param(_, hir::ParamName::Fresh)
| hir::LifetimeName::ImplicitObjectLifetimeDefault
| hir::LifetimeName::Implicit
| hir::LifetimeName::Underscore => {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -830,11 +830,11 @@ fn for_each_late_bound_region_defined_on<'tcx>(
fn_def_id: DefId,
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() {
let name = tcx.item_name(region_def_id.to_def_id());
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),
}));
f(liberated_region);
Expand Down
52 changes: 32 additions & 20 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use rustc_target::spec::abi::Abi;
use smallvec::SmallVec;
use std::fmt;

#[derive(Copy, Clone, Encodable, HashStable_Generic)]
#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
pub struct Lifetime {
pub hir_id: HirId,
pub span: Span,
Expand Down Expand Up @@ -60,7 +60,7 @@ pub enum ParamName {
/// ```
/// where `'f` is something like `Fresh(0)`. The indices are
/// unique per impl, but not necessarily continuous.
Fresh(LocalDefId),
Fresh,

/// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors). Occurs
Expand All @@ -72,9 +72,7 @@ impl ParamName {
pub fn ident(&self) -> Ident {
match *self {
ParamName::Plain(ident) => ident,
ParamName::Fresh(_) | ParamName::Error => {
Ident::with_dummy_span(kw::UnderscoreLifetime)
}
ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
}
}

Expand All @@ -90,7 +88,7 @@ impl ParamName {
#[derive(HashStable_Generic)]
pub enum LifetimeName {
/// User-given names or fresh (synthetic) names.
Param(ParamName),
Param(LocalDefId, ParamName),

/// User wrote nothing (e.g., the lifetime in `&u32`).
Implicit,
Expand Down Expand Up @@ -127,7 +125,7 @@ impl LifetimeName {
| LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
LifetimeName::Param(param_name) => param_name.ident(),
LifetimeName::Param(_, param_name) => param_name.ident(),
}
}

Expand All @@ -136,9 +134,9 @@ impl LifetimeName {
LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Implicit
| LifetimeName::Underscore
| LifetimeName::Param(ParamName::Fresh(_))
| LifetimeName::Param(_, ParamName::Fresh)
| LifetimeName::Error => true,
LifetimeName::Static | LifetimeName::Param(_) => false,
LifetimeName::Static | LifetimeName::Param(..) => false,
}
}

Expand All @@ -148,12 +146,12 @@ impl LifetimeName {
| LifetimeName::Implicit
| LifetimeName::Underscore => true,

// It might seem surprising that `Fresh(_)` counts as
// It might seem surprising that `Fresh` counts as
// *not* elided -- but this is because, as far as the code
// in the compiler is concerned -- `Fresh(_)` variants act
// in the compiler is concerned -- `Fresh` variants act
// equivalently to "some fresh name". They correspond to
// early-bound regions on an impl, in other words.
LifetimeName::Error | LifetimeName::Param(_) | LifetimeName::Static => false,
LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
}
}

Expand All @@ -163,8 +161,8 @@ impl LifetimeName {

pub fn normalize_to_macros_2_0(&self) -> LifetimeName {
match *self {
LifetimeName::Param(param_name) => {
LifetimeName::Param(param_name.normalize_to_macros_2_0())
LifetimeName::Param(def_id, param_name) => {
LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0())
}
lifetime_name => lifetime_name,
}
Expand All @@ -177,12 +175,6 @@ impl fmt::Display for Lifetime {
}
}

impl fmt::Debug for Lifetime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "lifetime({}: {})", self.hir_id, self.name.ident())
}
}

impl Lifetime {
pub fn is_elided(&self) -> bool {
self.name.is_elided()
Expand Down Expand Up @@ -628,6 +620,16 @@ impl<'hir> Generics<'hir> {
})
}

pub fn outlives_for_param(
&self,
param_def_id: LocalDefId,
) -> impl Iterator<Item = &WhereRegionPredicate<'_>> {
self.predicates.iter().filter_map(move |pred| match pred {
WherePredicate::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => Some(rp),
_ => None,
})
}

pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|bound| {
Expand Down Expand Up @@ -769,6 +771,16 @@ pub struct WhereRegionPredicate<'hir> {
pub bounds: GenericBounds<'hir>,
}

impl<'hir> WhereRegionPredicate<'hir> {
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
match self.lifetime.name {
LifetimeName::Param(id, _) => id == param_def_id,
_ => false,
}
}
}

/// An equality predicate (e.g., `T = int`); currently unsupported.
#[derive(Debug, HashStable_Generic)]
pub struct WhereEqPredicate<'hir> {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,11 +510,11 @@ pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
visitor.visit_id(lifetime.hir_id);
match lifetime.name {
LifetimeName::Param(ParamName::Plain(ident)) => {
LifetimeName::Param(_, ParamName::Plain(ident)) => {
visitor.visit_ident(ident);
}
LifetimeName::Param(ParamName::Fresh(_))
| LifetimeName::Param(ParamName::Error)
LifetimeName::Param(_, ParamName::Fresh)
| LifetimeName::Param(_, ParamName::Error)
| LifetimeName::Static
| LifetimeName::Error
| LifetimeName::Implicit
Expand Down Expand Up @@ -879,7 +879,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
visitor.visit_id(param.hir_id);
match param.name {
ParamName::Plain(ident) => visitor.visit_ident(ident),
ParamName::Error | ParamName::Fresh(_) => {}
ParamName::Error | ParamName::Fresh => {}
}
match param.kind {
GenericParamKind::Lifetime { .. } => {}
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,11 @@ impl<'hir> Map<'hir> {
match node.node {
OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
OwnerNode::Item(Item {
OwnerNode::ForeignItem(ForeignItem {
kind: ForeignItemKind::Fn(_, _, generics),
..
})
| OwnerNode::Item(Item {
kind:
ItemKind::Fn(_, generics, _)
| ItemKind::TyAlias(_, generics)
Expand Down
11 changes: 5 additions & 6 deletions compiler/rustc_middle/src/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::ItemLocalId;
use rustc_macros::HashStable;
use rustc_span::symbol::Symbol;

#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum Region {
Expand All @@ -22,12 +21,12 @@ pub enum Region {
/// 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<Symbol>),
/// 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.
/// Information that allows us to suggest args of the form `<'_>` in case
/// no generic arguments were provided for a path.
Elided,
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1584,7 +1584,7 @@ rustc_queries! {
Option<&'tcx FxHashMap<ItemLocalId, 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" }
}
/// For a given item (like a struct), gets the default lifetimes to be used
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2803,6 +2803,13 @@ impl<'tcx> TyCtxt<'tcx> {
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> {
self.mk_bound_variable_kinds(
self.late_bound_vars_map(id.owner)
Expand Down

0 comments on commit 76340ce

Please sign in to comment.