Skip to content

Commit e6a9f7e

Browse files
Plumb inference obligations through select.rs and beyond
1 parent 527d5d2 commit e6a9f7e

File tree

8 files changed

+271
-157
lines changed

8 files changed

+271
-157
lines changed

src/librustc/middle/const_eval.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use middle::cstore::{self, CrateStore, InlinedItem};
2020
use middle::{infer, subst, traits};
2121
use middle::def::Def;
2222
use middle::subst::Subst;
23+
use middle::traits::SelectionOk;
2324
use middle::def_id::DefId;
2425
use middle::pat_util::def_to_path;
2526
use middle::ty::{self, Ty};
@@ -1241,15 +1242,22 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
12411242
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
12421243
trait_ref.to_poly_trait_predicate());
12431244
let selection = match selcx.select(&obligation) {
1244-
Ok(Some(vtable)) => vtable,
1245+
Ok(SelectionOk { selection: Some(vtable), obligations }) => {
1246+
// FIXME these obligations should be propagated or selected on
1247+
assert!(obligations.is_empty());
1248+
vtable
1249+
},
12451250
// Still ambiguous, so give up and let the caller decide whether this
12461251
// expression is really needed yet. Some associated constant values
12471252
// can't be evaluated until monomorphization is done in trans.
1248-
Ok(None) => {
1249-
return None
1253+
Ok(SelectionOk { selection: None, obligations }) => {
1254+
// FIXME these obligations should be propagated or selected on or... maybe they don't
1255+
// need to be?
1256+
assert!(obligations.is_empty());
1257+
return None;
12501258
}
12511259
Err(_) => {
1252-
return None
1260+
return None;
12531261
}
12541262
};
12551263

src/librustc/middle/traits/fulfill.rs

+29-23
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use super::ObligationCause;
2727
use super::PredicateObligation;
2828
use super::project;
2929
use super::report_overflow_error_cycle;
30-
use super::select::SelectionContext;
30+
use super::select::{SelectionContext, SelectionOk};
3131
use super::Unimplemented;
3232
use super::util::predicate_for_builtin_bound;
3333

@@ -487,34 +487,40 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
487487

488488
let trait_obligation = obligation.with(data.clone());
489489
match selcx.select(&trait_obligation) {
490-
Ok(Some(vtable)) => {
490+
Ok(SelectionOk { selection: Some(vtable), obligations: inferred_obligations }) => {
491491
info!("selecting trait `{:?}` at depth {} yielded Ok(Some)",
492492
data, obligation.recursion_depth);
493-
Ok(Some(vtable.nested_obligations()))
493+
let mut nested_obligations = vtable.nested_obligations();
494+
nested_obligations.extend(inferred_obligations);
495+
Ok(Some(nested_obligations))
494496
}
495-
Ok(None) => {
497+
Ok(SelectionOk { selection: None, obligations: inferred_obligations }) => {
496498
info!("selecting trait `{:?}` at depth {} yielded Ok(None)",
497499
data, obligation.recursion_depth);
498500

499-
// This is a bit subtle: for the most part, the
500-
// only reason we can fail to make progress on
501-
// trait selection is because we don't have enough
502-
// information about the types in the trait. One
503-
// exception is that we sometimes haven't decided
504-
// what kind of closure a closure is. *But*, in
505-
// that case, it turns out, the type of the
506-
// closure will also change, because the closure
507-
// also includes references to its upvars as part
508-
// of its type, and those types are resolved at
509-
// the same time.
510-
pending_obligation.stalled_on =
511-
trait_ref_type_vars(selcx, data.to_poly_trait_ref());
512-
513-
debug!("process_predicate: pending obligation {:?} now stalled on {:?}",
514-
selcx.infcx().resolve_type_vars_if_possible(obligation),
515-
pending_obligation.stalled_on);
516-
517-
Ok(None)
501+
if inferred_obligations.is_empty() {
502+
// This is a bit subtle: for the most part, the
503+
// only reason we can fail to make progress on
504+
// trait selection is because we don't have enough
505+
// information about the types in the trait. One
506+
// exception is that we sometimes haven't decided
507+
// what kind of closure a closure is. *But*, in
508+
// that case, it turns out, the type of the
509+
// closure will also change, because the closure
510+
// also includes references to its upvars as part
511+
// of its type, and those types are resolved at
512+
// the same time.
513+
pending_obligation.stalled_on =
514+
trait_ref_type_vars(selcx, data.to_poly_trait_ref());
515+
516+
debug!("process_predicate: pending obligation {:?} now stalled on {:?}",
517+
selcx.infcx().resolve_type_vars_if_possible(obligation),
518+
pending_obligation.stalled_on);
519+
520+
Ok(None)
521+
} else {
522+
Ok(Some(inferred_obligations))
523+
}
518524
}
519525
Err(selection_err) => {
520526
info!("selecting trait `{:?}` at depth {} yielded Err",

src/librustc/middle/traits/mod.rs

+2-21
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
//! Trait Resolution. See the Book for more.
1212
13-
pub use self::SelectionError::*;
1413
pub use self::FulfillmentErrorCode::*;
1514
pub use self::Vtable::*;
1615
pub use self::ObligationCauseCode::*;
@@ -48,6 +47,8 @@ pub use self::object_safety::is_vtable_safe_method;
4847
pub use self::select::EvaluationCache;
4948
pub use self::select::SelectionContext;
5049
pub use self::select::SelectionCache;
50+
pub use self::select::{Selection, SelectionError, SelectionOk, SelectionResult};
51+
pub use self::select::{Unimplemented, OutputTypeParameterMismatch, TraitNotObjectSafe};
5152
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
5253
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
5354
pub use self::util::elaborate_predicates;
@@ -163,17 +164,6 @@ pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
163164
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
164165
pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
165166

166-
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
167-
168-
#[derive(Clone,Debug)]
169-
pub enum SelectionError<'tcx> {
170-
Unimplemented,
171-
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
172-
ty::PolyTraitRef<'tcx>,
173-
ty::error::TypeError<'tcx>),
174-
TraitNotObjectSafe(DefId),
175-
}
176-
177167
pub struct FulfillmentError<'tcx> {
178168
pub obligation: PredicateObligation<'tcx>,
179169
pub code: FulfillmentErrorCode<'tcx>
@@ -186,15 +176,6 @@ pub enum FulfillmentErrorCode<'tcx> {
186176
CodeAmbiguity,
187177
}
188178

189-
/// When performing resolution, it is typically the case that there
190-
/// can be one of three outcomes:
191-
///
192-
/// - `Ok(Some(r))`: success occurred with result `r`
193-
/// - `Ok(None)`: could not definitely determine anything, usually due
194-
/// to inconclusive type inference.
195-
/// - `Err(e)`: error `e` occurred
196-
pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
197-
198179
/// Given the successful resolution of an obligation, the `Vtable`
199180
/// indicates where the vtable comes from. Note that while we call this
200181
/// a "vtable", it does not necessarily indicate dynamic dispatch at

src/librustc/middle/traits/project.rs

+21-11
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use super::Obligation;
1818
use super::ObligationCause;
1919
use super::PredicateObligation;
2020
use super::SelectionContext;
21-
use super::SelectionError;
21+
use super::{SelectionError, SelectionOk};
2222
use super::VtableClosureData;
2323
use super::VtableImplData;
2424
use super::util;
@@ -90,8 +90,8 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
9090
debug!("poly_project_and_unify_type(obligation={:?})",
9191
obligation);
9292

93-
let infcx = selcx.infcx();
94-
infcx.commit_if_ok(|snapshot| {
93+
selcx.commit_if_ok(|selcx, snapshot| {
94+
let infcx = selcx.infcx();
9595
let (skol_predicate, skol_map) =
9696
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
9797

@@ -657,24 +657,30 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
657657
{
658658
debug!("assemble_candidates_from_predicates(obligation={:?})",
659659
obligation);
660-
let infcx = selcx.infcx();
661660
for predicate in env_predicates {
662661
debug!("assemble_candidates_from_predicates: predicate={:?}",
663662
predicate);
664663
match predicate {
665664
ty::Predicate::Projection(ref data) => {
666665
let same_name = data.item_name() == obligation.predicate.item_name;
667666

668-
let is_match = same_name && infcx.probe(|_| {
667+
let is_match = same_name && selcx.probe(|selcx, _| {
669668
let origin = TypeOrigin::Misc(obligation.cause.span);
670669
let data_poly_trait_ref =
671670
data.to_poly_trait_ref();
672671
let obligation_poly_trait_ref =
673672
obligation_trait_ref.to_poly_trait_ref();
674-
infcx.sub_poly_trait_refs(false,
675-
origin,
676-
data_poly_trait_ref,
677-
obligation_poly_trait_ref).is_ok()
673+
match selcx.infcx().sub_poly_trait_refs(false,
674+
origin,
675+
data_poly_trait_ref,
676+
obligation_poly_trait_ref)
677+
{
678+
Ok(InferOk { obligations, .. }) => {
679+
selcx.extend_inferred_obligations(obligations);
680+
true
681+
},
682+
Err(_) => false,
683+
}
678684
});
679685

680686
debug!("assemble_candidates_from_predicates: candidate={:?} \
@@ -734,8 +740,12 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
734740
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
735741
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
736742
let vtable = match selcx.select(&trait_obligation) {
737-
Ok(Some(vtable)) => vtable,
738-
Ok(None) => {
743+
Ok(SelectionOk { selection: Some(vtable), obligations }) => {
744+
selcx.extend_inferred_obligations(obligations);
745+
vtable
746+
},
747+
Ok(SelectionOk { selection: None, obligations }) => {
748+
selcx.extend_inferred_obligations(obligations);
739749
candidate_set.ambiguous = true;
740750
return Ok(());
741751
}

0 commit comments

Comments
 (0)