Move the list of region obligations into the fulfillment context.

This commit is contained in:
Niko Matsakis 2014-12-05 02:57:17 -05:00
parent 9bdd7f0040
commit 70be49d2c7
4 changed files with 83 additions and 67 deletions

View file

@ -9,11 +9,15 @@
// except according to those terms.
use middle::mem_categorization::Typer;
use middle::ty;
use middle::infer::InferCtxt;
use middle::ty::{mod, Ty};
use middle::infer::{mod, InferCtxt};
use std::collections::HashSet;
use std::collections::hash_map::{Occupied, Vacant};
use std::default::Default;
use std::rc::Rc;
use syntax::ast;
use util::ppaux::Repr;
use util::nodemap::NodeMap;
use super::CodeAmbiguity;
use super::TraitObligation;
@ -47,6 +51,38 @@ pub struct FulfillmentContext<'tcx> {
// attempted to select. This is used to avoid repeating work
// when `select_new_obligations` is called.
attempted_mark: uint,
// A set of constraints that regionck must validate. Each
// constraint has the form `T:'a`, meaning "some type `T` must
// outlive the lifetime 'a". These constraints derive from
// instantiated type parameters. So if you had a struct defined
// like
//
// struct Foo<T:'static> { ... }
//
// then in some expression `let x = Foo { ... }` it will
// instantiate the type parameter `T` with a fresh type `$0`. At
// the same time, it will record a region obligation of
// `$0:'static`. This will get checked later by regionck. (We
// can't generally check these things right away because we have
// to wait until types are resolved.)
//
// These are stored in a map keyed to the id of the innermost
// enclosing fn body / static initializer expression. This is
// because the location where the obligation was incurred can be
// relevant with respect to which sublifetime assumptions are in
// place. The reason that we store under the fn-id, and not
// something more fine-grained, is so that it is easier for
// regionck to be sure that it has found *all* the region
// obligations (otherwise, it's easy to fail to walk to a
// particular node-id).
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
}
pub struct RegionObligation<'tcx> {
pub sub_region: ty::Region,
pub sup_type: Ty<'tcx>,
pub origin: infer::SubregionOrigin<'tcx>,
}
impl<'tcx> FulfillmentContext<'tcx> {
@ -55,6 +91,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
duplicate_set: HashSet::new(),
trait_obligations: Vec::new(),
attempted_mark: 0,
region_obligations: NodeMap::new(),
}
}
@ -71,6 +108,26 @@ impl<'tcx> FulfillmentContext<'tcx> {
}
}
pub fn register_region_obligation(&mut self,
body_id: ast::NodeId,
region_obligation: RegionObligation<'tcx>)
{
match self.region_obligations.entry(body_id) {
Vacant(entry) => { entry.set(vec![region_obligation]); },
Occupied(mut entry) => { entry.get_mut().push(region_obligation); },
}
}
pub fn region_obligations(&self,
body_id: ast::NodeId)
-> &[RegionObligation<'tcx>]
{
match self.region_obligations.get(&body_id) {
None => Default::default(),
Some(vec) => vec.as_slice(),
}
}
pub fn select_all_or_error<'a>(&mut self,
infcx: &InferCtxt<'a,'tcx>,
param_env: &ty::ParameterEnvironment<'tcx>,
@ -208,3 +265,12 @@ impl<'tcx> FulfillmentContext<'tcx> {
}
}
}
impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("RegionObligation(sub_region={}, sup_type={}, origin={})",
self.sub_region.repr(tcx),
self.sup_type.repr(tcx),
self.origin.repr(tcx))
}
}

View file

@ -25,7 +25,7 @@ use syntax::ast;
use syntax::codemap::{Span, DUMMY_SP};
use util::common::ErrorReported;
pub use self::fulfill::FulfillmentContext;
pub use self::fulfill::{FulfillmentContext, RegionObligation};
pub use self::select::SelectionContext;
pub use self::select::SelectionCache;
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};

View file

@ -84,13 +84,14 @@ use self::TupleArgumentsFlag::*;
use astconv::{mod, ast_region_to_region, ast_ty_to_ty, AstConv};
use check::_match::pat_ctxt;
use middle::{const_eval, def, traits};
use middle::{const_eval, def};
use middle::infer;
use middle::lang_items::IteratorItem;
use middle::mem_categorization::{mod, McResult};
use middle::pat_util::{mod, pat_id_map};
use middle::region::CodeExtent;
use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace};
use middle::traits;
use middle::ty::{FnSig, VariantInfo, Polytype};
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
use middle::ty::{mod, Ty};
@ -108,7 +109,6 @@ use util::ppaux::{mod, UserString, Repr};
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
use std::cell::{Cell, Ref, RefCell};
use std::collections::hash_map::{Occupied, Vacant};
use std::mem::replace;
use std::rc::Rc;
use syntax::{mod, abi, attr};
@ -161,42 +161,10 @@ pub struct Inherited<'a, 'tcx: 'a> {
// one is never copied into the tcx: it is only used by regionck.
fn_sig_map: RefCell<NodeMap<Vec<Ty<'tcx>>>>,
// A set of constraints that regionck must validate. Each
// constraint has the form `T:'a`, meaning "some type `T` must
// outlive the lifetime 'a". These constraints derive from
// instantiated type parameters. So if you had a struct defined
// like
//
// struct Foo<T:'static> { ... }
//
// then in some expression `let x = Foo { ... }` it will
// instantiate the type parameter `T` with a fresh type `$0`. At
// the same time, it will record a region obligation of
// `$0:'static`. This will get checked later by regionck. (We
// can't generally check these things right away because we have
// to wait until types are resolved.)
//
// These are stored in a map keyed to the id of the innermost
// enclosing fn body / static initializer expression. This is
// because the location where the obligation was incurred can be
// relevant with respect to which sublifetime assumptions are in
// place. The reason that we store under the fn-id, and not
// something more fine-grained, is so that it is easier for
// regionck to be sure that it has found *all* the region
// obligations (otherwise, it's easy to fail to walk to a
// particular node-id).
region_obligations: RefCell<NodeMap<Vec<RegionObligation<'tcx>>>>,
// Tracks trait obligations incurred during this function body.
fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
}
struct RegionObligation<'tcx> {
sub_region: ty::Region,
sup_type: Ty<'tcx>,
origin: infer::SubregionOrigin<'tcx>,
}
/// When type-checking an expression, we propagate downward
/// whatever type hint we are able in the form of an `Expectation`.
enum Expectation<'tcx> {
@ -328,7 +296,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
upvar_borrow_map: RefCell::new(FnvHashMap::new()),
unboxed_closures: RefCell::new(DefIdMap::new()),
fn_sig_map: RefCell::new(NodeMap::new()),
region_obligations: RefCell::new(NodeMap::new()),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
}
}
@ -1988,15 +1955,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
r: ty::Region)
{
let mut region_obligations = self.inh.region_obligations.borrow_mut();
let region_obligation = RegionObligation { sub_region: r,
sup_type: ty,
origin: origin };
match region_obligations.entry(self.body_id) {
Vacant(entry) => { entry.set(vec![region_obligation]); },
Occupied(mut entry) => { entry.get_mut().push(region_obligation); },
}
let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
let region_obligation = traits::RegionObligation { sub_region: r,
sup_type: ty,
origin: origin };
fulfillment_cx.register_region_obligation(self.body_id, region_obligation);
}
pub fn add_default_region_param_bounds(&self,
@ -5833,11 +5796,3 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
}
}
impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("RegionObligation(sub_region={}, sup_type={}, origin={})",
self.sub_region.repr(tcx),
self.sup_type.repr(tcx),
self.origin.repr(tcx))
}
}

View file

@ -353,18 +353,13 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
fn visit_region_obligations(&mut self, node_id: ast::NodeId)
{
debug!("visit_region_obligations: node_id={}", node_id);
let region_obligations = self.fcx.inh.region_obligations.borrow();
match region_obligations.get(&node_id) {
None => { }
Some(vec) => {
for r_o in vec.iter() {
debug!("visit_region_obligations: r_o={}",
r_o.repr(self.tcx()));
let sup_type = self.resolve_type(r_o.sup_type);
type_must_outlive(self, r_o.origin.clone(),
sup_type, r_o.sub_region);
}
}
let fulfillment_cx = self.fcx.inh.fulfillment_cx.borrow();
for r_o in fulfillment_cx.region_obligations(node_id).iter() {
debug!("visit_region_obligations: r_o={}",
r_o.repr(self.tcx()));
let sup_type = self.resolve_type(r_o.sup_type);
type_must_outlive(self, r_o.origin.clone(),
sup_type, r_o.sub_region);
}
}