Manipulate lifetimes by LocalDefId for region resolution.

This commit is contained in:
Camille GILLOT 2022-04-27 22:15:58 +02:00
parent 3a90bedb33
commit b1294e86bb
12 changed files with 161 additions and 170 deletions

View File

@ -672,9 +672,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
LifetimeRes::Param { .. } => { LifetimeRes::Param { .. } => {
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
} }
LifetimeRes::Fresh { param, .. } => { LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided),
(hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided)
}
LifetimeRes::Static | LifetimeRes::Error => return None, LifetimeRes::Static | LifetimeRes::Error => return None,
res => panic!( res => panic!(
"Unexpected lifetime resolution {:?} for {:?} at {:?}", "Unexpected lifetime resolution {:?} for {:?} at {:?}",
@ -1576,10 +1574,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id }) (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
} }
// Input lifetime like `'1`: // Input lifetime like `'1`:
LifetimeRes::Fresh { param, .. } => ( LifetimeRes::Fresh { param, .. } => {
hir::ParamName::Fresh(outer_def_id), (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
LifetimeRes::Fresh { param, binder: fn_node_id }, }
),
LifetimeRes::Static | LifetimeRes::Error => continue, LifetimeRes::Static | LifetimeRes::Error => continue,
res => { res => {
panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span) panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
@ -1749,7 +1746,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::Lifetime { ) -> hir::Lifetime {
debug!(?self.captured_lifetimes); debug!(?self.captured_lifetimes);
let name = match res { let name = match res {
LifetimeRes::Param { param, binder } => { LifetimeRes::Param { mut param, binder } => {
debug_assert_ne!(ident.name, kw::UnderscoreLifetime); debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
let p_name = ParamName::Plain(ident); let p_name = ParamName::Plain(ident);
if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) = if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
@ -1757,10 +1754,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&& !binders_to_ignore.contains(&binder) && !binders_to_ignore.contains(&binder)
{ {
match captures.entry(param) { match captures.entry(param) {
Entry::Occupied(_) => {} Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1),
Entry::Vacant(v) => { Entry::Vacant(v) => {
let p_id = self.resolver.next_node_id(); let p_id = self.resolver.next_node_id();
self.resolver.create_def( let p_def_id = self.resolver.create_def(
*parent_def_id, *parent_def_id,
p_id, p_id,
DefPathData::LifetimeNs(p_name.ident().name), DefPathData::LifetimeNs(p_name.ident().name),
@ -1769,10 +1766,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
); );
v.insert((span, p_id, p_name, res)); 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 } => { LifetimeRes::Fresh { mut param, binder } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
@ -1792,21 +1790,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span.with_parent(None), span.with_parent(None),
); );
let p_name = ParamName::Fresh(param); v.insert((span, p_id, ParamName::Fresh, res));
v.insert((span, p_id, p_name, res));
param = p_def_id; param = p_def_id;
} }
} }
} }
let p_name = ParamName::Fresh(param); hir::LifetimeName::Param(param, ParamName::Fresh)
hir::LifetimeName::Param(p_name)
} }
LifetimeRes::Anonymous { binder, elided } => { 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 }) = if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
&mut self.captured_lifetimes &mut self.captured_lifetimes
&& !binders_to_ignore.contains(&binder) && !binders_to_ignore.contains(&binder)
@ -1819,11 +1810,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ExpnId::root(), ExpnId::root(),
span.with_parent(None), span.with_parent(None),
); );
let p_name = ParamName::Fresh(p_def_id); captures.insert(p_def_id, (span, p_id, ParamName::Fresh, res));
captures.insert(p_def_id, (span, p_id, p_name, res)); hir::LifetimeName::Param(p_def_id, ParamName::Fresh)
hir::LifetimeName::Param(p_name) } else if elided {
hir::LifetimeName::Implicit
} else { } else {
l_name hir::LifetimeName::Underscore
} }
} }
LifetimeRes::Static => hir::LifetimeName::Static, LifetimeRes::Static => hir::LifetimeName::Static,
@ -1831,6 +1823,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span), res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
}; };
debug!(?self.captured_lifetimes); debug!(?self.captured_lifetimes);
debug!(?name);
hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name } hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
} }

View File

@ -567,14 +567,14 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let lifetime = let lifetime =
self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
match lifetime.name { 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::Error
| hir::LifetimeName::Static => { | hir::LifetimeName::Static => {
let lifetime_span = lifetime.span; let lifetime_span = lifetime.span;
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span)) Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
} }
hir::LifetimeName::Param(hir::ParamName::Fresh(_)) hir::LifetimeName::Param(_, hir::ParamName::Fresh)
| hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::ImplicitObjectLifetimeDefault
| hir::LifetimeName::Implicit | hir::LifetimeName::Implicit
| hir::LifetimeName::Underscore => { | hir::LifetimeName::Underscore => {

View File

@ -26,7 +26,7 @@ use rustc_target::spec::abi::Abi;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::fmt; use std::fmt;
#[derive(Copy, Clone, Encodable, HashStable_Generic)] #[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
pub struct Lifetime { pub struct Lifetime {
pub hir_id: HirId, pub hir_id: HirId,
pub span: Span, pub span: Span,
@ -60,7 +60,7 @@ pub enum ParamName {
/// ``` /// ```
/// where `'f` is something like `Fresh(0)`. The indices are /// where `'f` is something like `Fresh(0)`. The indices are
/// unique per impl, but not necessarily continuous. /// unique per impl, but not necessarily continuous.
Fresh(LocalDefId), Fresh,
/// Indicates an illegal name was given and an error has been /// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors). Occurs /// reported (so we should squelch other derived errors). Occurs
@ -72,9 +72,7 @@ impl ParamName {
pub fn ident(&self) -> Ident { pub fn ident(&self) -> Ident {
match *self { match *self {
ParamName::Plain(ident) => ident, ParamName::Plain(ident) => ident,
ParamName::Fresh(_) | ParamName::Error => { ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
Ident::with_dummy_span(kw::UnderscoreLifetime)
}
} }
} }
@ -90,7 +88,7 @@ impl ParamName {
#[derive(HashStable_Generic)] #[derive(HashStable_Generic)]
pub enum LifetimeName { pub enum LifetimeName {
/// User-given names or fresh (synthetic) names. /// User-given names or fresh (synthetic) names.
Param(ParamName), Param(LocalDefId, ParamName),
/// User wrote nothing (e.g., the lifetime in `&u32`). /// User wrote nothing (e.g., the lifetime in `&u32`).
Implicit, Implicit,
@ -127,7 +125,7 @@ impl LifetimeName {
| LifetimeName::Error => Ident::empty(), | LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime), LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime), LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
LifetimeName::Param(param_name) => param_name.ident(), LifetimeName::Param(_, param_name) => param_name.ident(),
} }
} }
@ -136,9 +134,9 @@ impl LifetimeName {
LifetimeName::ImplicitObjectLifetimeDefault LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Implicit | LifetimeName::Implicit
| LifetimeName::Underscore | LifetimeName::Underscore
| LifetimeName::Param(ParamName::Fresh(_)) | LifetimeName::Param(_, ParamName::Fresh)
| LifetimeName::Error => true, | LifetimeName::Error => true,
LifetimeName::Static | LifetimeName::Param(_) => false, LifetimeName::Static | LifetimeName::Param(..) => false,
} }
} }
@ -148,12 +146,12 @@ impl LifetimeName {
| LifetimeName::Implicit | LifetimeName::Implicit
| LifetimeName::Underscore => true, | 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 // *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 // equivalently to "some fresh name". They correspond to
// early-bound regions on an impl, in other words. // early-bound regions on an impl, in other words.
LifetimeName::Error | LifetimeName::Param(_) | LifetimeName::Static => false, LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
} }
} }
@ -163,8 +161,8 @@ impl LifetimeName {
pub fn normalize_to_macros_2_0(&self) -> LifetimeName { pub fn normalize_to_macros_2_0(&self) -> LifetimeName {
match *self { match *self {
LifetimeName::Param(param_name) => { LifetimeName::Param(def_id, param_name) => {
LifetimeName::Param(param_name.normalize_to_macros_2_0()) LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0())
} }
lifetime_name => lifetime_name, lifetime_name => lifetime_name,
} }
@ -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 { impl Lifetime {
pub fn is_elided(&self) -> bool { pub fn is_elided(&self) -> bool {
self.name.is_elided() self.name.is_elided()
@ -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> { 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( self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|bound| { |bound| {
@ -769,6 +771,16 @@ pub struct WhereRegionPredicate<'hir> {
pub bounds: GenericBounds<'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. /// An equality predicate (e.g., `T = int`); currently unsupported.
#[derive(Debug, HashStable_Generic)] #[derive(Debug, HashStable_Generic)]
pub struct WhereEqPredicate<'hir> { pub struct WhereEqPredicate<'hir> {

View File

@ -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) { pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
visitor.visit_id(lifetime.hir_id); visitor.visit_id(lifetime.hir_id);
match lifetime.name { match lifetime.name {
LifetimeName::Param(ParamName::Plain(ident)) => { LifetimeName::Param(_, ParamName::Plain(ident)) => {
visitor.visit_ident(ident); visitor.visit_ident(ident);
} }
LifetimeName::Param(ParamName::Fresh(_)) LifetimeName::Param(_, ParamName::Fresh)
| LifetimeName::Param(ParamName::Error) | LifetimeName::Param(_, ParamName::Error)
| LifetimeName::Static | LifetimeName::Static
| LifetimeName::Error | LifetimeName::Error
| LifetimeName::Implicit | LifetimeName::Implicit
@ -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); visitor.visit_id(param.hir_id);
match param.name { match param.name {
ParamName::Plain(ident) => visitor.visit_ident(ident), ParamName::Plain(ident) => visitor.visit_ident(ident),
ParamName::Error | ParamName::Fresh(_) => {} ParamName::Error | ParamName::Fresh => {}
} }
match param.kind { match param.kind {
GenericParamKind::Lifetime { .. } => {} GenericParamKind::Lifetime { .. } => {}

View File

@ -6,7 +6,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::ItemLocalId; use rustc_hir::ItemLocalId;
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_span::symbol::Symbol;
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum Region { pub enum Region {
@ -22,12 +21,12 @@ pub enum Region {
/// so that we can e.g. suggest elided-lifetimes-in-paths of the form <'_, '_> e.g. /// 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)] #[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum LifetimeScopeForPath { pub enum LifetimeScopeForPath {
// Contains all lifetime names that are in scope and could possibly be used in generics /// Contains all lifetime names that are in scope and could possibly be used in generics
// arguments of path. /// arguments of path.
NonElided(Vec<Symbol>), NonElided(Vec<LocalDefId>),
// Information that allows us to suggest args of the form `<'_>` in case /// Information that allows us to suggest args of the form `<'_>` in case
// no generic arguments were provided for a path. /// no generic arguments were provided for a path.
Elided, Elided,
} }

View File

@ -13,7 +13,7 @@ use rustc_ast::{
}; };
use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust::path_segment_to_string; 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::{ use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan, MultiSpan,
@ -21,7 +21,7 @@ use rustc_errors::{
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; 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_hir::PrimTy;
use rustc_session::lint; use rustc_session::lint;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
@ -2082,7 +2082,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
/// Returns whether to add `'static` lifetime to the suggested lifetime list. /// Returns whether to add `'static` lifetime to the suggested lifetime list.
pub(crate) fn report_elision_failure( pub(crate) fn report_elision_failure(
&mut self, &self,
diag: &mut Diagnostic, diag: &mut Diagnostic,
params: &[ElisionFailureInfo], params: &[ElisionFailureInfo],
) -> bool { ) -> bool {
@ -2187,10 +2187,27 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
&self, &self,
err: &mut Diagnostic, err: &mut Diagnostic,
mut spans_with_counts: Vec<(Span, usize)>, mut spans_with_counts: Vec<(Span, usize)>,
lifetime_names: &FxHashSet<Symbol>, in_scope_lifetimes: FxIndexSet<LocalDefId>,
lifetime_spans: Vec<Span>, params: Option<&[ElisionFailureInfo]>,
params: &[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 let snippets: Vec<Option<String>> = spans_with_counts
.iter() .iter()
.map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok()) .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())

View File

@ -8,14 +8,14 @@
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}; use rustc_data_structures::fx::{FxHashMap, 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::hir_id::ItemLocalId;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName}; use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet}; use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
@ -33,9 +33,9 @@ use std::mem::take;
use tracing::{debug, span, Level}; use tracing::{debug, span, Level};
trait RegionExt { trait RegionExt {
fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region); fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region; fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region;
@ -51,22 +51,22 @@ trait RegionExt {
} }
impl RegionExt for Region { impl RegionExt for Region {
fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) { fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
let i = *index; let i = *index;
*index += 1; *index += 1;
let def_id = hir_map.local_def_id(param.hir_id); let def_id = hir_map.local_def_id(param.hir_id);
debug!("Region::early: index={} def_id={:?}", i, def_id); debug!("Region::early: index={} def_id={:?}", i, def_id);
(param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id())) (def_id, Region::EarlyBound(i, def_id.to_def_id()))
} }
fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
let depth = ty::INNERMOST; let depth = ty::INNERMOST;
let def_id = hir_map.local_def_id(param.hir_id); let def_id = hir_map.local_def_id(param.hir_id);
debug!( debug!(
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}", "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
idx, param, depth, def_id, idx, param, depth, def_id,
); );
(param.name.normalize_to_macros_2_0(), Region::LateBound(depth, idx, def_id.to_def_id())) (def_id, Region::LateBound(depth, idx, def_id.to_def_id()))
} }
fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region { fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region {
@ -178,7 +178,7 @@ enum Scope<'a> {
Binder { Binder {
/// We use an IndexMap here because we want these lifetimes in order /// We use an IndexMap here because we want these lifetimes in order
/// for diagnostics. /// for diagnostics.
lifetimes: FxIndexMap<hir::ParamName, Region>, lifetimes: FxIndexMap<LocalDefId, Region>,
/// if we extend this scope with another scope, what is the next index /// if we extend this scope with another scope, what is the next index
/// we should use for an early-bound region? /// we should use for an early-bound region?
@ -554,10 +554,7 @@ fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
loop { loop {
match scope { match scope {
Scope::Binder { lifetimes, s, .. } => { Scope::Binder { lifetimes, s, .. } => {
available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p { available_lifetimes.extend(lifetimes.keys());
hir::ParamName::Plain(ident) => Some(ident.name),
_ => None,
}));
scope = s; scope = s;
} }
Scope::Body { s, .. } => { Scope::Body { s, .. } => {
@ -841,7 +838,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}; };
self.missing_named_lifetime_spots self.missing_named_lifetime_spots
.push(MissingLifetimeSpot::HigherRanked { span, span_type }); .push(MissingLifetimeSpot::HigherRanked { span, span_type });
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
.generic_params .generic_params
.iter() .iter()
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
@ -898,7 +895,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// cc #48468 // cc #48468
self.resolve_elided_lifetimes(&[lifetime]) self.resolve_elided_lifetimes(&[lifetime])
} }
LifetimeName::Param(_) | LifetimeName::Static => { LifetimeName::Param(..) | LifetimeName::Static => {
// If the user wrote an explicit name, use that. // If the user wrote an explicit name, use that.
self.visit_lifetime(lifetime); self.visit_lifetime(lifetime);
} }
@ -1016,17 +1013,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
for param in generics.params { for param in generics.params {
match param.kind { match param.kind {
GenericParamKind::Lifetime { .. } => { GenericParamKind::Lifetime { .. } => {
let (name, reg) = Region::early(self.tcx.hir(), &mut index, &param); let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
if let hir::ParamName::Plain(Ident { if let hir::ParamName::Plain(Ident {
name: kw::UnderscoreLifetime, name: kw::UnderscoreLifetime,
.. ..
}) = name }) = param.name
{ {
// Pick the elided lifetime "definition" if one exists // Pick the elided lifetime "definition" if one exists
// and use it to make an elision scope. // and use it to make an elision scope.
elision = Some(reg); elision = Some(reg);
} else { } else {
lifetimes.insert(name, reg); lifetimes.insert(def_id, reg);
} }
} }
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@ -1174,7 +1171,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let mut index = self.next_early_index(); let mut index = self.next_early_index();
let mut non_lifetime_count = 0; let mut non_lifetime_count = 0;
debug!("visit_ty: index = {}", index); debug!("visit_ty: index = {}", index);
let lifetimes: FxIndexMap<hir::ParamName, Region> = generics let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params .params
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
@ -1218,15 +1215,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
#[tracing::instrument(level = "debug", skip(self))] #[tracing::instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if lifetime_ref.is_elided() { match lifetime_ref.name {
self.resolve_elided_lifetimes(&[lifetime_ref]); hir::LifetimeName::ImplicitObjectLifetimeDefault
return; | hir::LifetimeName::Implicit
| hir::LifetimeName::Underscore => self.resolve_elided_lifetimes(&[lifetime_ref]),
hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
hir::LifetimeName::Param(param_def_id, _) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
} }
if lifetime_ref.is_static() { // If we've already reported an error, just ignore `lifetime_ref`.
self.insert_lifetime(lifetime_ref, Region::Static); hir::LifetimeName::Error => {}
return;
} }
self.resolve_lifetime_ref(lifetime_ref);
} }
fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) { fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) {
@ -1311,7 +1310,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
ref bound_generic_params, ref bound_generic_params,
.. ..
}) => { }) => {
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
bound_generic_params bound_generic_params
.iter() .iter()
.filter(|param| { .filter(|param| {
@ -1433,7 +1432,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
let initial_bound_vars = binders.len() as u32; let initial_bound_vars = binders.len() as u32;
let mut lifetimes: FxIndexMap<hir::ParamName, Region> = FxIndexMap::default(); let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default();
let binders_iter = trait_ref let binders_iter = trait_ref
.bound_generic_params .bound_generic_params
.iter() .iter()
@ -1580,14 +1579,17 @@ fn object_lifetime_defaults_for_item<'tcx>(
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => { GenericParamKind::Lifetime { .. } => {
Some((param.hir_id, hir::LifetimeName::Param(param.name))) let param_def_id = tcx.hir().local_def_id(param.hir_id);
Some((
param_def_id,
hir::LifetimeName::Param(param_def_id, param.name),
))
} }
_ => None, _ => None,
}) })
.enumerate() .enumerate()
.find(|&(_, (_, lt_name))| lt_name == name) .find(|&(_, (_, lt_name))| lt_name == name)
.map_or(Set1::Many, |(i, (id, _))| { .map_or(Set1::Many, |(i, (def_id, _))| {
let def_id = tcx.hir().local_def_id(id);
Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
}) })
} }
@ -1660,7 +1662,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
) 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.map, decl, generics); 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;
@ -1680,7 +1682,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut non_lifetime_count = 0; let mut non_lifetime_count = 0;
let mut named_late_bound_vars = 0; let mut named_late_bound_vars = 0;
let lifetimes: FxIndexMap<hir::ParamName, Region> = generics let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params .params
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
@ -1763,14 +1765,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.next_early_index_helper(false) self.next_early_index_helper(false)
} }
fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) { #[tracing::instrument(level = "debug", skip(self))]
debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref); fn resolve_lifetime_ref(
&mut self,
// If we've already reported an error, just ignore `lifetime_ref`. region_def_id: LocalDefId,
if let LifetimeName::Error = lifetime_ref.name { lifetime_ref: &'tcx hir::Lifetime,
return; ) {
}
// Walk up the scope chain, tracking the number of fn scopes // Walk up the scope chain, tracking the number of fn scopes
// that we pass through, until we find a lifetime with the // that we pass through, until we find a lifetime with the
// given name or we run out of scopes. // given name or we run out of scopes.
@ -1790,15 +1790,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} }
Scope::Binder { ref lifetimes, scope_type, s, .. } => { Scope::Binder { ref lifetimes, scope_type, s, .. } => {
match lifetime_ref.name { if let Some(&def) = lifetimes.get(&region_def_id) {
LifetimeName::Param(param_name) => {
if let Some(&def) = lifetimes.get(&param_name.normalize_to_macros_2_0())
{
break Some(def.shifted(late_depth)); break Some(def.shifted(late_depth));
} }
}
_ => bug!("expected LifetimeName::Param"),
}
match scope_type { match scope_type {
BinderScopeType::Normal => late_depth += 1, BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {} BinderScopeType::Concatenating => {}
@ -2473,8 +2467,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut late_depth = 0; let mut late_depth = 0;
let mut scope = self.scope; let mut scope = self.scope;
let mut lifetime_names = FxHashSet::default(); let mut in_scope_lifetimes = FxIndexSet::default();
let mut lifetime_spans = vec![];
let error = loop { let error = loop {
match *scope { match *scope {
// Do not assign any resolution, it will be inferred. // Do not assign any resolution, it will be inferred.
@ -2484,12 +2477,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Binder { s, ref lifetimes, scope_type, .. } => { Scope::Binder { s, ref lifetimes, scope_type, .. } => {
// collect named lifetimes for suggestions // collect named lifetimes for suggestions
for name in lifetimes.keys() { in_scope_lifetimes.extend(lifetimes.keys().copied());
if let hir::ParamName::Plain(name) = name {
lifetime_names.insert(name.name);
lifetime_spans.push(name.span);
}
}
match scope_type { match scope_type {
BinderScopeType::Normal => late_depth += 1, BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {} BinderScopeType::Concatenating => {}
@ -2524,12 +2512,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
match scope { match scope {
Scope::Binder { ref lifetimes, s, .. } => { Scope::Binder { ref lifetimes, s, .. } => {
// Collect named lifetimes for suggestions. // Collect named lifetimes for suggestions.
for name in lifetimes.keys() { in_scope_lifetimes.extend(lifetimes.keys().copied());
if let hir::ParamName::Plain(name) = name {
lifetime_names.insert(name.name);
lifetime_spans.push(name.span);
}
}
scope = s; scope = s;
} }
Scope::ObjectLifetimeDefault { ref s, .. } Scope::ObjectLifetimeDefault { ref s, .. }
@ -2574,19 +2557,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len()); let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
if let Some(params) = error {
// If there's no lifetime available, suggest `'static`.
if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() {
lifetime_names.insert(kw::StaticLifetime);
}
}
self.add_missing_lifetime_specifiers_label( self.add_missing_lifetime_specifiers_label(
&mut err, &mut err,
spans_with_counts, spans_with_counts,
&lifetime_names, in_scope_lifetimes,
lifetime_spans, error,
error.unwrap_or(&[]),
); );
err.emit(); err.emit();
} }
@ -2647,8 +2622,9 @@ 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(map))] #[tracing::instrument(level = "debug", skip(tcx, map))]
fn insert_late_bound_lifetimes( fn insert_late_bound_lifetimes(
tcx: TyCtxt<'_>,
map: &mut NamedRegionMap, map: &mut NamedRegionMap,
decl: &hir::FnDecl<'_>, decl: &hir::FnDecl<'_>,
generics: &hir::Generics<'_>, generics: &hir::Generics<'_>,
@ -2683,15 +2659,16 @@ fn insert_late_bound_lifetimes(
hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue,
} }
let lt_name = hir::LifetimeName::Param(param.name.normalize_to_macros_2_0()); let param_def_id = tcx.hir().local_def_id(param.hir_id);
// appears in the where clauses? early-bound. // appears in the where clauses? early-bound.
if appears_in_where_clause.regions.contains(&lt_name) { if appears_in_where_clause.regions.contains(&param_def_id) {
continue; continue;
} }
// does not appear in the inputs, but appears in the return type? early-bound. // does not appear in the inputs, but appears in the return type? early-bound.
if !constrained_by_input.regions.contains(&lt_name) if !constrained_by_input.regions.contains(&param_def_id)
&& appears_in_output.regions.contains(&lt_name) && appears_in_output.regions.contains(&param_def_id)
{ {
continue; continue;
} }
@ -2706,7 +2683,7 @@ fn insert_late_bound_lifetimes(
#[derive(Default)] #[derive(Default)]
struct ConstrainedCollector { struct ConstrainedCollector {
regions: FxHashSet<hir::LifetimeName>, regions: FxHashSet<LocalDefId>,
} }
impl<'v> Visitor<'v> for ConstrainedCollector { impl<'v> Visitor<'v> for ConstrainedCollector {
@ -2738,18 +2715,22 @@ fn insert_late_bound_lifetimes(
} }
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0()); if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
self.regions.insert(def_id);
}
} }
} }
#[derive(Default)] #[derive(Default)]
struct AllCollector { struct AllCollector {
regions: FxHashSet<hir::LifetimeName>, regions: FxHashSet<LocalDefId>,
} }
impl<'v> Visitor<'v> for AllCollector { impl<'v> Visitor<'v> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0()); if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
self.regions.insert(def_id);
}
} }
} }
} }

View File

@ -514,7 +514,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
param_names param_names
.iter() .iter()
.take(num_params_to_take) .take(num_params_to_take)
.map(|p| p.as_str()) .map(|def_id| {
self.tcx.item_name(def_id.to_def_id()).to_ident_string()
})
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
} else { } else {

View File

@ -475,24 +475,14 @@ fn clean_generic_param<'tcx>(
generics: Option<&hir::Generics<'tcx>>, generics: Option<&hir::Generics<'tcx>>,
param: &hir::GenericParam<'tcx>, param: &hir::GenericParam<'tcx>,
) -> GenericParamDef { ) -> GenericParamDef {
let did = cx.tcx.hir().local_def_id(param.hir_id);
let (name, kind) = match param.kind { let (name, kind) = match param.kind {
hir::GenericParamKind::Lifetime { .. } => { hir::GenericParamKind::Lifetime { .. } => {
let outlives = if let Some(generics) = generics { let outlives = if let Some(generics) = generics {
generics generics
.predicates .outlives_for_param(did)
.iter() .filter(|bp| !bp.in_where_clause)
.flat_map(|pred| { .flat_map(|bp| bp.bounds)
match pred {
hir::WherePredicate::RegionPredicate(rp)
if rp.lifetime.name == hir::LifetimeName::Param(param.name)
&& !rp.in_where_clause =>
{
rp.bounds
}
_ => &[],
}
.iter()
})
.map(|bound| match bound { .map(|bound| match bound {
hir::GenericBound::Outlives(lt) => lt.clean(cx), hir::GenericBound::Outlives(lt) => lt.clean(cx),
_ => panic!(), _ => panic!(),
@ -504,7 +494,6 @@ fn clean_generic_param<'tcx>(
(param.name.ident().name, GenericParamDefKind::Lifetime { outlives }) (param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
} }
hir::GenericParamKind::Type { ref default, synthetic } => { hir::GenericParamKind::Type { ref default, synthetic } => {
let did = cx.tcx.hir().local_def_id(param.hir_id);
let bounds = if let Some(generics) = generics { let bounds = if let Some(generics) = generics {
generics generics
.bounds_for_param(did) .bounds_for_param(did)
@ -528,7 +517,7 @@ fn clean_generic_param<'tcx>(
hir::GenericParamKind::Const { ty, default } => ( hir::GenericParamKind::Const { ty, default } => (
param.name.ident().name, param.name.ident().name,
GenericParamDefKind::Const { GenericParamDefKind::Const {
did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(), did: did.to_def_id(),
ty: Box::new(ty.clean(cx)), ty: Box::new(ty.clean(cx)),
default: default.map(|ct| { default: default.map(|ct| {
let def_id = cx.tcx.hir().local_def_id(ct.hir_id); let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
@ -1459,7 +1448,7 @@ impl<'tcx> Clean<'tcx, Type> for hir::Ty<'tcx> {
// Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though; // Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
// there's no case where it could cause the function to fail to compile. // there's no case where it could cause the function to fail to compile.
let elided = let elided =
l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_))); l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
let lifetime = if elided { None } else { Some(l.clean(cx)) }; let lifetime = if elided { None } else { Some(l.clean(cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) } BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
} }

View File

@ -371,7 +371,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
if let Some(ref lt) = *lifetime { if let Some(ref lt) = *lifetime {
if lt.name == LifetimeName::Static { if lt.name == LifetimeName::Static {
self.lts.push(RefLt::Static); self.lts.push(RefLt::Static);
} else if let LifetimeName::Param(ParamName::Fresh(_)) = lt.name { } else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name {
// Fresh lifetimes generated should be ignored. // Fresh lifetimes generated should be ignored.
} else if lt.is_elided() { } else if lt.is_elided() {
self.lts.push(RefLt::Unnamed); self.lts.push(RefLt::Unnamed);

View File

@ -343,7 +343,7 @@ impl fmt::Display for RefPrefix {
use fmt::Write; use fmt::Write;
f.write_char('&')?; f.write_char('&')?;
match self.lt { match self.lt {
LifetimeName::Param(ParamName::Plain(name)) => { LifetimeName::Param(_, ParamName::Plain(name)) => {
name.fmt(f)?; name.fmt(f)?;
f.write_char(' ')?; f.write_char(' ')?;
}, },

View File

@ -902,16 +902,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_lifetime(&mut self, lifetime: Lifetime) { pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
std::mem::discriminant(&lifetime.name).hash(&mut self.s); std::mem::discriminant(&lifetime.name).hash(&mut self.s);
if let LifetimeName::Param(ref name) = lifetime.name { if let LifetimeName::Param(param_id, ref name) = lifetime.name {
std::mem::discriminant(name).hash(&mut self.s); std::mem::discriminant(name).hash(&mut self.s);
param_id.hash(&mut self.s);
match name { match name {
ParamName::Plain(ref ident) => { ParamName::Plain(ref ident) => {
ident.name.hash(&mut self.s); ident.name.hash(&mut self.s);
}, },
ParamName::Fresh(ref size) => { ParamName::Fresh | ParamName::Error => {},
size.hash(&mut self.s);
},
ParamName::Error => {},
} }
} }
} }