From 08034eb1a58518f7fc684ad325d32195d48a9fe3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis <niko@alum.mit.edu> Date: Thu, 21 Apr 2016 05:10:10 -0400 Subject: [PATCH] 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. --- src/librustc/hir/intravisit.rs | 54 ++-- src/librustc/infer/error_reporting.rs | 4 +- src/librustc/infer/higher_ranked/mod.rs | 2 - src/librustc/middle/resolve_lifetime.rs | 293 ++++++++++++-------- src/librustc/ty/mod.rs | 8 +- src/librustc/ty/sty.rs | 21 +- src/librustc/util/ppaux.rs | 13 +- src/librustc_metadata/tydecode.rs | 17 +- src/librustc_metadata/tyencode.rs | 15 +- src/librustc_typeck/astconv.rs | 35 ++- src/librustc_typeck/collect.rs | 21 +- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 13 files changed, 315 insertions(+), 172 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 84a666ebef1..d47de676e79 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -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, ¶m.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); } } } diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 628fd569d40..804a0cd400c 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -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); } _ => () diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 9ea2a830c9e..4dac47ea6c3 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -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}; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 4cc9b0b4353..dcc84fb0439 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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); } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b37fad0ba30..54ef17dce8f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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); } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 32434d40e61..5a648dcbab7 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -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)] diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 1a802064b61..a851e8354a9 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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), } diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index c94af9c5b3a..984ac226d85 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -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(); diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 343c452f891..87a2e50bb25 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -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); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index fc1abb56d5a..472d6ac67f4 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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(), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 92027a56ec1..e65f3f0ff41 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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)) diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index a532f9744f4..612007da0e9 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -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(¶m_id) { + match tcx.named_region_map.defs.get(¶m_id) { Some(&rl::DefEarlyBoundRegion(_, _, lifetime_decl_id)) => lifetime_decl_id, Some(_) => bug!("should not encounter non early-bound cases"), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bf503141ff6..0f3c62aca2a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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(..) |