From 70be49d2c7372313921f8121d5c4fe83821a3b65 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Dec 2014 02:57:17 -0500 Subject: [PATCH] Move the list of region obligations into the fulfillment context. --- src/librustc/middle/traits/fulfill.rs | 70 ++++++++++++++++++++++++++- src/librustc/middle/traits/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 59 +++------------------- src/librustc_typeck/check/regionck.rs | 19 +++----- 4 files changed, 83 insertions(+), 67 deletions(-) diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index f6428efc4e4..d0e401d3551 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -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 { ... } + // + // 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>>, +} + +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)) + } +} diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 2600640a17d..aab1fbcdbfd 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -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}; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 265766029b5..c7be362f187 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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>>>, - // 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 { ... } - // - // 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>>>, - // Tracks trait obligations incurred during this function body. fulfillment_cx: RefCell>, } -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)) - } -} diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index c53ad34a6d2..1564287f15f 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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); } }