diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2b080c54da1..f734ff84f63 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -35,7 +35,7 @@ use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::{self, Span, DUMMY_SP}; -use util::nodemap::{NodeMap, FxHashMap}; +use util::nodemap::FxHashMap; use arena::DroplessArena; use self::combine::CombineFields; @@ -179,7 +179,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // for each body-id in this map, which will process the // obligations within. This is expected to be done 'late enough' // that all type inference variables have been bound and so forth. - region_obligations: RefCell>>>, + region_obligations: RefCell)>>, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -450,7 +450,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), - region_obligations: RefCell::new(NodeMap()), + region_obligations: RefCell::new(vec![]), })) } } @@ -478,6 +478,7 @@ pub struct CombinedSnapshot<'a, 'tcx:'a> { int_snapshot: unify::Snapshot, float_snapshot: unify::Snapshot, region_constraints_snapshot: RegionSnapshot, + region_obligations_snapshot: usize, was_in_snapshot: bool, _in_progress_tables: Option>>, } @@ -786,6 +787,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot: self.int_unification_table.borrow_mut().snapshot(), float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_constraints_snapshot: self.borrow_region_constraints().start_snapshot(), + region_obligations_snapshot: self.region_obligations.borrow().len(), was_in_snapshot: in_snapshot, // Borrow tables "in progress" (i.e. during typeck) // to ban writes from within a snapshot to them. @@ -802,6 +804,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_constraints_snapshot, + region_obligations_snapshot, was_in_snapshot, _in_progress_tables } = snapshot; @@ -819,6 +822,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.float_unification_table .borrow_mut() .rollback_to(float_snapshot); + self.region_obligations + .borrow_mut() + .truncate(region_obligations_snapshot); self.borrow_region_constraints() .rollback_to(region_constraints_snapshot); } @@ -830,6 +836,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_constraints_snapshot, + region_obligations_snapshot: _, was_in_snapshot, _in_progress_tables } = snapshot; diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index 2fb085bc1d8..32f09795668 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -86,9 +86,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ) { self.region_obligations .borrow_mut() - .entry(body_id) - .or_insert(vec![]) - .push(obligation); + .push((body_id, obligation)); } /// Process the region obligations that must be proven (during @@ -131,10 +129,16 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId, ) { - let region_obligations = match self.region_obligations.borrow_mut().remove(&body_id) { - None => vec![], - Some(vec) => vec, - }; + assert!(!self.in_snapshot.get(), "cannot process registered region obligations in a snapshot"); + + // pull out the region obligations with the given `body_id` (leaving the rest) + let mut my_region_obligations = Vec::with_capacity(self.region_obligations.borrow().len()); + { + let mut r_o = self.region_obligations.borrow_mut(); + for (_, obligation) in r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id) { + my_region_obligations.push(obligation); + } + } let outlives = TypeOutlives::new(self, region_bound_pairs, implicit_region_bound, param_env); @@ -143,7 +147,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { sup_type, sub_region, cause, - } in region_obligations + } in my_region_obligations { let origin = SubregionOrigin::from_obligation_cause( &cause, @@ -170,11 +174,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { outlives.type_must_outlive(origin, ty, region); } - /// Ignore the region obligations for a given `body_id`, not bothering to - /// prove them. This function should not really exist; it is used to accommodate some older - /// code for the time being. - pub fn ignore_region_obligations(&self, body_id: ast::NodeId) { - self.region_obligations.borrow_mut().remove(&body_id); + /// Ignore the region obligations, not bothering to prove + /// them. This function should not really exist; it is used to + /// accommodate some older code for the time being. + pub fn ignore_region_obligations(&self) { + assert!(!self.in_snapshot.get(), "cannot ignore registered region obligations in a snapshot"); + + self.region_obligations.borrow_mut().clear(); } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 66113ffef3d..5e9019c92c5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -45,6 +45,7 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] +#![feature(drain_filter)] #![feature(i128_type)] #![feature(match_default_bindings)] #![feature(inclusive_range_syntax)] diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 9314c9d051d..55b1a913f0d 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -511,7 +511,6 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, unnormalized_env.reveal); tcx.infer_ctxt().enter(|infcx| { - let body_id = cause.body_id; let predicates = match fully_normalize( &infcx, cause, @@ -546,7 +545,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // properly, and that code is currently largely confined to // regionck (though I made some efforts to extract it // out). -nmatsakis - let _ = infcx.ignore_region_obligations(body_id); + let _ = infcx.ignore_region_obligations(); infcx.resolve_regions_and_report_errors(region_context, ®ion_scope_tree, &free_regions); let predicates = match infcx.fully_resolve(&predicates) {