Skip to content

Commit c83d152

Browse files
committed
Introduce ProcessResult.
A tri-valued enum is nicer than Result<Option<T>>, and it's slightly faster.
1 parent f14b5d9 commit c83d152

File tree

3 files changed

+107
-95
lines changed

3 files changed

+107
-95
lines changed

src/librustc/traits/fulfill.rs

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use infer::{RegionObligation, InferCtxt};
1212
use mir::interpret::GlobalId;
1313
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
1414
use ty::error::ExpectedFound;
15-
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
16-
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
15+
use rustc_data_structures::obligation_forest::{Error, ForestObligation, ObligationForest};
16+
use rustc_data_structures::obligation_forest::{ObligationProcessor, ProcessResult};
1717
use std::marker::PhantomData;
1818
use hir::def_id::DefId;
1919
use middle::const_val::{ConstEvalErr, ErrKind};
@@ -263,16 +263,16 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
263263
type Error = FulfillmentErrorCode<'tcx>;
264264

265265
/// Processes a predicate obligation and returns either:
266-
/// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true
267-
/// - `Ok(None)` if we don't have enough info to be sure
268-
/// - `Err` if the predicate does not hold
266+
/// - `Changed(v)` if the predicate is true, presuming that `v` are also true
267+
/// - `Unchanged` if we don't have enough info to be sure
268+
/// - `Error(e)` if the predicate does not hold
269269
///
270270
/// This is always inlined, despite its size, because it has a single
271271
/// callsite and it is called *very* frequently.
272272
#[inline(always)]
273273
fn process_obligation(&mut self,
274274
pending_obligation: &mut Self::Obligation)
275-
-> Result<Option<Vec<Self::Obligation>>, Self::Error>
275+
-> ProcessResult<Self::Obligation, Self::Error>
276276
{
277277
// if we were stalled on some unresolved variables, first check
278278
// whether any of them have been resolved; if not, don't bother
@@ -286,7 +286,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
286286
self.selcx.infcx()
287287
.resolve_type_vars_if_possible(&pending_obligation.obligation),
288288
pending_obligation.stalled_on);
289-
return Ok(None);
289+
return ProcessResult::Unchanged;
290290
}
291291
pending_obligation.stalled_on = vec![];
292292
}
@@ -308,15 +308,15 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
308308
if self.selcx.infcx().predicate_must_hold(&obligation) {
309309
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
310310
data, obligation.recursion_depth);
311-
return Ok(Some(vec![]))
311+
return ProcessResult::Changed(vec![])
312312
}
313313
}
314314

315315
match self.selcx.select(&trait_obligation) {
316316
Ok(Some(vtable)) => {
317317
debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)",
318318
data, obligation.recursion_depth);
319-
Ok(Some(mk_pending(vtable.nested_obligations())))
319+
ProcessResult::Changed(mk_pending(vtable.nested_obligations()))
320320
}
321321
Ok(None) => {
322322
debug!("selecting trait `{:?}` at depth {} yielded Ok(None)",
@@ -342,21 +342,21 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
342342
self.selcx.infcx().resolve_type_vars_if_possible(obligation),
343343
pending_obligation.stalled_on);
344344

345-
Ok(None)
345+
ProcessResult::Unchanged
346346
}
347347
Err(selection_err) => {
348348
info!("selecting trait `{:?}` at depth {} yielded Err",
349349
data, obligation.recursion_depth);
350350

351-
Err(CodeSelectionError(selection_err))
351+
ProcessResult::Error(CodeSelectionError(selection_err))
352352
}
353353
}
354354
}
355355

356356
ty::Predicate::RegionOutlives(ref binder) => {
357357
match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
358-
Ok(()) => Ok(Some(Vec::new())),
359-
Err(_) => Err(CodeSelectionError(Unimplemented)),
358+
Ok(()) => ProcessResult::Changed(vec![]),
359+
Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
360360
}
361361
}
362362

@@ -373,7 +373,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
373373
// If so, this obligation is an error (for now). Eventually we should be
374374
// able to support additional cases here, like `for<'a> &'a str: 'a`.
375375
None => {
376-
Err(CodeSelectionError(Unimplemented))
376+
ProcessResult::Error(CodeSelectionError(Unimplemented))
377377
}
378378
// Otherwise, we have something of the form
379379
// `for<'a> T: 'a where 'a not in T`, which we can treat as
@@ -389,7 +389,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
389389
cause: obligation.cause.clone(),
390390
});
391391
}
392-
Ok(Some(vec![]))
392+
ProcessResult::Changed(vec![])
393393
}
394394
}
395395
}
@@ -404,7 +404,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
404404
cause: obligation.cause.clone()
405405
});
406406
}
407-
Ok(Some(vec![]))
407+
ProcessResult::Changed(vec![])
408408
}
409409
}
410410
}
@@ -416,32 +416,32 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
416416
let tcx = self.selcx.tcx();
417417
pending_obligation.stalled_on =
418418
trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx));
419-
Ok(None)
419+
ProcessResult::Unchanged
420420
}
421-
Ok(Some(os)) => Ok(Some(mk_pending(os))),
422-
Err(e) => Err(CodeProjectionError(e))
421+
Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)),
422+
Err(e) => ProcessResult::Error(CodeProjectionError(e))
423423
}
424424
}
425425

426426
ty::Predicate::ObjectSafe(trait_def_id) => {
427427
if !self.selcx.tcx().is_object_safe(trait_def_id) {
428-
Err(CodeSelectionError(Unimplemented))
428+
ProcessResult::Error(CodeSelectionError(Unimplemented))
429429
} else {
430-
Ok(Some(Vec::new()))
430+
ProcessResult::Changed(vec![])
431431
}
432432
}
433433

434434
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
435435
match self.selcx.infcx().closure_kind(closure_def_id, closure_substs) {
436436
Some(closure_kind) => {
437437
if closure_kind.extends(kind) {
438-
Ok(Some(vec![]))
438+
ProcessResult::Changed(vec![])
439439
} else {
440-
Err(CodeSelectionError(Unimplemented))
440+
ProcessResult::Error(CodeSelectionError(Unimplemented))
441441
}
442442
}
443443
None => {
444-
Ok(None)
444+
ProcessResult::Unchanged
445445
}
446446
}
447447
}
@@ -453,9 +453,9 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
453453
ty, obligation.cause.span) {
454454
None => {
455455
pending_obligation.stalled_on = vec![ty];
456-
Ok(None)
456+
ProcessResult::Unchanged
457457
}
458-
Some(os) => Ok(Some(mk_pending(os)))
458+
Some(os) => ProcessResult::Changed(mk_pending(os))
459459
}
460460
}
461461

@@ -467,24 +467,25 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
467467
// None means that both are unresolved.
468468
pending_obligation.stalled_on = vec![subtype.skip_binder().a,
469469
subtype.skip_binder().b];
470-
Ok(None)
470+
ProcessResult::Unchanged
471471
}
472472
Some(Ok(ok)) => {
473-
Ok(Some(mk_pending(ok.obligations)))
473+
ProcessResult::Changed(mk_pending(ok.obligations))
474474
}
475475
Some(Err(err)) => {
476476
let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected,
477477
subtype.skip_binder().a,
478478
subtype.skip_binder().b);
479-
Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err))
479+
ProcessResult::Error(
480+
FulfillmentErrorCode::CodeSubtypeError(expected_found, err))
480481
}
481482
}
482483
}
483484

484485
ty::Predicate::ConstEvaluatable(def_id, substs) => {
485486
match self.selcx.tcx().lift_to_global(&obligation.param_env) {
486487
None => {
487-
Ok(None)
488+
ProcessResult::Unchanged
488489
}
489490
Some(param_env) => {
490491
match self.selcx.tcx().lift_to_global(&substs) {
@@ -502,19 +503,22 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
502503
};
503504
match self.selcx.tcx().at(obligation.cause.span)
504505
.const_eval(param_env.and(cid)) {
505-
Ok(_) => Ok(Some(vec![])),
506-
Err(err) => Err(CodeSelectionError(ConstEvalFailure(err)))
506+
Ok(_) => ProcessResult::Changed(vec![]),
507+
Err(err) => ProcessResult::Error(
508+
CodeSelectionError(ConstEvalFailure(err)))
507509
}
508510
} else {
509-
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
510-
span: obligation.cause.span,
511-
kind: ErrKind::CouldNotResolve.into(),
512-
})))
511+
ProcessResult::Error(
512+
CodeSelectionError(ConstEvalFailure(ConstEvalErr {
513+
span: obligation.cause.span,
514+
kind: ErrKind::CouldNotResolve.into(),
515+
}))
516+
)
513517
}
514518
},
515519
None => {
516520
pending_obligation.stalled_on = substs.types().collect();
517-
Ok(None)
521+
ProcessResult::Unchanged
518522
}
519523
}
520524
}

src/librustc_data_structures/obligation_forest/mod.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub trait ObligationProcessor {
4141

4242
fn process_obligation(&mut self,
4343
obligation: &mut Self::Obligation)
44-
-> Result<Option<Vec<Self::Obligation>>, Self::Error>;
44+
-> ProcessResult<Self::Obligation, Self::Error>;
4545

4646
/// As we do the cycle check, we invoke this callback when we
4747
/// encounter an actual cycle. `cycle` is an iterator that starts
@@ -57,6 +57,14 @@ pub trait ObligationProcessor {
5757
where I: Clone + Iterator<Item=&'c Self::Obligation>;
5858
}
5959

60+
/// The result type used by `process_obligation`.
61+
#[derive(Debug)]
62+
pub enum ProcessResult<O, E> {
63+
Unchanged,
64+
Changed(Vec<O>),
65+
Error(E),
66+
}
67+
6068
pub struct ObligationForest<O: ForestObligation> {
6169
/// The list of obligations. In between calls to
6270
/// `process_obligations`, this list only contains nodes in the
@@ -136,8 +144,8 @@ pub struct Outcome<O, E> {
136144

137145
/// If true, then we saw no successful obligations, which means
138146
/// there is no point in further iteration. This is based on the
139-
/// assumption that when trait matching returns `Err` or
140-
/// `Ok(None)`, those results do not affect environmental
147+
/// assumption that when trait matching returns `Error` or
148+
/// `Unchanged`, those results do not affect environmental
141149
/// inference state. (Note that if we invoke `process_obligations`
142150
/// with no pending obligations, stalled will be true.)
143151
pub stalled: bool,
@@ -270,11 +278,11 @@ impl<O: ForestObligation> ObligationForest<O> {
270278
result);
271279

272280
match result {
273-
Ok(None) => {
274-
// no change in state
281+
ProcessResult::Unchanged => {
282+
// No change in state.
275283
}
276-
Ok(Some(children)) => {
277-
// if we saw a Some(_) result, we are not (yet) stalled
284+
ProcessResult::Changed(children) => {
285+
// We are not (yet) stalled.
278286
stalled = false;
279287
self.nodes[index].state.set(NodeState::Success);
280288

@@ -290,7 +298,7 @@ impl<O: ForestObligation> ObligationForest<O> {
290298
}
291299
}
292300
}
293-
Err(err) => {
301+
ProcessResult::Error(err) => {
294302
stalled = false;
295303
let backtrace = self.error_at(index);
296304
errors.push(Error {

0 commit comments

Comments
 (0)