add Issue32330 warning marker to bound regions

This indicates whether this `BoundRegion` will change from late to early
bound when issue 32330 is fixed. It also indicates the function on
which the lifetime is declared.
This commit is contained in:
Niko Matsakis 2016-04-21 05:10:10 -04:00
parent 11984340bf
commit 08034eb1a5
13 changed files with 315 additions and 172 deletions

View File

@ -132,6 +132,9 @@ pub trait Visitor<'v> : Sized {
fn visit_generics(&mut self, g: &'v Generics) {
walk_generics(self, g)
}
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
walk_where_predicate(self, predicate)
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) {
walk_fn(self, fk, fd, b, s)
}
@ -529,29 +532,34 @@ pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics
walk_list!(visitor, visit_ty, &param.default);
}
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
for predicate in &generics.where_clause.predicates {
match predicate {
&WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
ref bounds,
ref bound_lifetimes,
..}) => {
visitor.visit_ty(bounded_ty);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
}
&WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
ref bounds,
..}) => {
visitor.visit_lifetime(lifetime);
walk_list!(visitor, visit_lifetime, bounds);
}
&WherePredicate::EqPredicate(WhereEqPredicate{id,
ref path,
ref ty,
..}) => {
visitor.visit_path(path, id);
visitor.visit_ty(ty);
}
walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
}
pub fn walk_where_predicate<'v, V: Visitor<'v>>(
visitor: &mut V,
predicate: &'v WherePredicate)
{
match predicate {
&WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
ref bounds,
ref bound_lifetimes,
..}) => {
visitor.visit_ty(bounded_ty);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
}
&WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
ref bounds,
..}) => {
visitor.visit_lifetime(lifetime);
walk_list!(visitor, visit_lifetime, bounds);
}
&WherePredicate::EqPredicate(WhereEqPredicate{id,
ref path,
ref ty,
..}) => {
visitor.visit_path(path, id);
visitor.visit_ty(ty);
}
}
}

View File

@ -1140,7 +1140,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
ty::BrAnon(i) => {
anon_nums.insert(i);
}
ty::BrNamed(_, name) => {
ty::BrNamed(_, name, _) => {
region_names.insert(name);
}
_ => ()
@ -1154,7 +1154,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
for sr in self.same_regions {
for br in &sr.regions {
match *br {
ty::BrNamed(_, name) => {
ty::BrNamed(_, name, _) => {
all_region_names.insert(name);
}
_ => ()

View File

@ -13,14 +13,12 @@
use super::{CombinedSnapshot,
InferCtxt,
LateBoundRegion,
HigherRankedType,
SubregionOrigin,
SkolemizationMap};
use super::combine::CombineFields;
use super::region_inference::{TaintDirections};
use infer::error_reporting;
use ty::{self, TyCtxt, Binder, TypeFoldable};
use ty::error::TypeError;
use ty::relate::{Relate, RelateResult, TypeRelation};

View File

@ -22,6 +22,7 @@ use dep_graph::DepNode;
use hir::map::Map;
use session::Session;
use hir::def::{Def, DefMap};
use hir::def_id::DefId;
use middle::region;
use ty::subst;
use ty;
@ -32,6 +33,7 @@ use syntax::codemap::Span;
use syntax::parse::token::keywords;
use util::nodemap::NodeMap;
use rustc_data_structures::fnv::FnvHashSet;
use hir;
use hir::print::lifetime_to_string;
use hir::intravisit::{self, Visitor, FnKind};
@ -50,11 +52,21 @@ pub enum DefRegion {
// Maps the id of each lifetime reference to the lifetime decl
// that it corresponds to.
pub type NamedRegionMap = NodeMap<DefRegion>;
pub struct NamedRegionMap {
// maps from every use of a named (not anonymous) lifetime to a
// `DefRegion` describing how that region is bound
pub defs: NodeMap<DefRegion>,
struct LifetimeContext<'a> {
// the set of lifetime def ids that are late-bound; late-bound ids
// are named regions appearing in fn arguments that do not appear
// in where-clauses
pub late_bound: NodeMap<ty::Issue32330>,
}
struct LifetimeContext<'a, 'tcx: 'a> {
sess: &'a Session,
named_region_map: &'a mut NamedRegionMap,
hir_map: &'a Map<'tcx>,
map: &'a mut NamedRegionMap,
scope: Scope<'a>,
def_map: &'a DefMap,
// Deep breath. Our representation for poly trait refs contains a single
@ -101,21 +113,25 @@ pub fn krate(sess: &Session,
-> Result<NamedRegionMap, usize> {
let _task = hir_map.dep_graph.in_task(DepNode::ResolveLifetimes);
let krate = hir_map.krate();
let mut named_region_map = NodeMap();
let mut map = NamedRegionMap {
defs: NodeMap(),
late_bound: NodeMap(),
};
sess.track_errors(|| {
krate.visit_all_items(&mut LifetimeContext {
sess: sess,
named_region_map: &mut named_region_map,
hir_map: hir_map,
map: &mut map,
scope: &ROOT_SCOPE,
def_map: def_map,
trait_ref_hack: false,
labels_in_fn: vec![],
});
})?;
Ok(named_region_map)
Ok(map)
}
impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
assert!(self.labels_in_fn.is_empty());
@ -164,8 +180,12 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
// Items always introduce a new root scope
self.with(RootScope, |_, this| {
match item.node {
hir::ForeignItemFn(_, ref generics) => {
this.visit_early_late(subst::FnSpace, generics, |this| {
hir::ForeignItemFn(ref decl, ref generics) => {
this.visit_early_late(item.id,
subst::FnSpace,
decl,
generics,
|this| {
intravisit::walk_foreign_item(this, item);
})
}
@ -179,24 +199,27 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
replace(&mut self.labels_in_fn, saved);
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, _, _, _, _, _) => {
self.visit_early_late(subst::FnSpace, generics, |this| {
this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
self.visit_early_late(fn_id, subst::FnSpace, decl, generics, |this| {
this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)
})
}
FnKind::Method(_, sig, _, _) => {
self.visit_early_late(subst::FnSpace, &sig.generics, |this| {
this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
})
self.visit_early_late(
fn_id,
subst::FnSpace,
decl,
&sig.generics,
|this| this.add_scope_and_walk_fn(fk, decl, b, s, fn_id));
}
FnKind::Closure(_) => {
// Closures have their own set of labels, save labels just
// like for foreign items above.
let saved = replace(&mut self.labels_in_fn, vec![]);
let result = self.add_scope_and_walk_fn(fk, fd, b, s, fn_id);
let result = self.add_scope_and_walk_fn(fk, decl, b, s, fn_id);
replace(&mut self.labels_in_fn, saved);
result
}
@ -240,7 +263,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
self.visit_early_late(
subst::FnSpace, &sig.generics,
trait_item.id, subst::FnSpace,
&sig.decl, &sig.generics,
|this| intravisit::walk_trait_item(this, trait_item))
} else {
intravisit::walk_trait_item(self, trait_item);
@ -380,8 +404,7 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha
// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
// if one of the label shadows a lifetime or another label.
fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) {
struct GatherLabels<'a> {
sess: &'a Session,
scope: Scope<'a>,
@ -468,7 +491,7 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
}
}
impl<'a> LifetimeContext<'a> {
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
fn add_scope_and_walk_fn<'b>(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
@ -501,10 +524,11 @@ impl<'a> LifetimeContext<'a> {
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
F: FnOnce(Scope, &mut LifetimeContext),
{
let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
let LifetimeContext {sess, hir_map, ref mut map, ..} = *self;
let mut this = LifetimeContext {
sess: sess,
named_region_map: *named_region_map,
hir_map: hir_map,
map: *map,
scope: &wrap_scope,
def_map: self.def_map,
trait_ref_hack: self.trait_ref_hack,
@ -534,20 +558,27 @@ impl<'a> LifetimeContext<'a> {
/// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
/// ordering is not important there.
fn visit_early_late<F>(&mut self,
fn_id: ast::NodeId,
early_space: subst::ParamSpace,
decl: &hir::FnDecl,
generics: &hir::Generics,
walk: F) where
F: FnOnce(&mut LifetimeContext),
{
let referenced_idents = early_bound_lifetime_names(generics);
let fn_def_id = self.hir_map.local_def_id(fn_id);
insert_late_bound_lifetimes(self.map,
fn_def_id,
decl,
generics);
debug!("visit_early_late: referenced_idents={:?}",
referenced_idents);
let (late, early): (Vec<_>, _) =
generics.lifetimes
.iter()
.cloned()
.partition(|l| self.map.late_bound.contains_key(&l.lifetime.id));
let (early, late): (Vec<_>, _) = generics.lifetimes.iter().cloned().partition(
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
self.with(EarlyScope(early_space, &early, self.scope), move |old_scope, this| {
let this = self;
this.with(EarlyScope(early_space, &early, this.scope), move |old_scope, this| {
this.with(LateScope(&late, this.scope), move |_, this| {
this.check_lifetime_defs(old_scope, &generics.lifetimes);
walk(this);
@ -756,11 +787,12 @@ impl<'a> LifetimeContext<'a> {
probably a bug in syntax::fold");
}
debug!("lifetime_ref={:?} id={:?} resolved to {:?}",
lifetime_to_string(lifetime_ref),
lifetime_ref.id,
def);
self.named_region_map.insert(lifetime_ref.id, def);
debug!("lifetime_ref={:?} id={:?} resolved to {:?} span={:?}",
lifetime_to_string(lifetime_ref),
lifetime_ref.id,
def,
self.sess.codemap().span_to_string(lifetime_ref.span));
self.map.defs.insert(lifetime_ref.id, def);
}
}
@ -777,95 +809,132 @@ fn search_lifetimes<'a>(lifetimes: &'a [hir::LifetimeDef],
///////////////////////////////////////////////////////////////////////////
pub fn early_bound_lifetimes<'a>(generics: &'a hir::Generics) -> Vec<hir::LifetimeDef> {
let referenced_idents = early_bound_lifetime_names(generics);
if referenced_idents.is_empty() {
return Vec::new();
/// Detects late-bound lifetimes and inserts them into
/// `map.late_bound`.
///
/// A region declared on a fn is **late-bound** if:
/// - it is constrained by an argument type;
/// - it does not appear in a where-clause.
///
/// "Constrained" basically means that it appears in any type but
/// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
fn_def_id: DefId,
decl: &hir::FnDecl,
generics: &hir::Generics) {
debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
let mut constrained_by_input = ConstrainedCollector { regions: FnvHashSet() };
for arg in &decl.inputs {
constrained_by_input.visit_ty(&arg.ty);
}
generics.lifetimes.iter()
.filter(|l| referenced_idents.iter().any(|&i| i == l.lifetime.name))
.cloned()
.collect()
}
let mut appears_in_output = AllCollector { regions: FnvHashSet() };
intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
/// Given a set of generic declarations, returns a list of names containing all early bound
/// lifetime names for those generics. (In fact, this list may also contain other names.)
fn early_bound_lifetime_names(generics: &hir::Generics) -> Vec<ast::Name> {
// Create two lists, dividing the lifetimes into early/late bound.
// Initially, all of them are considered late, but we will move
// things from late into early as we go if we find references to
// them.
let mut early_bound = Vec::new();
let mut late_bound = generics.lifetimes.iter()
.map(|l| l.lifetime.name)
.collect();
debug!("insert_late_bound_lifetimes: constrained_by_input={:?}",
constrained_by_input.regions);
// Any lifetime that appears in a type bound is early.
{
let mut collector =
FreeLifetimeCollector { early_bound: &mut early_bound,
late_bound: &mut late_bound };
for ty_param in generics.ty_params.iter() {
walk_list!(&mut collector, visit_ty_param_bound, &ty_param.bounds);
}
for predicate in &generics.where_clause.predicates {
match predicate {
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ref bounds,
ref bounded_ty,
..}) => {
collector.visit_ty(&bounded_ty);
walk_list!(&mut collector, visit_ty_param_bound, bounds);
}
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime,
ref bounds,
..}) => {
collector.visit_lifetime(lifetime);
for bound in bounds {
collector.visit_lifetime(bound);
}
}
&hir::WherePredicate::EqPredicate(_) => bug!("unimplemented")
}
}
// Walk the lifetimes that appear in where clauses.
//
// Subtle point: because we disallow nested bindings, we can just
// ignore binders here and scrape up all names we see.
let mut appears_in_where_clause = AllCollector { regions: FnvHashSet() };
for ty_param in generics.ty_params.iter() {
walk_list!(&mut appears_in_where_clause,
visit_ty_param_bound,
&ty_param.bounds);
}
// Any lifetime that either has a bound or is referenced by a
// bound is early.
walk_list!(&mut appears_in_where_clause,
visit_where_predicate,
&generics.where_clause.predicates);
for lifetime_def in &generics.lifetimes {
if !lifetime_def.bounds.is_empty() {
shuffle(&mut early_bound, &mut late_bound,
lifetime_def.lifetime.name);
for bound in &lifetime_def.bounds {
shuffle(&mut early_bound, &mut late_bound,
bound.name);
}
}
}
return early_bound;
struct FreeLifetimeCollector<'a> {
early_bound: &'a mut Vec<ast::Name>,
late_bound: &'a mut Vec<ast::Name>,
}
impl<'a, 'v> Visitor<'v> for FreeLifetimeCollector<'a> {
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
shuffle(self.early_bound, self.late_bound,
lifetime_ref.name);
// `'a: 'b` means both `'a` and `'b` are referenced
appears_in_where_clause.visit_lifetime_def(lifetime_def);
}
}
fn shuffle(early_bound: &mut Vec<ast::Name>,
late_bound: &mut Vec<ast::Name>,
name: ast::Name) {
match late_bound.iter().position(|n| *n == name) {
Some(index) => {
late_bound.swap_remove(index);
early_bound.push(name);
debug!("insert_late_bound_lifetimes: appears_in_where_clause={:?}",
appears_in_where_clause.regions);
// Late bound regions are those that:
// - appear in the inputs
// - do not appear in the where-clauses
for lifetime in &generics.lifetimes {
let name = lifetime.lifetime.name;
// appears in the where clauses? early-bound.
if appears_in_where_clause.regions.contains(&name) { continue; }
// does not appear in the inputs, but appears in the return
// type? eventually this will be early-bound, but for now we
// just mark it so we can issue warnings.
let constrained_by_input = constrained_by_input.regions.contains(&name);
let appears_in_output = appears_in_output.regions.contains(&name);
let will_change = !constrained_by_input && appears_in_output;
let issue_32330 = if will_change {
ty::Issue32330::WillChange {
fn_def_id: fn_def_id,
region_name: name,
}
None => { }
} else {
ty::Issue32330::WontChange
};
debug!("insert_late_bound_lifetimes: \
lifetime {:?} with id {:?} is late-bound ({:?}",
lifetime.lifetime.name, lifetime.lifetime.id, issue_32330);
let prev = map.late_bound.insert(lifetime.lifetime.id, issue_32330);
assert!(prev.is_none(), "visited lifetime {:?} twice", lifetime.lifetime.id);
}
return;
struct ConstrainedCollector {
regions: FnvHashSet<ast::Name>,
}
impl<'v> Visitor<'v> for ConstrainedCollector {
fn visit_ty(&mut self, ty: &'v hir::Ty) {
match ty.node {
hir::TyPath(Some(_), _) => {
// ignore lifetimes appearing in associated type
// projections, as they are not *constrained*
// (defined above)
}
hir::TyPath(None, ref path) => {
// consider only the lifetimes on the final
// segment; I am not sure it's even currently
// valid to have them elsewhere, but even if it
// is, those would be potentially inputs to
// projections
if let Some(last_segment) = path.segments.last() {
self.visit_path_segment(path.span, last_segment);
}
}
_ => {
intravisit::walk_ty(self, ty);
}
}
}
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
self.regions.insert(lifetime_ref.name);
}
}
struct AllCollector {
regions: FnvHashSet<ast::Name>,
}
impl<'v> Visitor<'v> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
self.regions.insert(lifetime_ref.name);
}
}
}

View File

@ -60,6 +60,7 @@ pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy};
pub use self::sty::{ClosureSubsts, TypeAndMut};
pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
pub use self::sty::Issue32330;
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
pub use self::sty::BoundRegion::*;
pub use self::sty::FnOutput::*;
@ -527,7 +528,7 @@ bitflags! {
// Present if the type belongs in a local type context.
// Only set for TyInfer other than Fresh.
const KEEP_IN_LOCAL_TCX = 1 << 10,
const KEEP_IN_LOCAL_TCX = 1 << 11,
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
@ -740,7 +741,8 @@ impl RegionParameterDef {
})
}
pub fn to_bound_region(&self) -> ty::BoundRegion {
ty::BoundRegion::BrNamed(self.def_id, self.name)
// this is an early bound region, so unaffected by #32330
ty::BoundRegion::BrNamed(self.def_id, self.name, Issue32330::WontChange)
}
}
@ -2836,7 +2838,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
for def in generics.regions.as_slice() {
let region =
ReFree(FreeRegion { scope: free_id_outlive,
bound_region: BrNamed(def.def_id, def.name) });
bound_region: def.to_bound_region() });
debug!("push_region_params {:?}", region);
regions.push(def.space, region);
}

View File

@ -58,7 +58,7 @@ pub enum BoundRegion {
///
/// The def-id is needed to distinguish free regions in
/// the event of shadowing.
BrNamed(DefId, Name),
BrNamed(DefId, Name, Issue32330),
/// Fresh bound identifiers created during GLB computations.
BrFresh(u32),
@ -68,6 +68,25 @@ pub enum BoundRegion {
BrEnv
}
/// True if this late-bound region is unconstrained, and hence will
/// become early-bound once #32330 is fixed.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash,
RustcEncodable, RustcDecodable)]
pub enum Issue32330 {
WontChange,
/// this region will change from late-bound to early-bound once
/// #32330 is fixed.
WillChange {
/// fn where is region declared
fn_def_id: DefId,
/// name of region; duplicates the info in BrNamed but convenient
/// to have it here, and this code is only temporary
region_name: ast::Name,
}
}
// NB: If you change this, you'll probably want to change the corresponding
// AST structure in libsyntax/ast.rs as well.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]

View File

@ -261,7 +261,7 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
let new_value = tcx.replace_late_bound_regions(&value, |br| {
let _ = start_or_continue(f, "for<", ", ");
ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
ty::BrNamed(_, name) => {
ty::BrNamed(_, name, _) => {
let _ = write!(f, "{}", name);
br
}
@ -270,7 +270,9 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
ty::BrEnv => {
let name = token::intern("'r");
let _ = write!(f, "{}", name);
ty::BrNamed(tcx.map.local_def_id(CRATE_NODE_ID), name)
ty::BrNamed(tcx.map.local_def_id(CRATE_NODE_ID),
name,
ty::Issue32330::WontChange)
}
})
}).0;
@ -485,7 +487,7 @@ impl fmt::Display for ty::BoundRegion {
}
match *self {
BrNamed(_, name) => write!(f, "{}", name),
BrNamed(_, name, _) => write!(f, "{}", name),
BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
}
}
@ -496,8 +498,9 @@ impl fmt::Debug for ty::BoundRegion {
match *self {
BrAnon(n) => write!(f, "BrAnon({:?})", n),
BrFresh(n) => write!(f, "BrFresh({:?})", n),
BrNamed(did, name) => {
write!(f, "BrNamed({:?}:{:?}, {:?})", did.krate, did.index, name)
BrNamed(did, name, issue32330) => {
write!(f, "BrNamed({:?}:{:?}, {:?}, {:?})",
did.krate, did.index, name, issue32330)
}
BrEnv => "BrEnv".fmt(f),
}

View File

@ -158,8 +158,21 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
}
'[' => {
let def = self.parse_def();
let name = token::intern(&self.parse_str(']'));
ty::BrNamed(def, name)
let name = token::intern(&self.parse_str('|'));
let issue32330 = match self.next() {
'n' => {
assert_eq!(self.next(), ']');
ty::Issue32330::WontChange
}
'y' => {
ty::Issue32330::WillChange {
fn_def_id: self.parse_def(),
region_name: token::intern(&self.parse_str(']')),
}
}
c => panic!("expected n or y not {}", c)
};
ty::BrNamed(def, name, issue32330)
}
'f' => {
let id = self.parse_u32();

View File

@ -308,10 +308,17 @@ fn enc_bound_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, br: ty::BoundRegion) {
ty::BrAnon(idx) => {
write!(w, "a{}|", idx);
}
ty::BrNamed(d, name) => {
write!(w, "[{}|{}]",
(cx.ds)(cx.tcx, d),
name);
ty::BrNamed(d, name, issue32330) => {
write!(w, "[{}|{}|",
(cx.ds)(cx.tcx, d),
name);
match issue32330 {
ty::Issue32330::WontChange =>
write!(w, "n]"),
ty::Issue32330::WillChange { fn_def_id, region_name } =>
write!(w, "y{}|{}]", (cx.ds)(cx.tcx, fn_def_id), region_name),
};
}
ty::BrFresh(id) => {
write!(w, "f{}|", id);

View File

@ -170,7 +170,7 @@ type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjection
pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime)
-> ty::Region {
let r = match tcx.named_region_map.get(&lifetime.id) {
let r = match tcx.named_region_map.defs.get(&lifetime.id) {
None => {
// should have been recorded by the `resolve_lifetime` pass
span_bug!(lifetime.span, "unresolved lifetime");
@ -181,7 +181,20 @@ pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime)
}
Some(&rl::DefLateBoundRegion(debruijn, id)) => {
ty::ReLateBound(debruijn, ty::BrNamed(tcx.map.local_def_id(id), lifetime.name))
// If this region is declared on a function, it will have
// an entry in `late_bound`, but if it comes from
// `for<'a>` in some type or something, it won't
// necessarily have one. In that case though, we won't be
// changed from late to early bound, so we can just
// substitute false.
let issue_32330 = tcx.named_region_map
.late_bound
.get(&id)
.cloned()
.unwrap_or(ty::Issue32330::WontChange);
ty::ReLateBound(debruijn, ty::BrNamed(tcx.map.local_def_id(id),
lifetime.name,
issue_32330))
}
Some(&rl::DefEarlyBoundRegion(space, index, _)) => {
@ -193,11 +206,21 @@ pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime)
}
Some(&rl::DefFreeRegion(scope, id)) => {
// As in DefLateBoundRegion above, could be missing for some late-bound
// regions, but also for early-bound regions.
let issue_32330 = tcx.named_region_map
.late_bound
.get(&id)
.cloned()
.unwrap_or(ty::Issue32330::WontChange);
ty::ReFree(ty::FreeRegion {
scope: scope.to_code_extent(&tcx.region_maps),
bound_region: ty::BrNamed(tcx.map.local_def_id(id),
lifetime.name)
})
lifetime.name,
issue_32330)
})
// (*) -- not late-bound, won't change
}
};
@ -911,7 +934,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
let br_name = match *br {
ty::BrNamed(_, name) => name,
ty::BrNamed(_, name, _) => name,
_ => {
span_bug!(
binding.span,
@ -1675,7 +1698,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
for br in late_bound_in_ret.difference(&late_bound_in_args) {
let br_name = match *br {
ty::BrNamed(_, name) => name,
ty::BrNamed(_, name, _) => name,
_ => {
span_bug!(
bf.decl.output.span(),

View File

@ -64,7 +64,6 @@ use hir::def::Def;
use hir::def_id::DefId;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
use middle::resolve_lifetime;
use middle::const_val::ConstVal;
use rustc_const_eval::EvalHint::UncheckedExprHint;
use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
@ -1745,14 +1744,16 @@ fn add_unsized_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
/// the lifetimes that are declared. For fns or methods, we have to
/// screen out those that do not appear in any where-clauses etc using
/// `resolve_lifetime::early_bound_lifetimes`.
fn early_bound_lifetimes_from_generics(space: ParamSpace,
ast_generics: &hir::Generics)
-> Vec<hir::LifetimeDef>
fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>(
ccx: &CrateCtxt<'a, 'tcx>,
ast_generics: &'hir hir::Generics)
-> Vec<&'hir hir::LifetimeDef>
{
match space {
SelfSpace | TypeSpace => ast_generics.lifetimes.to_vec(),
FnSpace => resolve_lifetime::early_bound_lifetimes(ast_generics),
}
ast_generics
.lifetimes
.iter()
.filter(|l| !ccx.tcx.named_region_map.late_bound.contains_key(&l.lifetime.id))
.collect()
}
fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
@ -1781,7 +1782,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
// Collect the region predicates that were declared inline as
// well. In the case of parameters declared on a fn or method, we
// have to be careful to only iterate over early-bound regions.
let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics);
let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
for (index, param) in early_lifetimes.iter().enumerate() {
let index = index as u32;
let region =
@ -1864,7 +1865,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
let tcx = ccx.tcx;
let mut result = base_generics.clone();
let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics);
let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
for (i, l) in early_lifetimes.iter().enumerate() {
let bounds = l.bounds.iter()
.map(|l| ast_region_to_region(tcx, l))

View File

@ -144,7 +144,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
let tcx = self.terms_cx.tcx;
assert!(is_lifetime(&tcx.map, param_id));
match tcx.named_region_map.get(&param_id) {
match tcx.named_region_map.defs.get(&param_id) {
Some(&rl::DefEarlyBoundRegion(_, _, lifetime_decl_id))
=> lifetime_decl_id,
Some(_) => bug!("should not encounter non early-bound cases"),

View File

@ -819,7 +819,7 @@ impl Clean<Option<Lifetime>> for ty::Region {
fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
match *self {
ty::ReStatic => Some(Lifetime::statik()),
ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
ty::ReLateBound(_, ty::BrNamed(_, name, _)) => Some(Lifetime(name.to_string())),
ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
ty::ReLateBound(..) |