Skip to content

Commit 4375693

Browse files
committed
switch the fulfillment context to use the new obligation forest;
this commit won't build because, as of this version, no coinductive reasoning at all is really supported
1 parent 0defb15 commit 4375693

File tree

1 file changed

+90
-129
lines changed

1 file changed

+90
-129
lines changed

src/librustc/middle/traits/fulfill.rs

+90-129
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use middle::infer::InferCtxt;
1212
use middle::ty::{self, Ty, TypeFoldable};
13+
use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
1314

1415
use syntax::ast;
1516
use util::common::ErrorReported;
@@ -20,6 +21,7 @@ use super::CodeProjectionError;
2021
use super::CodeSelectionError;
2122
use super::is_object_safe;
2223
use super::FulfillmentError;
24+
use super::FulfillmentErrorCode;
2325
use super::ObligationCause;
2426
use super::PredicateObligation;
2527
use super::project;
@@ -57,7 +59,7 @@ pub struct FulfillmentContext<'tcx> {
5759

5860
// A list of all obligations that have been registered with this
5961
// fulfillment context.
60-
predicates: Vec<PendingPredicateObligation<'tcx>>,
62+
predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
6163

6264
// A set of constraints that regionck must validate. Each
6365
// constraint has the form `T:'a`, meaning "some type `T` must
@@ -122,7 +124,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
122124
pub fn new(errors_will_be_reported: bool) -> FulfillmentContext<'tcx> {
123125
FulfillmentContext {
124126
duplicate_set: FulfilledPredicates::new(),
125-
predicates: Vec::new(),
127+
predicates: ObligationForest::new(),
126128
region_obligations: NodeMap(),
127129
errors_will_be_reported: errors_will_be_reported,
128130
}
@@ -202,7 +204,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
202204
obligation: obligation,
203205
stalled_on: vec![]
204206
};
205-
self.predicates.push(obligation);
207+
self.predicates.push_root(obligation);
206208
}
207209

208210
pub fn region_obligations(&self,
@@ -220,14 +222,11 @@ impl<'tcx> FulfillmentContext<'tcx> {
220222
-> Result<(),Vec<FulfillmentError<'tcx>>>
221223
{
222224
try!(self.select_where_possible(infcx));
223-
224-
// Anything left is ambiguous.
225-
let errors: Vec<FulfillmentError> =
226-
self.predicates
227-
.iter()
228-
.map(|o| FulfillmentError::new(o.obligation.clone(), CodeAmbiguity))
229-
.collect();
230-
225+
let errors: Vec<_> =
226+
self.predicates.to_errors(CodeAmbiguity)
227+
.into_iter()
228+
.map(|e| to_fulfillment_error(e))
229+
.collect();
231230
if errors.is_empty() {
232231
Ok(())
233232
} else {
@@ -240,11 +239,11 @@ impl<'tcx> FulfillmentContext<'tcx> {
240239
-> Result<(),Vec<FulfillmentError<'tcx>>>
241240
{
242241
let mut selcx = SelectionContext::new(infcx);
243-
self.select(&mut selcx, false)
242+
self.select(&mut selcx)
244243
}
245244

246-
pub fn pending_obligations(&self) -> &[PendingPredicateObligation<'tcx>] {
247-
&self.predicates
245+
pub fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>> {
246+
self.predicates.pending_obligations()
248247
}
249248

250249
fn is_duplicate_or_add(&mut self,
@@ -273,58 +272,43 @@ impl<'tcx> FulfillmentContext<'tcx> {
273272
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
274273
/// only attempts to select obligations that haven't been seen before.
275274
fn select<'a>(&mut self,
276-
selcx: &mut SelectionContext<'a, 'tcx>,
277-
only_new_obligations: bool)
275+
selcx: &mut SelectionContext<'a, 'tcx>)
278276
-> Result<(),Vec<FulfillmentError<'tcx>>>
279277
{
280-
debug!("select({} obligations, only_new_obligations={}) start",
281-
self.predicates.len(),
282-
only_new_obligations);
278+
debug!("select(obligation-forest-size={})", self.predicates.len());
283279

284280
let mut errors = Vec::new();
285281

286282
loop {
287-
let count = self.predicates.len();
283+
debug!("select_where_possible: starting another iteration");
288284

289-
debug!("select_where_possible({} obligations) iteration",
290-
count);
285+
// Process pending obligations.
286+
let outcome = {
287+
let region_obligations = &mut self.region_obligations;
288+
self.predicates.process_obligations(
289+
|obligation, backtrace| process_predicate(selcx,
290+
obligation,
291+
backtrace,
292+
region_obligations))
293+
};
291294

292-
let mut new_obligations = Vec::new();
295+
debug!("select_where_possible: outcome={:?}", outcome);
293296

294-
// First pass: walk each obligation, retaining
295-
// only those that we cannot yet process.
296-
{
297-
let region_obligations = &mut self.region_obligations;
298-
let mut i = 0;
299-
while i < self.predicates.len() {
300-
let processed = process_predicate(selcx,
301-
&mut self.predicates[i],
302-
&mut new_obligations,
303-
&mut errors,
304-
region_obligations);
305-
if processed {
306-
self.predicates.swap_remove(i);
307-
} else {
308-
i += 1;
309-
}
310297
}
311298
}
312299

313-
if self.predicates.len() == count {
314-
// Nothing changed.
315-
break;
316-
}
300+
errors.extend(
301+
outcome.errors.into_iter()
302+
.map(|e| to_fulfillment_error(e)));
317303

318-
// Now go through all the successful ones,
319-
// registering any nested obligations for the future.
320-
for new_obligation in new_obligations {
321-
self.register_predicate_obligation(selcx.infcx(), new_obligation);
304+
// If nothing new was added, no need to keep looping.
305+
if outcome.stalled {
306+
break;
322307
}
323308
}
324309

325-
debug!("select({} obligations, {} errors) done",
326-
self.predicates.len(),
327-
errors.len());
310+
debug!("select({} predicates remaining, {} errors) done",
311+
self.predicates.len(), errors.len());
328312

329313
if errors.is_empty() {
330314
Ok(())
@@ -334,20 +318,37 @@ impl<'tcx> FulfillmentContext<'tcx> {
334318
}
335319
}
336320

321+
/// Like `process_predicate1`, but wrap result into a pending predicate.
337322
fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
338323
pending_obligation: &mut PendingPredicateObligation<'tcx>,
339-
new_obligations: &mut Vec<PredicateObligation<'tcx>>,
340-
errors: &mut Vec<FulfillmentError<'tcx>>,
324+
backtrace: Backtrace<PendingPredicateObligation<'tcx>>,
341325
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
342-
-> bool
326+
-> Result<Option<Vec<PendingPredicateObligation<'tcx>>>,
327+
FulfillmentErrorCode<'tcx>>
343328
{
344-
/*!
345-
* Processes a predicate obligation and modifies the appropriate
346-
* output array with the successful/error result. Returns `false`
347-
* if the predicate could not be processed due to insufficient
348-
* type inference.
349-
*/
329+
match process_predicate1(selcx, pending_obligation, backtrace, region_obligations) {
330+
Ok(Some(v)) => Ok(Some(v.into_iter()
331+
.map(|o| PendingPredicateObligation {
332+
obligation: o,
333+
stalled_on: vec![]
334+
})
335+
.collect())),
336+
Ok(None) => Ok(None),
337+
Err(e) => Err(e)
338+
}
339+
}
350340

341+
/// Processes a predicate obligation and returns either:
342+
/// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true
343+
/// - `Ok(None)` if we don't have enough info to be sure
344+
/// - `Err` if the predicate does not hold
345+
fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
346+
pending_obligation: &mut PendingPredicateObligation<'tcx>,
347+
backtrace: Backtrace<PendingPredicateObligation<'tcx>>,
348+
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
349+
-> Result<Option<Vec<PredicateObligation<'tcx>>>,
350+
FulfillmentErrorCode<'tcx>>
351+
{
351352
// if we were stalled on some unresolved variables, first check
352353
// whether any of them have been resolved; if not, don't bother
353354
// doing more work yet
@@ -359,16 +360,19 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
359360
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
360361
selcx.infcx().resolve_type_vars_if_possible(&pending_obligation.obligation),
361362
pending_obligation.stalled_on);
362-
return false;
363+
return Ok(None);
363364
}
364365
pending_obligation.stalled_on = vec![];
365366
}
366367

367-
let obligation = &mut pending_obligation.obligation;
368+
let obligation = &pending_obligation.obligation;
368369
match obligation.predicate {
369370
ty::Predicate::Trait(ref data) => {
370371
let trait_obligation = obligation.with(data.clone());
371372
match selcx.select(&trait_obligation) {
373+
Ok(Some(vtable)) => {
374+
Ok(Some(vtable.nested_obligations()))
375+
}
372376
Ok(None) => {
373377
// This is a bit subtle: for the most part, the
374378
// only reason we can fail to make progress on
@@ -395,50 +399,26 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
395399
selcx.infcx().resolve_type_vars_if_possible(obligation),
396400
pending_obligation.stalled_on);
397401

398-
false
399-
}
400-
Ok(Some(s)) => {
401-
new_obligations.append(&mut s.nested_obligations());
402-
true
402+
Ok(None)
403403
}
404404
Err(selection_err) => {
405-
debug!("predicate: {:?} error: {:?}",
406-
obligation,
407-
selection_err);
408-
errors.push(
409-
FulfillmentError::new(
410-
obligation.clone(),
411-
CodeSelectionError(selection_err)));
412-
true
405+
Err(CodeSelectionError(selection_err))
413406
}
414407
}
415408
}
416409

417410
ty::Predicate::Equate(ref binder) => {
418411
match selcx.infcx().equality_predicate(obligation.cause.span, binder) {
419-
Ok(()) => { }
420-
Err(_) => {
421-
errors.push(
422-
FulfillmentError::new(
423-
obligation.clone(),
424-
CodeSelectionError(Unimplemented)));
425-
}
412+
Ok(()) => Ok(Some(Vec::new())),
413+
Err(_) => Err(CodeSelectionError(Unimplemented)),
426414
}
427-
true
428415
}
429416

430417
ty::Predicate::RegionOutlives(ref binder) => {
431418
match selcx.infcx().region_outlives_predicate(obligation.cause.span, binder) {
432-
Ok(()) => { }
433-
Err(_) => {
434-
errors.push(
435-
FulfillmentError::new(
436-
obligation.clone(),
437-
CodeSelectionError(Unimplemented)));
438-
}
419+
Ok(()) => Ok(Some(Vec::new())),
420+
Err(_) => Err(CodeSelectionError(Unimplemented)),
439421
}
440-
441-
true
442422
}
443423

444424
ty::Predicate::TypeOutlives(ref binder) => {
@@ -454,17 +434,15 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
454434
// If so, this obligation is an error (for now). Eventually we should be
455435
// able to support additional cases here, like `for<'a> &'a str: 'a`.
456436
None => {
457-
errors.push(
458-
FulfillmentError::new(
459-
obligation.clone(),
460-
CodeSelectionError(Unimplemented)))
437+
Err(CodeSelectionError(Unimplemented))
461438
}
462439
// Otherwise, we have something of the form
463440
// `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
464441
Some(t_a) => {
465442
register_region_obligation(t_a, ty::ReStatic,
466443
obligation.cause.clone(),
467444
region_obligations);
445+
Ok(Some(vec![]))
468446
}
469447
}
470448
}
@@ -473,55 +451,30 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
473451
register_region_obligation(t_a, r_b,
474452
obligation.cause.clone(),
475453
region_obligations);
454+
Ok(Some(vec![]))
476455
}
477456
}
478-
true
479457
}
480458

481459
ty::Predicate::Projection(ref data) => {
482460
let project_obligation = obligation.with(data.clone());
483-
let result = project::poly_project_and_unify_type(selcx, &project_obligation);
484-
debug!("process_predicate: poly_project_and_unify_type({:?}) returned {:?}",
485-
project_obligation,
486-
result);
487-
match result {
488-
Ok(Some(obligations)) => {
489-
new_obligations.extend(obligations);
490-
true
491-
}
492-
Ok(None) => {
493-
false
494-
}
495-
Err(err) => {
496-
errors.push(
497-
FulfillmentError::new(
498-
obligation.clone(),
499-
CodeProjectionError(err)));
500-
true
501-
}
461+
match project::poly_project_and_unify_type(selcx, &project_obligation) {
462+
Ok(v) => Ok(v),
463+
Err(e) => Err(CodeProjectionError(e))
502464
}
503465
}
504466

505467
ty::Predicate::ObjectSafe(trait_def_id) => {
506468
if !is_object_safe(selcx.tcx(), trait_def_id) {
507-
errors.push(FulfillmentError::new(
508-
obligation.clone(),
509-
CodeSelectionError(Unimplemented)));
469+
Err(CodeSelectionError(Unimplemented))
470+
} else {
471+
Ok(Some(Vec::new()))
510472
}
511-
true
512473
}
513474

514475
ty::Predicate::WellFormed(ty) => {
515-
match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
516-
ty, obligation.cause.span) {
517-
Some(obligations) => {
518-
new_obligations.extend(obligations);
519-
true
520-
}
521-
None => {
522-
false
523-
}
524-
}
476+
Ok(ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
477+
ty, obligation.cause.span))
525478
}
526479
}
527480
}
@@ -559,3 +512,11 @@ impl<'tcx> FulfilledPredicates<'tcx> {
559512
!self.set.insert(key.clone())
560513
}
561514
}
515+
516+
fn to_fulfillment_error<'tcx>(
517+
error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>)
518+
-> FulfillmentError<'tcx>
519+
{
520+
let obligation = error.backtrace.into_iter().next().unwrap().obligation;
521+
FulfillmentError::new(obligation, error.error)
522+
}

0 commit comments

Comments
 (0)