Skip to content

Commit 882048d

Browse files
committed
move region constraints into inference context
1 parent 835875d commit 882048d

File tree

5 files changed

+97
-99
lines changed

5 files changed

+97
-99
lines changed

src/librustc/infer/mod.rs

+76-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use std::fmt;
3636
use syntax::ast;
3737
use errors::DiagnosticBuilder;
3838
use syntax_pos::{self, Span, DUMMY_SP};
39-
use util::nodemap::FxHashMap;
39+
use util::nodemap::{NodeMap, FxHashMap};
4040
use arena::DroplessArena;
4141

4242
use self::combine::CombineFields;
@@ -135,6 +135,32 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
135135

136136
// This flag is true while there is an active snapshot.
137137
in_snapshot: Cell<bool>,
138+
139+
// A set of constraints that regionck must validate. Each
140+
// constraint has the form `T:'a`, meaning "some type `T` must
141+
// outlive the lifetime 'a". These constraints derive from
142+
// instantiated type parameters. So if you had a struct defined
143+
// like
144+
//
145+
// struct Foo<T:'static> { ... }
146+
//
147+
// then in some expression `let x = Foo { ... }` it will
148+
// instantiate the type parameter `T` with a fresh type `$0`. At
149+
// the same time, it will record a region obligation of
150+
// `$0:'static`. This will get checked later by regionck. (We
151+
// can't generally check these things right away because we have
152+
// to wait until types are resolved.)
153+
//
154+
// These are stored in a map keyed to the id of the innermost
155+
// enclosing fn body / static initializer expression. This is
156+
// because the location where the obligation was incurred can be
157+
// relevant with respect to which sublifetime assumptions are in
158+
// place. The reason that we store under the fn-id, and not
159+
// something more fine-grained, is so that it is easier for
160+
// regionck to be sure that it has found *all* the region
161+
// obligations (otherwise, it's easy to fail to walk to a
162+
// particular node-id).
163+
region_obligations: RefCell<NodeMap<Vec<RegionObligation<'tcx>>>>,
138164
}
139165

140166
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
@@ -317,6 +343,14 @@ pub enum FixupError {
317343
UnresolvedTy(TyVid)
318344
}
319345

346+
/// See the `region_obligations` field for more information.
347+
#[derive(Clone)]
348+
pub struct RegionObligation<'tcx> {
349+
pub sub_region: ty::Region<'tcx>,
350+
pub sup_type: Ty<'tcx>,
351+
pub cause: ObligationCause<'tcx>,
352+
}
353+
320354
impl fmt::Display for FixupError {
321355
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322356
use self::FixupError::*;
@@ -386,6 +420,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
386420
tainted_by_errors_flag: Cell::new(false),
387421
err_count_on_creation: tcx.sess.err_count(),
388422
in_snapshot: Cell::new(false),
423+
region_obligations: RefCell::new(NodeMap()),
389424
}))
390425
}
391426
}
@@ -953,6 +988,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
953988
})
954989
}
955990

991+
/// Registers that the given region obligation must be resolved
992+
/// from within the scope of `body_id`. These regions are enqueued
993+
/// and later processed by regionck, when full type information is
994+
/// available (see `region_obligations` field for more
995+
/// information).
996+
pub fn register_region_obligation(&self,
997+
body_id: ast::NodeId,
998+
obligation: RegionObligation<'tcx>)
999+
{
1000+
self.region_obligations.borrow_mut().entry(body_id)
1001+
.or_insert(vec![])
1002+
.push(obligation);
1003+
}
1004+
1005+
/// Get the region obligations that must be proven (during
1006+
/// `regionck`) for the given `body_id` (removing them from the
1007+
/// map as a side-effect).
1008+
pub fn take_region_obligations(&self,
1009+
body_id: ast::NodeId)
1010+
-> Vec<RegionObligation<'tcx>>
1011+
{
1012+
match self.region_obligations.borrow_mut().remove(&body_id) {
1013+
None => vec![],
1014+
Some(vec) => vec,
1015+
}
1016+
}
1017+
9561018
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
9571019
self.type_variables
9581020
.borrow_mut()
@@ -1073,6 +1135,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10731135
region_context: DefId,
10741136
region_map: &region::ScopeTree,
10751137
free_regions: &FreeRegionMap<'tcx>) {
1138+
// TODO assert!(self.region_obligations.borrow().is_empty(),
1139+
// TODO "region_obligations not empty: {:#?}",
1140+
// TODO self.region_obligations.borrow());
1141+
10761142
let region_rels = RegionRelations::new(self.tcx,
10771143
region_context,
10781144
region_map,
@@ -1533,3 +1599,12 @@ impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
15331599
self.cause.visit_with(visitor) || self.values.visit_with(visitor)
15341600
}
15351601
}
1602+
1603+
impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
1604+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1605+
write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})",
1606+
self.sub_region,
1607+
self.sup_type)
1608+
}
1609+
}
1610+

src/librustc/traits/fulfill.rs

+18-83
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use infer::{InferCtxt, InferOk};
11+
use infer::{RegionObligation, InferCtxt, InferOk};
1212
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
1313
use ty::error::ExpectedFound;
1414
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
1515
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
1616
use std::marker::PhantomData;
17-
use syntax::ast;
18-
use util::nodemap::NodeMap;
1917
use hir::def_id::DefId;
2018

2119
use super::CodeAmbiguity;
@@ -48,39 +46,6 @@ pub struct FulfillmentContext<'tcx> {
4846
// A list of all obligations that have been registered with this
4947
// fulfillment context.
5048
predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
51-
52-
// A set of constraints that regionck must validate. Each
53-
// constraint has the form `T:'a`, meaning "some type `T` must
54-
// outlive the lifetime 'a". These constraints derive from
55-
// instantiated type parameters. So if you had a struct defined
56-
// like
57-
//
58-
// struct Foo<T:'static> { ... }
59-
//
60-
// then in some expression `let x = Foo { ... }` it will
61-
// instantiate the type parameter `T` with a fresh type `$0`. At
62-
// the same time, it will record a region obligation of
63-
// `$0:'static`. This will get checked later by regionck. (We
64-
// can't generally check these things right away because we have
65-
// to wait until types are resolved.)
66-
//
67-
// These are stored in a map keyed to the id of the innermost
68-
// enclosing fn body / static initializer expression. This is
69-
// because the location where the obligation was incurred can be
70-
// relevant with respect to which sublifetime assumptions are in
71-
// place. The reason that we store under the fn-id, and not
72-
// something more fine-grained, is so that it is easier for
73-
// regionck to be sure that it has found *all* the region
74-
// obligations (otherwise, it's easy to fail to walk to a
75-
// particular node-id).
76-
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
77-
}
78-
79-
#[derive(Clone)]
80-
pub struct RegionObligation<'tcx> {
81-
pub sub_region: ty::Region<'tcx>,
82-
pub sup_type: Ty<'tcx>,
83-
pub cause: ObligationCause<'tcx>,
8449
}
8550

8651
#[derive(Clone, Debug)]
@@ -94,7 +59,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
9459
pub fn new() -> FulfillmentContext<'tcx> {
9560
FulfillmentContext {
9661
predicates: ObligationForest::new(),
97-
region_obligations: NodeMap(),
9862
}
9963
}
10064

@@ -184,17 +148,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
184148
}
185149
}
186150

187-
188-
pub fn region_obligations(&self,
189-
body_id: ast::NodeId)
190-
-> &[RegionObligation<'tcx>]
191-
{
192-
match self.region_obligations.get(&body_id) {
193-
None => Default::default(),
194-
Some(vec) => vec,
195-
}
196-
}
197-
198151
pub fn select_all_or_error(&mut self,
199152
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
200153
-> Result<(),Vec<FulfillmentError<'tcx>>>
@@ -237,10 +190,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
237190
debug!("select: starting another iteration");
238191

239192
// Process pending obligations.
240-
let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
241-
selcx,
242-
region_obligations: &mut self.region_obligations,
243-
});
193+
let outcome = self.predicates.process_obligations(&mut FulfillProcessor { selcx });
244194
debug!("select: outcome={:?}", outcome);
245195

246196
// FIXME: if we kept the original cache key, we could mark projection
@@ -269,7 +219,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
269219

270220
struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
271221
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
272-
region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>,
273222
}
274223

275224
impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
@@ -280,9 +229,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
280229
obligation: &mut Self::Obligation)
281230
-> Result<Option<Vec<Self::Obligation>>, Self::Error>
282231
{
283-
process_predicate(self.selcx,
284-
obligation,
285-
self.region_obligations)
232+
process_predicate(self.selcx, obligation)
286233
.map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
287234
obligation: o,
288235
stalled_on: vec![]
@@ -321,8 +268,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't
321268
/// - `Err` if the predicate does not hold
322269
fn process_predicate<'a, 'gcx, 'tcx>(
323270
selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
324-
pending_obligation: &mut PendingPredicateObligation<'tcx>,
325-
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
271+
pending_obligation: &mut PendingPredicateObligation<'tcx>)
326272
-> Result<Option<Vec<PredicateObligation<'tcx>>>,
327273
FulfillmentErrorCode<'tcx>>
328274
{
@@ -444,18 +390,26 @@ fn process_predicate<'a, 'gcx, 'tcx>(
444390
// `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
445391
Some(t_a) => {
446392
let r_static = selcx.tcx().types.re_static;
447-
register_region_obligation(t_a, r_static,
448-
obligation.cause.clone(),
449-
region_obligations);
393+
selcx.infcx().register_region_obligation(
394+
obligation.cause.body_id,
395+
RegionObligation {
396+
sup_type: t_a,
397+
sub_region: r_static,
398+
cause: obligation.cause.clone(),
399+
});
450400
Ok(Some(vec![]))
451401
}
452402
}
453403
}
454404
// If there aren't, register the obligation.
455405
Some(ty::OutlivesPredicate(t_a, r_b)) => {
456-
register_region_obligation(t_a, r_b,
457-
obligation.cause.clone(),
458-
region_obligations);
406+
selcx.infcx().register_region_obligation(
407+
obligation.cause.body_id,
408+
RegionObligation {
409+
sup_type: t_a,
410+
sub_region: r_b,
411+
cause: obligation.cause.clone()
412+
});
459413
Ok(Some(vec![]))
460414
}
461415
}
@@ -558,25 +512,6 @@ fn process_predicate<'a, 'gcx, 'tcx>(
558512
}
559513
}
560514

561-
562-
fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
563-
r_b: ty::Region<'tcx>,
564-
cause: ObligationCause<'tcx>,
565-
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
566-
{
567-
let region_obligation = RegionObligation { sup_type: t_a,
568-
sub_region: r_b,
569-
cause: cause };
570-
571-
debug!("register_region_obligation({:?}, cause={:?})",
572-
region_obligation, region_obligation.cause);
573-
574-
region_obligations.entry(region_obligation.cause.body_id)
575-
.or_insert(vec![])
576-
.push(region_obligation);
577-
578-
}
579-
580515
fn to_fulfillment_error<'tcx>(
581516
error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>)
582517
-> FulfillmentError<'tcx>

src/librustc/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use syntax::ast;
3030
use syntax_pos::{Span, DUMMY_SP};
3131

3232
pub use self::coherence::{orphan_check, overlapping_impls, OrphanCheckErr, OverlapResult};
33-
pub use self::fulfill::{FulfillmentContext, RegionObligation};
33+
pub use self::fulfill::FulfillmentContext;
3434
pub use self::project::MismatchedProjectionTypes;
3535
pub use self::project::{normalize, normalize_projection_type, Normalized};
3636
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};

src/librustc/traits/structural_impls.rs

-7
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,6 @@ impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
2626
}
2727
}
2828

29-
impl<'tcx> fmt::Debug for traits::RegionObligation<'tcx> {
30-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31-
write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})",
32-
self.sub_region,
33-
self.sup_type)
34-
}
35-
}
3629
impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
3730
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3831
write!(f, "Obligation(predicate={:?},depth={})",

src/librustc_typeck/check/regionck.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
360360

361361
// Make a copy of the region obligations vec because we'll need
362362
// to be able to borrow the fulfillment-cx below when projecting.
363-
let region_obligations =
364-
self.fulfillment_cx
365-
.borrow()
366-
.region_obligations(node_id)
367-
.to_vec();
363+
let region_obligations = self.infcx.take_region_obligations(node_id);
368364

369365
for r_o in &region_obligations {
370366
debug!("visit_region_obligations: r_o={:?} cause={:?}",
@@ -375,8 +371,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
375371
}
376372

377373
// Processing the region obligations should not cause the list to grow further:
378-
assert_eq!(region_obligations.len(),
379-
self.fulfillment_cx.borrow().region_obligations(node_id).len());
374+
assert!(self.infcx.take_region_obligations(node_id).is_empty());
380375
}
381376

382377
fn code_to_origin(&self,

0 commit comments

Comments
 (0)