Skip to content

Commit 9c6d35d

Browse files
author
Ariel Ben-Yehuda
committed
evaluate projections outside the outer probe in recursive evaluation
1 parent f37b4fe commit 9c6d35d

File tree

2 files changed

+77
-156
lines changed

2 files changed

+77
-156
lines changed

src/librustc/middle/traits/select.rs

+46-156
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// except according to those terms.
1010

1111
//! See `README.md` for high-level documentation
12-
#![allow(dead_code)] // FIXME -- just temporarily
1312
1413
pub use self::MethodMatchResult::*;
1514
pub use self::MethodMatchedData::*;
@@ -190,7 +189,6 @@ pub enum MethodMatchedData {
190189
/// parameter environment.
191190
#[derive(PartialEq,Eq,Debug,Clone)]
192191
enum SelectionCandidate<'tcx> {
193-
PhantomFnCandidate,
194192
BuiltinCandidate(ty::BuiltinBound),
195193
ParamCandidate(ty::PolyTraitRef<'tcx>),
196194
ImplCandidate(DefId),
@@ -403,8 +401,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
403401
debug!("evaluate_obligation({:?})",
404402
obligation);
405403

406-
self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
407-
.may_apply()
404+
self.infcx.probe(|_| {
405+
self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
406+
.may_apply()
407+
})
408408
}
409409

410410
fn evaluate_predicates_recursively<'a,'o,I>(&mut self,
@@ -415,7 +415,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
415415
{
416416
let mut result = EvaluatedToOk;
417417
for obligation in predicates {
418-
match self.evaluate_predicate_recursively(stack, obligation) {
418+
let eval = self.evaluate_predicate_recursively(stack, obligation);
419+
debug!("evaluate_predicate_recursively({:?}) = {:?}",
420+
obligation, eval);
421+
match eval {
419422
EvaluatedToErr => { return EvaluatedToErr; }
420423
EvaluatedToAmbig => { result = EvaluatedToAmbig; }
421424
EvaluatedToUnknown => {
@@ -454,10 +457,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
454457
}
455458

456459
ty::Predicate::Equate(ref p) => {
457-
let result = self.infcx.probe(|_| {
458-
self.infcx.equality_predicate(obligation.cause.span, p)
459-
});
460-
match result {
460+
// does this code ever run?
461+
match self.infcx.equality_predicate(obligation.cause.span, p) {
461462
Ok(()) => EvaluatedToOk,
462463
Err(_) => EvaluatedToErr
463464
}
@@ -489,21 +490,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
489490
}
490491

491492
ty::Predicate::Projection(ref data) => {
492-
self.infcx.probe(|_| {
493-
let project_obligation = obligation.with(data.clone());
494-
match project::poly_project_and_unify_type(self, &project_obligation) {
495-
Ok(Some(subobligations)) => {
496-
self.evaluate_predicates_recursively(previous_stack,
497-
subobligations.iter())
498-
}
499-
Ok(None) => {
500-
EvaluatedToAmbig
501-
}
502-
Err(_) => {
503-
EvaluatedToErr
504-
}
493+
let project_obligation = obligation.with(data.clone());
494+
match project::poly_project_and_unify_type(self, &project_obligation) {
495+
Ok(Some(subobligations)) => {
496+
self.evaluate_predicates_recursively(previous_stack,
497+
subobligations.iter())
505498
}
506-
})
499+
Ok(None) => {
500+
EvaluatedToAmbig
501+
}
502+
Err(_) => {
503+
EvaluatedToErr
504+
}
505+
}
507506
}
508507
}
509508
}
@@ -610,40 +609,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
610609
}
611610

612611
match self.candidate_from_obligation(stack) {
613-
Ok(Some(c)) => self.winnow_candidate(stack, &c),
612+
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
614613
Ok(None) => EvaluatedToAmbig,
615614
Err(..) => EvaluatedToErr
616615
}
617616
}
618617

619-
/// Evaluates whether the impl with id `impl_def_id` could be applied to the self type
620-
/// `obligation_self_ty`. This can be used either for trait or inherent impls.
621-
pub fn evaluate_impl(&mut self,
622-
impl_def_id: DefId,
623-
obligation: &TraitObligation<'tcx>)
624-
-> bool
618+
/// Further evaluate `candidate` to decide whether all type parameters match and whether nested
619+
/// obligations are met. Returns true if `candidate` remains viable after this further
620+
/// scrutiny.
621+
fn evaluate_candidate<'o>(&mut self,
622+
stack: &TraitObligationStack<'o, 'tcx>,
623+
candidate: &SelectionCandidate<'tcx>)
624+
-> EvaluationResult
625625
{
626-
debug!("evaluate_impl(impl_def_id={:?}, obligation={:?})",
627-
impl_def_id,
628-
obligation);
629-
630-
self.infcx.probe(|snapshot| {
631-
match self.match_impl(impl_def_id, obligation, snapshot) {
632-
Ok((substs, skol_map)) => {
633-
let vtable_impl = self.vtable_impl(impl_def_id,
634-
substs,
635-
obligation.cause.clone(),
636-
obligation.recursion_depth + 1,
637-
skol_map,
638-
snapshot);
639-
self.winnow_selection(TraitObligationStackList::empty(),
640-
VtableImpl(vtable_impl)).may_apply()
641-
}
642-
Err(()) => {
643-
false
626+
debug!("evaluate_candidate: depth={} candidate={:?}",
627+
stack.obligation.recursion_depth, candidate);
628+
let result = self.infcx.probe(|_| {
629+
let candidate = (*candidate).clone();
630+
match self.confirm_candidate(stack.obligation, candidate) {
631+
Ok(selection) => {
632+
self.evaluate_predicates_recursively(
633+
stack.list(),
634+
selection.nested_obligations().iter())
644635
}
636+
Err(..) => EvaluatedToErr
645637
}
646-
})
638+
});
639+
debug!("evaluate_candidate: depth={} result={:?}",
640+
stack.obligation.recursion_depth, result);
641+
result
647642
}
648643

649644
fn pick_evaluation_cache(&self) -> &EvaluationCache<'tcx> {
@@ -779,7 +774,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
779774
// Instead, we select the right impl now but report `Bar does
780775
// not implement Clone`.
781776
if candidates.len() > 1 {
782-
candidates.retain(|c| self.winnow_candidate(stack, c).may_apply())
777+
candidates.retain(|c| self.evaluate_candidate(stack, c).may_apply())
783778
}
784779

785780
// If there are STILL multiple candidate, we can further reduce
@@ -1184,9 +1179,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11841179
Ok(obligations) => {
11851180
self.evaluate_predicates_recursively(stack.list(), obligations.iter())
11861181
}
1187-
Err(()) => {
1188-
EvaluatedToErr
1189-
}
1182+
Err(()) => EvaluatedToErr
11901183
}
11911184
})
11921185
}
@@ -1525,37 +1518,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15251518
// attempt to evaluate recursive bounds to see if they are
15261519
// satisfied.
15271520

1528-
/// Further evaluate `candidate` to decide whether all type parameters match and whether nested
1529-
/// obligations are met. Returns true if `candidate` remains viable after this further
1530-
/// scrutiny.
1531-
fn winnow_candidate<'o>(&mut self,
1532-
stack: &TraitObligationStack<'o, 'tcx>,
1533-
candidate: &SelectionCandidate<'tcx>)
1534-
-> EvaluationResult
1535-
{
1536-
debug!("winnow_candidate: candidate={:?}", candidate);
1537-
let result = self.infcx.probe(|_| {
1538-
let candidate = (*candidate).clone();
1539-
match self.confirm_candidate(stack.obligation, candidate) {
1540-
Ok(selection) => self.winnow_selection(stack.list(),
1541-
selection),
1542-
Err(..) => EvaluatedToErr
1543-
}
1544-
});
1545-
debug!("winnow_candidate depth={} result={:?}",
1546-
stack.obligation.recursion_depth, result);
1547-
result
1548-
}
1549-
1550-
fn winnow_selection<'o>(&mut self,
1551-
stack: TraitObligationStackList<'o,'tcx>,
1552-
selection: Selection<'tcx>)
1553-
-> EvaluationResult
1554-
{
1555-
self.evaluate_predicates_recursively(stack,
1556-
selection.nested_obligations().iter())
1557-
}
1558-
15591521
/// Returns true if `candidate_i` should be dropped in favor of
15601522
/// `candidate_j`. Generally speaking we will drop duplicate
15611523
/// candidates and prefer where-clause candidates.
@@ -1581,9 +1543,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15811543
"default implementations shouldn't be recorded \
15821544
when there are other valid candidates");
15831545
}
1584-
&PhantomFnCandidate => {
1585-
self.tcx().sess.bug("PhantomFn didn't short-circuit selection");
1586-
}
15871546
&ImplCandidate(..) |
15881547
&ClosureCandidate(..) |
15891548
&FnPointerCandidate(..) |
@@ -2013,7 +1972,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20131972
try!(self.confirm_builtin_candidate(obligation, builtin_bound))))
20141973
}
20151974

2016-
PhantomFnCandidate |
20171975
ErrorCandidate => {
20181976
Ok(VtableBuiltin(VtableBuiltinData { nested: vec![] }))
20191977
}
@@ -2788,74 +2746,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
27882746
}
27892747
}
27902748

2791-
/// Determines whether the self type declared against
2792-
/// `impl_def_id` matches `obligation_self_ty`. If successful,
2793-
/// returns the substitutions used to make them match. See
2794-
/// `match_impl()`. For example, if `impl_def_id` is declared
2795-
/// as:
2796-
///
2797-
/// impl<T:Copy> Foo for Box<T> { ... }
2798-
///
2799-
/// and `obligation_self_ty` is `int`, we'd get back an `Err(_)`
2800-
/// result. But if `obligation_self_ty` were `Box<int>`, we'd get
2801-
/// back `Ok(T=int)`.
2802-
fn match_inherent_impl(&mut self,
2803-
impl_def_id: DefId,
2804-
obligation_cause: &ObligationCause,
2805-
obligation_self_ty: Ty<'tcx>)
2806-
-> Result<Substs<'tcx>,()>
2807-
{
2808-
// Create fresh type variables for each type parameter declared
2809-
// on the impl etc.
2810-
let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
2811-
obligation_cause.span,
2812-
impl_def_id);
2813-
2814-
// Find the self type for the impl.
2815-
let impl_self_ty = self.tcx().lookup_item_type(impl_def_id).ty;
2816-
let impl_self_ty = impl_self_ty.subst(self.tcx(), &impl_substs);
2817-
2818-
debug!("match_impl_self_types(obligation_self_ty={:?}, impl_self_ty={:?})",
2819-
obligation_self_ty,
2820-
impl_self_ty);
2821-
2822-
match self.match_self_types(obligation_cause,
2823-
impl_self_ty,
2824-
obligation_self_ty) {
2825-
Ok(()) => {
2826-
debug!("Matched impl_substs={:?}", impl_substs);
2827-
Ok(impl_substs)
2828-
}
2829-
Err(()) => {
2830-
debug!("NoMatch");
2831-
Err(())
2832-
}
2833-
}
2834-
}
2835-
2836-
fn match_self_types(&mut self,
2837-
cause: &ObligationCause,
2838-
2839-
// The self type provided by the impl/caller-obligation:
2840-
provided_self_ty: Ty<'tcx>,
2841-
2842-
// The self type the obligation is for:
2843-
required_self_ty: Ty<'tcx>)
2844-
-> Result<(),()>
2845-
{
2846-
// FIXME(#5781) -- equating the types is stronger than
2847-
// necessary. Should consider variance of trait w/r/t Self.
2848-
2849-
let origin = infer::RelateSelfType(cause.span);
2850-
match self.infcx.eq_types(false,
2851-
origin,
2852-
provided_self_ty,
2853-
required_self_ty) {
2854-
Ok(()) => Ok(()),
2855-
Err(_) => Err(()),
2856-
}
2857-
}
2858-
28592749
///////////////////////////////////////////////////////////////////////////
28602750
// Miscellany
28612751

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// check that trait matching can handle impls whose types are only
12+
// constrained by a projection.
13+
14+
trait IsU32 {}
15+
impl IsU32 for u32 {}
16+
17+
trait Mirror { type Image: ?Sized; }
18+
impl<T: ?Sized> Mirror for T { type Image = T; }
19+
20+
trait Bar {}
21+
impl<U: Mirror, V: Mirror<Image=L>, L: Mirror<Image=U>> Bar for V
22+
where U::Image: IsU32 {}
23+
24+
trait Foo { fn name() -> &'static str; }
25+
impl Foo for u64 { fn name() -> &'static str { "u64" } }
26+
impl<T: Bar> Foo for T { fn name() -> &'static str { "Bar" }}
27+
28+
fn main() {
29+
assert_eq!(<u64 as Foo>::name(), "u64");
30+
assert_eq!(<u32 as Foo>::name(), "Bar");
31+
}

0 commit comments

Comments
 (0)