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
13 changed files with 315 additions and 172 deletions
|
@ -132,6 +132,9 @@ pub trait Visitor<'v> : Sized {
|
||||||
fn visit_generics(&mut self, g: &'v Generics) {
|
fn visit_generics(&mut self, g: &'v Generics) {
|
||||||
walk_generics(self, g)
|
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) {
|
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) {
|
||||||
walk_fn(self, fk, fd, b, s)
|
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_ty, ¶m.default);
|
||||||
}
|
}
|
||||||
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
|
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
|
||||||
for predicate in &generics.where_clause.predicates {
|
walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
|
||||||
match predicate {
|
}
|
||||||
&WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
|
|
||||||
ref bounds,
|
pub fn walk_where_predicate<'v, V: Visitor<'v>>(
|
||||||
ref bound_lifetimes,
|
visitor: &mut V,
|
||||||
..}) => {
|
predicate: &'v WherePredicate)
|
||||||
visitor.visit_ty(bounded_ty);
|
{
|
||||||
walk_list!(visitor, visit_ty_param_bound, bounds);
|
match predicate {
|
||||||
walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
|
&WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
|
||||||
}
|
ref bounds,
|
||||||
&WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
|
ref bound_lifetimes,
|
||||||
ref bounds,
|
..}) => {
|
||||||
..}) => {
|
visitor.visit_ty(bounded_ty);
|
||||||
visitor.visit_lifetime(lifetime);
|
walk_list!(visitor, visit_ty_param_bound, bounds);
|
||||||
walk_list!(visitor, visit_lifetime, bounds);
|
walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
|
||||||
}
|
}
|
||||||
&WherePredicate::EqPredicate(WhereEqPredicate{id,
|
&WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
|
||||||
ref path,
|
ref bounds,
|
||||||
ref ty,
|
..}) => {
|
||||||
..}) => {
|
visitor.visit_lifetime(lifetime);
|
||||||
visitor.visit_path(path, id);
|
walk_list!(visitor, visit_lifetime, bounds);
|
||||||
visitor.visit_ty(ty);
|
}
|
||||||
}
|
&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) => {
|
ty::BrAnon(i) => {
|
||||||
anon_nums.insert(i);
|
anon_nums.insert(i);
|
||||||
}
|
}
|
||||||
ty::BrNamed(_, name) => {
|
ty::BrNamed(_, name, _) => {
|
||||||
region_names.insert(name);
|
region_names.insert(name);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
|
@ -1154,7 +1154,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
|
||||||
for sr in self.same_regions {
|
for sr in self.same_regions {
|
||||||
for br in &sr.regions {
|
for br in &sr.regions {
|
||||||
match *br {
|
match *br {
|
||||||
ty::BrNamed(_, name) => {
|
ty::BrNamed(_, name, _) => {
|
||||||
all_region_names.insert(name);
|
all_region_names.insert(name);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
|
|
|
@ -13,14 +13,12 @@
|
||||||
|
|
||||||
use super::{CombinedSnapshot,
|
use super::{CombinedSnapshot,
|
||||||
InferCtxt,
|
InferCtxt,
|
||||||
LateBoundRegion,
|
|
||||||
HigherRankedType,
|
HigherRankedType,
|
||||||
SubregionOrigin,
|
SubregionOrigin,
|
||||||
SkolemizationMap};
|
SkolemizationMap};
|
||||||
use super::combine::CombineFields;
|
use super::combine::CombineFields;
|
||||||
use super::region_inference::{TaintDirections};
|
use super::region_inference::{TaintDirections};
|
||||||
|
|
||||||
use infer::error_reporting;
|
|
||||||
use ty::{self, TyCtxt, Binder, TypeFoldable};
|
use ty::{self, TyCtxt, Binder, TypeFoldable};
|
||||||
use ty::error::TypeError;
|
use ty::error::TypeError;
|
||||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||||
|
|
|
@ -22,6 +22,7 @@ use dep_graph::DepNode;
|
||||||
use hir::map::Map;
|
use hir::map::Map;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use hir::def::{Def, DefMap};
|
use hir::def::{Def, DefMap};
|
||||||
|
use hir::def_id::DefId;
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use ty::subst;
|
use ty::subst;
|
||||||
use ty;
|
use ty;
|
||||||
|
@ -32,6 +33,7 @@ use syntax::codemap::Span;
|
||||||
use syntax::parse::token::keywords;
|
use syntax::parse::token::keywords;
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
|
|
||||||
|
use rustc_data_structures::fnv::FnvHashSet;
|
||||||
use hir;
|
use hir;
|
||||||
use hir::print::lifetime_to_string;
|
use hir::print::lifetime_to_string;
|
||||||
use hir::intravisit::{self, Visitor, FnKind};
|
use hir::intravisit::{self, Visitor, FnKind};
|
||||||
|
@ -50,11 +52,21 @@ pub enum DefRegion {
|
||||||
|
|
||||||
// Maps the id of each lifetime reference to the lifetime decl
|
// Maps the id of each lifetime reference to the lifetime decl
|
||||||
// that it corresponds to.
|
// 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,
|
sess: &'a Session,
|
||||||
named_region_map: &'a mut NamedRegionMap,
|
hir_map: &'a Map<'tcx>,
|
||||||
|
map: &'a mut NamedRegionMap,
|
||||||
scope: Scope<'a>,
|
scope: Scope<'a>,
|
||||||
def_map: &'a DefMap,
|
def_map: &'a DefMap,
|
||||||
// Deep breath. Our representation for poly trait refs contains a single
|
// Deep breath. Our representation for poly trait refs contains a single
|
||||||
|
@ -101,21 +113,25 @@ pub fn krate(sess: &Session,
|
||||||
-> Result<NamedRegionMap, usize> {
|
-> Result<NamedRegionMap, usize> {
|
||||||
let _task = hir_map.dep_graph.in_task(DepNode::ResolveLifetimes);
|
let _task = hir_map.dep_graph.in_task(DepNode::ResolveLifetimes);
|
||||||
let krate = hir_map.krate();
|
let krate = hir_map.krate();
|
||||||
let mut named_region_map = NodeMap();
|
let mut map = NamedRegionMap {
|
||||||
|
defs: NodeMap(),
|
||||||
|
late_bound: NodeMap(),
|
||||||
|
};
|
||||||
sess.track_errors(|| {
|
sess.track_errors(|| {
|
||||||
krate.visit_all_items(&mut LifetimeContext {
|
krate.visit_all_items(&mut LifetimeContext {
|
||||||
sess: sess,
|
sess: sess,
|
||||||
named_region_map: &mut named_region_map,
|
hir_map: hir_map,
|
||||||
|
map: &mut map,
|
||||||
scope: &ROOT_SCOPE,
|
scope: &ROOT_SCOPE,
|
||||||
def_map: def_map,
|
def_map: def_map,
|
||||||
trait_ref_hack: false,
|
trait_ref_hack: false,
|
||||||
labels_in_fn: vec![],
|
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) {
|
fn visit_item(&mut self, item: &hir::Item) {
|
||||||
assert!(self.labels_in_fn.is_empty());
|
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
|
// Items always introduce a new root scope
|
||||||
self.with(RootScope, |_, this| {
|
self.with(RootScope, |_, this| {
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ForeignItemFn(_, ref generics) => {
|
hir::ForeignItemFn(ref decl, ref generics) => {
|
||||||
this.visit_early_late(subst::FnSpace, generics, |this| {
|
this.visit_early_late(item.id,
|
||||||
|
subst::FnSpace,
|
||||||
|
decl,
|
||||||
|
generics,
|
||||||
|
|this| {
|
||||||
intravisit::walk_foreign_item(this, item);
|
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);
|
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) {
|
b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
|
||||||
match fk {
|
match fk {
|
||||||
FnKind::ItemFn(_, generics, _, _, _, _, _) => {
|
FnKind::ItemFn(_, generics, _, _, _, _, _) => {
|
||||||
self.visit_early_late(subst::FnSpace, generics, |this| {
|
self.visit_early_late(fn_id, subst::FnSpace, decl, generics, |this| {
|
||||||
this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
|
this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
FnKind::Method(_, sig, _, _) => {
|
FnKind::Method(_, sig, _, _) => {
|
||||||
self.visit_early_late(subst::FnSpace, &sig.generics, |this| {
|
self.visit_early_late(
|
||||||
this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
|
fn_id,
|
||||||
})
|
subst::FnSpace,
|
||||||
|
decl,
|
||||||
|
&sig.generics,
|
||||||
|
|this| this.add_scope_and_walk_fn(fk, decl, b, s, fn_id));
|
||||||
}
|
}
|
||||||
FnKind::Closure(_) => {
|
FnKind::Closure(_) => {
|
||||||
// Closures have their own set of labels, save labels just
|
// Closures have their own set of labels, save labels just
|
||||||
// like for foreign items above.
|
// like for foreign items above.
|
||||||
let saved = replace(&mut self.labels_in_fn, vec![]);
|
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);
|
replace(&mut self.labels_in_fn, saved);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -240,7 +263,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||||
|
|
||||||
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
|
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
|
||||||
self.visit_early_late(
|
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))
|
|this| intravisit::walk_trait_item(this, trait_item))
|
||||||
} else {
|
} else {
|
||||||
intravisit::walk_trait_item(self, trait_item);
|
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
|
// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
|
||||||
// if one of the label shadows a lifetime or another label.
|
// 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> {
|
struct GatherLabels<'a> {
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
scope: Scope<'a>,
|
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,
|
fn add_scope_and_walk_fn<'b>(&mut self,
|
||||||
fk: FnKind,
|
fk: FnKind,
|
||||||
fd: &hir::FnDecl,
|
fd: &hir::FnDecl,
|
||||||
|
@ -501,10 +524,11 @@ impl<'a> LifetimeContext<'a> {
|
||||||
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
|
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
|
||||||
F: FnOnce(Scope, &mut LifetimeContext),
|
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 {
|
let mut this = LifetimeContext {
|
||||||
sess: sess,
|
sess: sess,
|
||||||
named_region_map: *named_region_map,
|
hir_map: hir_map,
|
||||||
|
map: *map,
|
||||||
scope: &wrap_scope,
|
scope: &wrap_scope,
|
||||||
def_map: self.def_map,
|
def_map: self.def_map,
|
||||||
trait_ref_hack: self.trait_ref_hack,
|
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
|
/// bound lifetimes are resolved by name and associated with a binder id (`binder_id`), so the
|
||||||
/// ordering is not important there.
|
/// ordering is not important there.
|
||||||
fn visit_early_late<F>(&mut self,
|
fn visit_early_late<F>(&mut self,
|
||||||
|
fn_id: ast::NodeId,
|
||||||
early_space: subst::ParamSpace,
|
early_space: subst::ParamSpace,
|
||||||
|
decl: &hir::FnDecl,
|
||||||
generics: &hir::Generics,
|
generics: &hir::Generics,
|
||||||
walk: F) where
|
walk: F) where
|
||||||
F: FnOnce(&mut LifetimeContext),
|
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={:?}",
|
let (late, early): (Vec<_>, _) =
|
||||||
referenced_idents);
|
generics.lifetimes
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.partition(|l| self.map.late_bound.contains_key(&l.lifetime.id));
|
||||||
|
|
||||||
let (early, late): (Vec<_>, _) = generics.lifetimes.iter().cloned().partition(
|
let this = self;
|
||||||
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
|
this.with(EarlyScope(early_space, &early, this.scope), move |old_scope, this| {
|
||||||
|
|
||||||
self.with(EarlyScope(early_space, &early, self.scope), move |old_scope, this| {
|
|
||||||
this.with(LateScope(&late, this.scope), move |_, this| {
|
this.with(LateScope(&late, this.scope), move |_, this| {
|
||||||
this.check_lifetime_defs(old_scope, &generics.lifetimes);
|
this.check_lifetime_defs(old_scope, &generics.lifetimes);
|
||||||
walk(this);
|
walk(this);
|
||||||
|
@ -756,11 +787,12 @@ impl<'a> LifetimeContext<'a> {
|
||||||
probably a bug in syntax::fold");
|
probably a bug in syntax::fold");
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("lifetime_ref={:?} id={:?} resolved to {:?}",
|
debug!("lifetime_ref={:?} id={:?} resolved to {:?} span={:?}",
|
||||||
lifetime_to_string(lifetime_ref),
|
lifetime_to_string(lifetime_ref),
|
||||||
lifetime_ref.id,
|
lifetime_ref.id,
|
||||||
def);
|
def,
|
||||||
self.named_region_map.insert(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> {
|
/// Detects late-bound lifetimes and inserts them into
|
||||||
let referenced_idents = early_bound_lifetime_names(generics);
|
/// `map.late_bound`.
|
||||||
if referenced_idents.is_empty() {
|
///
|
||||||
return Vec::new();
|
/// 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()
|
let mut appears_in_output = AllCollector { regions: FnvHashSet() };
|
||||||
.filter(|l| referenced_idents.iter().any(|&i| i == l.lifetime.name))
|
intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
|
||||||
.cloned()
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a set of generic declarations, returns a list of names containing all early bound
|
debug!("insert_late_bound_lifetimes: constrained_by_input={:?}",
|
||||||
/// lifetime names for those generics. (In fact, this list may also contain other names.)
|
constrained_by_input.regions);
|
||||||
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();
|
|
||||||
|
|
||||||
// Any lifetime that appears in a type bound is early.
|
// Walk the lifetimes that appear in where clauses.
|
||||||
{
|
//
|
||||||
let mut collector =
|
// Subtle point: because we disallow nested bindings, we can just
|
||||||
FreeLifetimeCollector { early_bound: &mut early_bound,
|
// ignore binders here and scrape up all names we see.
|
||||||
late_bound: &mut late_bound };
|
let mut appears_in_where_clause = AllCollector { regions: FnvHashSet() };
|
||||||
for ty_param in generics.ty_params.iter() {
|
for ty_param in generics.ty_params.iter() {
|
||||||
walk_list!(&mut collector, visit_ty_param_bound, &ty_param.bounds);
|
walk_list!(&mut appears_in_where_clause,
|
||||||
}
|
visit_ty_param_bound,
|
||||||
for predicate in &generics.where_clause.predicates {
|
&ty_param.bounds);
|
||||||
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_list!(&mut appears_in_where_clause,
|
||||||
// Any lifetime that either has a bound or is referenced by a
|
visit_where_predicate,
|
||||||
// bound is early.
|
&generics.where_clause.predicates);
|
||||||
for lifetime_def in &generics.lifetimes {
|
for lifetime_def in &generics.lifetimes {
|
||||||
if !lifetime_def.bounds.is_empty() {
|
if !lifetime_def.bounds.is_empty() {
|
||||||
shuffle(&mut early_bound, &mut late_bound,
|
// `'a: 'b` means both `'a` and `'b` are referenced
|
||||||
lifetime_def.lifetime.name);
|
appears_in_where_clause.visit_lifetime_def(lifetime_def);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shuffle(early_bound: &mut Vec<ast::Name>,
|
debug!("insert_late_bound_lifetimes: appears_in_where_clause={:?}",
|
||||||
late_bound: &mut Vec<ast::Name>,
|
appears_in_where_clause.regions);
|
||||||
name: ast::Name) {
|
|
||||||
match late_bound.iter().position(|n| *n == name) {
|
// Late bound regions are those that:
|
||||||
Some(index) => {
|
// - appear in the inputs
|
||||||
late_bound.swap_remove(index);
|
// - do not appear in the where-clauses
|
||||||
early_bound.push(name);
|
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::{ClosureSubsts, TypeAndMut};
|
||||||
pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
|
pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
|
||||||
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
|
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::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
|
||||||
pub use self::sty::BoundRegion::*;
|
pub use self::sty::BoundRegion::*;
|
||||||
pub use self::sty::FnOutput::*;
|
pub use self::sty::FnOutput::*;
|
||||||
|
@ -527,7 +528,7 @@ bitflags! {
|
||||||
|
|
||||||
// Present if the type belongs in a local type context.
|
// Present if the type belongs in a local type context.
|
||||||
// Only set for TyInfer other than Fresh.
|
// 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 |
|
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
|
||||||
TypeFlags::HAS_SELF.bits |
|
TypeFlags::HAS_SELF.bits |
|
||||||
|
@ -740,7 +741,8 @@ impl RegionParameterDef {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn to_bound_region(&self) -> ty::BoundRegion {
|
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() {
|
for def in generics.regions.as_slice() {
|
||||||
let region =
|
let region =
|
||||||
ReFree(FreeRegion { scope: free_id_outlive,
|
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);
|
debug!("push_region_params {:?}", region);
|
||||||
regions.push(def.space, region);
|
regions.push(def.space, region);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub enum BoundRegion {
|
||||||
///
|
///
|
||||||
/// The def-id is needed to distinguish free regions in
|
/// The def-id is needed to distinguish free regions in
|
||||||
/// the event of shadowing.
|
/// the event of shadowing.
|
||||||
BrNamed(DefId, Name),
|
BrNamed(DefId, Name, Issue32330),
|
||||||
|
|
||||||
/// Fresh bound identifiers created during GLB computations.
|
/// Fresh bound identifiers created during GLB computations.
|
||||||
BrFresh(u32),
|
BrFresh(u32),
|
||||||
|
@ -68,6 +68,25 @@ pub enum BoundRegion {
|
||||||
BrEnv
|
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
|
// NB: If you change this, you'll probably want to change the corresponding
|
||||||
// AST structure in libsyntax/ast.rs as well.
|
// AST structure in libsyntax/ast.rs as well.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
#[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 new_value = tcx.replace_late_bound_regions(&value, |br| {
|
||||||
let _ = start_or_continue(f, "for<", ", ");
|
let _ = start_or_continue(f, "for<", ", ");
|
||||||
ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
|
ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
|
||||||
ty::BrNamed(_, name) => {
|
ty::BrNamed(_, name, _) => {
|
||||||
let _ = write!(f, "{}", name);
|
let _ = write!(f, "{}", name);
|
||||||
br
|
br
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,9 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
|
||||||
ty::BrEnv => {
|
ty::BrEnv => {
|
||||||
let name = token::intern("'r");
|
let name = token::intern("'r");
|
||||||
let _ = write!(f, "{}", name);
|
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;
|
}).0;
|
||||||
|
@ -485,7 +487,7 @@ impl fmt::Display for ty::BoundRegion {
|
||||||
}
|
}
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
BrNamed(_, name) => write!(f, "{}", name),
|
BrNamed(_, name, _) => write!(f, "{}", name),
|
||||||
BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
|
BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,8 +498,9 @@ impl fmt::Debug for ty::BoundRegion {
|
||||||
match *self {
|
match *self {
|
||||||
BrAnon(n) => write!(f, "BrAnon({:?})", n),
|
BrAnon(n) => write!(f, "BrAnon({:?})", n),
|
||||||
BrFresh(n) => write!(f, "BrFresh({:?})", n),
|
BrFresh(n) => write!(f, "BrFresh({:?})", n),
|
||||||
BrNamed(did, name) => {
|
BrNamed(did, name, issue32330) => {
|
||||||
write!(f, "BrNamed({:?}:{:?}, {:?})", did.krate, did.index, name)
|
write!(f, "BrNamed({:?}:{:?}, {:?}, {:?})",
|
||||||
|
did.krate, did.index, name, issue32330)
|
||||||
}
|
}
|
||||||
BrEnv => "BrEnv".fmt(f),
|
BrEnv => "BrEnv".fmt(f),
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,8 +158,21 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
|
||||||
}
|
}
|
||||||
'[' => {
|
'[' => {
|
||||||
let def = self.parse_def();
|
let def = self.parse_def();
|
||||||
let name = token::intern(&self.parse_str(']'));
|
let name = token::intern(&self.parse_str('|'));
|
||||||
ty::BrNamed(def, name)
|
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' => {
|
'f' => {
|
||||||
let id = self.parse_u32();
|
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) => {
|
ty::BrAnon(idx) => {
|
||||||
write!(w, "a{}|", idx);
|
write!(w, "a{}|", idx);
|
||||||
}
|
}
|
||||||
ty::BrNamed(d, name) => {
|
ty::BrNamed(d, name, issue32330) => {
|
||||||
write!(w, "[{}|{}]",
|
write!(w, "[{}|{}|",
|
||||||
(cx.ds)(cx.tcx, d),
|
(cx.ds)(cx.tcx, d),
|
||||||
name);
|
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) => {
|
ty::BrFresh(id) => {
|
||||||
write!(w, "f{}|", 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)
|
pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime)
|
||||||
-> ty::Region {
|
-> ty::Region {
|
||||||
let r = match tcx.named_region_map.get(&lifetime.id) {
|
let r = match tcx.named_region_map.defs.get(&lifetime.id) {
|
||||||
None => {
|
None => {
|
||||||
// should have been recorded by the `resolve_lifetime` pass
|
// should have been recorded by the `resolve_lifetime` pass
|
||||||
span_bug!(lifetime.span, "unresolved lifetime");
|
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)) => {
|
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, _)) => {
|
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)) => {
|
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 {
|
ty::ReFree(ty::FreeRegion {
|
||||||
scope: scope.to_code_extent(&tcx.region_maps),
|
scope: scope.to_code_extent(&tcx.region_maps),
|
||||||
bound_region: ty::BrNamed(tcx.map.local_def_id(id),
|
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);
|
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||||
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
||||||
let br_name = match *br {
|
let br_name = match *br {
|
||||||
ty::BrNamed(_, name) => name,
|
ty::BrNamed(_, name, _) => name,
|
||||||
_ => {
|
_ => {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
binding.span,
|
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);
|
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
|
||||||
for br in late_bound_in_ret.difference(&late_bound_in_args) {
|
for br in late_bound_in_ret.difference(&late_bound_in_args) {
|
||||||
let br_name = match *br {
|
let br_name = match *br {
|
||||||
ty::BrNamed(_, name) => name,
|
ty::BrNamed(_, name, _) => name,
|
||||||
_ => {
|
_ => {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
bf.decl.output.span(),
|
bf.decl.output.span(),
|
||||||
|
|
|
@ -64,7 +64,6 @@ use hir::def::Def;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use constrained_type_params as ctp;
|
use constrained_type_params as ctp;
|
||||||
use middle::lang_items::SizedTraitLangItem;
|
use middle::lang_items::SizedTraitLangItem;
|
||||||
use middle::resolve_lifetime;
|
|
||||||
use middle::const_val::ConstVal;
|
use middle::const_val::ConstVal;
|
||||||
use rustc_const_eval::EvalHint::UncheckedExprHint;
|
use rustc_const_eval::EvalHint::UncheckedExprHint;
|
||||||
use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
|
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
|
/// 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
|
/// screen out those that do not appear in any where-clauses etc using
|
||||||
/// `resolve_lifetime::early_bound_lifetimes`.
|
/// `resolve_lifetime::early_bound_lifetimes`.
|
||||||
fn early_bound_lifetimes_from_generics(space: ParamSpace,
|
fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>(
|
||||||
ast_generics: &hir::Generics)
|
ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
-> Vec<hir::LifetimeDef>
|
ast_generics: &'hir hir::Generics)
|
||||||
|
-> Vec<&'hir hir::LifetimeDef>
|
||||||
{
|
{
|
||||||
match space {
|
ast_generics
|
||||||
SelfSpace | TypeSpace => ast_generics.lifetimes.to_vec(),
|
.lifetimes
|
||||||
FnSpace => resolve_lifetime::early_bound_lifetimes(ast_generics),
|
.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>,
|
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
|
// Collect the region predicates that were declared inline as
|
||||||
// well. In the case of parameters declared on a fn or method, we
|
// well. In the case of parameters declared on a fn or method, we
|
||||||
// have to be careful to only iterate over early-bound regions.
|
// 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() {
|
for (index, param) in early_lifetimes.iter().enumerate() {
|
||||||
let index = index as u32;
|
let index = index as u32;
|
||||||
let region =
|
let region =
|
||||||
|
@ -1864,7 +1865,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
let mut result = base_generics.clone();
|
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() {
|
for (i, l) in early_lifetimes.iter().enumerate() {
|
||||||
let bounds = l.bounds.iter()
|
let bounds = l.bounds.iter()
|
||||||
.map(|l| ast_region_to_region(tcx, l))
|
.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 {
|
fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
|
||||||
let tcx = self.terms_cx.tcx;
|
let tcx = self.terms_cx.tcx;
|
||||||
assert!(is_lifetime(&tcx.map, param_id));
|
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))
|
Some(&rl::DefEarlyBoundRegion(_, _, lifetime_decl_id))
|
||||||
=> lifetime_decl_id,
|
=> lifetime_decl_id,
|
||||||
Some(_) => bug!("should not encounter non early-bound cases"),
|
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> {
|
fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
|
||||||
match *self {
|
match *self {
|
||||||
ty::ReStatic => Some(Lifetime::statik()),
|
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::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
|
||||||
|
|
||||||
ty::ReLateBound(..) |
|
ty::ReLateBound(..) |
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue