1
Fork 0

Auto merge of #41914 - eddyb:region-refactor, r=nikomatsakis

rustc: simpler ParameterEnvironment and free regions.

The commits describe the slow transformation but the highlights are:
* `ReEarlyBound` is considered free, with a scope based on the item that defined the lifetime parameter, and the root body of the `RegionMaps` in use, removing the need for `free_substs`
* `liberate_late_bound_regions` and `implicit_region_bound` moved to typeck
* `CodeExtent` not interned at all now - ideally it would be 2 `u32` but it's small anyway

Future work building up on this could include:
* `ParameterEnvironment` becoming just the result of `predicates_of`
  * interning makes my "parent chain" scheme unnecessary
* `implicit_region_bound` could be retrieved from `RegionMaps`
* renaming `CodeExtent` to `Scope`
  * generalizing "call site" to "use site" or something better to include constants
* renaming `RegionMaps` to `ScopeTree` and its API to talk about "parents" explicitly
This commit is contained in:
bors 2017-05-13 17:56:09 +00:00
commit 826d8f3850
69 changed files with 707 additions and 1100 deletions

View file

@ -10,6 +10,7 @@
use rustc_data_structures::graph; use rustc_data_structures::graph;
use cfg::*; use cfg::*;
use middle::region::CodeExtent;
use ty::{self, TyCtxt}; use ty::{self, TyCtxt};
use syntax::ast; use syntax::ast;
use syntax::ptr::P; use syntax::ptr::P;
@ -586,8 +587,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
scope_id: ast::NodeId, scope_id: ast::NodeId,
to_index: CFGIndex) { to_index: CFGIndex) {
let mut data = CFGEdgeData { exiting_scopes: vec![] }; let mut data = CFGEdgeData { exiting_scopes: vec![] };
let mut scope = self.tcx.node_extent(from_expr.id); let mut scope = CodeExtent::Misc(from_expr.id);
let target_scope = self.tcx.node_extent(scope_id); let target_scope = CodeExtent::Misc(scope_id);
let region_maps = self.tcx.region_maps(self.owner_def_id); let region_maps = self.tcx.region_maps(self.owner_def_id);
while scope != target_scope { while scope != target_scope {
data.exiting_scopes.push(scope.node_id()); data.exiting_scopes.push(scope.node_id());

View file

@ -39,7 +39,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::subst::Kind<'t
} }
} }
impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionKind<'tcx> { impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionKind {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'tcx>, hcx: &mut StableHashingContext<'a, 'tcx>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
@ -54,7 +54,8 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionKind<'tc
db.depth.hash_stable(hcx, hasher); db.depth.hash_stable(hcx, hasher);
i.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher);
} }
ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => { ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => {
def_id.hash_stable(hcx, hasher);
index.hash_stable(hcx, hasher); index.hash_stable(hcx, hasher);
name.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher);
} }
@ -409,11 +410,6 @@ impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region {
Free(call_site_scope_data, decl) Free(call_site_scope_data, decl)
}); });
impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData {
fn_id,
body_id
});
impl_stable_hash_for!(struct ty::DebruijnIndex { impl_stable_hash_for!(struct ty::DebruijnIndex {
depth depth
}); });
@ -432,25 +428,24 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
FnPtrAddrCast FnPtrAddrCast
}); });
impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::middle::region::CodeExtentData impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::middle::region::CodeExtent
{ {
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'tcx>, hcx: &mut StableHashingContext<'a, 'tcx>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {
use middle::region::CodeExtentData; use middle::region::CodeExtent;
mem::discriminant(self).hash_stable(hcx, hasher); mem::discriminant(self).hash_stable(hcx, hasher);
match *self { match *self {
CodeExtentData::Misc(node_id) | CodeExtent::Misc(node_id) |
CodeExtentData::DestructionScope(node_id) => { CodeExtent::DestructionScope(node_id) => {
node_id.hash_stable(hcx, hasher); node_id.hash_stable(hcx, hasher);
} }
CodeExtentData::CallSiteScope { fn_id, body_id } | CodeExtent::CallSiteScope(body_id) |
CodeExtentData::ParameterScope { fn_id, body_id } => { CodeExtent::ParameterScope(body_id) => {
fn_id.hash_stable(hcx, hasher);
body_id.hash_stable(hcx, hasher); body_id.hash_stable(hcx, hasher);
} }
CodeExtentData::Remainder(block_remainder) => { CodeExtent::Remainder(block_remainder) => {
block_remainder.hash_stable(hcx, hasher); block_remainder.hash_stable(hcx, hasher);
} }
} }
@ -466,7 +461,7 @@ impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo {
custom_kind custom_kind
}); });
impl_stable_hash_for!(struct ty::FreeRegion<'tcx> { impl_stable_hash_for!(struct ty::FreeRegion {
scope, scope,
bound_region bound_region
}); });

View file

@ -423,15 +423,6 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
return Ok(r); return Ok(r);
} }
// Early-bound regions should really have been substituted away before
// we get to this point.
ty::ReEarlyBound(..) => {
span_bug!(
self.span,
"Encountered early bound region when generalizing: {:?}",
r);
}
// Always make a fresh region variable for skolemized regions; // Always make a fresh region variable for skolemized regions;
// the higher-ranked decision procedures rely on this. // the higher-ranked decision procedures rely on this.
ty::ReSkolemized(..) => { } ty::ReSkolemized(..) => { }
@ -442,6 +433,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
ty::ReStatic | ty::ReStatic |
ty::ReScope(..) | ty::ReScope(..) |
ty::ReVar(..) | ty::ReVar(..) |
ty::ReEarlyBound(..) |
ty::ReFree(..) => { ty::ReFree(..) => {
match self.ambient_variance { match self.ambient_variance {
ty::Invariant => return Ok(r), ty::Invariant => return Ok(r),

View file

@ -151,19 +151,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
return; return;
} }
}; };
let scope_decorated_tag = match *scope { let scope_decorated_tag = match scope {
region::CodeExtentData::Misc(_) => tag, region::CodeExtent::Misc(_) => tag,
region::CodeExtentData::CallSiteScope { .. } => { region::CodeExtent::CallSiteScope(_) => {
"scope of call-site for function" "scope of call-site for function"
} }
region::CodeExtentData::ParameterScope { .. } => { region::CodeExtent::ParameterScope(_) => {
"scope of function body" "scope of function body"
} }
region::CodeExtentData::DestructionScope(_) => { region::CodeExtent::DestructionScope(_) => {
new_string = format!("destruction scope surrounding {}", tag); new_string = format!("destruction scope surrounding {}", tag);
&new_string[..] &new_string[..]
} }
region::CodeExtentData::Remainder(r) => { region::CodeExtent::Remainder(r) => {
new_string = format!("block suffix following statement {}", new_string = format!("block suffix following statement {}",
r.first_statement_index); r.first_statement_index);
&new_string[..] &new_string[..]
@ -172,8 +172,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
explain_span(self, scope_decorated_tag, span) explain_span(self, scope_decorated_tag, span)
} }
ty::ReEarlyBound(_) |
ty::ReFree(_) => {
let scope = match *region {
ty::ReEarlyBound(ref br) => {
self.parent_def_id(br.def_id).unwrap()
}
ty::ReFree(ref fr) => fr.scope,
_ => bug!()
};
let prefix = match *region {
ty::ReEarlyBound(ref br) => {
format!("the lifetime {} as defined on", br.name)
}
ty::ReFree(ref fr) => { ty::ReFree(ref fr) => {
let prefix = match fr.bound_region { match fr.bound_region {
ty::BrAnon(idx) => { ty::BrAnon(idx) => {
format!("the anonymous lifetime #{} defined on", idx + 1) format!("the anonymous lifetime #{} defined on", idx + 1)
} }
@ -182,9 +195,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
format!("the lifetime {} as defined on", format!("the lifetime {} as defined on",
fr.bound_region) fr.bound_region)
} }
}
}
_ => bug!()
}; };
let node = fr.scope.map(|s| s.node_id()) let node = self.hir.as_local_node_id(scope)
.unwrap_or(DUMMY_NODE_ID); .unwrap_or(DUMMY_NODE_ID);
let unknown; let unknown;
let tag = match self.hir.find(node) { let tag = match self.hir.find(node) {
@ -199,12 +215,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
Some(_) => { Some(_) => {
unknown = format!("unexpected node ({}) for scope {:?}. \ unknown = format!("unexpected node ({}) for scope {:?}. \
Please report a bug.", Please report a bug.",
self.hir.node_to_string(node), fr.scope); self.hir.node_to_string(node), scope);
&unknown &unknown
} }
None => { None => {
unknown = format!("unknown node for scope {:?}. \ unknown = format!("unknown node for scope {:?}. \
Please report a bug.", fr.scope); Please report a bug.", scope);
&unknown &unknown
} }
}; };
@ -216,8 +232,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::ReEmpty => ("the empty lifetime".to_owned(), None), ty::ReEmpty => ("the empty lifetime".to_owned(), None),
ty::ReEarlyBound(ref data) => (data.name.to_string(), None),
// FIXME(#13998) ReSkolemized should probably print like // FIXME(#13998) ReSkolemized should probably print like
// ReFree rather than dumping Debug output on the user. // ReFree rather than dumping Debug output on the user.
// //
@ -797,6 +811,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
let mut err = match *sub { let mut err = match *sub {
ty::ReEarlyBound(_) |
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print? // Does the required lifetime have a nice name we can print?
let mut err = struct_span_err!(self.tcx.sess, let mut err = struct_span_err!(self.tcx.sess,

View file

@ -85,13 +85,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r { match *r {
ty::ReEarlyBound(..) |
ty::ReLateBound(..) => { ty::ReLateBound(..) => {
// leave bound regions alone // leave bound regions alone
r r
} }
ty::ReStatic | ty::ReStatic |
ty::ReEarlyBound(..) |
ty::ReFree(_) | ty::ReFree(_) |
ty::ReScope(_) | ty::ReScope(_) |
ty::ReVar(_) | ty::ReVar(_) |

View file

@ -274,7 +274,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
-> ty::Region<'tcx> { -> ty::Region<'tcx> {
// Regions that pre-dated the LUB computation stay as they are. // Regions that pre-dated the LUB computation stay as they are.
if !is_var_in_set(new_vars, r0) { if !is_var_in_set(new_vars, r0) {
assert!(!r0.is_bound()); assert!(!r0.is_late_bound());
debug!("generalize_region(r0={:?}): not new variable", r0); debug!("generalize_region(r0={:?}): not new variable", r0);
return r0; return r0;
} }
@ -288,7 +288,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
debug!("generalize_region(r0={:?}): \ debug!("generalize_region(r0={:?}): \
non-new-variables found in {:?}", non-new-variables found in {:?}",
r0, tainted); r0, tainted);
assert!(!r0.is_bound()); assert!(!r0.is_late_bound());
return r0; return r0;
} }
@ -371,7 +371,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
r0: ty::Region<'tcx>) r0: ty::Region<'tcx>)
-> ty::Region<'tcx> { -> ty::Region<'tcx> {
if !is_var_in_set(new_vars, r0) { if !is_var_in_set(new_vars, r0) {
assert!(!r0.is_bound()); assert!(!r0.is_late_bound());
return r0; return r0;
} }
@ -424,7 +424,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
return rev_lookup(infcx, span, a_map, a_r.unwrap()); return rev_lookup(infcx, span, a_map, a_r.unwrap());
} else if a_r.is_none() && b_r.is_none() { } else if a_r.is_none() && b_r.is_none() {
// Not related to bound variables from either fn: // Not related to bound variables from either fn:
assert!(!r0.is_bound()); assert!(!r0.is_late_bound());
return r0; return r0;
} else { } else {
// Other: // Other:

View file

@ -450,10 +450,10 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
-> (Option<&'a ty::TypeckTables<'tcx>>, -> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>, Option<ty::TypeckTables<'tcx>>,
Option<ty::ParameterEnvironment<'tcx>>) { Option<ty::ParameterEnvironment<'tcx>>) {
let item_id = tcx.hir.body_owner(self); let def_id = tcx.hir.body_owner_def_id(self);
(Some(tcx.typeck_tables_of(tcx.hir.local_def_id(item_id))), (Some(tcx.typeck_tables_of(def_id)),
None, None,
Some(ty::ParameterEnvironment::for_item(tcx, item_id))) Some(tcx.parameter_environment(def_id)))
} }
} }
@ -1009,7 +1009,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
pub fn add_given(&self, pub fn add_given(&self,
sub: ty::FreeRegion<'tcx>, sub: ty::Region<'tcx>,
sup: ty::RegionVid) sup: ty::RegionVid)
{ {
self.region_vars.add_given(sub, sup); self.region_vars.add_given(sub, sup);
@ -1324,7 +1324,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn resolve_regions_and_report_errors(&self, pub fn resolve_regions_and_report_errors(&self,
region_context: DefId, region_context: DefId,
region_map: &RegionMaps<'tcx>, region_map: &RegionMaps,
free_regions: &FreeRegionMap<'tcx>) { free_regions: &FreeRegionMap<'tcx>) {
let region_rels = RegionRelations::new(self.tcx, let region_rels = RegionRelations::new(self.tcx,
region_context, region_context,

View file

@ -124,20 +124,20 @@ struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
graph_name: String, graph_name: String,
region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>, region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>,
map: &'a FxHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>, map: &'a FxHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
node_ids: FxHashMap<Node<'tcx>, usize>, node_ids: FxHashMap<Node, usize>,
} }
#[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)] #[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)]
enum Node<'tcx> { enum Node {
RegionVid(ty::RegionVid), RegionVid(ty::RegionVid),
Region(ty::RegionKind<'tcx>), Region(ty::RegionKind),
} }
// type Edge = Constraint; // type Edge = Constraint;
#[derive(Clone, PartialEq, Eq, Debug, Copy)] #[derive(Clone, PartialEq, Eq, Debug, Copy)]
enum Edge<'tcx> { enum Edge<'tcx> {
Constraint(Constraint<'tcx>), Constraint(Constraint<'tcx>),
EnclScope(CodeExtent<'tcx>, CodeExtent<'tcx>), EnclScope(CodeExtent, CodeExtent),
} }
impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> {
@ -176,7 +176,7 @@ impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> {
} }
impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
type Node = Node<'tcx>; type Node = Node;
type Edge = Edge<'tcx>; type Edge = Edge<'tcx>;
fn graph_id(&self) -> dot::Id { fn graph_id(&self) -> dot::Id {
dot::Id::new(&*self.graph_name).unwrap() dot::Id::new(&*self.graph_name).unwrap()
@ -209,7 +209,7 @@ impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
} }
} }
fn constraint_to_nodes<'tcx>(c: &Constraint<'tcx>) -> (Node<'tcx>, Node<'tcx>) { fn constraint_to_nodes(c: &Constraint) -> (Node, Node) {
match *c { match *c {
Constraint::ConstrainVarSubVar(rv_1, rv_2) => Constraint::ConstrainVarSubVar(rv_1, rv_2) =>
(Node::RegionVid(rv_1), Node::RegionVid(rv_2)), (Node::RegionVid(rv_1), Node::RegionVid(rv_2)),
@ -222,7 +222,7 @@ fn constraint_to_nodes<'tcx>(c: &Constraint<'tcx>) -> (Node<'tcx>, Node<'tcx>) {
} }
} }
fn edge_to_nodes<'tcx>(e: &Edge<'tcx>) -> (Node<'tcx>, Node<'tcx>) { fn edge_to_nodes(e: &Edge) -> (Node, Node) {
match *e { match *e {
Edge::Constraint(ref c) => constraint_to_nodes(c), Edge::Constraint(ref c) => constraint_to_nodes(c),
Edge::EnclScope(sub, sup) => { Edge::EnclScope(sub, sup) => {
@ -233,9 +233,9 @@ fn edge_to_nodes<'tcx>(e: &Edge<'tcx>) -> (Node<'tcx>, Node<'tcx>) {
} }
impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
type Node = Node<'tcx>; type Node = Node;
type Edge = Edge<'tcx>; type Edge = Edge<'tcx>;
fn nodes(&self) -> dot::Nodes<Node<'tcx>> { fn nodes(&self) -> dot::Nodes<Node> {
let mut set = FxHashSet(); let mut set = FxHashSet();
for node in self.node_ids.keys() { for node in self.node_ids.keys() {
set.insert(*node); set.insert(*node);
@ -250,12 +250,12 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
debug!("region graph has {} edges", v.len()); debug!("region graph has {} edges", v.len());
Cow::Owned(v) Cow::Owned(v)
} }
fn source(&self, edge: &Edge<'tcx>) -> Node<'tcx> { fn source(&self, edge: &Edge<'tcx>) -> Node {
let (n1, _) = edge_to_nodes(edge); let (n1, _) = edge_to_nodes(edge);
debug!("edge {:?} has source {:?}", edge, n1); debug!("edge {:?} has source {:?}", edge, n1);
n1 n1
} }
fn target(&self, edge: &Edge<'tcx>) -> Node<'tcx> { fn target(&self, edge: &Edge<'tcx>) -> Node {
let (_, n2) = edge_to_nodes(edge); let (_, n2) = edge_to_nodes(edge);
debug!("edge {:?} has target {:?}", edge, n2); debug!("edge {:?} has target {:?}", edge, n2);
n2 n2

View file

@ -29,7 +29,6 @@ use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased};
use ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::cmp::Ordering::{self, Less, Greater, Equal};
use std::fmt; use std::fmt;
use std::mem; use std::mem;
use std::u32; use std::u32;
@ -127,7 +126,7 @@ pub enum UndoLogEntry<'tcx> {
AddVerify(usize), AddVerify(usize),
/// We added the given `given` /// We added the given `given`
AddGiven(ty::FreeRegion<'tcx>, ty::RegionVid), AddGiven(Region<'tcx>, ty::RegionVid),
/// We added a GLB/LUB "combinaton variable" /// We added a GLB/LUB "combinaton variable"
AddCombination(CombineMapType, TwoRegions<'tcx>), AddCombination(CombineMapType, TwoRegions<'tcx>),
@ -213,7 +212,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// record the fact that `'a <= 'b` is implied by the fn signature, // record the fact that `'a <= 'b` is implied by the fn signature,
// and then ignore the constraint when solving equations. This is // and then ignore the constraint when solving equations. This is
// a bit of a hack but seems to work. // a bit of a hack but seems to work.
givens: RefCell<FxHashSet<(ty::FreeRegion<'tcx>, ty::RegionVid)>>, givens: RefCell<FxHashSet<(Region<'tcx>, ty::RegionVid)>>,
lubs: RefCell<CombineMap<'tcx>>, lubs: RefCell<CombineMap<'tcx>>,
glbs: RefCell<CombineMap<'tcx>>, glbs: RefCell<CombineMap<'tcx>>,
@ -309,8 +308,7 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
self.add_edge(a, b); self.add_edge(a, b);
} }
&AddGiven(a, b) => { &AddGiven(a, b) => {
self.add_edge(tcx.mk_region(ReFree(a)), self.add_edge(a, tcx.mk_region(ReVar(b)));
tcx.mk_region(ReVar(b)));
} }
&AddVerify(i) => { &AddVerify(i) => {
verifys[i].bound.for_each_region(&mut |b| { verifys[i].bound.for_each_region(&mut |b| {
@ -661,7 +659,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
} }
} }
pub fn add_given(&self, sub: ty::FreeRegion<'tcx>, sup: ty::RegionVid) { pub fn add_given(&self, sub: Region<'tcx>, sup: ty::RegionVid) {
// cannot add givens once regions are resolved // cannot add givens once regions are resolved
assert!(self.values_are_none()); assert!(self.values_are_none());
@ -702,9 +700,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
origin); origin);
match (sub, sup) { match (sub, sup) {
(&ReEarlyBound(..), _) |
(&ReLateBound(..), _) | (&ReLateBound(..), _) |
(_, &ReEarlyBound(..)) |
(_, &ReLateBound(..)) => { (_, &ReLateBound(..)) => {
span_bug!(origin.span(), span_bug!(origin.span(),
"cannot relate bound region: {:?} <= {:?}", "cannot relate bound region: {:?} <= {:?}",
@ -908,8 +904,6 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
match (a, b) { match (a, b) {
(&ReLateBound(..), _) | (&ReLateBound(..), _) |
(_, &ReLateBound(..)) | (_, &ReLateBound(..)) |
(&ReEarlyBound(..), _) |
(_, &ReEarlyBound(..)) |
(&ReErased, _) | (&ReErased, _) |
(_, &ReErased) => { (_, &ReErased) => {
bug!("cannot relate region: LUB({:?}, {:?})", a, b); bug!("cannot relate region: LUB({:?}, {:?})", a, b);
@ -931,18 +925,31 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
b); b);
} }
(&ReFree(fr), &ReScope(s_id)) | (&ReEarlyBound(_), &ReScope(s_id)) |
(&ReScope(s_id), &ReFree(fr)) => { (&ReScope(s_id), &ReEarlyBound(_)) |
(&ReFree(_), &ReScope(s_id)) |
(&ReScope(s_id), &ReFree(_)) => {
// A "free" region can be interpreted as "some region // A "free" region can be interpreted as "some region
// at least as big as the block fr.scope_id". So, we can // at least as big as fr.scope". So, we can
// reasonably compare free regions and scopes: // reasonably compare free regions and scopes:
if let Some(fr_scope) = fr.scope { let fr_scope = match (a, b) {
(&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => {
region_rels.region_maps.early_free_extent(self.tcx, br)
}
(&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => {
region_rels.region_maps.free_extent(self.tcx, fr)
}
_ => bug!()
};
let r_id = region_rels.region_maps.nearest_common_ancestor(fr_scope, s_id); let r_id = region_rels.region_maps.nearest_common_ancestor(fr_scope, s_id);
if r_id == fr_scope { if r_id == fr_scope {
// if the free region's scope `fr.scope_id` is bigger than // if the free region's scope `fr.scope` is bigger than
// the scope region `s_id`, then the LUB is the free // the scope region `s_id`, then the LUB is the free
// region itself: // region itself:
return self.tcx.mk_region(ReFree(fr)); match (a, b) {
(_, &ReScope(_)) => return a,
(&ReScope(_), _) => return b,
_ => bug!()
} }
} }
@ -959,6 +966,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
self.tcx.mk_region(ReScope(lub)) self.tcx.mk_region(ReScope(lub))
} }
(&ReEarlyBound(_), &ReEarlyBound(_)) |
(&ReFree(_), &ReEarlyBound(_)) |
(&ReEarlyBound(_), &ReFree(_)) |
(&ReFree(_), &ReFree(_)) => { (&ReFree(_), &ReFree(_)) => {
region_rels.lub_free_regions(a, b) region_rels.lub_free_regions(a, b)
} }
@ -1041,13 +1051,13 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
let mut givens = self.givens.borrow_mut(); let mut givens = self.givens.borrow_mut();
let seeds: Vec<_> = givens.iter().cloned().collect(); let seeds: Vec<_> = givens.iter().cloned().collect();
for (fr, vid) in seeds { for (r, vid) in seeds {
let seed_index = NodeIndex(vid.index as usize); let seed_index = NodeIndex(vid.index as usize);
for succ_index in graph.depth_traverse(seed_index, OUTGOING) { for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
let succ_index = succ_index.0 as u32; let succ_index = succ_index.0 as u32;
if succ_index < self.num_vars() { if succ_index < self.num_vars() {
let succ_vid = RegionVid { index: succ_index }; let succ_vid = RegionVid { index: succ_index };
givens.insert((fr, succ_vid)); givens.insert((r, succ_vid));
} }
} }
} }
@ -1096,8 +1106,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
// Check if this relationship is implied by a given. // Check if this relationship is implied by a given.
match *a_region { match *a_region {
ty::ReFree(fr) => { ty::ReEarlyBound(_) |
if self.givens.borrow().contains(&(fr, b_vid)) { ty::ReFree(_) => {
if self.givens.borrow().contains(&(a_region, b_vid)) {
debug!("given"); debug!("given");
return false; return false;
} }
@ -1333,16 +1344,15 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
// We place free regions first because we are special casing // We place free regions first because we are special casing
// SubSupConflict(ReFree, ReFree) when reporting error, and so // SubSupConflict(ReFree, ReFree) when reporting error, and so
// the user will more likely get a specific suggestion. // the user will more likely get a specific suggestion.
fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering { fn region_order_key(x: &RegionAndOrigin) -> u8 {
match (a.region, b.region) { match *x.region {
(&ReFree(..), &ReFree(..)) => Equal, ReEarlyBound(_) => 0,
(&ReFree(..), _) => Less, ReFree(_) => 1,
(_, &ReFree(..)) => Greater, _ => 2
(..) => Equal,
} }
} }
lower_bounds.sort_by(|a, b| free_regions_first(a, b)); lower_bounds.sort_by_key(region_order_key);
upper_bounds.sort_by(|a, b| free_regions_first(a, b)); upper_bounds.sort_by_key(region_order_key);
for lower_bound in &lower_bounds { for lower_bound in &lower_bounds {
for upper_bound in &upper_bounds { for upper_bound in &upper_bounds {

View file

@ -271,7 +271,7 @@ enum PassArgs {
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
region_maps: &'a RegionMaps<'tcx>, region_maps: &'a RegionMaps,
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
-> Self -> Self
{ {
@ -283,7 +283,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a), pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
region_maps: &'a RegionMaps<'tcx>, region_maps: &'a RegionMaps,
options: mc::MemCategorizationOptions) options: mc::MemCategorizationOptions)
-> Self -> Self
{ {

View file

@ -35,7 +35,7 @@ pub struct RegionRelations<'a, 'gcx: 'tcx, 'tcx: 'a> {
pub context: DefId, pub context: DefId,
/// region maps for the given context /// region maps for the given context
pub region_maps: &'a RegionMaps<'tcx>, pub region_maps: &'a RegionMaps,
/// free-region relationships /// free-region relationships
pub free_regions: &'a FreeRegionMap<'tcx>, pub free_regions: &'a FreeRegionMap<'tcx>,
@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
pub fn new( pub fn new(
tcx: TyCtxt<'a, 'gcx, 'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>,
context: DefId, context: DefId,
region_maps: &'a RegionMaps<'tcx>, region_maps: &'a RegionMaps,
free_regions: &'a FreeRegionMap<'tcx>, free_regions: &'a FreeRegionMap<'tcx>,
) -> Self { ) -> Self {
Self { Self {
@ -71,26 +71,27 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
(&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) => (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
self.region_maps.is_subscope_of(sub_scope, super_scope), self.region_maps.is_subscope_of(sub_scope, super_scope),
(&ty::ReScope(sub_scope), &ty::ReFree(fr)) => { (&ty::ReScope(sub_scope), &ty::ReEarlyBound(ref br)) => {
// 1. It is safe to unwrap `fr.scope` because we let fr_scope = self.region_maps.early_free_extent(self.tcx, br);
// should only ever wind up comparing against self.region_maps.is_subscope_of(sub_scope, fr_scope)
// `ReScope` in the context of a method or
// body, where `fr.scope` should be `Some`.
self.region_maps.is_subscope_of(sub_scope, fr.scope.unwrap() /*1*/) ||
self.is_static(super_region)
} }
(&ty::ReFree(_), &ty::ReFree(_)) => (&ty::ReScope(sub_scope), &ty::ReFree(ref fr)) => {
self.free_regions.relation.contains(&sub_region, &super_region) || let fr_scope = self.region_maps.free_extent(self.tcx, fr);
self.is_static(super_region), self.region_maps.is_subscope_of(sub_scope, fr_scope)
}
(&ty::ReStatic, &ty::ReFree(_)) => (&ty::ReEarlyBound(_), &ty::ReEarlyBound(_)) |
self.is_static(super_region), (&ty::ReFree(_), &ty::ReEarlyBound(_)) |
(&ty::ReEarlyBound(_), &ty::ReFree(_)) |
(&ty::ReFree(_), &ty::ReFree(_)) =>
self.free_regions.relation.contains(&sub_region, &super_region),
_ => _ =>
false, false,
} }
}; };
let result = result || self.is_static(super_region);
debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}", debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
sub_region, super_region, result); sub_region, super_region, result);
result result
@ -101,11 +102,11 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
debug!("is_static(super_region={:?})", super_region); debug!("is_static(super_region={:?})", super_region);
match *super_region { match *super_region {
ty::ReStatic => true, ty::ReStatic => true,
ty::ReFree(_) => { ty::ReEarlyBound(_) | ty::ReFree(_) => {
let re_static = self.tcx.mk_region(ty::ReStatic); let re_static = self.tcx.mk_region(ty::ReStatic);
self.free_regions.relation.contains(&re_static, &super_region) self.free_regions.relation.contains(&re_static, &super_region)
} }
_ => bug!("only free regions should be given to `is_static`") _ => false
} }
} }
@ -142,11 +143,9 @@ impl<'tcx> FreeRegionMap<'tcx> {
for implied_bound in implied_bounds { for implied_bound in implied_bounds {
debug!("implied bound: {:?}", implied_bound); debug!("implied bound: {:?}", implied_bound);
match *implied_bound { match *implied_bound {
ImpliedBound::RegionSubRegion(a @ &ty::ReFree(_), b @ &ty::ReFree(_)) | ImpliedBound::RegionSubRegion(a, b) => {
ImpliedBound::RegionSubRegion(a @ &ty::ReStatic, b @ &ty::ReFree(_)) => {
self.relate_regions(a, b); self.relate_regions(a, b);
} }
ImpliedBound::RegionSubRegion(..) |
ImpliedBound::RegionSubParam(..) | ImpliedBound::RegionSubParam(..) |
ImpliedBound::RegionSubProjection(..) => { ImpliedBound::RegionSubProjection(..) => {
} }
@ -170,41 +169,27 @@ impl<'tcx> FreeRegionMap<'tcx> {
// No region bounds here // No region bounds here
} }
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
match (r_a, r_b) {
// `'static: 'x` is not notable
(&ty::ReStatic, &ty::ReFree(_)) => {},
(&ty::ReFree(_), &ty::ReStatic) |
(&ty::ReFree(_), &ty::ReFree(_)) => {
// Record that `'a:'b`. Or, put another way, `'b <= 'a`.
self.relate_regions(r_b, r_a); self.relate_regions(r_b, r_a);
} }
_ => {
// All named regions are instantiated with free regions.
bug!("record_region_bounds: non free region: {:?} / {:?}",
r_a,
r_b);
}
}
}
} }
} }
} }
// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
// (with the exception that `'static: 'x` is not notable)
fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
assert!(match *sub { ty::ReFree(_) | ty::ReStatic => true, _ => false }); if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) {
assert!(match *sup { ty::ReFree(_) | ty::ReStatic => true, _ => false });
self.relation.add(sub, sup) self.relation.add(sub, sup)
} }
}
pub fn lub_free_regions<'a, 'gcx>(&self, pub fn lub_free_regions<'a, 'gcx>(&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>,
r_a: Region<'tcx>, r_a: Region<'tcx>,
r_b: Region<'tcx>) r_b: Region<'tcx>)
-> Region<'tcx> { -> Region<'tcx> {
assert!(match *r_a { ty::ReFree(_) => true, _ => false }); assert!(is_free(r_a));
assert!(match *r_b { ty::ReFree(_) => true, _ => false }); assert!(is_free(r_b));
let result = if r_a == r_b { r_a } else { let result = if r_a == r_b { r_a } else {
match self.relation.postdom_upper_bound(&r_a, &r_b) { match self.relation.postdom_upper_bound(&r_a, &r_b) {
None => tcx.mk_region(ty::ReStatic), None => tcx.mk_region(ty::ReStatic),
@ -216,6 +201,13 @@ impl<'tcx> FreeRegionMap<'tcx> {
} }
} }
fn is_free(r: Region) -> bool {
match *r {
ty::ReEarlyBound(_) | ty::ReFree(_) => true,
_ => false
}
}
impl_stable_hash_for!(struct FreeRegionMap<'tcx> { impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
relation relation
}); });

View file

@ -96,9 +96,6 @@
//! //!
//! - `fallthrough_ln`: a live node that represents a fallthrough //! - `fallthrough_ln`: a live node that represents a fallthrough
//! //!
//! - `no_ret_var`: a synthetic variable that is only 'read' from, the
//! fallthrough node. This allows us to detect functions where we fail
//! to return explicitly.
//! - `clean_exit_var`: a synthetic variable that is only 'read' from the //! - `clean_exit_var`: a synthetic variable that is only 'read' from the
//! fallthrough node. It is only live if the function could converge //! fallthrough node. It is only live if the function could converge
//! via means other than an explicit `return` expression. That is, it is //! via means other than an explicit `return` expression. That is, it is
@ -110,9 +107,7 @@ use self::LiveNodeKind::*;
use self::VarKind::*; use self::VarKind::*;
use hir::def::*; use hir::def::*;
use ty::{self, TyCtxt, ParameterEnvironment}; use ty::{self, TyCtxt};
use traits::{self, Reveal};
use ty::subst::Subst;
use lint; use lint;
use util::nodemap::NodeMap; use util::nodemap::NodeMap;
@ -256,7 +251,6 @@ struct LocalInfo {
enum VarKind { enum VarKind {
Arg(NodeId, ast::Name), Arg(NodeId, ast::Name),
Local(LocalInfo), Local(LocalInfo),
ImplicitRet,
CleanExit CleanExit
} }
@ -313,7 +307,7 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => { Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => {
self.variable_map.insert(node_id, v); self.variable_map.insert(node_id, v);
}, },
ImplicitRet | CleanExit => {} CleanExit => {}
} }
debug!("{:?} is {:?}", v, vk); debug!("{:?} is {:?}", v, vk);
@ -335,7 +329,6 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
Local(LocalInfo { name, .. }) | Arg(_, name) => { Local(LocalInfo { name, .. }) | Arg(_, name) => {
name.to_string() name.to_string()
}, },
ImplicitRet => "<implicit-ret>".to_string(),
CleanExit => "<clean-exit>".to_string() CleanExit => "<clean-exit>".to_string()
} }
} }
@ -382,7 +375,6 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
// check for various error conditions // check for various error conditions
lsets.visit_body(body); lsets.visit_body(body);
lsets.check_ret(id, sp, entry_ln, body);
lsets.warn_about_unused_args(body, entry_ln); lsets.warn_about_unused_args(body, entry_ln);
} }
@ -500,7 +492,6 @@ fn invalid_users() -> Users {
struct Specials { struct Specials {
exit_ln: LiveNode, exit_ln: LiveNode,
fallthrough_ln: LiveNode, fallthrough_ln: LiveNode,
no_ret_var: Variable,
clean_exit_var: Variable clean_exit_var: Variable
} }
@ -534,7 +525,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
let specials = Specials { let specials = Specials {
exit_ln: ir.add_live_node(ExitNode), exit_ln: ir.add_live_node(ExitNode),
fallthrough_ln: ir.add_live_node(ExitNode), fallthrough_ln: ir.add_live_node(ExitNode),
no_ret_var: ir.add_variable(ImplicitRet),
clean_exit_var: ir.add_variable(CleanExit) clean_exit_var: ir.add_variable(CleanExit)
}; };
@ -1420,45 +1410,6 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
} }
impl<'a, 'tcx> Liveness<'a, 'tcx> { impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn check_ret(&self,
id: NodeId,
sp: Span,
entry_ln: LiveNode,
body: &hir::Body)
{
let fn_ty = self.ir.tcx.type_of(self.ir.tcx.hir.local_def_id(id));
let fn_sig = match fn_ty.sty {
ty::TyClosure(closure_def_id, substs) => {
self.ir.tcx.closure_type(closure_def_id)
.subst(self.ir.tcx, substs.substs)
}
_ => fn_ty.fn_sig()
};
let fn_ret = fn_sig.output();
// within the fn body, late-bound regions are liberated
// and must outlive the *call-site* of the function.
let fn_ret =
self.ir.tcx.liberate_late_bound_regions(
Some(self.ir.tcx.call_site_extent(id, body.value.id)),
&fn_ret);
if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
let is_nil = self.ir.tcx.infer_ctxt(param_env, Reveal::All).enter(|infcx| {
let cause = traits::ObligationCause::dummy();
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
});
// for nil return types, it is ok to not return a value expl.
if !is_nil {
span_bug!(sp, "not all control paths return a value");
}
}
}
fn check_lvalue(&mut self, expr: &'tcx Expr) { fn check_lvalue(&mut self, expr: &'tcx Expr) {
match expr.node { match expr.node {
hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {

View file

@ -290,7 +290,7 @@ impl ast_node for hir::Pat {
#[derive(Clone)] #[derive(Clone)]
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
pub region_maps: &'a RegionMaps<'tcx>, pub region_maps: &'a RegionMaps,
options: MemCategorizationOptions, options: MemCategorizationOptions,
} }
@ -406,7 +406,7 @@ impl MutabilityCategory {
impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
/// Context should be the `DefId` we use to fetch region-maps. /// Context should be the `DefId` we use to fetch region-maps.
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
region_maps: &'a RegionMaps<'tcx>) region_maps: &'a RegionMaps)
-> MemCategorizationContext<'a, 'gcx, 'tcx> { -> MemCategorizationContext<'a, 'gcx, 'tcx> {
MemCategorizationContext::with_options(infcx, MemCategorizationContext::with_options(infcx,
region_maps, region_maps,
@ -414,7 +414,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
} }
pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
region_maps: &'a RegionMaps<'tcx>, region_maps: &'a RegionMaps,
options: MemCategorizationOptions) options: MemCategorizationOptions)
-> MemCategorizationContext<'a, 'gcx, 'tcx> { -> MemCategorizationContext<'a, 'gcx, 'tcx> {
MemCategorizationContext { MemCategorizationContext {
@ -785,26 +785,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
cmt_result: cmt_<'tcx>) cmt_result: cmt_<'tcx>)
-> cmt_<'tcx> -> cmt_<'tcx>
{ {
// Look up the node ID of the closure body so we can construct
// a free region within it
let fn_body_id = {
let fn_expr = match self.tcx().hir.find(upvar_id.closure_expr_id) {
Some(hir_map::NodeExpr(e)) => e,
_ => bug!()
};
match fn_expr.node {
hir::ExprClosure(.., body_id, _) => body_id,
_ => bug!()
}
};
// Region of environment pointer // Region of environment pointer
let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion { let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion {
// The environment of a closure is guaranteed to // The environment of a closure is guaranteed to
// outlive any bindings introduced in the body of the // outlive any bindings introduced in the body of the
// closure itself. // closure itself.
scope: Some(self.tcx().item_extent(fn_body_id.node_id)), scope: self.tcx().hir.local_def_id(upvar_id.closure_expr_id),
bound_region: ty::BrEnv bound_region: ty::BrEnv
})); }));
@ -853,7 +839,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
pub fn temporary_scope(&self, id: ast::NodeId) -> (ty::Region<'tcx>, ty::Region<'tcx>) pub fn temporary_scope(&self, id: ast::NodeId) -> (ty::Region<'tcx>, ty::Region<'tcx>)
{ {
let (scope, old_scope) = let (scope, old_scope) =
self.region_maps.old_and_new_temporary_scope(self.tcx(), id); self.region_maps.old_and_new_temporary_scope(id);
(self.tcx().mk_region(match scope { (self.tcx().mk_region(match scope {
Some(scope) => ty::ReScope(scope), Some(scope) => ty::ReScope(scope),
None => ty::ReStatic None => ty::ReStatic

View file

@ -22,7 +22,6 @@ use ty;
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
use serialize;
use syntax::codemap; use syntax::codemap;
use syntax::ast; use syntax::ast;
use syntax_pos::Span; use syntax_pos::Span;
@ -35,11 +34,6 @@ use hir::intravisit::{self, Visitor, NestedVisitorMap};
use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local}; use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local};
use mir::transform::MirSource; use mir::transform::MirSource;
pub type CodeExtent<'tcx> = &'tcx CodeExtentData;
impl<'tcx> serialize::UseSpecializedEncodable for CodeExtent<'tcx> {}
impl<'tcx> serialize::UseSpecializedDecodable for CodeExtent<'tcx> {}
/// CodeExtent represents a statically-describable extent that can be /// CodeExtent represents a statically-describable extent that can be
/// used to bound the lifetime/region for values. /// used to bound the lifetime/region for values.
/// ///
@ -102,16 +96,16 @@ impl<'tcx> serialize::UseSpecializedDecodable for CodeExtent<'tcx> {}
/// actually attach a more meaningful ordering to scopes than the one /// actually attach a more meaningful ordering to scopes than the one
/// generated via deriving here. /// generated via deriving here.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)] #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)]
pub enum CodeExtentData { pub enum CodeExtent {
Misc(ast::NodeId), Misc(ast::NodeId),
// extent of the call-site for a function or closure (outlives // extent of the call-site for a function or closure (outlives
// the parameters as well as the body). // the parameters as well as the body).
CallSiteScope { fn_id: ast::NodeId, body_id: ast::NodeId }, CallSiteScope(hir::BodyId),
// extent of parameters passed to a function or closure (they // extent of parameters passed to a function or closure (they
// outlive its body) // outlive its body)
ParameterScope { fn_id: ast::NodeId, body_id: ast::NodeId }, ParameterScope(hir::BodyId),
// extent of destructors for temporaries of node-id // extent of destructors for temporaries of node-id
DestructionScope(ast::NodeId), DestructionScope(ast::NodeId),
@ -120,23 +114,6 @@ pub enum CodeExtentData {
Remainder(BlockRemainder) Remainder(BlockRemainder)
} }
/// extent of call-site for a function/method.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
RustcDecodable, Debug, Copy)]
pub struct CallSiteScopeData {
pub fn_id: ast::NodeId, pub body_id: ast::NodeId,
}
impl CallSiteScopeData {
pub fn to_code_extent<'a, 'tcx, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> CodeExtent<'tcx> {
tcx.intern_code_extent(
match *self {
CallSiteScopeData { fn_id, body_id } =>
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id },
})
}
}
/// Represents a subscope of `block` for a binding that is introduced /// Represents a subscope of `block` for a binding that is introduced
/// by `block.stmts[first_statement_index]`. Such subscopes represent /// by `block.stmts[first_statement_index]`. Such subscopes represent
/// a suffix of the block. Note that each subscope does not include /// a suffix of the block. Note that each subscope does not include
@ -148,9 +125,9 @@ impl CallSiteScopeData {
/// * the subscope with `first_statement_index == 0` is scope of both /// * the subscope with `first_statement_index == 0` is scope of both
/// `a` and `b`; it does not include EXPR_1, but does include /// `a` and `b`; it does not include EXPR_1, but does include
/// everything after that first `let`. (If you want a scope that /// everything after that first `let`. (If you want a scope that
/// includes EXPR_1 as well, then do not use `CodeExtentData::Remainder`, /// includes EXPR_1 as well, then do not use `CodeExtent::Remainder`,
/// but instead another `CodeExtent` that encompasses the whole block, /// but instead another `CodeExtent` that encompasses the whole block,
/// e.g. `CodeExtentData::Misc`. /// e.g. `CodeExtent::Misc`.
/// ///
/// * the subscope with `first_statement_index == 1` is scope of `c`, /// * the subscope with `first_statement_index == 1` is scope of `c`,
/// and thus does not include EXPR_2, but covers the `...`. /// and thus does not include EXPR_2, but covers the `...`.
@ -161,21 +138,21 @@ pub struct BlockRemainder {
pub first_statement_index: u32, pub first_statement_index: u32,
} }
impl CodeExtentData { impl CodeExtent {
/// Returns a node id associated with this scope. /// Returns a node id associated with this scope.
/// ///
/// NB: likely to be replaced as API is refined; e.g. pnkfelix /// NB: likely to be replaced as API is refined; e.g. pnkfelix
/// anticipates `fn entry_node_id` and `fn each_exit_node_id`. /// anticipates `fn entry_node_id` and `fn each_exit_node_id`.
pub fn node_id(&self) -> ast::NodeId { pub fn node_id(&self) -> ast::NodeId {
match *self { match *self {
CodeExtentData::Misc(node_id) => node_id, CodeExtent::Misc(node_id) => node_id,
// These cases all return rough approximations to the // These cases all return rough approximations to the
// precise extent denoted by `self`. // precise extent denoted by `self`.
CodeExtentData::Remainder(br) => br.block, CodeExtent::Remainder(br) => br.block,
CodeExtentData::DestructionScope(node_id) => node_id, CodeExtent::DestructionScope(node_id) => node_id,
CodeExtentData::CallSiteScope { fn_id: _, body_id } | CodeExtent::CallSiteScope(body_id) |
CodeExtentData::ParameterScope { fn_id: _, body_id } => body_id, CodeExtent::ParameterScope(body_id) => body_id.node_id,
} }
} }
@ -186,12 +163,12 @@ impl CodeExtentData {
match hir_map.find(self.node_id()) { match hir_map.find(self.node_id()) {
Some(hir_map::NodeBlock(ref blk)) => { Some(hir_map::NodeBlock(ref blk)) => {
match *self { match *self {
CodeExtentData::CallSiteScope { .. } | CodeExtent::CallSiteScope(_) |
CodeExtentData::ParameterScope { .. } | CodeExtent::ParameterScope(_) |
CodeExtentData::Misc(_) | CodeExtent::Misc(_) |
CodeExtentData::DestructionScope(_) => Some(blk.span), CodeExtent::DestructionScope(_) => Some(blk.span),
CodeExtentData::Remainder(r) => { CodeExtent::Remainder(r) => {
assert_eq!(r.block, blk.id); assert_eq!(r.block, blk.id);
// Want span for extent starting after the // Want span for extent starting after the
// indexed statement and ending at end of // indexed statement and ending at end of
@ -214,21 +191,29 @@ impl CodeExtentData {
} }
/// The region maps encode information about region relationships. /// The region maps encode information about region relationships.
pub struct RegionMaps<'tcx> { pub struct RegionMaps {
/// If not empty, this body is the root of this region hierarchy.
root_body: Option<hir::BodyId>,
/// The parent of the root body owner, if the latter is an
/// an associated const or method, as impls/traits can also
/// have lifetime parameters free in this body.
root_parent: Option<ast::NodeId>,
/// `scope_map` maps from a scope id to the enclosing scope id; /// `scope_map` maps from a scope id to the enclosing scope id;
/// this is usually corresponding to the lexical nesting, though /// this is usually corresponding to the lexical nesting, though
/// in the case of closures the parent scope is the innermost /// in the case of closures the parent scope is the innermost
/// conditional expression or repeating block. (Note that the /// conditional expression or repeating block. (Note that the
/// enclosing scope id for the block associated with a closure is /// enclosing scope id for the block associated with a closure is
/// the closure itself.) /// the closure itself.)
scope_map: FxHashMap<CodeExtent<'tcx>, CodeExtent<'tcx>>, scope_map: FxHashMap<CodeExtent, CodeExtent>,
/// `var_map` maps from a variable or binding id to the block in /// `var_map` maps from a variable or binding id to the block in
/// which that variable is declared. /// which that variable is declared.
var_map: NodeMap<CodeExtent<'tcx>>, var_map: NodeMap<CodeExtent>,
/// maps from a node-id to the associated destruction scope (if any) /// maps from a node-id to the associated destruction scope (if any)
destruction_scopes: NodeMap<CodeExtent<'tcx>>, destruction_scopes: NodeMap<CodeExtent>,
/// `rvalue_scopes` includes entries for those expressions whose cleanup scope is /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
/// larger than the default. The map goes from the expression id /// larger than the default. The map goes from the expression id
@ -236,14 +221,14 @@ pub struct RegionMaps<'tcx> {
/// table, the appropriate cleanup scope is the innermost /// table, the appropriate cleanup scope is the innermost
/// enclosing statement, conditional expression, or repeating /// enclosing statement, conditional expression, or repeating
/// block (see `terminating_scopes`). /// block (see `terminating_scopes`).
rvalue_scopes: NodeMap<CodeExtent<'tcx>>, rvalue_scopes: NodeMap<CodeExtent>,
/// Records the value of rvalue scopes before they were shrunk by /// Records the value of rvalue scopes before they were shrunk by
/// #36082, for error reporting. /// #36082, for error reporting.
/// ///
/// FIXME: this should be temporary. Remove this by 1.18.0 or /// FIXME: this should be temporary. Remove this by 1.18.0 or
/// so. /// so.
shrunk_rvalue_scopes: NodeMap<CodeExtent<'tcx>>, shrunk_rvalue_scopes: NodeMap<CodeExtent>,
/// Encodes the hierarchy of fn bodies. Every fn body (including /// Encodes the hierarchy of fn bodies. Every fn body (including
/// closures) forms its own distinct region hierarchy, rooted in /// closures) forms its own distinct region hierarchy, rooted in
@ -259,7 +244,7 @@ pub struct RegionMaps<'tcx> {
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Context<'tcx> { pub struct Context {
/// the root of the current region tree. This is typically the id /// the root of the current region tree. This is typically the id
/// of the innermost fn body. Each fn forms its own disjoint tree /// of the innermost fn body. Each fn forms its own disjoint tree
/// in the region hierarchy. These fn bodies are themselves /// in the region hierarchy. These fn bodies are themselves
@ -269,21 +254,19 @@ pub struct Context<'tcx> {
root_id: Option<ast::NodeId>, root_id: Option<ast::NodeId>,
/// the scope that contains any new variables declared /// the scope that contains any new variables declared
var_parent: Option<CodeExtent<'tcx>>, var_parent: Option<CodeExtent>,
/// region parent of expressions etc /// region parent of expressions etc
parent: Option<CodeExtent<'tcx>>, parent: Option<CodeExtent>,
} }
struct RegionResolutionVisitor<'a, 'tcx: 'a> { struct RegionResolutionVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Generated maps: // Generated maps:
region_maps: &'a mut RegionMaps<'tcx>, region_maps: RegionMaps,
cx: Context<'tcx>, cx: Context,
map: &'a hir_map::Map<'tcx>,
/// `terminating_scopes` is a set containing the ids of each /// `terminating_scopes` is a set containing the ids of each
/// statement, or conditional/repeating expression. These scopes /// statement, or conditional/repeating expression. These scopes
@ -309,9 +292,11 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
} }
impl<'tcx> RegionMaps<'tcx> { impl<'tcx> RegionMaps {
pub fn new() -> Self { pub fn new() -> Self {
RegionMaps { RegionMaps {
root_body: None,
root_parent: None,
scope_map: FxHashMap(), scope_map: FxHashMap(),
destruction_scopes: FxHashMap(), destruction_scopes: FxHashMap(),
var_map: NodeMap(), var_map: NodeMap(),
@ -322,8 +307,8 @@ impl<'tcx> RegionMaps<'tcx> {
} }
pub fn record_code_extent(&mut self, pub fn record_code_extent(&mut self,
child: CodeExtent<'tcx>, child: CodeExtent,
parent: Option<CodeExtent<'tcx>>) { parent: Option<CodeExtent>) {
debug!("{:?}.parent = {:?}", child, parent); debug!("{:?}.parent = {:?}", child, parent);
if let Some(p) = parent { if let Some(p) = parent {
@ -332,24 +317,24 @@ impl<'tcx> RegionMaps<'tcx> {
} }
// record the destruction scopes for later so we can query them // record the destruction scopes for later so we can query them
if let &CodeExtentData::DestructionScope(n) = child { if let CodeExtent::DestructionScope(n) = child {
self.destruction_scopes.insert(n, child); self.destruction_scopes.insert(n, child);
} }
} }
pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(CodeExtent<'tcx>, CodeExtent<'tcx>) { pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(CodeExtent, CodeExtent) {
for (&child, &parent) in &self.scope_map { for (&child, &parent) in &self.scope_map {
e(child, parent) e(child, parent)
} }
} }
pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, CodeExtent<'tcx>) { pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, CodeExtent) {
for (child, parent) in self.var_map.iter() { for (child, &parent) in self.var_map.iter() {
e(child, parent) e(child, parent)
} }
} }
pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent<'tcx>> { pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent> {
self.destruction_scopes.get(&n).cloned() self.destruction_scopes.get(&n).cloned()
} }
@ -373,48 +358,46 @@ impl<'tcx> RegionMaps<'tcx> {
} }
} }
fn record_var_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) { fn record_var_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime); debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
assert!(var != lifetime.node_id()); assert!(var != lifetime.node_id());
self.var_map.insert(var, lifetime); self.var_map.insert(var, lifetime);
} }
fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) { fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime); debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
assert!(var != lifetime.node_id()); assert!(var != lifetime.node_id());
self.rvalue_scopes.insert(var, lifetime); self.rvalue_scopes.insert(var, lifetime);
} }
fn record_shrunk_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) { fn record_shrunk_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime); debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
assert!(var != lifetime.node_id()); assert!(var != lifetime.node_id());
self.shrunk_rvalue_scopes.insert(var, lifetime); self.shrunk_rvalue_scopes.insert(var, lifetime);
} }
pub fn opt_encl_scope(&self, id: CodeExtent<'tcx>) -> Option<CodeExtent<'tcx>> { pub fn opt_encl_scope(&self, id: CodeExtent) -> Option<CodeExtent> {
//! Returns the narrowest scope that encloses `id`, if any. //! Returns the narrowest scope that encloses `id`, if any.
self.scope_map.get(&id).cloned() self.scope_map.get(&id).cloned()
} }
#[allow(dead_code)] // used in cfg #[allow(dead_code)] // used in cfg
pub fn encl_scope(&self, id: CodeExtent<'tcx>) -> CodeExtent<'tcx> { pub fn encl_scope(&self, id: CodeExtent) -> CodeExtent {
//! Returns the narrowest scope that encloses `id`, if any. //! Returns the narrowest scope that encloses `id`, if any.
self.opt_encl_scope(id).unwrap() self.opt_encl_scope(id).unwrap()
} }
/// Returns the lifetime of the local variable `var_id` /// Returns the lifetime of the local variable `var_id`
pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent<'tcx> { pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent {
match self.var_map.get(&var_id) { match self.var_map.get(&var_id) {
Some(&r) => r, Some(&r) => r,
None => { bug!("no enclosing scope for id {:?}", var_id); } None => { bug!("no enclosing scope for id {:?}", var_id); }
} }
} }
pub fn temporary_scope2<'a, 'gcx: 'tcx>(&self, pub fn temporary_scope2(&self, expr_id: ast::NodeId)
tcx: TyCtxt<'a, 'gcx, 'tcx>, -> (Option<CodeExtent>, bool) {
expr_id: ast::NodeId) let temporary_scope = self.temporary_scope(expr_id);
-> (Option<CodeExtent<'tcx>>, bool) {
let temporary_scope = self.temporary_scope(tcx, expr_id);
let was_shrunk = match self.shrunk_rvalue_scopes.get(&expr_id) { let was_shrunk = match self.shrunk_rvalue_scopes.get(&expr_id) {
Some(&s) => { Some(&s) => {
info!("temporary_scope2({:?}, scope={:?}, shrunk={:?})", info!("temporary_scope2({:?}, scope={:?}, shrunk={:?})",
@ -427,23 +410,18 @@ impl<'tcx> RegionMaps<'tcx> {
(temporary_scope, was_shrunk) (temporary_scope, was_shrunk)
} }
pub fn old_and_new_temporary_scope<'a, 'gcx: 'tcx>(&self, pub fn old_and_new_temporary_scope(&self, expr_id: ast::NodeId)
tcx: TyCtxt<'a, 'gcx, 'tcx>, -> (Option<CodeExtent>,
expr_id: ast::NodeId) Option<CodeExtent>)
-> (Option<CodeExtent<'tcx>>,
Option<CodeExtent<'tcx>>)
{ {
let temporary_scope = self.temporary_scope(tcx, expr_id); let temporary_scope = self.temporary_scope(expr_id);
(temporary_scope, (temporary_scope,
self.shrunk_rvalue_scopes self.shrunk_rvalue_scopes
.get(&expr_id).cloned() .get(&expr_id).cloned()
.or(temporary_scope)) .or(temporary_scope))
} }
pub fn temporary_scope<'a, 'gcx: 'tcx>(&self, pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<CodeExtent> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
expr_id: ast::NodeId)
-> Option<CodeExtent<'tcx>> {
//! Returns the scope when temp created by expr_id will be cleaned up //! Returns the scope when temp created by expr_id will be cleaned up
// check for a designated rvalue scope // check for a designated rvalue scope
@ -456,11 +434,11 @@ impl<'tcx> RegionMaps<'tcx> {
// if there's one. Static items, for instance, won't // if there's one. Static items, for instance, won't
// have an enclosing scope, hence no scope will be // have an enclosing scope, hence no scope will be
// returned. // returned.
let mut id = tcx.node_extent(expr_id); let mut id = CodeExtent::Misc(expr_id);
while let Some(&p) = self.scope_map.get(id) { while let Some(&p) = self.scope_map.get(&id) {
match *p { match p {
CodeExtentData::DestructionScope(..) => { CodeExtent::DestructionScope(..) => {
debug!("temporary_scope({:?}) = {:?} [enclosing]", debug!("temporary_scope({:?}) = {:?} [enclosing]",
expr_id, id); expr_id, id);
return Some(id); return Some(id);
@ -473,7 +451,7 @@ impl<'tcx> RegionMaps<'tcx> {
return None; return None;
} }
pub fn var_region(&self, id: ast::NodeId) -> ty::RegionKind<'tcx> { pub fn var_region(&self, id: ast::NodeId) -> ty::RegionKind {
//! Returns the lifetime of the variable `id`. //! Returns the lifetime of the variable `id`.
let scope = ty::ReScope(self.var_scope(id)); let scope = ty::ReScope(self.var_scope(id));
@ -515,9 +493,9 @@ impl<'tcx> RegionMaps<'tcx> {
/// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest /// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest
/// scope which is greater than or equal to both `scope_a` and `scope_b`. /// scope which is greater than or equal to both `scope_a` and `scope_b`.
pub fn nearest_common_ancestor(&self, pub fn nearest_common_ancestor(&self,
scope_a: CodeExtent<'tcx>, scope_a: CodeExtent,
scope_b: CodeExtent<'tcx>) scope_b: CodeExtent)
-> CodeExtent<'tcx> { -> CodeExtent {
if scope_a == scope_b { return scope_a; } if scope_a == scope_b { return scope_a; }
/// [1] The initial values for `a_buf` and `b_buf` are not used. /// [1] The initial values for `a_buf` and `b_buf` are not used.
@ -525,9 +503,9 @@ impl<'tcx> RegionMaps<'tcx> {
/// is re-initialized with new values (or else fallback to a /// is re-initialized with new values (or else fallback to a
/// heap-allocated vector). /// heap-allocated vector).
let mut a_buf: [CodeExtent; 32] = [scope_a /* [1] */; 32]; let mut a_buf: [CodeExtent; 32] = [scope_a /* [1] */; 32];
let mut a_vec: Vec<CodeExtent<'tcx>> = vec![]; let mut a_vec: Vec<CodeExtent> = vec![];
let mut b_buf: [CodeExtent; 32] = [scope_b /* [1] */; 32]; let mut b_buf: [CodeExtent; 32] = [scope_b /* [1] */; 32];
let mut b_vec: Vec<CodeExtent<'tcx>> = vec![]; let mut b_vec: Vec<CodeExtent> = vec![];
let scope_map = &self.scope_map; let scope_map = &self.scope_map;
let a_ancestors = ancestors_of(scope_map, scope_a, &mut a_buf, &mut a_vec); let a_ancestors = ancestors_of(scope_map, scope_a, &mut a_buf, &mut a_vec);
let b_ancestors = ancestors_of(scope_map, scope_b, &mut b_buf, &mut b_vec); let b_ancestors = ancestors_of(scope_map, scope_b, &mut b_buf, &mut b_vec);
@ -551,8 +529,8 @@ impl<'tcx> RegionMaps<'tcx> {
let a_root_scope = a_ancestors[a_index]; let a_root_scope = a_ancestors[a_index];
let b_root_scope = a_ancestors[a_index]; let b_root_scope = a_ancestors[a_index];
return match (a_root_scope, b_root_scope) { return match (a_root_scope, b_root_scope) {
(&CodeExtentData::DestructionScope(a_root_id), (CodeExtent::DestructionScope(a_root_id),
&CodeExtentData::DestructionScope(b_root_id)) => { CodeExtent::DestructionScope(b_root_id)) => {
if self.fn_is_enclosed_by(a_root_id, b_root_id) { if self.fn_is_enclosed_by(a_root_id, b_root_id) {
// `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a` // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
scope_b scope_b
@ -583,11 +561,11 @@ impl<'tcx> RegionMaps<'tcx> {
} }
} }
fn ancestors_of<'a, 'tcx>(scope_map: &FxHashMap<CodeExtent<'tcx>, CodeExtent<'tcx>>, fn ancestors_of<'a, 'tcx>(scope_map: &FxHashMap<CodeExtent, CodeExtent>,
scope: CodeExtent<'tcx>, scope: CodeExtent,
buf: &'a mut [CodeExtent<'tcx>; 32], buf: &'a mut [CodeExtent; 32],
vec: &'a mut Vec<CodeExtent<'tcx>>) vec: &'a mut Vec<CodeExtent>)
-> &'a [CodeExtent<'tcx>] { -> &'a [CodeExtent] {
// debug!("ancestors_of(scope={:?})", scope); // debug!("ancestors_of(scope={:?})", scope);
let mut scope = scope; let mut scope = scope;
@ -595,7 +573,7 @@ impl<'tcx> RegionMaps<'tcx> {
while i < 32 { while i < 32 {
buf[i] = scope; buf[i] = scope;
match scope_map.get(&scope) { match scope_map.get(&scope) {
Some(superscope) => scope = superscope, Some(&superscope) => scope = superscope,
_ => return &buf[..i+1] _ => return &buf[..i+1]
} }
i += 1; i += 1;
@ -606,12 +584,55 @@ impl<'tcx> RegionMaps<'tcx> {
loop { loop {
vec.push(scope); vec.push(scope);
match scope_map.get(&scope) { match scope_map.get(&scope) {
Some(superscope) => scope = superscope, Some(&superscope) => scope = superscope,
_ => return &*vec _ => return &*vec
} }
} }
} }
} }
/// Assuming that the provided region was defined within this `RegionMaps`,
/// returns the outermost `CodeExtent` that the region outlives.
pub fn early_free_extent<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
br: &ty::EarlyBoundRegion)
-> CodeExtent {
let param_owner = tcx.parent_def_id(br.def_id).unwrap();
let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
let body_id = tcx.hir.maybe_body_owned_by(param_owner_id).unwrap_or_else(|| {
// The lifetime was defined on node that doesn't own a body,
// which in practice can only mean a trait or an impl, that
// is the parent of a method, and that is enforced below.
assert_eq!(Some(param_owner_id), self.root_parent,
"free_extent: {:?} not recognized by the region maps for {:?}",
param_owner,
self.root_body.map(|body| tcx.hir.body_owner_def_id(body)));
// The trait/impl lifetime is in scope for the method's body.
self.root_body.unwrap()
});
CodeExtent::CallSiteScope(body_id)
}
/// Assuming that the provided region was defined within this `RegionMaps`,
/// returns the outermost `CodeExtent` that the region outlives.
pub fn free_extent<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, fr: &ty::FreeRegion)
-> CodeExtent {
let param_owner = match fr.bound_region {
ty::BoundRegion::BrNamed(def_id, _) => {
tcx.parent_def_id(def_id).unwrap()
}
_ => fr.scope
};
// Ensure that the named late-bound lifetimes were defined
// on the same function that they ended up being freed in.
assert_eq!(param_owner, fr.scope);
let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
CodeExtent::CallSiteScope(tcx.hir.body_owned_by(param_owner_id))
}
} }
/// Records the lifetime of a local variable as `cx.var_parent` /// Records the lifetime of a local variable as `cx.var_parent`
@ -633,7 +654,6 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
debug!("resolve_block(blk.id={:?})", blk.id); debug!("resolve_block(blk.id={:?})", blk.id);
let prev_cx = visitor.cx; let prev_cx = visitor.cx;
let block_extent = visitor.new_node_extent_with_dtor(blk.id);
// We treat the tail expression in the block (if any) somewhat // We treat the tail expression in the block (if any) somewhat
// differently from the statements. The issue has to do with // differently from the statements. The issue has to do with
@ -660,11 +680,8 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
// `other_argument()` has run and also the call to `quux(..)` // `other_argument()` has run and also the call to `quux(..)`
// itself has returned. // itself has returned.
visitor.cx = Context { visitor.enter_node_extent_with_dtor(blk.id);
root_id: prev_cx.root_id, visitor.cx.var_parent = visitor.cx.parent;
var_parent: Some(block_extent),
parent: Some(block_extent),
};
{ {
// This block should be kept approximately in sync with // This block should be kept approximately in sync with
@ -680,17 +697,13 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
// has the previous subscope in the block as a parent, // has the previous subscope in the block as a parent,
// except for the first such subscope, which has the // except for the first such subscope, which has the
// block itself as a parent. // block itself as a parent.
let stmt_extent = visitor.new_code_extent( visitor.enter_code_extent(
CodeExtentData::Remainder(BlockRemainder { CodeExtent::Remainder(BlockRemainder {
block: blk.id, block: blk.id,
first_statement_index: i as u32 first_statement_index: i as u32
}) })
); );
visitor.cx = Context { visitor.cx.var_parent = visitor.cx.parent;
root_id: prev_cx.root_id,
var_parent: Some(stmt_extent),
parent: Some(stmt_extent),
};
} }
visitor.visit_stmt(statement) visitor.visit_stmt(statement)
} }
@ -711,7 +724,7 @@ fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &
} }
fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) { fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) {
visitor.new_node_extent(pat.id); visitor.record_code_extent(CodeExtent::Misc(pat.id));
// If this is a binding then record the lifetime of that binding. // If this is a binding then record the lifetime of that binding.
if let PatKind::Binding(..) = pat.node { if let PatKind::Binding(..) = pat.node {
@ -731,20 +744,20 @@ fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt:
// statement plus its destructors, and thus the extent for which // statement plus its destructors, and thus the extent for which
// regions referenced by the destructors need to survive. // regions referenced by the destructors need to survive.
visitor.terminating_scopes.insert(stmt_id); visitor.terminating_scopes.insert(stmt_id);
let stmt_extent = visitor.new_node_extent_with_dtor(stmt_id);
let prev_parent = visitor.cx.parent; let prev_parent = visitor.cx.parent;
visitor.cx.parent = Some(stmt_extent); visitor.enter_node_extent_with_dtor(stmt_id);
intravisit::walk_stmt(visitor, stmt); intravisit::walk_stmt(visitor, stmt);
visitor.cx.parent = prev_parent; visitor.cx.parent = prev_parent;
} }
fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: &'tcx hir::Expr) { fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: &'tcx hir::Expr) {
debug!("resolve_expr(expr.id={:?})", expr.id); debug!("resolve_expr(expr.id={:?})", expr.id);
let expr_extent = visitor.new_node_extent_with_dtor(expr.id);
let prev_cx = visitor.cx; let prev_cx = visitor.cx;
visitor.cx.parent = Some(expr_extent); visitor.enter_node_extent_with_dtor(expr.id);
{ {
let terminating_scopes = &mut visitor.terminating_scopes; let terminating_scopes = &mut visitor.terminating_scopes;
@ -784,7 +797,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
} }
hir::ExprMatch(..) => { hir::ExprMatch(..) => {
visitor.cx.var_parent = Some(expr_extent); visitor.cx.var_parent = visitor.cx.parent;
} }
hir::ExprAssignOp(..) | hir::ExprIndex(..) | hir::ExprAssignOp(..) | hir::ExprIndex(..) |
@ -971,7 +984,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>( fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>(
visitor: &mut RegionResolutionVisitor<'a, 'tcx>, visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
expr: &hir::Expr, expr: &hir::Expr,
blk_id: CodeExtent<'tcx>) blk_id: CodeExtent)
{ {
match expr.node { match expr.node {
hir::ExprAddrOf(_, ref subexpr) => { hir::ExprAddrOf(_, ref subexpr) => {
@ -1021,7 +1034,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
/// Note: ET is intended to match "rvalues or lvalues based on rvalues". /// Note: ET is intended to match "rvalues or lvalues based on rvalues".
fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
expr: &hir::Expr, expr: &hir::Expr,
blk_scope: CodeExtent<'tcx>, blk_scope: CodeExtent,
is_shrunk: bool) { is_shrunk: bool) {
let mut expr = expr; let mut expr = expr;
loop { loop {
@ -1054,43 +1067,28 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
} }
impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> { impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
pub fn intern_code_extent(&mut self,
data: CodeExtentData,
parent: Option<CodeExtent<'tcx>>)
-> CodeExtent<'tcx> {
let code_extent = self.tcx.intern_code_extent(data);
self.region_maps.record_code_extent(code_extent, parent);
code_extent
}
pub fn intern_node(&mut self,
n: ast::NodeId,
parent: Option<CodeExtent<'tcx>>) -> CodeExtent<'tcx> {
self.intern_code_extent(CodeExtentData::Misc(n), parent)
}
/// Records the current parent (if any) as the parent of `child_scope`. /// Records the current parent (if any) as the parent of `child_scope`.
fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent<'tcx> { fn record_code_extent(&mut self, child_scope: CodeExtent) {
let parent = self.cx.parent; let parent = self.cx.parent;
self.intern_code_extent(child_scope, parent) self.region_maps.record_code_extent(child_scope, parent);
} }
fn new_node_extent(&mut self, child_scope: ast::NodeId) -> CodeExtent<'tcx> { /// Records the current parent (if any) as the parent of `child_scope`,
self.new_code_extent(CodeExtentData::Misc(child_scope)) /// and sets `child_scope` as the new current parent.
fn enter_code_extent(&mut self, child_scope: CodeExtent) {
self.record_code_extent(child_scope);
self.cx.parent = Some(child_scope);
} }
fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent<'tcx> { fn enter_node_extent_with_dtor(&mut self, id: ast::NodeId) {
// If node was previously marked as a terminating scope during the // If node was previously marked as a terminating scope during the
// recursive visit of its parent node in the AST, then we need to // recursive visit of its parent node in the AST, then we need to
// account for the destruction scope representing the extent of // account for the destruction scope representing the extent of
// the destructors that run immediately after it completes. // the destructors that run immediately after it completes.
if self.terminating_scopes.contains(&id) { if self.terminating_scopes.contains(&id) {
let ds = self.new_code_extent( self.enter_code_extent(CodeExtent::DestructionScope(id));
CodeExtentData::DestructionScope(id));
self.intern_node(id, Some(ds))
} else {
self.new_node_extent(id)
} }
self.enter_code_extent(CodeExtent::Misc(id));
} }
} }
@ -1105,7 +1103,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
fn visit_body(&mut self, body: &'tcx hir::Body) { fn visit_body(&mut self, body: &'tcx hir::Body) {
let body_id = body.id(); let body_id = body.id();
let owner_id = self.map.body_owner(body_id); let owner_id = self.tcx.hir.body_owner(body_id);
debug!("visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})", debug!("visit_body(id={:?}, span={:?}, body.id={:?}, cx.parent={:?})",
owner_id, owner_id,
@ -1127,10 +1125,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
} }
self.cx.root_id = Some(body_id.node_id); self.cx.root_id = Some(body_id.node_id);
self.cx.parent = Some(self.new_code_extent( self.enter_code_extent(CodeExtent::CallSiteScope(body_id));
CodeExtentData::CallSiteScope { fn_id: owner_id, body_id: body_id.node_id })); self.enter_code_extent(CodeExtent::ParameterScope(body_id));
self.cx.parent = Some(self.new_code_extent(
CodeExtentData::ParameterScope { fn_id: owner_id, body_id: body_id.node_id }));
// The arguments and `self` are parented to the fn. // The arguments and `self` are parented to the fn.
self.cx.var_parent = self.cx.parent.take(); self.cx.var_parent = self.cx.parent.take();
@ -1165,21 +1161,18 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
} }
fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> Rc<RegionMaps<'tcx>> -> Rc<RegionMaps>
{ {
let closure_base_def_id = tcx.closure_base_def_id(def_id); let closure_base_def_id = tcx.closure_base_def_id(def_id);
if closure_base_def_id != def_id { if closure_base_def_id != def_id {
return tcx.region_maps(closure_base_def_id); return tcx.region_maps(closure_base_def_id);
} }
let mut maps = RegionMaps::new();
let id = tcx.hir.as_local_node_id(def_id).unwrap(); let id = tcx.hir.as_local_node_id(def_id).unwrap();
if let Some(body) = tcx.hir.maybe_body_owned_by(id) { let maps = if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
let mut visitor = RegionResolutionVisitor { let mut visitor = RegionResolutionVisitor {
tcx: tcx, tcx,
region_maps: &mut maps, region_maps: RegionMaps::new(),
map: &tcx.hir,
cx: Context { cx: Context {
root_id: None, root_id: None,
parent: None, parent: None,
@ -1188,8 +1181,25 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
terminating_scopes: NodeSet(), terminating_scopes: NodeSet(),
}; };
visitor.visit_body(tcx.hir.body(body)); visitor.region_maps.root_body = Some(body);
// If the item is an associated const or a method,
// record its impl/trait parent, as it can also have
// lifetime parameters free in this body.
match tcx.hir.get(id) {
hir::map::NodeImplItem(_) |
hir::map::NodeTraitItem(_) => {
visitor.region_maps.root_parent = Some(tcx.hir.get_parent(id));
} }
_ => {}
}
visitor.visit_body(tcx.hir.body(body));
visitor.region_maps
} else {
RegionMaps::new()
};
Rc::new(maps) Rc::new(maps)
} }

View file

@ -19,7 +19,6 @@ use hir::map::Map;
use session::Session; use session::Session;
use hir::def::Def; use hir::def::Def;
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::region;
use ty; use ty;
use std::cell::Cell; use std::cell::Cell;
@ -42,7 +41,7 @@ pub enum Region {
EarlyBound(/* index */ u32, /* lifetime decl */ ast::NodeId), EarlyBound(/* index */ u32, /* lifetime decl */ ast::NodeId),
LateBound(ty::DebruijnIndex, /* lifetime decl */ ast::NodeId), LateBound(ty::DebruijnIndex, /* lifetime decl */ ast::NodeId),
LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32), LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32),
Free(region::CallSiteScopeData, /* lifetime decl */ ast::NodeId), Free(DefId, /* lifetime decl */ ast::NodeId),
} }
impl Region { impl Region {
@ -895,11 +894,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}; };
if let Some(mut def) = result { if let Some(mut def) = result {
if let Some(body_id) = outermost_body { if let Region::EarlyBound(..) = def {
// Do not free early-bound regions, only late-bound ones.
} else if let Some(body_id) = outermost_body {
let fn_id = self.hir_map.body_owner(body_id); let fn_id = self.hir_map.body_owner(body_id);
let scope_data = region::CallSiteScopeData {
fn_id: fn_id, body_id: body_id.node_id
};
match self.hir_map.get(fn_id) { match self.hir_map.get(fn_id) {
hir::map::NodeItem(&hir::Item { hir::map::NodeItem(&hir::Item {
node: hir::ItemFn(..), .. node: hir::ItemFn(..), ..
@ -910,7 +908,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
hir::map::NodeImplItem(&hir::ImplItem { hir::map::NodeImplItem(&hir::ImplItem {
node: hir::ImplItemKind::Method(..), .. node: hir::ImplItemKind::Method(..), ..
}) => { }) => {
def = Region::Free(scope_data, def.id().unwrap()); let scope = self.hir_map.local_def_id(fn_id);
def = Region::Free(scope, def.id().unwrap());
} }
_ => {} _ => {}
} }

View file

@ -206,9 +206,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}; };
// Search for a predicate like `Self : Sized` amongst the trait bounds. // Search for a predicate like `Self : Sized` amongst the trait bounds.
let free_substs = self.construct_free_substs(def_id, None);
let predicates = self.predicates_of(def_id); let predicates = self.predicates_of(def_id);
let predicates = predicates.instantiate(self, free_substs).predicates; let predicates = predicates.instantiate_identity(self).predicates;
elaborate_predicates(self, predicates) elaborate_predicates(self, predicates)
.any(|predicate| { .any(|predicate| {
match predicate { match predicate {

View file

@ -179,12 +179,8 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
// create a parameter environment corresponding to a (skolemized) instantiation of impl1 // create a parameter environment corresponding to a (skolemized) instantiation of impl1
let penv = tcx.construct_parameter_environment(DUMMY_SP, let penv = tcx.parameter_environment(impl1_def_id);
impl1_def_id, let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
None);
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
.unwrap()
.subst(tcx, &penv.free_substs);
// Create a infcx, taking the predicates of impl1 as assumptions: // Create a infcx, taking the predicates of impl1 as assumptions:
let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| { let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {

View file

@ -197,7 +197,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
// I want to be conservative. --nmatsakis // I want to be conservative. --nmatsakis
let ty_max = data.skip_binder().0; let ty_max = data.skip_binder().0;
let r_min = data.skip_binder().1; let r_min = data.skip_binder().1;
if r_min.is_bound() { if r_min.is_late_bound() {
return; return;
} }
@ -206,7 +206,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
tcx.outlives_components(ty_max) tcx.outlives_components(ty_max)
.into_iter() .into_iter()
.filter_map(|component| match component { .filter_map(|component| match component {
Component::Region(r) => if r.is_bound() { Component::Region(r) => if r.is_late_bound() {
None None
} else { } else {
Some(ty::Predicate::RegionOutlives( Some(ty::Predicate::RegionOutlives(

View file

@ -21,7 +21,6 @@ use hir::map as hir_map;
use hir::map::DisambiguatedDefPathData; use hir::map::DisambiguatedDefPathData;
use middle::free_region::FreeRegionMap; use middle::free_region::FreeRegionMap;
use middle::lang_items; use middle::lang_items;
use middle::region::{CodeExtent, CodeExtentData};
use middle::resolve_lifetime; use middle::resolve_lifetime;
use middle::stability; use middle::stability;
use mir::Mir; use mir::Mir;
@ -99,7 +98,7 @@ pub struct CtxtInterners<'tcx> {
type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>, type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>,
type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>, type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>,
substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>, substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
region: RefCell<FxHashSet<Interned<'tcx, RegionKind<'tcx>>>>, region: RefCell<FxHashSet<Interned<'tcx, RegionKind>>>,
existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>, existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>, predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>,
} }
@ -548,8 +547,6 @@ pub struct GlobalCtxt<'tcx> {
layout_interner: RefCell<FxHashSet<&'tcx Layout>>, layout_interner: RefCell<FxHashSet<&'tcx Layout>>,
code_extent_interner: RefCell<FxHashSet<CodeExtent<'tcx>>>,
/// A vector of every trait accessible in the whole crate /// A vector of every trait accessible in the whole crate
/// (i.e. including those from subcrates). This is used only for /// (i.e. including those from subcrates). This is used only for
/// error reporting, and so is lazily initialised and generally /// error reporting, and so is lazily initialised and generally
@ -651,32 +648,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
interned interned
} }
pub fn node_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> {
self.intern_code_extent(CodeExtentData::Misc(n))
}
// Returns the code extent for an item - the destruction scope.
pub fn item_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> {
self.intern_code_extent(CodeExtentData::DestructionScope(n))
}
pub fn call_site_extent(self, fn_id: ast::NodeId, body_id: ast::NodeId) -> CodeExtent<'gcx> {
assert!(fn_id != body_id);
self.intern_code_extent(CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id })
}
pub fn intern_code_extent(self, data: CodeExtentData) -> CodeExtent<'gcx> {
if let Some(st) = self.code_extent_interner.borrow().get(&data) {
return st;
}
let interned = self.global_interners.arena.alloc(data);
if let Some(prev) = self.code_extent_interner.borrow_mut().replace(interned) {
bug!("Tried to overwrite interned code-extent: {:?}", prev)
}
interned
}
pub fn intern_layout(self, layout: Layout) -> &'gcx Layout { pub fn intern_layout(self, layout: Layout) -> &'gcx Layout {
if let Some(layout) = self.layout_interner.borrow().get(&layout) { if let Some(layout) = self.layout_interner.borrow().get(&layout) {
return layout; return layout;
@ -764,7 +735,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
data_layout: data_layout, data_layout: data_layout,
layout_cache: RefCell::new(FxHashMap()), layout_cache: RefCell::new(FxHashMap()),
layout_interner: RefCell::new(FxHashSet()), layout_interner: RefCell::new(FxHashSet()),
code_extent_interner: RefCell::new(FxHashSet()),
layout_depth: Cell::new(0), layout_depth: Cell::new(0),
derive_macros: RefCell::new(NodeMap()), derive_macros: RefCell::new(NodeMap()),
stability_interner: RefCell::new(FxHashSet()), stability_interner: RefCell::new(FxHashSet()),
@ -843,15 +813,6 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
} }
} }
impl<'a, 'tcx> Lift<'tcx> for ty::FreeRegion<'a> {
type Lifted = ty::FreeRegion<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
let scope = self.scope.map(|code_extent| tcx.intern_code_extent(*code_extent));
let bound_region = self.bound_region;
Some(ty::FreeRegion { scope, bound_region })
}
}
impl<'a, 'tcx> Lift<'tcx> for Region<'a> { impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
type Lifted = Region<'tcx>; type Lifted = Region<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> {
@ -1115,8 +1076,8 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> {
} }
} }
impl<'tcx> Borrow<RegionKind<'tcx>> for Interned<'tcx, RegionKind<'tcx>> { impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
fn borrow<'a>(&'a self) -> &'a RegionKind<'tcx> { fn borrow<'a>(&'a self) -> &'a RegionKind {
&self.0 &self.0
} }
} }
@ -1215,7 +1176,7 @@ direct_interners!('tcx,
&ty::ReVar(_) | &ty::ReSkolemized(..) => true, &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
_ => false _ => false
} }
}) -> RegionKind<'tcx> }) -> RegionKind
); );
macro_rules! slice_interners { macro_rules! slice_interners {

View file

@ -39,7 +39,6 @@
//! These methods return true to indicate that the visitor has found what it is looking for //! These methods return true to indicate that the visitor has found what it is looking for
//! and does not need to visit anything else. //! and does not need to visit anything else.
use middle::region;
use ty::subst::Substs; use ty::subst::Substs;
use ty::adjustment; use ty::adjustment;
use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
@ -326,23 +325,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
(result, replacer.map) (result, replacer.map)
} }
/// Replace any late-bound regions bound in `value` with free variants attached to scope-id
/// `scope_id`.
pub fn liberate_late_bound_regions<T>(self,
all_outlive_scope: Option<region::CodeExtent<'tcx>>,
value: &Binder<T>)
-> T
where T : TypeFoldable<'tcx>
{
self.replace_late_bound_regions(value, |br| {
self.mk_region(ty::ReFree(ty::FreeRegion {
scope: all_outlive_scope,
bound_region: br
}))
}).0
}
/// Flattens two binding levels into one. So `for<'a> for<'b> Foo` /// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
/// becomes `for<'a,'b> Foo`. /// becomes `for<'a,'b> Foo`.
pub fn flatten_late_bound_regions<T>(self, bound2_value: &Binder<Binder<T>>) pub fn flatten_late_bound_regions<T>(self, bound2_value: &Binder<Binder<T>>)
@ -554,7 +536,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// regions. See comment on `shift_regions_through_binders` method in // regions. See comment on `shift_regions_through_binders` method in
// `subst.rs` for more details. // `subst.rs` for more details.
pub fn shift_region<'tcx>(region: ty::RegionKind<'tcx>, amount: u32) -> ty::RegionKind<'tcx> { pub fn shift_region(region: ty::RegionKind, amount: u32) -> ty::RegionKind {
match region { match region {
ty::ReLateBound(debruijn, br) => { ty::ReLateBound(debruijn, br) => {
ty::ReLateBound(debruijn.shifted(amount), br) ty::ReLateBound(debruijn.shifted(amount), br)

View file

@ -1268,11 +1268,10 @@ impl<'a, 'gcx, 'tcx> Layout {
let kind = if def.is_enum() || def.variants[0].fields.len() == 0{ let kind = if def.is_enum() || def.variants[0].fields.len() == 0{
StructKind::AlwaysSizedUnivariant StructKind::AlwaysSizedUnivariant
} else { } else {
let param_env = tcx.construct_parameter_environment(DUMMY_SP, let param_env = tcx.parameter_environment(def.did);
def.did, None);
let fields = &def.variants[0].fields; let fields = &def.variants[0].fields;
let last_field = &fields[fields.len()-1]; let last_field = &fields[fields.len()-1];
let always_sized = last_field.ty(tcx, param_env.free_substs) let always_sized = tcx.type_of(last_field.did)
.is_sized(tcx, &param_env, DUMMY_SP); .is_sized(tcx, &param_env, DUMMY_SP);
if !always_sized { StructKind::MaybeUnsizedUnivariant } if !always_sized { StructKind::MaybeUnsizedUnivariant }
else { StructKind::AlwaysSizedUnivariant } else { StructKind::AlwaysSizedUnivariant }

View file

@ -801,7 +801,7 @@ define_maps! { <'tcx>
/// Per-function `RegionMaps`. The `DefId` should be the owner-def-id for the fn body; /// Per-function `RegionMaps`. The `DefId` should be the owner-def-id for the fn body;
/// in the case of closures or "inline" expressions, this will be redirected to the enclosing /// in the case of closures or "inline" expressions, this will be redirected to the enclosing
/// fn item. /// fn item.
[] region_maps: RegionMaps(DefId) -> Rc<RegionMaps<'tcx>>, [] region_maps: RegionMaps(DefId) -> Rc<RegionMaps>,
[] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>, [] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>,

View file

@ -23,8 +23,8 @@ use ich::StableHashingContext;
use middle::const_val::ConstVal; use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::privacy::AccessLevels; use middle::privacy::AccessLevels;
use middle::region::CodeExtent;
use middle::resolve_lifetime::ObjectLifetimeDefault; use middle::resolve_lifetime::ObjectLifetimeDefault;
use middle::region::CodeExtent;
use mir::Mir; use mir::Mir;
use traits; use traits;
use ty; use ty;
@ -732,11 +732,18 @@ pub struct RegionParameterDef {
impl RegionParameterDef { impl RegionParameterDef {
pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion {
ty::EarlyBoundRegion { ty::EarlyBoundRegion {
def_id: self.def_id,
index: self.index, index: self.index,
name: self.name, name: self.name,
} }
} }
pub fn to_bound_region(&self) -> ty::BoundRegion {
self.to_early_bound_region_data().to_bound_region()
}
}
impl ty::EarlyBoundRegion {
pub fn to_bound_region(&self) -> ty::BoundRegion { pub fn to_bound_region(&self) -> ty::BoundRegion {
ty::BoundRegion::BrNamed(self.def_id, self.name) ty::BoundRegion::BrNamed(self.def_id, self.name)
} }
@ -816,6 +823,21 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs))) instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs)))
} }
pub fn instantiate_identity(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-> InstantiatedPredicates<'tcx> {
let mut instantiated = InstantiatedPredicates::empty();
self.instantiate_identity_into(tcx, &mut instantiated);
instantiated
}
fn instantiate_identity_into(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
instantiated: &mut InstantiatedPredicates<'tcx>) {
if let Some(def_id) = self.parent {
tcx.predicates_of(def_id).instantiate_identity_into(tcx, instantiated);
}
instantiated.predicates.extend(&self.predicates)
}
pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
poly_trait_ref: &ty::PolyTraitRef<'tcx>) poly_trait_ref: &ty::PolyTraitRef<'tcx>)
-> InstantiatedPredicates<'tcx> -> InstantiatedPredicates<'tcx>
@ -1241,31 +1263,11 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
/// more distinctions clearer. /// more distinctions clearer.
#[derive(Clone)] #[derive(Clone)]
pub struct ParameterEnvironment<'tcx> { pub struct ParameterEnvironment<'tcx> {
/// See `construct_free_substs` for details.
pub free_substs: &'tcx Substs<'tcx>,
/// Each type parameter has an implicit region bound that
/// indicates it must outlive at least the function body (the user
/// may specify stronger requirements). This field indicates the
/// region of the callee. If it is `None`, then the parameter
/// environment is for an item or something where the "callee" is
/// not clear.
pub implicit_region_bound: Option<ty::Region<'tcx>>,
/// Obligations that the caller must satisfy. This is basically /// Obligations that the caller must satisfy. This is basically
/// the set of bounds on the in-scope type parameters, translated /// the set of bounds on the in-scope type parameters, translated
/// into Obligations, and elaborated and normalized. /// into Obligations, and elaborated and normalized.
pub caller_bounds: &'tcx [ty::Predicate<'tcx>], pub caller_bounds: &'tcx [ty::Predicate<'tcx>],
/// Scope that is attached to free regions for this scope. This is
/// usually the id of the fn body, but for more abstract scopes
/// like structs we use None or the item extent.
///
/// FIXME(#3696). It would be nice to refactor so that free
/// regions don't have this implicit scope and instead introduce
/// relationships in the environment.
pub free_id_outlive: Option<CodeExtent<'tcx>>,
/// A cache for `moves_by_default`. /// A cache for `moves_by_default`.
pub is_copy_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>, pub is_copy_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
@ -1282,120 +1284,12 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
-> ParameterEnvironment<'tcx> -> ParameterEnvironment<'tcx>
{ {
ParameterEnvironment { ParameterEnvironment {
free_substs: self.free_substs,
implicit_region_bound: self.implicit_region_bound,
caller_bounds: caller_bounds, caller_bounds: caller_bounds,
free_id_outlive: self.free_id_outlive,
is_copy_cache: RefCell::new(FxHashMap()), is_copy_cache: RefCell::new(FxHashMap()),
is_sized_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()),
is_freeze_cache: RefCell::new(FxHashMap()), is_freeze_cache: RefCell::new(FxHashMap()),
} }
} }
/// Construct a parameter environment given an item, impl item, or trait item
pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
-> ParameterEnvironment<'tcx> {
match tcx.hir.find(id) {
Some(hir_map::NodeImplItem(ref impl_item)) => {
match impl_item.node {
hir::ImplItemKind::Type(_) => {
// associated types don't have their own entry (for some reason),
// so for now just grab environment for the impl
let impl_id = tcx.hir.get_parent(id);
let impl_def_id = tcx.hir.local_def_id(impl_id);
tcx.construct_parameter_environment(impl_item.span,
impl_def_id,
Some(tcx.item_extent(id)))
}
hir::ImplItemKind::Const(_, body) |
hir::ImplItemKind::Method(_, body) => {
tcx.construct_parameter_environment(
impl_item.span,
tcx.hir.local_def_id(id),
Some(tcx.call_site_extent(id, body.node_id)))
}
}
}
Some(hir_map::NodeTraitItem(trait_item)) => {
match trait_item.node {
hir::TraitItemKind::Type(..) |
hir::TraitItemKind::Const(_, None) |
hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_))=> {
tcx.construct_parameter_environment(trait_item.span,
tcx.hir.local_def_id(id),
Some(tcx.item_extent(id)))
}
hir::TraitItemKind::Const(_, Some(body)) |
hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body)) => {
tcx.construct_parameter_environment(
trait_item.span,
tcx.hir.local_def_id(id),
Some(tcx.call_site_extent(id, body.node_id)))
}
}
}
Some(hir_map::NodeItem(item)) => {
match item.node {
hir::ItemConst(_, body) |
hir::ItemStatic(.., body) |
hir::ItemFn(.., body) => {
tcx.construct_parameter_environment(
item.span,
tcx.hir.local_def_id(id),
Some(tcx.call_site_extent(id, body.node_id)))
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemTy(..) |
hir::ItemImpl(..) |
hir::ItemTrait(..) => {
let def_id = tcx.hir.local_def_id(id);
tcx.construct_parameter_environment(item.span,
def_id,
Some(tcx.item_extent(id)))
}
_ => {
span_bug!(item.span,
"ParameterEnvironment::for_item():
can't create a parameter \
environment for this kind of item")
}
}
}
Some(hir_map::NodeExpr(expr)) => {
// This is a convenience to allow closures to work.
if let hir::ExprClosure(.., body, _) = expr.node {
let def_id = tcx.hir.local_def_id(id);
let base_def_id = tcx.closure_base_def_id(def_id);
tcx.construct_parameter_environment(
expr.span,
base_def_id,
Some(tcx.call_site_extent(id, body.node_id)))
} else {
tcx.empty_parameter_environment()
}
}
Some(hir_map::NodeForeignItem(item)) => {
let def_id = tcx.hir.local_def_id(id);
tcx.construct_parameter_environment(item.span,
def_id,
None)
}
Some(hir_map::NodeStructCtor(..)) |
Some(hir_map::NodeVariant(..)) => {
let def_id = tcx.hir.local_def_id(id);
tcx.construct_parameter_environment(tcx.hir.span(id),
def_id,
None)
}
it => {
bug!("ParameterEnvironment::from_item(): \
`{}` = {:?} is unsupported",
tcx.hir.node_to_string(id), it)
}
}
}
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -2497,64 +2391,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// are no free type/lifetime parameters in scope. /// are no free type/lifetime parameters in scope.
pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> {
ty::ParameterEnvironment { ty::ParameterEnvironment {
free_substs: self.intern_substs(&[]),
caller_bounds: Slice::empty(), caller_bounds: Slice::empty(),
implicit_region_bound: None,
free_id_outlive: None,
is_copy_cache: RefCell::new(FxHashMap()), is_copy_cache: RefCell::new(FxHashMap()),
is_sized_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()),
is_freeze_cache: RefCell::new(FxHashMap()), is_freeze_cache: RefCell::new(FxHashMap()),
} }
} }
/// Constructs and returns a substitution that can be applied to move from
/// the "outer" view of a type or method to the "inner" view.
/// In general, this means converting from bound parameters to
/// free parameters. Since we currently represent bound/free type
/// parameters in the same way, this only has an effect on regions.
pub fn construct_free_substs(self,
def_id: DefId,
free_id_outlive: Option<CodeExtent<'gcx>>)
-> &'gcx Substs<'gcx> {
let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| {
// map bound 'a => free 'a
self.global_tcx().mk_region(ReFree(FreeRegion {
scope: free_id_outlive,
bound_region: def.to_bound_region()
}))
}, |def, _| {
// map T => T
self.global_tcx().mk_param_from_def(def)
});
debug!("construct_parameter_environment: {:?}", substs);
substs
}
/// See `ParameterEnvironment` struct def'n for details. /// See `ParameterEnvironment` struct def'n for details.
/// If you were using `free_id: NodeId`, you might try `self.region_maps().item_extent(free_id)` pub fn parameter_environment(self, def_id: DefId) -> ParameterEnvironment<'gcx> {
/// for the `free_id_outlive` parameter. (But note that this is not always quite right.)
pub fn construct_parameter_environment(self,
span: Span,
def_id: DefId,
free_id_outlive: Option<CodeExtent<'gcx>>)
-> ParameterEnvironment<'gcx>
{
//
// Construct the free substs.
//
let free_substs = self.construct_free_substs(def_id, free_id_outlive);
// //
// Compute the bounds on Self and the type parameters. // Compute the bounds on Self and the type parameters.
// //
let tcx = self.global_tcx(); let tcx = self.global_tcx();
let generic_predicates = tcx.predicates_of(def_id); let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx);
let bounds = generic_predicates.instantiate(tcx, free_substs);
let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds));
let predicates = bounds.predicates; let predicates = bounds.predicates;
// Finally, we have to normalize the bounds in the environment, in // Finally, we have to normalize the bounds in the environment, in
@ -2571,23 +2422,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// //
let unnormalized_env = ty::ParameterEnvironment { let unnormalized_env = ty::ParameterEnvironment {
free_substs: free_substs,
implicit_region_bound: free_id_outlive.map(|f| tcx.mk_region(ty::ReScope(f))),
caller_bounds: tcx.intern_predicates(&predicates), caller_bounds: tcx.intern_predicates(&predicates),
free_id_outlive: free_id_outlive,
is_copy_cache: RefCell::new(FxHashMap()), is_copy_cache: RefCell::new(FxHashMap()),
is_sized_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()),
is_freeze_cache: RefCell::new(FxHashMap()), is_freeze_cache: RefCell::new(FxHashMap()),
}; };
let body_id = free_id_outlive.map(|f| f.node_id()) let body_id = self.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
.unwrap_or(DUMMY_NODE_ID); self.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id)
let cause = traits::ObligationCause::misc(span, body_id); });
let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
} }
pub fn node_scope_region(self, id: NodeId) -> Region<'tcx> { pub fn node_scope_region(self, id: NodeId) -> Region<'tcx> {
self.mk_region(ty::ReScope(self.node_extent(id))) self.mk_region(ty::ReScope(CodeExtent::Misc(id)))
} }
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`

View file

@ -204,7 +204,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region<'tcx>>) { fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region<'tcx>>) {
for r in regions { for r in regions {
if !r.is_bound() { if !r.is_late_bound() {
out.push(Component::Region(r)); out.push(Component::Region(r));
} }
} }

View file

@ -43,12 +43,8 @@ pub struct TypeAndMut<'tcx> {
RustcEncodable, RustcDecodable, Copy)] RustcEncodable, RustcDecodable, Copy)]
/// A "free" region `fr` can be interpreted as "some region /// A "free" region `fr` can be interpreted as "some region
/// at least as big as the scope `fr.scope`". /// at least as big as the scope `fr.scope`".
/// pub struct FreeRegion {
/// If `fr.scope` is None, then this is in some context (e.g., an pub scope: DefId,
/// impl) where lifetimes are more abstract and the notion of the
/// caller/callee stack frames are not applicable.
pub struct FreeRegion<'tcx> {
pub scope: Option<region::CodeExtent<'tcx>>,
pub bound_region: BoundRegion, pub bound_region: BoundRegion,
} }
@ -688,7 +684,7 @@ pub struct DebruijnIndex {
pub depth: u32, pub depth: u32,
} }
pub type Region<'tcx> = &'tcx RegionKind<'tcx>; pub type Region<'tcx> = &'tcx RegionKind;
/// Representation of regions. /// Representation of regions.
/// ///
@ -747,7 +743,7 @@ pub type Region<'tcx> = &'tcx RegionKind<'tcx>;
/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ /// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
#[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)] #[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)]
pub enum RegionKind<'tcx> { pub enum RegionKind {
// Region bound in a type or fn declaration which will be // Region bound in a type or fn declaration which will be
// substituted 'early' -- that is, at the same time when type // substituted 'early' -- that is, at the same time when type
// parameters are substituted. // parameters are substituted.
@ -760,12 +756,12 @@ pub enum RegionKind<'tcx> {
/// When checking a function body, the types of all arguments and so forth /// When checking a function body, the types of all arguments and so forth
/// that refer to bound region parameters are modified to refer to free /// that refer to bound region parameters are modified to refer to free
/// region parameters. /// region parameters.
ReFree(FreeRegion<'tcx>), ReFree(FreeRegion),
/// A concrete region naming some statically determined extent /// A concrete region naming some statically determined extent
/// (e.g. an expression or sequence of statements) within the /// (e.g. an expression or sequence of statements) within the
/// current function. /// current function.
ReScope(region::CodeExtent<'tcx>), ReScope(region::CodeExtent),
/// Static data that has an "infinite" lifetime. Top in the region lattice. /// Static data that has an "infinite" lifetime. Top in the region lattice.
ReStatic, ReStatic,
@ -794,6 +790,7 @@ impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {}
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
pub struct EarlyBoundRegion { pub struct EarlyBoundRegion {
pub def_id: DefId,
pub index: u32, pub index: u32,
pub name: Name, pub name: Name,
} }
@ -909,10 +906,9 @@ impl DebruijnIndex {
} }
/// Region utilities /// Region utilities
impl<'tcx> RegionKind<'tcx> { impl RegionKind {
pub fn is_bound(&self) -> bool { pub fn is_late_bound(&self) -> bool {
match *self { match *self {
ty::ReEarlyBound(..) => true,
ty::ReLateBound(..) => true, ty::ReLateBound(..) => true,
_ => false, _ => false,
} }
@ -933,7 +929,7 @@ impl<'tcx> RegionKind<'tcx> {
} }
/// Returns the depth of `self` from the (1-based) binding level `depth` /// Returns the depth of `self` from the (1-based) binding level `depth`
pub fn from_depth(&self, depth: u32) -> RegionKind<'tcx> { pub fn from_depth(&self, depth: u32) -> RegionKind {
match *self { match *self {
ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex { ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
depth: debruijn.depth - (depth - 1) depth: debruijn.depth - (depth - 1)

View file

@ -688,9 +688,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
self.hash(db.depth); self.hash(db.depth);
self.hash(i); self.hash(i);
} }
ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => { ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
self.hash(index); self.def_id(def_id);
self.hash(name.as_str());
} }
ty::ReLateBound(..) | ty::ReLateBound(..) |
ty::ReFree(..) | ty::ReFree(..) |

View file

@ -458,7 +458,7 @@ impl fmt::Debug for ty::BoundRegion {
} }
} }
impl<'tcx> fmt::Debug for ty::RegionKind<'tcx> { impl fmt::Debug for ty::RegionKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
ty::ReEarlyBound(ref data) => { ty::ReEarlyBound(ref data) => {
@ -506,17 +506,11 @@ impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> { impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ParameterEnvironment(\ write!(f, "ParameterEnvironment({:?})", self.caller_bounds)
free_substs={:?}, \
implicit_region_bound={:?}, \
caller_bounds={:?})",
self.free_substs,
self.implicit_region_bound,
self.caller_bounds)
} }
} }
impl<'tcx> fmt::Display for ty::RegionKind<'tcx> { impl<'tcx> fmt::Display for ty::RegionKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if verbose() { if verbose() {
return write!(f, "{:?}", *self); return write!(f, "{:?}", *self);
@ -544,7 +538,7 @@ impl<'tcx> fmt::Display for ty::RegionKind<'tcx> {
} }
} }
impl<'tcx> fmt::Debug for ty::FreeRegion<'tcx> { impl fmt::Debug for ty::FreeRegion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ReFree({:?}, {:?})", write!(f, "ReFree({:?}, {:?})",
self.scope, self.bound_region) self.scope, self.bound_region)

View file

@ -232,7 +232,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}) })
} }
pub fn each_in_scope_loan<F>(&self, scope: region::CodeExtent<'tcx>, mut op: F) -> bool where pub fn each_in_scope_loan<F>(&self, scope: region::CodeExtent, mut op: F) -> bool where
F: FnMut(&Loan<'tcx>) -> bool, F: FnMut(&Loan<'tcx>) -> bool,
{ {
//! Like `each_issued_loan()`, but only considers loans that are //! Like `each_issued_loan()`, but only considers loans that are
@ -248,7 +248,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
} }
fn each_in_scope_loan_affecting_path<F>(&self, fn each_in_scope_loan_affecting_path<F>(&self,
scope: region::CodeExtent<'tcx>, scope: region::CodeExtent,
loan_path: &LoanPath<'tcx>, loan_path: &LoanPath<'tcx>,
mut op: F) mut op: F)
-> bool where -> bool where
@ -708,7 +708,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
let mut ret = UseOk; let mut ret = UseOk;
self.each_in_scope_loan_affecting_path( self.each_in_scope_loan_affecting_path(
self.tcx().node_extent(expr_id), use_path, |loan| { region::CodeExtent::Misc(expr_id), use_path, |loan| {
if !compatible_borrow_kinds(loan.kind, borrow_kind) { if !compatible_borrow_kinds(loan.kind, borrow_kind) {
ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span); ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
false false
@ -822,7 +822,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
// Check that we don't invalidate any outstanding loans // Check that we don't invalidate any outstanding loans
if let Some(loan_path) = opt_loan_path(&assignee_cmt) { if let Some(loan_path) = opt_loan_path(&assignee_cmt) {
let scope = self.tcx().node_extent(assignment_id); let scope = region::CodeExtent::Misc(assignment_id);
self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| { self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
self.report_illegal_mutation(assignment_span, &loan_path, loan); self.report_illegal_mutation(assignment_span, &loan_path, loan);
false false

View file

@ -24,7 +24,7 @@ use syntax_pos::Span;
type R = Result<(),()>; type R = Result<(),()>;
pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
item_scope: region::CodeExtent<'tcx>, item_scope: region::CodeExtent,
span: Span, span: Span,
cause: euv::LoanCause, cause: euv::LoanCause,
cmt: mc::cmt<'tcx>, cmt: mc::cmt<'tcx>,
@ -52,7 +52,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
bccx: &'a BorrowckCtxt<'a, 'tcx>, bccx: &'a BorrowckCtxt<'a, 'tcx>,
// the scope of the function body for the enclosing item // the scope of the function body for the enclosing item
item_scope: region::CodeExtent<'tcx>, item_scope: region::CodeExtent,
span: Span, span: Span,
cause: euv::LoanCause, cause: euv::LoanCause,

View file

@ -45,7 +45,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
bccx: bccx, bccx: bccx,
infcx: &infcx, infcx: &infcx,
all_loans: Vec::new(), all_loans: Vec::new(),
item_ub: bccx.tcx.node_extent(body.node_id), item_ub: region::CodeExtent::Misc(body.node_id),
move_data: MoveData::new(), move_data: MoveData::new(),
move_error_collector: move_error::MoveErrorCollector::new(), move_error_collector: move_error::MoveErrorCollector::new(),
}; };
@ -66,7 +66,7 @@ struct GatherLoanCtxt<'a, 'tcx: 'a> {
all_loans: Vec<Loan<'tcx>>, all_loans: Vec<Loan<'tcx>>,
/// `item_ub` is used as an upper-bound on the lifetime whenever we /// `item_ub` is used as an upper-bound on the lifetime whenever we
/// ask for the scope of an expression categorized as an upvar. /// ask for the scope of an expression categorized as an upvar.
item_ub: region::CodeExtent<'tcx>, item_ub: region::CodeExtent,
} }
impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
@ -353,13 +353,18 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
let loan_scope = match *loan_region { let loan_scope = match *loan_region {
ty::ReScope(scope) => scope, ty::ReScope(scope) => scope,
ty::ReFree(ref fr) => fr.scope.unwrap_or(self.item_ub), ty::ReEarlyBound(ref br) => {
self.bccx.region_maps.early_free_extent(self.tcx(), br)
}
ty::ReFree(ref fr) => {
self.bccx.region_maps.free_extent(self.tcx(), fr)
}
ty::ReStatic => self.item_ub, ty::ReStatic => self.item_ub,
ty::ReEmpty | ty::ReEmpty |
ty::ReLateBound(..) | ty::ReLateBound(..) |
ty::ReEarlyBound(..) |
ty::ReVar(..) | ty::ReVar(..) |
ty::ReSkolemized(..) | ty::ReSkolemized(..) |
ty::ReErased => { ty::ReErased => {
@ -371,7 +376,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
}; };
debug!("loan_scope = {:?}", loan_scope); debug!("loan_scope = {:?}", loan_scope);
let borrow_scope = self.tcx().node_extent(borrow_id); let borrow_scope = region::CodeExtent::Misc(borrow_id);
let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope); let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope);
debug!("gen_scope = {:?}", gen_scope); debug!("gen_scope = {:?}", gen_scope);
@ -450,9 +455,9 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
} }
pub fn compute_gen_scope(&self, pub fn compute_gen_scope(&self,
borrow_scope: region::CodeExtent<'tcx>, borrow_scope: region::CodeExtent,
loan_scope: region::CodeExtent<'tcx>) loan_scope: region::CodeExtent)
-> region::CodeExtent<'tcx> { -> region::CodeExtent {
//! Determine when to introduce the loan. Typically the loan //! Determine when to introduce the loan. Typically the loan
//! is introduced at the point of the borrow, but in some cases, //! is introduced at the point of the borrow, but in some cases,
//! notably method arguments, the loan may be introduced only //! notably method arguments, the loan may be introduced only
@ -465,8 +470,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
} }
} }
pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent<'tcx>, lp: &LoanPath<'tcx>) pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent, lp: &LoanPath<'tcx>)
-> region::CodeExtent<'tcx> { -> region::CodeExtent {
//! Determine when the loan restrictions go out of scope. //! Determine when the loan restrictions go out of scope.
//! This is either when the lifetime expires or when the //! This is either when the lifetime expires or when the
//! local variable which roots the loan-path goes out of scope, //! local variable which roots the loan-path goes out of scope,

View file

@ -44,7 +44,7 @@ impl MirPass for ElaborateDrops {
_ => return _ => return
} }
let id = src.item_id(); let id = src.item_id();
let param_env = ty::ParameterEnvironment::for_item(tcx, id); let param_env = tcx.parameter_environment(tcx.hir.local_def_id(id));
let move_data = MoveData::gather_moves(mir, tcx, &param_env); let move_data = MoveData::gather_moves(mir, tcx, &param_env);
let elaborate_patch = { let elaborate_patch = {
let mir = &*mir; let mir = &*mir;

View file

@ -65,7 +65,7 @@ pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
// steals it, but it forces the `borrowck` query. // steals it, but it forces the `borrowck` query.
let mir = &tcx.mir_validated(def_id).borrow(); let mir = &tcx.mir_validated(def_id).borrow();
let param_env = ty::ParameterEnvironment::for_item(tcx, id); let param_env = tcx.parameter_environment(def_id);
let move_data = MoveData::gather_moves(mir, tcx, &param_env); let move_data = MoveData::gather_moves(mir, tcx, &param_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());

View file

@ -208,7 +208,7 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> {
// Some in `borrowck_fn` and cleared later // Some in `borrowck_fn` and cleared later
tables: &'a ty::TypeckTables<'tcx>, tables: &'a ty::TypeckTables<'tcx>,
region_maps: Rc<RegionMaps<'tcx>>, region_maps: Rc<RegionMaps>,
owner_def_id: DefId, owner_def_id: DefId,
} }
@ -228,13 +228,13 @@ pub struct Loan<'tcx> {
/// cases, notably method arguments, the loan may be introduced /// cases, notably method arguments, the loan may be introduced
/// only later, once it comes into scope. See also /// only later, once it comes into scope. See also
/// `GatherLoanCtxt::compute_gen_scope`. /// `GatherLoanCtxt::compute_gen_scope`.
gen_scope: region::CodeExtent<'tcx>, gen_scope: region::CodeExtent,
/// kill_scope indicates when the loan goes out of scope. This is /// kill_scope indicates when the loan goes out of scope. This is
/// either when the lifetime expires or when the local variable /// either when the lifetime expires or when the local variable
/// which roots the loan-path goes out of scope, whichever happens /// which roots the loan-path goes out of scope, whichever happens
/// faster. See also `GatherLoanCtxt::compute_kill_scope`. /// faster. See also `GatherLoanCtxt::compute_kill_scope`.
kill_scope: region::CodeExtent<'tcx>, kill_scope: region::CodeExtent,
span: Span, span: Span,
cause: euv::LoanCause, cause: euv::LoanCause,
} }
@ -334,12 +334,12 @@ pub fn closure_to_block(closure_id: ast::NodeId,
} }
impl<'a, 'tcx> LoanPath<'tcx> { impl<'a, 'tcx> LoanPath<'tcx> {
pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent<'tcx> { pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent {
match self.kind { match self.kind {
LpVar(local_id) => bccx.region_maps.var_scope(local_id), LpVar(local_id) => bccx.region_maps.var_scope(local_id),
LpUpvar(upvar_id) => { LpUpvar(upvar_id) => {
let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx); let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx);
bccx.tcx.node_extent(block_id) region::CodeExtent::Misc(block_id)
} }
LpDowncast(ref base, _) | LpDowncast(ref base, _) |
LpExtend(ref base, ..) => base.kill_scope(bccx), LpExtend(ref base, ..) => base.kill_scope(bccx),
@ -513,6 +513,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
match (&err.code, &err.cause) { match (&err.code, &err.cause) {
(&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _), (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _),
&BorrowViolation(euv::ClosureCapture(span))) | &BorrowViolation(euv::ClosureCapture(span))) |
(&err_out_of_scope(&ty::ReScope(_), &ty::ReEarlyBound(..), _),
&BorrowViolation(euv::ClosureCapture(span))) |
(&err_out_of_scope(&ty::ReScope(_), &ty::ReFree(..), _), (&err_out_of_scope(&ty::ReScope(_), &ty::ReFree(..), _),
&BorrowViolation(euv::ClosureCapture(span))) => { &BorrowViolation(euv::ClosureCapture(span))) => {
return self.report_out_of_scope_escaping_closure_capture(&err, span); return self.report_out_of_scope_escaping_closure_capture(&err, span);

View file

@ -46,14 +46,13 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
b: hir::BodyId, s: Span, id: ast::NodeId) { b: hir::BodyId, s: Span, id: ast::NodeId) {
intravisit::walk_fn(self, fk, fd, b, s, id); intravisit::walk_fn(self, fk, fd, b, s, id);
let region_context = self.tcx.hir.local_def_id(id); let def_id = self.tcx.hir.local_def_id(id);
let region_maps = self.tcx.region_maps(region_context);
MatchVisitor { MatchVisitor {
tcx: self.tcx, tcx: self.tcx,
tables: self.tcx.body_tables(b), tables: self.tcx.body_tables(b),
region_maps: &region_maps, region_maps: &self.tcx.region_maps(def_id),
param_env: &ty::ParameterEnvironment::for_item(self.tcx, id) param_env: &self.tcx.parameter_environment(def_id)
}.visit_body(self.tcx.hir.body(b)); }.visit_body(self.tcx.hir.body(b));
} }
} }
@ -71,7 +70,7 @@ struct MatchVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>, tables: &'a ty::TypeckTables<'tcx>,
param_env: &'a ty::ParameterEnvironment<'tcx>, param_env: &'a ty::ParameterEnvironment<'tcx>,
region_maps: &'a RegionMaps<'tcx>, region_maps: &'a RegionMaps,
} }
impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {

View file

@ -17,7 +17,6 @@ use rustc_resolve::MakeGlobMap;
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::middle::free_region::FreeRegionMap; use rustc::middle::free_region::FreeRegionMap;
use rustc::middle::region::{CodeExtent, RegionMaps}; use rustc::middle::region::{CodeExtent, RegionMaps};
use rustc::middle::region::CodeExtentData;
use rustc::middle::resolve_lifetime; use rustc::middle::resolve_lifetime;
use rustc::middle::stability; use rustc::middle::stability;
use rustc::ty::subst::{Kind, Subst}; use rustc::ty::subst::{Kind, Subst};
@ -45,7 +44,7 @@ use rustc::hir;
struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>, infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>,
region_maps: &'a mut RegionMaps<'tcx>, region_maps: &'a mut RegionMaps,
} }
struct RH<'a> { struct RH<'a> {
@ -168,8 +167,8 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
self.infcx.tcx self.infcx.tcx
} }
pub fn create_region_hierarchy(&mut self, rh: &RH, parent: CodeExtent<'tcx>) { pub fn create_region_hierarchy(&mut self, rh: &RH, parent: CodeExtent) {
let me = self.tcx().intern_code_extent(CodeExtentData::Misc(rh.id)); let me = CodeExtent::Misc(rh.id);
self.region_maps.record_code_extent(me, Some(parent)); self.region_maps.record_code_extent(me, Some(parent));
for child_rh in rh.sub { for child_rh in rh.sub {
self.create_region_hierarchy(child_rh, me); self.create_region_hierarchy(child_rh, me);
@ -181,7 +180,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
// children of 1, etc // children of 1, etc
let node = ast::NodeId::from_u32; let node = ast::NodeId::from_u32;
let dscope = self.tcx().intern_code_extent(CodeExtentData::DestructionScope(node(1))); let dscope = CodeExtent::DestructionScope(node(1));
self.region_maps.record_code_extent(dscope, None); self.region_maps.record_code_extent(dscope, None);
self.create_region_hierarchy(&RH { self.create_region_hierarchy(&RH {
id: node(1), id: node(1),
@ -296,8 +295,9 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> { pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
let name = Symbol::intern(name); let name = Symbol::intern(name);
self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
index: index, def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
name: name, index,
name,
})) }))
} }
@ -326,19 +326,19 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
} }
pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> { pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
let r = ty::ReScope(self.tcx().node_extent(ast::NodeId::from_u32(id))); let r = ty::ReScope(CodeExtent::Misc(ast::NodeId::from_u32(id)));
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
} }
pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region<'tcx> { pub fn re_free(&self, id: u32) -> ty::Region<'tcx> {
self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion { self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: Some(self.tcx().node_extent(nid)), scope: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
bound_region: ty::BrAnon(id), bound_region: ty::BrAnon(id),
})) }))
} }
pub fn t_rptr_free(&self, nid: u32, id: u32) -> Ty<'tcx> { pub fn t_rptr_free(&self, id: u32) -> Ty<'tcx> {
let r = self.re_free(ast::NodeId::from_u32(nid), id); let r = self.re_free(id);
self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
} }
@ -464,7 +464,7 @@ fn sub_free_bound_false() {
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
env.create_simple_region_hierarchy(); env.create_simple_region_hierarchy();
let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free1 = env.t_rptr_free(1);
let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_bound1 = env.t_rptr_late_bound(1);
env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
@ -482,7 +482,7 @@ fn sub_bound_free_true() {
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
env.create_simple_region_hierarchy(); env.create_simple_region_hierarchy();
let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_bound1 = env.t_rptr_late_bound(1);
let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free1 = env.t_rptr_free(1);
env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
}) })
@ -518,7 +518,7 @@ fn lub_free_bound_infer() {
env.create_simple_region_hierarchy(); env.create_simple_region_hierarchy();
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_bound1 = env.t_rptr_late_bound(1);
let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free1 = env.t_rptr_free(1);
env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize), env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize),
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
@ -541,7 +541,7 @@ fn lub_bound_free() {
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
env.create_simple_region_hierarchy(); env.create_simple_region_hierarchy();
let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_bound1 = env.t_rptr_late_bound(1);
let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free1 = env.t_rptr_free(1);
env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
@ -574,8 +574,8 @@ fn lub_bound_bound_inverse_order() {
fn lub_free_free() { fn lub_free_free() {
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
env.create_simple_region_hierarchy(); env.create_simple_region_hierarchy();
let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free1 = env.t_rptr_free(1);
let t_rptr_free2 = env.t_rptr_free(1, 2); let t_rptr_free2 = env.t_rptr_free(2);
let t_rptr_static = env.t_rptr_static(); let t_rptr_static = env.t_rptr_static();
env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
env.t_fn(&[t_rptr_free2], env.tcx().types.isize), env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
@ -600,8 +600,8 @@ fn lub_returning_scope() {
fn glb_free_free_with_common_scope() { fn glb_free_free_with_common_scope() {
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
env.create_simple_region_hierarchy(); env.create_simple_region_hierarchy();
let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free1 = env.t_rptr_free(1);
let t_rptr_free2 = env.t_rptr_free(1, 2); let t_rptr_free2 = env.t_rptr_free(2);
let t_rptr_scope = env.t_rptr_scope(1); let t_rptr_scope = env.t_rptr_scope(1);
env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
env.t_fn(&[t_rptr_free2], env.tcx().types.isize), env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
@ -625,7 +625,7 @@ fn glb_bound_free() {
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
env.create_simple_region_hierarchy(); env.create_simple_region_hierarchy();
let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_bound1 = env.t_rptr_late_bound(1);
let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free1 = env.t_rptr_free(1);
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
env.t_fn(&[t_rptr_free1], env.tcx().types.isize), env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
@ -751,7 +751,7 @@ fn escaping() {
assert!(!env.t_nil().has_escaping_regions()); assert!(!env.t_nil().has_escaping_regions());
let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free1 = env.t_rptr_free(1);
assert!(!t_rptr_free1.has_escaping_regions()); assert!(!t_rptr_free1.has_escaping_regions());
let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)); let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));

View file

@ -990,12 +990,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), traits::Obligation::new(traits::ObligationCause::misc(span, expr_id),
trait_ref.to_poly_trait_predicate()); trait_ref.to_poly_trait_predicate());
// unwrap() is ok here b/c `method` is the method let param_env = tcx.parameter_environment(method.def_id);
// defined in this crate whose body we are
// checking, so it's always local
let node_id = tcx.hir.as_local_node_id(method.def_id).unwrap();
let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
let mut selcx = traits::SelectionContext::new(&infcx); let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) { match selcx.select(&obligation) {
@ -1263,7 +1258,7 @@ impl LintPass for UnionsWithDropFields {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields {
fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) { fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) {
if let hir::ItemUnion(ref vdata, _) = item.node { if let hir::ItemUnion(ref vdata, _) = item.node {
let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); let param_env = &ctx.tcx.parameter_environment(ctx.tcx.hir.local_def_id(item.id));
for field in vdata.fields() { for field in vdata.fields() {
let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id)); let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id));
if field_ty.needs_drop(ctx.tcx, param_env) { if field_ty.needs_drop(ctx.tcx, param_env) {

View file

@ -21,7 +21,6 @@ use rustc::middle::cstore::LinkagePreference;
use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::middle::region;
use rustc::session::Session; use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
@ -360,12 +359,6 @@ impl<'a, 'tcx> SpecializedDecoder<ty::Region<'tcx>> for DecodeContext<'a, 'tcx>
} }
} }
impl<'a, 'tcx> SpecializedDecoder<region::CodeExtent<'tcx>> for DecodeContext<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<region::CodeExtent<'tcx>, Self::Error> {
Ok(self.tcx().intern_code_extent(Decodable::decode(self)?))
}
}
impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Error> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Error> {
Ok(self.tcx().mk_type_list((0..self.read_usize()?).map(|_| Decodable::decode(self)))?) Ok(self.tcx().mk_type_list((0..self.read_usize()?).map(|_| Decodable::decode(self)))?)

View file

@ -39,7 +39,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// The operand is known to be live until the end of `scope`. /// The operand is known to be live until the end of `scope`.
pub fn as_operand<M>(&mut self, pub fn as_operand<M>(&mut self,
block: BasicBlock, block: BasicBlock,
scope: Option<CodeExtent<'tcx>>, scope: Option<CodeExtent>,
expr: M) -> BlockAnd<Operand<'tcx>> expr: M) -> BlockAnd<Operand<'tcx>>
where M: Mirror<'tcx, Output = Expr<'tcx>> where M: Mirror<'tcx, Output = Expr<'tcx>>
{ {
@ -49,7 +49,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn expr_as_operand(&mut self, fn expr_as_operand(&mut self,
mut block: BasicBlock, mut block: BasicBlock,
scope: Option<CodeExtent<'tcx>>, scope: Option<CodeExtent>,
expr: Expr<'tcx>) expr: Expr<'tcx>)
-> BlockAnd<Operand<'tcx>> { -> BlockAnd<Operand<'tcx>> {
debug!("expr_as_operand(block={:?}, expr={:?})", block, expr); debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);

View file

@ -38,7 +38,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} }
/// Compile `expr`, yielding an rvalue. /// Compile `expr`, yielding an rvalue.
pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent<'tcx>>, expr: M) pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent>, expr: M)
-> BlockAnd<Rvalue<'tcx>> -> BlockAnd<Rvalue<'tcx>>
where M: Mirror<'tcx, Output = Expr<'tcx>> where M: Mirror<'tcx, Output = Expr<'tcx>>
{ {
@ -48,7 +48,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn expr_as_rvalue(&mut self, fn expr_as_rvalue(&mut self,
mut block: BasicBlock, mut block: BasicBlock,
scope: Option<CodeExtent<'tcx>>, scope: Option<CodeExtent>,
expr: Expr<'tcx>) expr: Expr<'tcx>)
-> BlockAnd<Rvalue<'tcx>> { -> BlockAnd<Rvalue<'tcx>> {
debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr); debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);

View file

@ -21,7 +21,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// up rvalues so as to freeze the value that will be consumed. /// up rvalues so as to freeze the value that will be consumed.
pub fn as_temp<M>(&mut self, pub fn as_temp<M>(&mut self,
block: BasicBlock, block: BasicBlock,
temp_lifetime: Option<CodeExtent<'tcx>>, temp_lifetime: Option<CodeExtent>,
expr: M) expr: M)
-> BlockAnd<Lvalue<'tcx>> -> BlockAnd<Lvalue<'tcx>>
where M: Mirror<'tcx, Output = Expr<'tcx>> where M: Mirror<'tcx, Output = Expr<'tcx>>
@ -32,7 +32,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn expr_as_temp(&mut self, fn expr_as_temp(&mut self,
mut block: BasicBlock, mut block: BasicBlock,
temp_lifetime: Option<CodeExtent<'tcx>>, temp_lifetime: Option<CodeExtent>,
expr: Expr<'tcx>) expr: Expr<'tcx>)
-> BlockAnd<Lvalue<'tcx>> { -> BlockAnd<Lvalue<'tcx>> {
debug!("expr_as_temp(block={:?}, expr={:?})", block, expr); debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);

View file

@ -14,7 +14,7 @@ use hair::cx::Cx;
use hair::Pattern; use hair::Pattern;
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::region::CodeExtent;
use rustc::mir::*; use rustc::mir::*;
use rustc::mir::transform::MirSource; use rustc::mir::transform::MirSource;
use rustc::mir::visit::MutVisitor; use rustc::mir::visit::MutVisitor;
@ -172,7 +172,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
{ {
let span = tcx.hir.span(ctor_id); let span = tcx.hir.span(ctor_id);
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v { if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id); let pe = tcx.parameter_environment(tcx.hir.local_def_id(ctor_id));
tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| { tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
let (mut mir, src) = let (mut mir, src) =
shim::build_adt_ctor(&infcx, ctor_id, fields, span); shim::build_adt_ctor(&infcx, ctor_id, fields, span);
@ -206,13 +206,14 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-> Ty<'tcx> { -> Ty<'tcx> {
let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id); let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
let closure_def_id = tcx.hir.local_def_id(closure_expr_id);
let region = ty::ReFree(ty::FreeRegion { let region = ty::ReFree(ty::FreeRegion {
scope: Some(tcx.item_extent(body_id.node_id)), scope: closure_def_id,
bound_region: ty::BoundRegion::BrEnv, bound_region: ty::BoundRegion::BrEnv,
}); });
let region = tcx.mk_region(region); let region = tcx.mk_region(region);
match tcx.closure_kind(tcx.hir.local_def_id(closure_expr_id)) { match tcx.closure_kind(closure_def_id) {
ty::ClosureKind::Fn => ty::ClosureKind::Fn =>
tcx.mk_ref(region, tcx.mk_ref(region,
ty::TypeAndMut { ty: closure_ty, ty::TypeAndMut { ty: closure_ty,
@ -337,12 +338,8 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
let span = tcx.hir.span(fn_id); let span = tcx.hir.span(fn_id);
let mut builder = Builder::new(hir.clone(), span, arguments.len(), return_ty); let mut builder = Builder::new(hir.clone(), span, arguments.len(), return_ty);
let call_site_extent = let call_site_extent = CodeExtent::CallSiteScope(body.id());
tcx.intern_code_extent( let arg_extent = CodeExtent::ParameterScope(body.id());
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body.value.id });
let arg_extent =
tcx.intern_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.value.id });
let mut block = START_BLOCK; let mut block = START_BLOCK;
unpack!(block = builder.in_scope(call_site_extent, block, |builder| { unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
unpack!(block = builder.in_scope(arg_extent, block, |builder| { unpack!(block = builder.in_scope(arg_extent, block, |builder| {
@ -405,22 +402,15 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
let span = tcx.hir.span(owner_id); let span = tcx.hir.span(owner_id);
let mut builder = Builder::new(hir.clone(), span, 0, ty); let mut builder = Builder::new(hir.clone(), span, 0, ty);
let extent = hir.region_maps.temporary_scope(tcx, ast_expr.id)
.unwrap_or(tcx.item_extent(owner_id));
let mut block = START_BLOCK; let mut block = START_BLOCK;
let _ = builder.in_scope(extent, block, |builder| {
let expr = builder.hir.mirror(ast_expr); let expr = builder.hir.mirror(ast_expr);
unpack!(block = builder.into(&Lvalue::Local(RETURN_POINTER), block, expr)); unpack!(block = builder.into_expr(&Lvalue::Local(RETURN_POINTER), block, expr));
let source_info = builder.source_info(span); let source_info = builder.source_info(span);
let return_block = builder.return_block(); builder.cfg.terminate(block, source_info, TerminatorKind::Return);
builder.cfg.terminate(block, source_info,
TerminatorKind::Goto { target: return_block });
builder.cfg.terminate(return_block, source_info,
TerminatorKind::Return);
return_block.unit() // Constants can't `return` so a return block should not be created.
}); assert_eq!(builder.cached_return_block, None);
builder.finish(vec![], ty) builder.finish(vec![], ty)
} }
@ -490,7 +480,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn args_and_body(&mut self, fn args_and_body(&mut self,
mut block: BasicBlock, mut block: BasicBlock,
arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)], arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
argument_extent: CodeExtent<'tcx>, argument_extent: CodeExtent,
ast_body: &'gcx hir::Expr) ast_body: &'gcx hir::Expr)
-> BlockAnd<()> -> BlockAnd<()>
{ {

View file

@ -87,7 +87,7 @@ should go to.
*/ */
use build::{BlockAnd, BlockAndExtension, Builder, CFG}; use build::{BlockAnd, BlockAndExtension, Builder, CFG};
use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::region::CodeExtent;
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::ty::subst::{Kind, Subst}; use rustc::ty::subst::{Kind, Subst};
@ -102,7 +102,7 @@ pub struct Scope<'tcx> {
visibility_scope: VisibilityScope, visibility_scope: VisibilityScope,
/// the extent of this scope within source code. /// the extent of this scope within source code.
extent: CodeExtent<'tcx>, extent: CodeExtent,
/// Whether there's anything to do for the cleanup path, that is, /// Whether there's anything to do for the cleanup path, that is,
/// when unwinding through this scope. This includes destructors, /// when unwinding through this scope. This includes destructors,
@ -137,7 +137,7 @@ pub struct Scope<'tcx> {
free: Option<FreeData<'tcx>>, free: Option<FreeData<'tcx>>,
/// The cache for drop chain on “normal” exit into a particular BasicBlock. /// The cache for drop chain on “normal” exit into a particular BasicBlock.
cached_exits: FxHashMap<(BasicBlock, CodeExtent<'tcx>), BasicBlock>, cached_exits: FxHashMap<(BasicBlock, CodeExtent), BasicBlock>,
} }
struct DropData<'tcx> { struct DropData<'tcx> {
@ -180,7 +180,7 @@ struct FreeData<'tcx> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BreakableScope<'tcx> { pub struct BreakableScope<'tcx> {
/// Extent of the loop /// Extent of the loop
pub extent: CodeExtent<'tcx>, pub extent: CodeExtent,
/// Where the body of the loop begins. `None` if block /// Where the body of the loop begins. `None` if block
pub continue_block: Option<BasicBlock>, pub continue_block: Option<BasicBlock>,
/// Block to branch into when the loop or block terminates (either by being `break`-en out /// Block to branch into when the loop or block terminates (either by being `break`-en out
@ -271,7 +271,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Convenience wrapper that pushes a scope and then executes `f` /// Convenience wrapper that pushes a scope and then executes `f`
/// to build its contents, popping the scope afterwards. /// to build its contents, popping the scope afterwards.
pub fn in_scope<F, R>(&mut self, pub fn in_scope<F, R>(&mut self,
extent: CodeExtent<'tcx>, extent: CodeExtent,
mut block: BasicBlock, mut block: BasicBlock,
f: F) f: F)
-> BlockAnd<R> -> BlockAnd<R>
@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// scope and call `pop_scope` afterwards. Note that these two /// scope and call `pop_scope` afterwards. Note that these two
/// calls must be paired; using `in_scope` as a convenience /// calls must be paired; using `in_scope` as a convenience
/// wrapper maybe preferable. /// wrapper maybe preferable.
pub fn push_scope(&mut self, extent: CodeExtent<'tcx>) { pub fn push_scope(&mut self, extent: CodeExtent) {
debug!("push_scope({:?})", extent); debug!("push_scope({:?})", extent);
let vis_scope = self.visibility_scope; let vis_scope = self.visibility_scope;
self.scopes.push(Scope { self.scopes.push(Scope {
@ -306,7 +306,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// drops onto the end of `block` that are needed. This must /// drops onto the end of `block` that are needed. This must
/// match 1-to-1 with `push_scope`. /// match 1-to-1 with `push_scope`.
pub fn pop_scope(&mut self, pub fn pop_scope(&mut self,
extent: CodeExtent<'tcx>, extent: CodeExtent,
mut block: BasicBlock) mut block: BasicBlock)
-> BlockAnd<()> { -> BlockAnd<()> {
debug!("pop_scope({:?}, {:?})", extent, block); debug!("pop_scope({:?}, {:?})", extent, block);
@ -330,7 +330,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// module comment for details. /// module comment for details.
pub fn exit_scope(&mut self, pub fn exit_scope(&mut self,
span: Span, span: Span,
extent: CodeExtent<'tcx>, extent: CodeExtent,
mut block: BasicBlock, mut block: BasicBlock,
target: BasicBlock) { target: BasicBlock) {
debug!("exit_scope(extent={:?}, block={:?}, target={:?})", extent, block, target); debug!("exit_scope(extent={:?}, block={:?}, target={:?})", extent, block, target);
@ -391,7 +391,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// resolving `break` and `continue`. /// resolving `break` and `continue`.
pub fn find_breakable_scope(&mut self, pub fn find_breakable_scope(&mut self,
span: Span, span: Span,
label: CodeExtent<'tcx>) label: CodeExtent)
-> &mut BreakableScope<'tcx> { -> &mut BreakableScope<'tcx> {
// find the loop-scope with the correct id // find the loop-scope with the correct id
self.breakable_scopes.iter_mut() self.breakable_scopes.iter_mut()
@ -411,12 +411,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Returns the extent of the scope which should be exited by a /// Returns the extent of the scope which should be exited by a
/// return. /// return.
pub fn extent_of_return_scope(&self) -> CodeExtent<'tcx> { pub fn extent_of_return_scope(&self) -> CodeExtent {
// The outermost scope (`scopes[0]`) will be the `CallSiteScope`. // The outermost scope (`scopes[0]`) will be the `CallSiteScope`.
// We want `scopes[1]`, which is the `ParameterScope`. // We want `scopes[1]`, which is the `ParameterScope`.
assert!(self.scopes.len() >= 2); assert!(self.scopes.len() >= 2);
assert!(match *self.scopes[1].extent { assert!(match self.scopes[1].extent {
CodeExtentData::ParameterScope { .. } => true, CodeExtent::ParameterScope(_) => true,
_ => false, _ => false,
}); });
self.scopes[1].extent self.scopes[1].extent
@ -424,7 +424,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Returns the topmost active scope, which is known to be alive until /// Returns the topmost active scope, which is known to be alive until
/// the next scope expression. /// the next scope expression.
pub fn topmost_scope(&self) -> CodeExtent<'tcx> { pub fn topmost_scope(&self) -> CodeExtent {
self.scopes.last().expect("topmost_scope: no scopes present").extent self.scopes.last().expect("topmost_scope: no scopes present").extent
} }
@ -434,7 +434,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// `extent`. /// `extent`.
pub fn schedule_drop(&mut self, pub fn schedule_drop(&mut self,
span: Span, span: Span,
extent: CodeExtent<'tcx>, extent: CodeExtent,
lvalue: &Lvalue<'tcx>, lvalue: &Lvalue<'tcx>,
lvalue_ty: Ty<'tcx>) { lvalue_ty: Ty<'tcx>) {
let needs_drop = self.hir.needs_drop(lvalue_ty); let needs_drop = self.hir.needs_drop(lvalue_ty);
@ -524,7 +524,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// There may only be one “free” scheduled in any given scope. /// There may only be one “free” scheduled in any given scope.
pub fn schedule_box_free(&mut self, pub fn schedule_box_free(&mut self,
span: Span, span: Span,
extent: CodeExtent<'tcx>, extent: CodeExtent,
value: &Lvalue<'tcx>, value: &Lvalue<'tcx>,
item_ty: Ty<'tcx>) { item_ty: Ty<'tcx>) {
for scope in self.scopes.iter_mut().rev() { for scope in self.scopes.iter_mut().rev() {

View file

@ -11,7 +11,7 @@
use hair::*; use hair::*;
use hair::cx::Cx; use hair::cx::Cx;
use hair::cx::to_ref::ToRef; use hair::cx::to_ref::ToRef;
use rustc::middle::region::{BlockRemainder, CodeExtentData}; use rustc::middle::region::{BlockRemainder, CodeExtent};
use rustc::hir; use rustc::hir;
use syntax::ast; use syntax::ast;
@ -24,7 +24,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
let stmts = mirror_stmts(cx, self.id, &*self.stmts); let stmts = mirror_stmts(cx, self.id, &*self.stmts);
Block { Block {
targeted_by_break: self.targeted_by_break, targeted_by_break: self.targeted_by_break,
extent: cx.tcx.node_extent(self.id), extent: CodeExtent::Misc(self.id),
span: self.span, span: self.span,
stmts: stmts, stmts: stmts,
expr: self.expr.to_ref(), expr: self.expr.to_ref(),
@ -44,7 +44,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
result.push(StmtRef::Mirror(Box::new(Stmt { result.push(StmtRef::Mirror(Box::new(Stmt {
span: stmt.span, span: stmt.span,
kind: StmtKind::Expr { kind: StmtKind::Expr {
scope: cx.tcx.node_extent(id), scope: CodeExtent::Misc(id),
expr: expr.to_ref(), expr: expr.to_ref(),
}, },
}))) })))
@ -55,19 +55,17 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
// ignore for purposes of the MIR // ignore for purposes of the MIR
} }
hir::DeclLocal(ref local) => { hir::DeclLocal(ref local) => {
let remainder_extent = CodeExtentData::Remainder(BlockRemainder { let remainder_extent = CodeExtent::Remainder(BlockRemainder {
block: block_id, block: block_id,
first_statement_index: index as u32, first_statement_index: index as u32,
}); });
let remainder_extent =
cx.tcx.intern_code_extent(remainder_extent);
let pattern = Pattern::from_hir(cx.tcx, cx.tables(), &local.pat); let pattern = Pattern::from_hir(cx.tcx, cx.tables(), &local.pat);
result.push(StmtRef::Mirror(Box::new(Stmt { result.push(StmtRef::Mirror(Box::new(Stmt {
span: stmt.span, span: stmt.span,
kind: StmtKind::Let { kind: StmtKind::Let {
remainder_scope: remainder_extent, remainder_scope: remainder_extent,
init_scope: cx.tcx.node_extent(id), init_scope: CodeExtent::Misc(id),
pattern: pattern, pattern: pattern,
initializer: local.init.to_ref(), initializer: local.init.to_ref(),
}, },
@ -84,7 +82,7 @@ pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
block: &'tcx hir::Block) block: &'tcx hir::Block)
-> ExprRef<'tcx> { -> ExprRef<'tcx> {
let block_ty = cx.tables().node_id_to_type(block.id); let block_ty = cx.tables().node_id_to_type(block.id);
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, block.id); let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(block.id);
let expr = Expr { let expr = Expr {
ty: block_ty, ty: block_ty,
temp_lifetime: temp_lifetime, temp_lifetime: temp_lifetime,

View file

@ -14,7 +14,6 @@ use rustc_const_math::ConstInt;
use hair::cx::Cx; use hair::cx::Cx;
use hair::cx::block; use hair::cx::block;
use hair::cx::to_ref::ToRef; use hair::cx::to_ref::ToRef;
use rustc::hir::map;
use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def::{Def, CtorKind};
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::{self, AdtKind, VariantDef, Ty};
@ -26,8 +25,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
type Output = Expr<'tcx>; type Output = Expr<'tcx>;
fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> { fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, self.id); let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(self.id);
let expr_extent = cx.tcx.node_extent(self.id); let expr_extent = CodeExtent::Misc(self.id);
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
@ -238,7 +237,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &'tcx hir::Expr) expr: &'tcx hir::Expr)
-> Expr<'tcx> { -> Expr<'tcx> {
let expr_ty = cx.tables().expr_ty(expr); let expr_ty = cx.tables().expr_ty(expr);
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id); let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
let kind = match expr.node { let kind = match expr.node {
// Here comes the interesting stuff: // Here comes the interesting stuff:
@ -610,7 +609,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
match dest.target_id { match dest.target_id {
hir::ScopeTarget::Block(target_id) | hir::ScopeTarget::Block(target_id) |
hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break { hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break {
label: cx.tcx.node_extent(target_id), label: CodeExtent::Misc(target_id),
value: value.to_ref(), value: value.to_ref(),
}, },
hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
@ -621,7 +620,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
match dest.target_id { match dest.target_id {
hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"), hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"),
hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue { hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue {
label: cx.tcx.node_extent(loop_id), label: CodeExtent::Misc(loop_id),
}, },
hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
bug!("invalid loop id for continue: {}", err) bug!("invalid loop id for continue: {}", err)
@ -686,7 +685,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
hir::ExprBox(ref value) => { hir::ExprBox(ref value) => {
ExprKind::Box { ExprKind::Box {
value: value.to_ref(), value: value.to_ref(),
value_extents: cx.tcx.node_extent(value.id), value_extents: CodeExtent::Misc(value.id),
} }
} }
hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() }, hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() },
@ -707,7 +706,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
method_call: ty::MethodCall) method_call: ty::MethodCall)
-> Expr<'tcx> { -> Expr<'tcx> {
let callee = cx.tables().method_map[&method_call]; let callee = cx.tables().method_map[&method_call];
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id); let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
Expr { Expr {
temp_lifetime: temp_lifetime, temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk, temp_lifetime_was_shrunk: was_shrunk,
@ -791,7 +790,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &'tcx hir::Expr, expr: &'tcx hir::Expr,
def: Def) def: Def)
-> ExprKind<'tcx> { -> ExprKind<'tcx> {
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id); let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
match def { match def {
Def::Local(def_id) => { Def::Local(def_id) => {
@ -807,33 +806,20 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
closure_expr_id); closure_expr_id);
let var_ty = cx.tables().node_id_to_type(id_var); let var_ty = cx.tables().node_id_to_type(id_var);
let body_id = match cx.tcx.hir.find(closure_expr_id) {
Some(map::NodeExpr(expr)) => {
match expr.node {
hir::ExprClosure(.., body, _) => body.node_id,
_ => {
span_bug!(expr.span, "closure expr is not a closure expr");
}
}
}
_ => {
span_bug!(expr.span, "ast-map has garbage for closure expr");
}
};
// FIXME free regions in closures are not right // FIXME free regions in closures are not right
let closure_ty = cx.tables().node_id_to_type(closure_expr_id); let closure_ty = cx.tables().node_id_to_type(closure_expr_id);
// FIXME we're just hard-coding the idea that the // FIXME we're just hard-coding the idea that the
// signature will be &self or &mut self and hence will // signature will be &self or &mut self and hence will
// have a bound region with number 0 // have a bound region with number 0
let closure_def_id = cx.tcx.hir.local_def_id(closure_expr_id);
let region = ty::ReFree(ty::FreeRegion { let region = ty::ReFree(ty::FreeRegion {
scope: Some(cx.tcx.node_extent(body_id)), scope: closure_def_id,
bound_region: ty::BoundRegion::BrAnon(0), bound_region: ty::BoundRegion::BrAnon(0),
}); });
let region = cx.tcx.mk_region(region); let region = cx.tcx.mk_region(region);
let self_expr = match cx.tcx.closure_kind(cx.tcx.hir.local_def_id(closure_expr_id)) { let self_expr = match cx.tcx.closure_kind(closure_def_id) {
ty::ClosureKind::Fn => { ty::ClosureKind::Fn => {
let ref_closure_ty = cx.tcx.mk_ref(region, let ref_closure_ty = cx.tcx.mk_ref(region,
ty::TypeAndMut { ty::TypeAndMut {
@ -979,7 +965,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
PassArgs::ByRef => { PassArgs::ByRef => {
let region = cx.tcx.node_scope_region(expr.id); let region = cx.tcx.node_scope_region(expr.id);
let (temp_lifetime, was_shrunk) = let (temp_lifetime, was_shrunk) =
cx.region_maps.temporary_scope2(cx.tcx, expr.id); cx.region_maps.temporary_scope2(expr.id);
argrefs.extend(args.iter() argrefs.extend(args.iter()
.map(|arg| { .map(|arg| {
let arg_ty = cx.tables().expr_ty_adjusted(arg); let arg_ty = cx.tables().expr_ty_adjusted(arg);
@ -1031,7 +1017,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
// construct the complete expression `foo()` for the overloaded call, // construct the complete expression `foo()` for the overloaded call,
// which will yield the &T type // which will yield the &T type
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id); let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args); let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
let ref_expr = Expr { let ref_expr = Expr {
temp_lifetime: temp_lifetime, temp_lifetime: temp_lifetime,
@ -1056,7 +1042,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
closure_expr_id: closure_expr.id, closure_expr_id: closure_expr.id,
}; };
let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap(); let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, closure_expr.id); let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(closure_expr.id);
let var_ty = cx.tables().node_id_to_type(id_var); let var_ty = cx.tables().node_id_to_type(id_var);
let captured_var = Expr { let captured_var = Expr {
temp_lifetime: temp_lifetime, temp_lifetime: temp_lifetime,

View file

@ -35,7 +35,7 @@ use std::rc::Rc;
pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>,
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
pub region_maps: Rc<RegionMaps<'tcx>>, pub region_maps: Rc<RegionMaps>,
constness: hir::Constness, constness: hir::Constness,
/// True if this constant/function needs overflow checks. /// True if this constant/function needs overflow checks.

View file

@ -32,7 +32,7 @@ pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPatt
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Block<'tcx> { pub struct Block<'tcx> {
pub targeted_by_break: bool, pub targeted_by_break: bool,
pub extent: CodeExtent<'tcx>, pub extent: CodeExtent,
pub span: Span, pub span: Span,
pub stmts: Vec<StmtRef<'tcx>>, pub stmts: Vec<StmtRef<'tcx>>,
pub expr: Option<ExprRef<'tcx>>, pub expr: Option<ExprRef<'tcx>>,
@ -53,7 +53,7 @@ pub struct Stmt<'tcx> {
pub enum StmtKind<'tcx> { pub enum StmtKind<'tcx> {
Expr { Expr {
/// scope for this statement; may be used as lifetime of temporaries /// scope for this statement; may be used as lifetime of temporaries
scope: CodeExtent<'tcx>, scope: CodeExtent,
/// expression being evaluated in this statement /// expression being evaluated in this statement
expr: ExprRef<'tcx>, expr: ExprRef<'tcx>,
@ -62,11 +62,11 @@ pub enum StmtKind<'tcx> {
Let { Let {
/// scope for variables bound in this let; covers this and /// scope for variables bound in this let; covers this and
/// remaining statements in block /// remaining statements in block
remainder_scope: CodeExtent<'tcx>, remainder_scope: CodeExtent,
/// scope for the initialization itself; might be used as /// scope for the initialization itself; might be used as
/// lifetime of temporaries /// lifetime of temporaries
init_scope: CodeExtent<'tcx>, init_scope: CodeExtent,
/// let <PAT> = ... /// let <PAT> = ...
pattern: Pattern<'tcx>, pattern: Pattern<'tcx>,
@ -97,7 +97,7 @@ pub struct Expr<'tcx> {
/// lifetime of this expression if it should be spilled into a /// lifetime of this expression if it should be spilled into a
/// temporary; should be None only if in a constant context /// temporary; should be None only if in a constant context
pub temp_lifetime: Option<CodeExtent<'tcx>>, pub temp_lifetime: Option<CodeExtent>,
/// whether this temp lifetime was shrunk by #36082. /// whether this temp lifetime was shrunk by #36082.
pub temp_lifetime_was_shrunk: bool, pub temp_lifetime_was_shrunk: bool,
@ -112,12 +112,12 @@ pub struct Expr<'tcx> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ExprKind<'tcx> { pub enum ExprKind<'tcx> {
Scope { Scope {
extent: CodeExtent<'tcx>, extent: CodeExtent,
value: ExprRef<'tcx>, value: ExprRef<'tcx>,
}, },
Box { Box {
value: ExprRef<'tcx>, value: ExprRef<'tcx>,
value_extents: CodeExtent<'tcx>, value_extents: CodeExtent,
}, },
Call { Call {
ty: ty::Ty<'tcx>, ty: ty::Ty<'tcx>,
@ -210,11 +210,11 @@ pub enum ExprKind<'tcx> {
arg: ExprRef<'tcx>, arg: ExprRef<'tcx>,
}, },
Break { Break {
label: CodeExtent<'tcx>, label: CodeExtent,
value: Option<ExprRef<'tcx>>, value: Option<ExprRef<'tcx>>,
}, },
Continue { Continue {
label: CodeExtent<'tcx>, label: CodeExtent,
}, },
Return { Return {
value: Option<ExprRef<'tcx>>, value: Option<ExprRef<'tcx>>,

View file

@ -15,7 +15,7 @@ use rustc::middle::const_val::ConstVal;
use rustc::mir::*; use rustc::mir::*;
use rustc::mir::transform::MirSource; use rustc::mir::transform::MirSource;
use rustc::ty::{self, Ty}; use rustc::ty::{self, Ty};
use rustc::ty::subst::{Kind, Subst}; use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::maps::Providers; use rustc::ty::maps::Providers;
use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@ -41,8 +41,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
{ {
debug!("make_shim({:?})", instance); debug!("make_shim({:?})", instance);
let did = instance.def_id(); let did = instance.def_id();
let span = tcx.def_span(did); let param_env = tcx.parameter_environment(did);
let param_env = tcx.construct_parameter_environment(span, did, None);
let mut result = match instance { let mut result = match instance {
ty::InstanceDef::Item(..) => ty::InstanceDef::Item(..) =>
@ -66,7 +65,6 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
build_call_shim( build_call_shim(
tcx, tcx,
&param_env,
def_id, def_id,
adjustment, adjustment,
CallKind::Indirect, CallKind::Indirect,
@ -78,7 +76,6 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
// trans::mir knows to turn to an actual virtual call. // trans::mir knows to turn to an actual virtual call.
build_call_shim( build_call_shim(
tcx, tcx,
&param_env,
def_id, def_id,
Adjustment::Identity, Adjustment::Identity,
CallKind::Direct(def_id), CallKind::Direct(def_id),
@ -94,7 +91,6 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
build_call_shim( build_call_shim(
tcx, tcx,
&param_env,
call_once, call_once,
Adjustment::RefMut, Adjustment::RefMut,
CallKind::Direct(call_mut), CallKind::Direct(call_mut),
@ -158,7 +154,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
let substs = if let Some(ty) = ty { let substs = if let Some(ty) = ty {
tcx.mk_substs(iter::once(Kind::from(ty))) tcx.mk_substs(iter::once(Kind::from(ty)))
} else { } else {
param_env.free_substs Substs::identity_for_item(tcx, def_id)
}; };
let fn_ty = tcx.type_of(def_id).subst(tcx, substs); let fn_ty = tcx.type_of(def_id).subst(tcx, substs);
let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
@ -272,7 +268,6 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
/// If `untuple_args` is a vec of types, the second argument of the /// If `untuple_args` is a vec of types, the second argument of the
/// function will be untupled as these types. /// function will be untupled as these types.
fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
param_env: &ty::ParameterEnvironment<'tcx>,
def_id: DefId, def_id: DefId,
rcvr_adjustment: Adjustment, rcvr_adjustment: Adjustment,
call_kind: CallKind, call_kind: CallKind,
@ -283,7 +278,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
call_kind={:?}, untuple_args={:?})", call_kind={:?}, untuple_args={:?})",
def_id, rcvr_adjustment, call_kind, untuple_args); def_id, rcvr_adjustment, call_kind, untuple_args);
let fn_ty = tcx.type_of(def_id).subst(tcx, param_env.free_substs); let fn_ty = tcx.type_of(def_id);
let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
let span = tcx.def_span(def_id); let span = tcx.def_span(def_id);
@ -325,9 +320,10 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
CallKind::Direct(def_id) => ( CallKind::Direct(def_id) => (
Operand::Constant(box Constant { Operand::Constant(box Constant {
span: span, span: span,
ty: tcx.type_of(def_id).subst(tcx, param_env.free_substs), ty: tcx.type_of(def_id),
literal: Literal::Value { literal: Literal::Value {
value: ConstVal::Function(def_id, param_env.free_substs), value: ConstVal::Function(def_id,
Substs::identity_for_item(tcx, def_id)),
}, },
}), }),
vec![rcvr] vec![rcvr]

View file

@ -219,7 +219,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
// FIXME: Give a bonus to functions with only a single caller // FIXME: Give a bonus to functions with only a single caller
let param_env = ty::ParameterEnvironment::for_item(tcx, self.source.item_id()); let def_id = tcx.hir.local_def_id(self.source.item_id());
let param_env = tcx.parameter_environment(def_id);
let mut first_block = true; let mut first_block = true;
let mut cost = 0; let mut cost = 0;

View file

@ -937,8 +937,7 @@ fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
return Qualif::NOT_CONST.bits(); return Qualif::NOT_CONST.bits();
} }
let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let param_env = tcx.parameter_environment(def_id);
let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, Mode::Const); let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, Mode::Const);
qualifier.qualify_const().bits() qualifier.qualify_const().bits()
@ -966,7 +965,7 @@ impl MirPass for QualifyAndPromoteConstants {
MirSource::Const(_) | MirSource::Const(_) |
MirSource::Promoted(..) => return MirSource::Promoted(..) => return
}; };
let param_env = ty::ParameterEnvironment::for_item(tcx, id); let param_env = tcx.parameter_environment(def_id);
if mode == Mode::Fn || mode == Mode::ConstFn { if mode == Mode::Fn || mode == Mode::ConstFn {
// This is ugly because Qualifier holds onto mir, // This is ugly because Qualifier holds onto mir,

View file

@ -751,7 +751,7 @@ impl MirPass for TypeckMir {
// broken MIR, so try not to report duplicate errors. // broken MIR, so try not to report duplicate errors.
return; return;
} }
let param_env = ty::ParameterEnvironment::for_item(tcx, item_id); let param_env = tcx.parameter_environment(def_id);
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
let mut checker = TypeChecker::new(&infcx, item_id); let mut checker = TypeChecker::new(&infcx, item_id);
{ {

View file

@ -41,12 +41,6 @@ pub trait AstConv<'gcx, 'tcx> {
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-> ty::GenericPredicates<'tcx>; -> ty::GenericPredicates<'tcx>;
/// Return an (optional) substitution to convert bound type parameters that
/// are in scope into free ones. This function should only return Some
/// within a fn body.
/// See ParameterEnvironment::free_substs for more information.
fn get_free_substs(&self) -> Option<&Substs<'tcx>>;
/// What lifetime should we use when a lifetime is omitted (and not elided)? /// What lifetime should we use when a lifetime is omitted (and not elided)?
fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>) fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
-> Option<ty::Region<'tcx>>; -> Option<ty::Region<'tcx>>;
@ -121,6 +115,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
Some(&rl::Region::EarlyBound(index, id)) => { Some(&rl::Region::EarlyBound(index, id)) => {
let name = tcx.hir.name(id); let name = tcx.hir.name(id);
tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: tcx.hir.local_def_id(id),
index: index, index: index,
name: name name: name
})) }))
@ -129,7 +124,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
Some(&rl::Region::Free(scope, id)) => { Some(&rl::Region::Free(scope, id)) => {
let name = tcx.hir.name(id); let name = tcx.hir.name(id);
tcx.mk_region(ty::ReFree(ty::FreeRegion { tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: Some(scope.to_code_extent(tcx)), scope,
bound_region: ty::BrNamed(tcx.hir.local_def_id(id), name) bound_region: ty::BrNamed(tcx.hir.local_def_id(id), name)
})) }))
@ -857,12 +852,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
} }
}; };
let trait_ref = if let Some(free_substs) = self.get_free_substs() {
trait_ref.subst(tcx, free_substs)
} else {
trait_ref
};
let candidates = let candidates =
traits::supertraits(tcx, ty::Binder(trait_ref)) traits::supertraits(tcx, ty::Binder(trait_ref))
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), .filter(|r| self.trait_defines_associated_type_named(r.def_id(),
@ -1020,12 +1009,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
assert_eq!(opt_self_ty, None); assert_eq!(opt_self_ty, None);
self.prohibit_type_params(&path.segments); self.prohibit_type_params(&path.segments);
let ty = tcx.at(span).type_of(def_id); tcx.at(span).type_of(def_id)
if let Some(free_substs) = self.get_free_substs() {
ty.subst(tcx, free_substs)
} else {
ty
}
} }
Def::SelfTy(Some(_), None) => { Def::SelfTy(Some(_), None) => {
// Self in trait. // Self in trait.

View file

@ -15,6 +15,7 @@ use super::{check_fn, Expectation, FnCtxt};
use astconv::AstConv; use astconv::AstConv;
use rustc::infer::type_variable::TypeVariableOrigin; use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::ty::{self, ToPolyTraitRef, Ty}; use rustc::ty::{self, ToPolyTraitRef, Ty};
use rustc::ty::subst::Substs;
use std::cmp; use std::cmp;
use std::iter; use std::iter;
use syntax::abi::Abi; use syntax::abi::Abi;
@ -60,12 +61,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
decl, decl,
Abi::RustCall, Abi::RustCall,
expected_sig); expected_sig);
// `deduce_expectations_from_expected_type` introduces late-bound
// lifetimes defined elsewhere, which we need to anonymize away.
let sig = self.tcx.anonymize_late_bound_regions(&sig);
// Create type variables (for now) to represent the transformed // Create type variables (for now) to represent the transformed
// types of upvars. These will be unified during the upvar // types of upvars. These will be unified during the upvar
// inference phase (`upvar.rs`). // inference phase (`upvar.rs`).
let base_substs = Substs::identity_for_item(self.tcx,
self.tcx.closure_base_def_id(expr_def_id));
let closure_type = self.tcx.mk_closure(expr_def_id, let closure_type = self.tcx.mk_closure(expr_def_id,
self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id, base_substs.extend_to(self.tcx, expr_def_id,
|_, _| span_bug!(expr.span, "closure has region param"), |_, _| span_bug!(expr.span, "closure has region param"),
|_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span)) |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
) )
@ -73,8 +79,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type); debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
let extent = self.tcx.call_site_extent(expr.id, body.value.id); let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig);
let fn_sig = self.tcx.liberate_late_bound_regions(Some(extent), &sig);
let fn_sig = self.inh.normalize_associated_types_in(body.value.span, let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
body.value.id, &fn_sig); body.value.id, &fn_sig);

View file

@ -167,16 +167,15 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Create a parameter environment that represents the implementation's // Create a parameter environment that represents the implementation's
// method. // method.
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_m_node_id); let impl_param_env = tcx.parameter_environment(impl_m.def_id);
// Create mapping from impl to skolemized. // Create mapping from impl to skolemized.
let impl_to_skol_substs = &impl_param_env.free_substs; let impl_to_skol_substs = Substs::identity_for_item(tcx, impl_m.def_id);
// Create mapping from trait to skolemized. // Create mapping from trait to skolemized.
let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx, let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
impl_m.container.id(), impl_m.container.id(),
trait_to_impl_substs.subst(tcx, trait_to_impl_substs);
impl_to_skol_substs));
debug!("compare_impl_method: trait_to_skol_substs={:?}", debug!("compare_impl_method: trait_to_skol_substs={:?}",
trait_to_skol_substs); trait_to_skol_substs);
@ -191,8 +190,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_m, impl_m,
&trait_m_generics, &trait_m_generics,
&impl_m_generics, &impl_m_generics,
trait_to_skol_substs, trait_to_skol_substs)?;
impl_to_skol_substs)?;
// Create obligations for each predicate declared by the impl // Create obligations for each predicate declared by the impl
// definition in the context of the trait's parameter // definition in the context of the trait's parameter
@ -200,7 +198,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// however, because we want to replace all late-bound regions with // however, because we want to replace all late-bound regions with
// region variables. // region variables.
let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap()); let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
@ -226,7 +224,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
normalize_cause.clone()); normalize_cause.clone());
tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| { tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| {
let inh = Inherited::new(infcx); let inh = Inherited::new(infcx, impl_m.def_id);
let infcx = &inh.infcx; let infcx = &inh.infcx;
debug!("compare_impl_method: caller_bounds={:?}", debug!("compare_impl_method: caller_bounds={:?}",
@ -273,8 +271,6 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
infer::HigherRankedType, infer::HigherRankedType,
&m_sig(impl_m)); &m_sig(impl_m));
let impl_sig =
impl_sig.subst(tcx, impl_to_skol_substs);
let impl_sig = let impl_sig =
inh.normalize_associated_types_in(impl_m_span, inh.normalize_associated_types_in(impl_m_span,
impl_m_node_id, impl_m_node_id,
@ -282,8 +278,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig)); let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
debug!("compare_impl_method: impl_fty={:?}", impl_fty); debug!("compare_impl_method: impl_fty={:?}", impl_fty);
let trait_sig = tcx.liberate_late_bound_regions( let trait_sig = inh.liberate_late_bound_regions(
infcx.parameter_environment.free_id_outlive, impl_m.def_id,
&m_sig(trait_m)); &m_sig(trait_m));
let trait_sig = let trait_sig =
trait_sig.subst(tcx, trait_to_skol_substs); trait_sig.subst(tcx, trait_to_skol_substs);
@ -370,8 +366,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_m: &ty::AssociatedItem, impl_m: &ty::AssociatedItem,
trait_generics: &ty::Generics, trait_generics: &ty::Generics,
impl_generics: &ty::Generics, impl_generics: &ty::Generics,
trait_to_skol_substs: &Substs<'tcx>, trait_to_skol_substs: &Substs<'tcx>)
impl_to_skol_substs: &Substs<'tcx>)
-> Result<(), ErrorReported> { -> Result<(), ErrorReported> {
let trait_params = &trait_generics.regions[..]; let trait_params = &trait_generics.regions[..];
let impl_params = &impl_generics.regions[..]; let impl_params = &impl_generics.regions[..];
@ -379,12 +374,10 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("check_region_bounds_on_impl_method: \ debug!("check_region_bounds_on_impl_method: \
trait_generics={:?} \ trait_generics={:?} \
impl_generics={:?} \ impl_generics={:?} \
trait_to_skol_substs={:?} \ trait_to_skol_substs={:?}",
impl_to_skol_substs={:?}",
trait_generics, trait_generics,
impl_generics, impl_generics,
trait_to_skol_substs, trait_to_skol_substs);
impl_to_skol_substs);
// Must have same number of early-bound lifetime parameters. // Must have same number of early-bound lifetime parameters.
// Unfortunately, if the user screws up the bounds, then this // Unfortunately, if the user screws up the bounds, then this
@ -726,7 +719,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
let inh = Inherited::new(infcx); let inh = Inherited::new(infcx, impl_c.def_id);
let infcx = &inh.infcx; let infcx = &inh.infcx;
// The below is for the most part highly similar to the procedure // The below is for the most part highly similar to the procedure
@ -739,22 +732,10 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Create a parameter environment that represents the implementation's // Create a parameter environment that represents the implementation's
// method. // method.
let impl_c_node_id = tcx.hir.as_local_node_id(impl_c.def_id).unwrap(); let impl_c_node_id = tcx.hir.as_local_node_id(impl_c.def_id).unwrap();
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_c_node_id);
// Create mapping from impl to skolemized.
let impl_to_skol_substs = &impl_param_env.free_substs;
// Create mapping from trait to skolemized.
let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
impl_c.container.id(),
trait_to_impl_substs.subst(tcx,
impl_to_skol_substs));
debug!("compare_const_impl: trait_to_skol_substs={:?}",
trait_to_skol_substs);
// Compute skolemized form of impl and trait const tys. // Compute skolemized form of impl and trait const tys.
let impl_ty = tcx.type_of(impl_c.def_id).subst(tcx, impl_to_skol_substs); let impl_ty = tcx.type_of(impl_c.def_id);
let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_skol_substs); let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id); let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id);
// There is no "body" here, so just pass dummy id. // There is no "body" here, so just pass dummy id.

View file

@ -76,17 +76,15 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
-> Result<(), ErrorReported> -> Result<(), ErrorReported>
{ {
let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap(); let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
// check that the impl type can be made to match the trait type. // check that the impl type can be made to match the trait type.
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id); let impl_param_env = tcx.parameter_environment(self_type_did);
tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| { tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| {
let tcx = infcx.tcx; let tcx = infcx.tcx;
let mut fulfillment_cx = traits::FulfillmentContext::new(); let mut fulfillment_cx = traits::FulfillmentContext::new();
let named_type = tcx.type_of(self_type_did); let named_type = tcx.type_of(self_type_did);
let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
let drop_impl_span = tcx.def_span(drop_impl_did); let drop_impl_span = tcx.def_span(drop_impl_did);
let fresh_impl_substs = let fresh_impl_substs =
@ -99,7 +97,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
fulfillment_cx.register_predicate_obligations(infcx, obligations); fulfillment_cx.register_predicate_obligations(infcx, obligations);
} }
Err(_) => { Err(_) => {
let item_span = tcx.hir.span(self_type_node_id); let item_span = tcx.def_span(self_type_did);
struct_span_err!(tcx.sess, drop_impl_span, E0366, struct_span_err!(tcx.sess, drop_impl_span, E0366,
"Implementations of Drop cannot be specialized") "Implementations of Drop cannot be specialized")
.span_note(item_span, .span_note(item_span,
@ -272,7 +270,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>, rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
ty: ty::Ty<'tcx>, ty: ty::Ty<'tcx>,
span: Span, span: Span,
scope: region::CodeExtent<'tcx>) scope: region::CodeExtent)
-> Result<(), ErrorReported> -> Result<(), ErrorReported>
{ {
debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",

View file

@ -88,10 +88,10 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_back::slice::ref_slice; use rustc_back::slice::ref_slice;
use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::middle::region::CodeExtent;
use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
use rustc::ty::{self, Ty, TyCtxt, Visibility}; use rustc::ty::{self, Ty, TyCtxt, Visibility};
use rustc::ty::{MethodCall, MethodCallee}; use rustc::ty::{MethodCall, MethodCallee};
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
@ -177,6 +177,14 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// variables to get the concrete type, which can be used to // variables to get the concrete type, which can be used to
// deanonymize TyAnon, after typeck is done with all functions. // deanonymize TyAnon, after typeck is done with all functions.
anon_types: RefCell<NodeMap<Ty<'tcx>>>, anon_types: RefCell<NodeMap<Ty<'tcx>>>,
/// Each type parameter has an implicit region bound that
/// indicates it must outlive at least the function body (the user
/// may specify stronger requirements). This field indicates the
/// region of the callee. If it is `None`, then the parameter
/// environment is for an item or something where the "callee" is
/// not clear.
implicit_region_bound: Option<ty::Region<'tcx>>,
} }
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
@ -523,16 +531,18 @@ impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> {
/// Necessary because we can't write the following bound: /// Necessary because we can't write the following bound:
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Inherited<'b, 'gcx, 'tcx>). /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Inherited<'b, 'gcx, 'tcx>).
pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx> infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx>,
def_id: DefId,
} }
impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId) pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId)
-> InheritedBuilder<'a, 'gcx, 'tcx> { -> InheritedBuilder<'a, 'gcx, 'tcx> {
let tables = ty::TypeckTables::empty(); let tables = ty::TypeckTables::empty();
let param_env = ParameterEnvironment::for_item(tcx, id); let param_env = tcx.parameter_environment(def_id);
InheritedBuilder { InheritedBuilder {
infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing) infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing),
def_id,
} }
} }
} }
@ -541,12 +551,20 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
fn enter<F, R>(&'tcx mut self, f: F) -> R fn enter<F, R>(&'tcx mut self, f: F) -> R
where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
{ {
self.infcx.enter(|infcx| f(Inherited::new(infcx))) let def_id = self.def_id;
self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
} }
} }
impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> Self {
let tcx = infcx.tcx;
let item_id = tcx.hir.as_local_node_id(def_id);
let body_id = item_id.and_then(|id| tcx.hir.maybe_body_owned_by(id));
let implicit_region_bound = body_id.map(|body| {
tcx.mk_region(ty::ReScope(CodeExtent::CallSiteScope(body)))
});
Inherited { Inherited {
infcx: infcx, infcx: infcx,
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
@ -554,6 +572,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()), deferred_cast_checks: RefCell::new(Vec::new()),
anon_types: RefCell::new(NodeMap()), anon_types: RefCell::new(NodeMap()),
implicit_region_bound,
} }
} }
@ -606,6 +625,22 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
obligations); obligations);
InferOk { value, obligations } InferOk { value, obligations }
} }
/// Replace any late-bound regions bound in `value` with
/// free variants attached to `all_outlive_scope`.
fn liberate_late_bound_regions<T>(&self,
all_outlive_scope: DefId,
value: &ty::Binder<T>)
-> T
where T: TypeFoldable<'tcx>
{
self.tcx.replace_late_bound_regions(value, |br| {
self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: all_outlive_scope,
bound_region: br
}))
}).0
}
} }
struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
@ -772,18 +807,15 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}); });
let body = tcx.hir.body(body_id); let body = tcx.hir.body(body_id);
Inherited::build(tcx, id).enter(|inh| { Inherited::build(tcx, def_id).enter(|inh| {
let fcx = if let Some(decl) = fn_decl { let fcx = if let Some(decl) = fn_decl {
let fn_sig = tcx.type_of(def_id).fn_sig(); let fn_sig = tcx.type_of(def_id).fn_sig();
check_abi(tcx, span, fn_sig.abi()); check_abi(tcx, span, fn_sig.abi());
// Compute the fty from point of view of inside fn. // Compute the fty from point of view of inside fn.
let fn_scope = inh.tcx.call_site_extent(id, body_id.node_id);
let fn_sig = let fn_sig =
fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs); inh.liberate_late_bound_regions(def_id, &fn_sig);
let fn_sig =
inh.tcx.liberate_late_bound_regions(Some(fn_scope), &fn_sig);
let fn_sig = let fn_sig =
inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig); inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
@ -1518,10 +1550,6 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
Some(&self.parameter_environment.free_substs)
}
fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
-> ty::GenericPredicates<'tcx> -> ty::GenericPredicates<'tcx>
{ {

View file

@ -87,7 +87,7 @@ use check::FnCtxt;
use middle::free_region::FreeRegionMap; use middle::free_region::FreeRegionMap;
use middle::mem_categorization as mc; use middle::mem_categorization as mc;
use middle::mem_categorization::Categorization; use middle::mem_categorization::Categorization;
use middle::region::{self, CodeExtent, RegionMaps}; use middle::region::{CodeExtent, RegionMaps};
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::traits; use rustc::traits;
@ -178,7 +178,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
pub region_maps: Rc<RegionMaps<'tcx>>, pub region_maps: Rc<RegionMaps>,
free_region_map: FreeRegionMap<'tcx>, free_region_map: FreeRegionMap<'tcx>,
@ -186,7 +186,7 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
body_id: ast::NodeId, body_id: ast::NodeId,
// call_site scope of innermost fn // call_site scope of innermost fn
call_site_scope: Option<CodeExtent<'tcx>>, call_site_scope: Option<CodeExtent>,
// id of innermost fn or loop // id of innermost fn or loop
repeating_scope: ast::NodeId, repeating_scope: ast::NodeId,
@ -224,8 +224,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
} }
} }
fn set_call_site_scope(&mut self, call_site_scope: Option<CodeExtent<'tcx>>) fn set_call_site_scope(&mut self, call_site_scope: Option<CodeExtent>)
-> Option<CodeExtent<'tcx>> { -> Option<CodeExtent> {
mem::replace(&mut self.call_site_scope, call_site_scope) mem::replace(&mut self.call_site_scope, call_site_scope)
} }
@ -286,8 +286,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
let body_id = body.id(); let body_id = body.id();
let call_site = self.tcx.intern_code_extent( let call_site = CodeExtent::CallSiteScope(body_id);
region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
let old_call_site_scope = self.set_call_site_scope(Some(call_site)); let old_call_site_scope = self.set_call_site_scope(Some(call_site));
let fn_sig = { let fn_sig = {
@ -312,7 +311,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
let old_body_id = self.set_body_id(body_id.node_id); let old_body_id = self.set_body_id(body_id.node_id);
self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span); self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span);
self.link_fn_args(self.tcx.node_extent(body_id.node_id), &body.arguments); self.link_fn_args(CodeExtent::Misc(body_id.node_id), &body.arguments);
self.visit_body(body); self.visit_body(body);
self.visit_region_obligations(body_id.node_id); self.visit_region_obligations(body_id.node_id);
@ -398,9 +397,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
for implication in implied_bounds { for implication in implied_bounds {
debug!("implication: {:?}", implication); debug!("implication: {:?}", implication);
match implication { match implication {
ImpliedBound::RegionSubRegion(&ty::ReFree(free_a), ImpliedBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_),
&ty::ReVar(vid_b)) |
ImpliedBound::RegionSubRegion(r_a @ &ty::ReFree(_),
&ty::ReVar(vid_b)) => { &ty::ReVar(vid_b)) => {
self.add_given(free_a, vid_b); self.add_given(r_a, vid_b);
} }
ImpliedBound::RegionSubParam(r_a, param_b) => { ImpliedBound::RegionSubParam(r_a, param_b) => {
self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); self.region_bound_pairs.push((r_a, GenericKind::Param(param_b)));
@ -876,7 +877,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
// call occurs. // call occurs.
// //
// FIXME(#6268) to support nested method calls, should be callee_id // FIXME(#6268) to support nested method calls, should be callee_id
let callee_scope = self.tcx.node_extent(call_expr.id); let callee_scope = CodeExtent::Misc(call_expr.id);
let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope)); let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
debug!("callee_region={:?}", callee_region); debug!("callee_region={:?}", callee_region);
@ -1029,7 +1030,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
debug!("constrain_index(index_expr=?, indexed_ty={}", debug!("constrain_index(index_expr=?, indexed_ty={}",
self.ty_to_string(indexed_ty)); self.ty_to_string(indexed_ty));
let r_index_expr = ty::ReScope(self.tcx.node_extent(index_expr.id)); let r_index_expr = ty::ReScope(CodeExtent::Misc(index_expr.id));
if let ty::TyRef(r_ptr, mt) = indexed_ty.sty { if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
match mt.ty.sty { match mt.ty.sty {
ty::TySlice(_) | ty::TyStr => { ty::TySlice(_) | ty::TyStr => {
@ -1109,7 +1110,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
/// Computes the guarantors for any ref bindings in a match and /// Computes the guarantors for any ref bindings in a match and
/// then ensures that the lifetime of the resulting pointer is /// then ensures that the lifetime of the resulting pointer is
/// linked to the lifetime of its guarantor (if any). /// linked to the lifetime of its guarantor (if any).
fn link_fn_args(&self, body_scope: CodeExtent<'tcx>, args: &[hir::Arg]) { fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
debug!("regionck::link_fn_args(body_scope={:?})", body_scope); debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
let mc = &mc::MemCategorizationContext::new(self, &self.region_maps); let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
for arg in args { for arg in args {
@ -1175,7 +1176,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
/// must outlive `callee_scope`. /// must outlive `callee_scope`.
fn link_by_ref(&self, fn link_by_ref(&self,
expr: &hir::Expr, expr: &hir::Expr,
callee_scope: CodeExtent<'tcx>) { callee_scope: CodeExtent) {
debug!("link_by_ref(expr={:?}, callee_scope={:?})", debug!("link_by_ref(expr={:?}, callee_scope={:?})",
expr, callee_scope); expr, callee_scope);
let mc = mc::MemCategorizationContext::new(self, &self.region_maps); let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
@ -1613,8 +1614,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
} }
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
let param_env = &self.parameter_environment;
debug!("param_bound(param_ty={:?})", debug!("param_bound(param_ty={:?})",
param_ty); param_ty);
@ -1622,7 +1621,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
// Add in the default bound of fn body that applies to all in // Add in the default bound of fn body that applies to all in
// scope type parameters: // scope type parameters:
param_bounds.extend(param_env.implicit_region_bound); param_bounds.extend(self.implicit_region_bound);
VerifyBound::AnyRegion(param_bounds) VerifyBound::AnyRegion(param_bounds)
} }
@ -1667,7 +1666,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
} }
let mut regions = ty.regions(); let mut regions = ty.regions();
regions.retain(|r| !r.is_bound()); // ignore late-bound regions regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
bounds.push(VerifyBound::AllRegions(regions)); bounds.push(VerifyBound::AllRegions(regions));
// remove bounds that must hold, since they are not interesting // remove bounds that must hold, since they are not interesting

View file

@ -13,7 +13,6 @@ use check::{Inherited, FnCtxt};
use constrained_type_params::{identify_constrained_type_params, Parameter}; use constrained_type_params::{identify_constrained_type_params, Parameter};
use hir::def_id::DefId; use hir::def_id::DefId;
use middle::region::{CodeExtent};
use rustc::traits::{self, ObligationCauseCode}; use rustc::traits::{self, ObligationCauseCode};
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::util::nodemap::{FxHashSet, FxHashMap};
@ -117,8 +116,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
error_192(tcx, item.span); error_192(tcx, item.span);
} }
} }
hir::ItemFn(.., body_id) => { hir::ItemFn(..) => {
self.check_item_fn(item, body_id); self.check_item_fn(item);
} }
hir::ItemStatic(..) => { hir::ItemStatic(..) => {
self.check_item_type(item); self.check_item_type(item);
@ -160,9 +159,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
sig_if_method: Option<&hir::MethodSig>) { sig_if_method: Option<&hir::MethodSig>) {
let code = self.code.clone(); let code = self.code.clone();
self.for_id(item_id, span).with_fcx(|fcx, this| { self.for_id(item_id, span).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
let free_id_outlive = fcx.parameter_environment.free_id_outlive;
let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id)); let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id));
let (mut implied_bounds, self_ty) = match item.container { let (mut implied_bounds, self_ty) = match item.container {
@ -174,25 +170,26 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
match item.kind { match item.kind {
ty::AssociatedKind::Const => { ty::AssociatedKind::Const => {
let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.tcx.type_of(item.def_id);
let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); let ty = fcx.normalize_associated_types_in(span, &ty);
fcx.register_wf_obligation(ty, span, code.clone()); fcx.register_wf_obligation(ty, span, code.clone());
} }
ty::AssociatedKind::Method => { ty::AssociatedKind::Method => {
reject_shadowing_type_parameters(fcx.tcx, item.def_id); reject_shadowing_type_parameters(fcx.tcx, item.def_id);
let method_ty = fcx.tcx.type_of(item.def_id); let method_ty = fcx.tcx.type_of(item.def_id);
let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let method_ty = fcx.normalize_associated_types_in(span, &method_ty);
let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); let predicates = fcx.tcx.predicates_of(item.def_id)
.instantiate_identity(fcx.tcx);
let predicates = fcx.normalize_associated_types_in(span, &predicates);
let sig = method_ty.fn_sig(); let sig = method_ty.fn_sig();
this.check_fn_or_method(fcx, span, sig, &predicates, this.check_fn_or_method(fcx, span, sig, &predicates,
free_id_outlive, &mut implied_bounds); item.def_id, &mut implied_bounds);
let sig_if_method = sig_if_method.expect("bad signature for method"); let sig_if_method = sig_if_method.expect("bad signature for method");
this.check_method_receiver(fcx, sig_if_method, &item, this.check_method_receiver(fcx, sig_if_method, &item, self_ty);
free_id_outlive, self_ty);
} }
ty::AssociatedKind::Type => { ty::AssociatedKind::Type => {
if item.defaultness.has_value() { if item.defaultness.has_value() {
let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.tcx.type_of(item.def_id);
let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); let ty = fcx.normalize_associated_types_in(span, &ty);
fcx.register_wf_obligation(ty, span, code.clone()); fcx.register_wf_obligation(ty, span, code.clone());
} }
} }
@ -210,7 +207,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
fn for_id<'tcx>(&self, id: ast::NodeId, span: Span) fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
-> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
CheckWfFcxBuilder { CheckWfFcxBuilder {
inherited: Inherited::build(self.tcx, id), inherited: Inherited::build(self.tcx, self.tcx.hir.local_def_id(id)),
code: self.code.clone(), code: self.code.clone(),
id: id, id: id,
span: span span: span
@ -242,9 +239,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
} }
} }
let free_substs = &fcx.parameter_environment.free_substs;
let def_id = fcx.tcx.hir.local_def_id(item.id); let def_id = fcx.tcx.hir.local_def_id(item.id);
let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs); let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
this.check_where_clauses(fcx, item.span, &predicates); this.check_where_clauses(fcx, item.span, &predicates);
vec![] // no implied bounds in a struct def'n vec![] // no implied bounds in a struct def'n
@ -320,30 +317,26 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
} }
self.for_item(item).with_fcx(|fcx, this| { self.for_item(item).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs; let predicates = fcx.tcx.predicates_of(trait_def_id).instantiate_identity(fcx.tcx);
let predicates = fcx.instantiate_bounds(item.span, trait_def_id, free_substs); let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
this.check_where_clauses(fcx, item.span, &predicates); this.check_where_clauses(fcx, item.span, &predicates);
vec![] vec![]
}); });
} }
fn check_item_fn(&mut self, fn check_item_fn(&mut self, item: &hir::Item) {
item: &hir::Item,
body_id: hir::BodyId)
{
self.for_item(item).with_fcx(|fcx, this| { self.for_item(item).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
let def_id = fcx.tcx.hir.local_def_id(item.id); let def_id = fcx.tcx.hir.local_def_id(item.id);
let ty = fcx.tcx.type_of(def_id); let ty = fcx.tcx.type_of(def_id);
let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty); let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
let sig = item_ty.fn_sig(); let sig = item_ty.fn_sig();
let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs); let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
let mut implied_bounds = vec![]; let mut implied_bounds = vec![];
let free_id_outlive = fcx.tcx.call_site_extent(item.id, body_id.node_id);
this.check_fn_or_method(fcx, item.span, sig, &predicates, this.check_fn_or_method(fcx, item.span, sig, &predicates,
Some(free_id_outlive), &mut implied_bounds); def_id, &mut implied_bounds);
implied_bounds implied_bounds
}) })
} }
@ -355,10 +348,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
self.for_item(item).with_fcx(|fcx, this| { self.for_item(item).with_fcx(|fcx, this| {
let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id)); let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
let item_ty = fcx.instantiate_type_scheme(item.span, let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
&fcx.parameter_environment
.free_substs,
&ty);
fcx.register_wf_obligation(item_ty, item.span, this.code.clone()); fcx.register_wf_obligation(item_ty, item.span, this.code.clone());
@ -374,15 +364,14 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
debug!("check_impl: {:?}", item); debug!("check_impl: {:?}", item);
self.for_item(item).with_fcx(|fcx, this| { self.for_item(item).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
let item_def_id = fcx.tcx.hir.local_def_id(item.id); let item_def_id = fcx.tcx.hir.local_def_id(item.id);
match *ast_trait_ref { match *ast_trait_ref {
Some(ref ast_trait_ref) => { Some(ref ast_trait_ref) => {
let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
let trait_ref = let trait_ref =
fcx.instantiate_type_scheme( fcx.normalize_associated_types_in(
ast_trait_ref.path.span, free_substs, &trait_ref); ast_trait_ref.path.span, &trait_ref);
let obligations = let obligations =
ty::wf::trait_obligations(fcx, ty::wf::trait_obligations(fcx,
fcx.body_id, fcx.body_id,
@ -394,12 +383,13 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
} }
None => { None => {
let self_ty = fcx.tcx.type_of(item_def_id); let self_ty = fcx.tcx.type_of(item_def_id);
let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty); let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty);
fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone());
} }
} }
let predicates = fcx.instantiate_bounds(item.span, item_def_id, free_substs); let predicates = fcx.tcx.predicates_of(item_def_id).instantiate_identity(fcx.tcx);
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
this.check_where_clauses(fcx, item.span, &predicates); this.check_where_clauses(fcx, item.span, &predicates);
fcx.impl_implied_bounds(item_def_id, item.span) fcx.impl_implied_bounds(item_def_id, item.span)
@ -429,12 +419,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
span: Span, span: Span,
sig: ty::PolyFnSig<'tcx>, sig: ty::PolyFnSig<'tcx>,
predicates: &ty::InstantiatedPredicates<'tcx>, predicates: &ty::InstantiatedPredicates<'tcx>,
free_id_outlive: Option<CodeExtent<'tcx>>, def_id: DefId,
implied_bounds: &mut Vec<Ty<'tcx>>) implied_bounds: &mut Vec<Ty<'tcx>>)
{ {
let free_substs = &fcx.parameter_environment.free_substs; let sig = fcx.normalize_associated_types_in(span, &sig);
let sig = fcx.instantiate_type_scheme(span, free_substs, &sig); let sig = fcx.liberate_late_bound_regions(def_id, &sig);
let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &sig);
for input_ty in sig.inputs() { for input_ty in sig.inputs() {
fcx.register_wf_obligation(&input_ty, span, self.code.clone()); fcx.register_wf_obligation(&input_ty, span, self.code.clone());
@ -453,7 +442,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
method_sig: &hir::MethodSig, method_sig: &hir::MethodSig,
method: &ty::AssociatedItem, method: &ty::AssociatedItem,
free_id_outlive: Option<CodeExtent<'tcx>>,
self_ty: ty::Ty<'tcx>) self_ty: ty::Ty<'tcx>)
{ {
// check that the type of the method's receiver matches the // check that the type of the method's receiver matches the
@ -467,10 +455,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
let span = method_sig.decl.inputs[0].span; let span = method_sig.decl.inputs[0].span;
let free_substs = &fcx.parameter_environment.free_substs;
let method_ty = fcx.tcx.type_of(method.def_id); let method_ty = fcx.tcx.type_of(method.def_id);
let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let fty = fcx.normalize_associated_types_in(span, &method_ty);
let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig()); let sig = fcx.liberate_late_bound_regions(method.def_id, &fty.fn_sig());
debug!("check_method_receiver: sig={:?}", sig); debug!("check_method_receiver: sig={:?}", sig);
@ -485,8 +472,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
} }
ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty) ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty)
}; };
let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty); let rcvr_ty = fcx.normalize_associated_types_in(span, &rcvr_ty);
let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive, let rcvr_ty = fcx.liberate_late_bound_regions(method.def_id,
&ty::Binder(rcvr_ty)); &ty::Binder(rcvr_ty));
debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
@ -632,9 +619,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
struct_def.fields().iter() struct_def.fields().iter()
.map(|field| { .map(|field| {
let field_ty = self.tcx.type_of(self.tcx.hir.local_def_id(field.id)); let field_ty = self.tcx.type_of(self.tcx.hir.local_def_id(field.id));
let field_ty = self.instantiate_type_scheme(field.span, let field_ty = self.normalize_associated_types_in(field.span,
&self.parameter_environment
.free_substs,
&field_ty); &field_ty);
AdtField { ty: field_ty, span: field.span } AdtField { ty: field_ty, span: field.span }
}) })
@ -649,19 +634,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> { fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
let free_substs = &self.parameter_environment.free_substs;
match self.tcx.impl_trait_ref(impl_def_id) { match self.tcx.impl_trait_ref(impl_def_id) {
Some(ref trait_ref) => { Some(ref trait_ref) => {
// Trait impl: take implied bounds from all types that // Trait impl: take implied bounds from all types that
// appear in the trait reference. // appear in the trait reference.
let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref); let trait_ref = self.normalize_associated_types_in(span, trait_ref);
trait_ref.substs.types().collect() trait_ref.substs.types().collect()
} }
None => { None => {
// Inherent impl: take implied bounds from the self type. // Inherent impl: take implied bounds from the self type.
let self_ty = self.tcx.type_of(impl_def_id); let self_ty = self.tcx.type_of(impl_def_id);
let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty); let self_ty = self.normalize_associated_types_in(span, &self_ty);
vec![self_ty] vec![self_ty]
} }
} }

View file

@ -19,7 +19,7 @@ use rustc::infer::{InferCtxt};
use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
use rustc::ty::adjustment; use rustc::ty::adjustment;
use rustc::ty::fold::{TypeFolder,TypeFoldable}; use rustc::ty::fold::{TypeFolder,TypeFoldable};
use rustc::util::nodemap::{DefIdMap, DefIdSet}; use rustc::util::nodemap::DefIdSet;
use syntax::ast; use syntax::ast;
use syntax_pos::Span; use syntax_pos::Span;
use std::mem; use std::mem;
@ -71,55 +71,17 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
tables: ty::TypeckTables<'gcx>, tables: ty::TypeckTables<'gcx>,
// Mapping from free regions of the function to the
// early-bound versions of them, visible from the
// outside of the function. This is needed by, and
// only populated if there are any `impl Trait`.
free_to_bound_regions: DefIdMap<ty::Region<'gcx>>,
body: &'gcx hir::Body, body: &'gcx hir::Body,
} }
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body) fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body)
-> WritebackCx<'cx, 'gcx, 'tcx> { -> WritebackCx<'cx, 'gcx, 'tcx> {
let mut wbcx = WritebackCx { WritebackCx {
fcx: fcx, fcx: fcx,
tables: ty::TypeckTables::empty(), tables: ty::TypeckTables::empty(),
free_to_bound_regions: DefIdMap(),
body: body body: body
};
// Only build the reverse mapping if `impl Trait` is used.
if fcx.anon_types.borrow().is_empty() {
return wbcx;
} }
let gcx = fcx.tcx.global_tcx();
let free_substs = fcx.parameter_environment.free_substs;
for (i, k) in free_substs.iter().enumerate() {
let r = if let Some(r) = k.as_region() {
r
} else {
continue;
};
match *r {
ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegion::BrNamed(def_id, name), ..
}) => {
let bound_region = gcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
index: i as u32,
name: name,
}));
wbcx.free_to_bound_regions.insert(def_id, bound_region);
}
_ => {
bug!("{:?} is not a free region for an early-bound lifetime", r);
}
}
}
wbcx
} }
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> { fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
@ -285,22 +247,16 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
let inside_ty = self.resolve(&concrete_ty, &node_id); let inside_ty = self.resolve(&concrete_ty, &node_id);
// Convert the type from the function into a type valid outside // Convert the type from the function into a type valid outside
// the function, by replacing free regions with early-bound ones. // the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| { let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
match *r { match *r {
// 'static is valid everywhere. // 'static and early-bound regions are valid.
ty::ReStatic => gcx.types.re_static, ty::ReStatic |
ty::ReEmpty => gcx.types.re_empty, ty::ReEarlyBound(_) |
ty::ReEmpty => r,
// Free regions that come from early-bound regions are valid.
ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegion::BrNamed(def_id, ..), ..
}) if self.free_to_bound_regions.contains_key(&def_id) => {
self.free_to_bound_regions[&def_id]
}
ty::ReFree(_) | ty::ReFree(_) |
ty::ReEarlyBound(_) |
ty::ReLateBound(..) | ty::ReLateBound(..) |
ty::ReScope(_) | ty::ReScope(_) |
ty::ReSkolemized(..) => { ty::ReSkolemized(..) => {

View file

@ -17,10 +17,8 @@ use rustc::middle::lang_items::UnsizeTraitLangItem;
use rustc::traits::{self, ObligationCause, Reveal}; use rustc::traits::{self, ObligationCause, Reveal};
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::ParameterEnvironment;
use rustc::ty::TypeFoldable; use rustc::ty::TypeFoldable;
use rustc::ty::adjustment::CoerceUnsizedInfo; use rustc::ty::adjustment::CoerceUnsizedInfo;
use rustc::ty::subst::Subst;
use rustc::ty::util::CopyImplementationError; use rustc::ty::util::CopyImplementationError;
use rustc::infer; use rustc::infer;
@ -107,8 +105,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
self_type); self_type);
let span = tcx.hir.span(impl_node_id); let span = tcx.hir.span(impl_node_id);
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id); let param_env = tcx.parameter_environment(impl_did);
let self_type = self_type.subst(tcx, &param_env.free_substs);
assert!(!self_type.has_escaping_regions()); assert!(!self_type.has_escaping_regions());
debug!("visit_implementation_of_copy: self_type={:?} (free)", debug!("visit_implementation_of_copy: self_type={:?} (free)",
@ -202,9 +199,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
target); target);
let span = tcx.hir.span(impl_node_id); let span = tcx.hir.span(impl_node_id);
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id); let param_env = tcx.parameter_environment(impl_did);
let source = source.subst(tcx, &param_env.free_substs);
let target = target.subst(tcx, &param_env.free_substs);
assert!(!source.has_escaping_regions()); assert!(!source.has_escaping_regions());
let err_info = CoerceUnsizedInfo { custom_kind: None }; let err_info = CoerceUnsizedInfo { custom_kind: None };

View file

@ -205,10 +205,6 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id)) self.tcx.at(span).type_param_predicates((self.item_def_id, def_id))
} }
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
None
}
fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>) fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>)
-> Option<ty::Region<'tcx>> { -> Option<ty::Region<'tcx>> {
None None
@ -1299,6 +1295,7 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let mut index = parent_count + has_own_self as u32; let mut index = parent_count + has_own_self as u32;
for param in early_bound_lifetimes_from_generics(tcx, ast_generics) { for param in early_bound_lifetimes_from_generics(tcx, ast_generics) {
let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: tcx.hir.local_def_id(param.lifetime.id),
index: index, index: index,
name: param.lifetime.name name: param.lifetime.name
})); }));

View file

@ -820,7 +820,7 @@ impl Clean<Lifetime> for ty::RegionParameterDef {
} }
} }
impl<'tcx> Clean<Option<Lifetime>> for ty::RegionKind<'tcx> { impl Clean<Option<Lifetime>> for ty::RegionKind {
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()),

View file

@ -11,17 +11,18 @@
pub trait Resources<'a> {} pub trait Resources<'a> {}
pub trait Buffer<'a, R: Resources<'a>> { pub trait Buffer<'a, R: Resources<'a>> {
//~^ NOTE the lifetime 'a as defined on the trait at 13:0...
//~| NOTE ...does not necessarily outlive the lifetime 'a as defined on the trait
fn select(&self) -> BufferViewHandle<R>; fn select(&self) -> BufferViewHandle<R>;
//~^ ERROR mismatched types //~^ ERROR mismatched types
//~| lifetime mismatch //~| lifetime mismatch
//~| NOTE expected type `Resources<'_>` //~| NOTE expected type `Resources<'_>`
//~| NOTE the lifetime 'a as defined on the method body at 14:4...
//~| NOTE ...does not necessarily outlive the anonymous lifetime #1 defined on the method body //~| NOTE ...does not necessarily outlive the anonymous lifetime #1 defined on the method body
//~| ERROR mismatched types //~| ERROR mismatched types
//~| lifetime mismatch //~| lifetime mismatch
//~| NOTE expected type `Resources<'_>` //~| NOTE expected type `Resources<'_>`
//~| NOTE the anonymous lifetime #1 defined on the method body at 14:4... //~| NOTE the anonymous lifetime #1 defined on the method body at 17:4...
//~| NOTE ...does not necessarily outlive the lifetime 'a as defined on the method body
} }
pub struct BufferViewHandle<'a, R: 'a+Resources<'a>>(&'a R); pub struct BufferViewHandle<'a, R: 'a+Resources<'a>>(&'a R);

View file

@ -11,14 +11,15 @@
struct RepeatMut<'a, T>(T, &'a ()); struct RepeatMut<'a, T>(T, &'a ());
impl<'a, T: 'a> Iterator for RepeatMut<'a, T> { impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
//~^ NOTE ...does not necessarily outlive the lifetime 'a as defined on the impl
type Item = &'a mut T; type Item = &'a mut T;
fn next(&'a mut self) -> Option<Self::Item> fn next(&'a mut self) -> Option<Self::Item>
//~^ ERROR method not compatible with trait //~^ ERROR method not compatible with trait
//~| lifetime mismatch //~| lifetime mismatch
//~| NOTE expected type `fn(&mut RepeatMut<'a, T>) -> std::option::Option<&mut T>` //~| NOTE expected type `fn(&mut RepeatMut<'a, T>) -> std::option::Option<&mut T>`
//~| NOTE the anonymous lifetime #1 defined on the method body
{ {
//~^ NOTE the anonymous lifetime #1 defined on the body
//~| NOTE ...does not necessarily outlive the lifetime 'a as defined on the body
Some(&mut self.0) Some(&mut self.0)
} }
} }

View file

@ -4,19 +4,17 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
12 | if x > y { x } else { y } 12 | if x > y { x } else { y }
| ^ | ^
| |
note: ...the reference is valid for the lifetime 'a as defined on the body at 11:43... note: ...the reference is valid for the lifetime 'a as defined on the function body at 11:0...
--> $DIR/ex1-return-one-existing-name-if-else.rs:11:44 --> $DIR/ex1-return-one-existing-name-if-else.rs:11:1
| |
11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { 11 | / fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
| ____________________________________________^
12 | | if x > y { x } else { y } 12 | | if x > y { x } else { y }
13 | | } 13 | | }
| |_^ | |_^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the body at 11:43 note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the function body at 11:0
--> $DIR/ex1-return-one-existing-name-if-else.rs:11:44 --> $DIR/ex1-return-one-existing-name-if-else.rs:11:1
| |
11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { 11 | / fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
| ____________________________________________^
12 | | if x > y { x } else { y } 12 | | if x > y { x } else { y }
13 | | } 13 | | }
| |_^ | |_^

View file

@ -6,19 +6,17 @@ error[E0308]: mismatched types
| |
= note: expected type `Ref<'a, _>` = note: expected type `Ref<'a, _>`
found type `Ref<'_, _>` found type `Ref<'_, _>`
note: the anonymous lifetime #2 defined on the body at 15:51... note: the anonymous lifetime #2 defined on the function body at 15:0...
--> $DIR/ex2a-push-one-existing-name.rs:15:52 --> $DIR/ex2a-push-one-existing-name.rs:15:1
| |
15 | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) { 15 | / fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
| ____________________________________________________^
16 | | x.push(y); 16 | | x.push(y);
17 | | } 17 | | }
| |_^ | |_^
note: ...does not necessarily outlive the lifetime 'a as defined on the body at 15:51 note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 15:0
--> $DIR/ex2a-push-one-existing-name.rs:15:52 --> $DIR/ex2a-push-one-existing-name.rs:15:1
| |
15 | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) { 15 | / fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
| ____________________________________________________^
16 | | x.push(y); 16 | | x.push(y);
17 | | } 17 | | }
| |_^ | |_^

View file

@ -6,19 +6,17 @@ error[E0308]: mismatched types
| |
= note: expected type `Ref<'_, _>` = note: expected type `Ref<'_, _>`
found type `Ref<'_, _>` found type `Ref<'_, _>`
note: the anonymous lifetime #3 defined on the body at 15:43... note: the anonymous lifetime #3 defined on the function body at 15:0...
--> $DIR/ex2b-push-no-existing-names.rs:15:44 --> $DIR/ex2b-push-no-existing-names.rs:15:1
| |
15 | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) { 15 | / fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
| ____________________________________________^
16 | | x.push(y); 16 | | x.push(y);
17 | | } 17 | | }
| |_^ | |_^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 15:43 note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 15:0
--> $DIR/ex2b-push-no-existing-names.rs:15:44 --> $DIR/ex2b-push-no-existing-names.rs:15:1
| |
15 | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) { 15 | / fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
| ____________________________________________^
16 | | x.push(y); 16 | | x.push(y);
17 | | } 17 | | }
| |_^ | |_^

View file

@ -4,11 +4,10 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
16 | let z = Ref { data: y.data }; 16 | let z = Ref { data: y.data };
| ^^^ | ^^^
| |
note: first, the lifetime cannot outlive the lifetime 'c as defined on the body at 15:66... note: first, the lifetime cannot outlive the lifetime 'c as defined on the function body at 15:0...
--> $DIR/ex2c-push-inference-variable.rs:15:67 --> $DIR/ex2c-push-inference-variable.rs:15:1
| |
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { 15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
| ___________________________________________________________________^
16 | | let z = Ref { data: y.data }; 16 | | let z = Ref { data: y.data };
17 | | x.push(z); 17 | | x.push(z);
18 | | } 18 | | }
@ -18,11 +17,10 @@ note: ...so that reference does not outlive borrowed content
| |
16 | let z = Ref { data: y.data }; 16 | let z = Ref { data: y.data };
| ^^^^^^ | ^^^^^^
note: but, the lifetime must be valid for the lifetime 'b as defined on the body at 15:66... note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 15:0...
--> $DIR/ex2c-push-inference-variable.rs:15:67 --> $DIR/ex2c-push-inference-variable.rs:15:1
| |
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { 15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
| ___________________________________________________________________^
16 | | let z = Ref { data: y.data }; 16 | | let z = Ref { data: y.data };
17 | | x.push(z); 17 | | x.push(z);
18 | | } 18 | | }

View file

@ -4,11 +4,10 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
17 | let b = Ref { data: y.data }; 17 | let b = Ref { data: y.data };
| ^^^ | ^^^
| |
note: first, the lifetime cannot outlive the lifetime 'c as defined on the body at 15:66... note: first, the lifetime cannot outlive the lifetime 'c as defined on the function body at 15:0...
--> $DIR/ex2d-push-inference-variable-2.rs:15:67 --> $DIR/ex2d-push-inference-variable-2.rs:15:1
| |
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { 15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
| ___________________________________________________________________^
16 | | let a: &mut Vec<Ref<i32>> = x; 16 | | let a: &mut Vec<Ref<i32>> = x;
17 | | let b = Ref { data: y.data }; 17 | | let b = Ref { data: y.data };
18 | | a.push(b); 18 | | a.push(b);
@ -19,11 +18,10 @@ note: ...so that reference does not outlive borrowed content
| |
17 | let b = Ref { data: y.data }; 17 | let b = Ref { data: y.data };
| ^^^^^^ | ^^^^^^
note: but, the lifetime must be valid for the lifetime 'b as defined on the body at 15:66... note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 15:0...
--> $DIR/ex2d-push-inference-variable-2.rs:15:67 --> $DIR/ex2d-push-inference-variable-2.rs:15:1
| |
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { 15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
| ___________________________________________________________________^
16 | | let a: &mut Vec<Ref<i32>> = x; 16 | | let a: &mut Vec<Ref<i32>> = x;
17 | | let b = Ref { data: y.data }; 17 | | let b = Ref { data: y.data };
18 | | a.push(b); 18 | | a.push(b);

View file

@ -4,11 +4,10 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
17 | let b = Ref { data: y.data }; 17 | let b = Ref { data: y.data };
| ^^^ | ^^^
| |
note: first, the lifetime cannot outlive the lifetime 'c as defined on the body at 15:66... note: first, the lifetime cannot outlive the lifetime 'c as defined on the function body at 15:0...
--> $DIR/ex2e-push-inference-variable-3.rs:15:67 --> $DIR/ex2e-push-inference-variable-3.rs:15:1
| |
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { 15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
| ___________________________________________________________________^
16 | | let a: &mut Vec<Ref<i32>> = x; 16 | | let a: &mut Vec<Ref<i32>> = x;
17 | | let b = Ref { data: y.data }; 17 | | let b = Ref { data: y.data };
18 | | Vec::push(a, b); 18 | | Vec::push(a, b);
@ -19,11 +18,10 @@ note: ...so that reference does not outlive borrowed content
| |
17 | let b = Ref { data: y.data }; 17 | let b = Ref { data: y.data };
| ^^^^^^ | ^^^^^^
note: but, the lifetime must be valid for the lifetime 'b as defined on the body at 15:66... note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 15:0...
--> $DIR/ex2e-push-inference-variable-3.rs:15:67 --> $DIR/ex2e-push-inference-variable-3.rs:15:1
| |
15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { 15 | / fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
| ___________________________________________________________________^
16 | | let a: &mut Vec<Ref<i32>> = x; 16 | | let a: &mut Vec<Ref<i32>> = x;
17 | | let b = Ref { data: y.data }; 17 | | let b = Ref { data: y.data };
18 | | Vec::push(a, b); 18 | | Vec::push(a, b);