Skip to content

Commit

Permalink
Manipulate lifetimes by LocalDefId for region resolution.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjgillot committed Jun 3, 2022
1 parent 3a90bed commit b1294e8
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 170 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
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
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
29 changes: 23 additions & 6 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ use rustc_ast::{
};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust::path_segment_to_string;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_session::lint;
use rustc_session::parse::feature_err;
Expand Down Expand Up @@ -2082,7 +2082,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {

/// Returns whether to add `'static` lifetime to the suggested lifetime list.
pub(crate) fn report_elision_failure(
&mut self,
&self,
diag: &mut Diagnostic,
params: &[ElisionFailureInfo],
) -> bool {
Expand Down Expand Up @@ -2187,10 +2187,27 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
&self,
err: &mut Diagnostic,
mut spans_with_counts: Vec<(Span, usize)>,
lifetime_names: &FxHashSet<Symbol>,
lifetime_spans: Vec<Span>,
params: &[ElisionFailureInfo],
in_scope_lifetimes: FxIndexSet<LocalDefId>,
params: Option<&[ElisionFailureInfo]>,
) {
let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes
.iter()
.filter_map(|def_id| {
let name = self.tcx.item_name(def_id.to_def_id());
let span = self.tcx.def_ident_span(def_id.to_def_id())?;
Some((name, span))
})
.filter(|&(n, _)| n != kw::UnderscoreLifetime)
.unzip();

if let Some(params) = params {
// If there's no lifetime available, suggest `'static`.
if self.report_elision_failure(err, params) && lifetime_names.is_empty() {
lifetime_names.insert(kw::StaticLifetime);
}
}
let params = params.unwrap_or(&[]);

let snippets: Vec<Option<String>> = spans_with_counts
.iter()
.map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
Expand Down
Loading

0 comments on commit b1294e8

Please sign in to comment.