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:
parent
11984340bf
commit
08034eb1a5
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
_ => ()
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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(),
|
||||
|
@ -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))
|
||||
|
@ -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"),
|
||||
|
@ -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(..) |
|
||||
|
Loading…
x
Reference in New Issue
Block a user