Skip to content

Commit 68f5cbb

Browse files
nikomatsakisJorge Aparicio
authored and
Jorge Aparicio
committed
Evaluate projection predicates during trait selection. Fixes #20296.
1 parent cddb41d commit 68f5cbb

File tree

2 files changed

+107
-12
lines changed

2 files changed

+107
-12
lines changed

src/librustc/middle/traits/select.rs

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
289289
}
290290
}
291291

292+
fn evaluate_predicates_recursively<'a,'o,I>(&mut self,
293+
stack: Option<&TraitObligationStack<'o, 'tcx>>,
294+
mut predicates: I)
295+
-> EvaluationResult<'tcx>
296+
where I : Iterator<&'a PredicateObligation<'tcx>>, 'tcx:'a
297+
{
298+
let mut result = EvaluatedToOk;
299+
for obligation in predicates {
300+
match self.evaluate_predicate_recursively(stack, obligation) {
301+
EvaluatedToErr(e) => { return EvaluatedToErr(e); }
302+
EvaluatedToAmbig => { result = EvaluatedToAmbig; }
303+
EvaluatedToOk => { }
304+
}
305+
}
306+
result
307+
}
308+
292309
fn evaluate_predicate_recursively<'o>(&mut self,
293310
previous_stack: Option<&TraitObligationStack<'o, 'tcx>>,
294311
obligation: &PredicateObligation<'tcx>)
@@ -320,9 +337,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
320337
EvaluatedToOk
321338
}
322339

323-
ty::Predicate::Projection(..) => {
324-
// FIXME(#20296) -- we should be able to give a more precise answer here
325-
EvaluatedToAmbig
340+
ty::Predicate::Projection(ref data) => {
341+
let result = self.infcx.probe(|_| {
342+
let project_obligation = obligation.with(data.clone());
343+
project::poly_project_and_unify_type(self, &project_obligation)
344+
});
345+
match result {
346+
Ok(Some(subobligations)) => {
347+
self.evaluate_predicates_recursively(previous_stack, subobligations.iter())
348+
}
349+
Ok(None) => {
350+
EvaluatedToAmbig
351+
}
352+
Err(_) => {
353+
EvaluatedToErr(Unimplemented)
354+
}
355+
}
326356
}
327357
}
328358
}
@@ -1026,15 +1056,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10261056
selection: Selection<'tcx>)
10271057
-> EvaluationResult<'tcx>
10281058
{
1029-
let mut result = EvaluatedToOk;
1030-
for obligation in selection.iter_nested() {
1031-
match self.evaluate_predicate_recursively(stack, obligation) {
1032-
EvaluatedToErr(e) => { return EvaluatedToErr(e); }
1033-
EvaluatedToAmbig => { result = EvaluatedToAmbig; }
1034-
EvaluatedToOk => { }
1035-
}
1036-
}
1037-
result
1059+
self.evaluate_predicates_recursively(stack, selection.iter_nested())
10381060
}
10391061

10401062
/// Returns true if `candidate_i` should be dropped in favor of `candidate_j`.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2014 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+
// Test that we evaluate projection predicates to winnow out
12+
// candidates during trait selection and method resolution (#20296).
13+
// If we don't properly winnow out candidates based on the output type
14+
// `Output=[A]`, then the impl marked with `(*)` is seen to conflict
15+
// with all the others.
16+
17+
#![feature(associated_types, default_type_params)]
18+
19+
use std::ops::Deref;
20+
21+
pub trait MyEq<Sized? U=Self> for Sized? {
22+
fn eq(&self, u: &U) -> bool;
23+
}
24+
25+
impl<A, B> MyEq<[B]> for [A]
26+
where A : MyEq<B>
27+
{
28+
fn eq(&self, other: &[B]) -> bool {
29+
self.len() == other.len() &&
30+
self.iter().zip(other.iter())
31+
.all(|(a, b)| MyEq::eq(a, b))
32+
}
33+
}
34+
35+
// (*) This impl conflicts with everything unless the `Output=[A]`
36+
// constraint is considered.
37+
impl<'a, A, B, Lhs> MyEq<[B; 0]> for Lhs
38+
where A: MyEq<B>, Lhs: Deref<Output=[A]>
39+
{
40+
fn eq(&self, other: &[B; 0]) -> bool {
41+
MyEq::eq(&**self, other.as_slice())
42+
}
43+
}
44+
45+
struct DerefWithHelper<H, T> {
46+
pub helper: H
47+
}
48+
49+
trait Helper<T> {
50+
fn helper_borrow(&self) -> &T;
51+
}
52+
53+
impl<T> Helper<T> for Option<T> {
54+
fn helper_borrow(&self) -> &T {
55+
self.as_ref().unwrap()
56+
}
57+
}
58+
59+
impl<T, H: Helper<T>> Deref for DerefWithHelper<H, T> {
60+
type Output = T;
61+
62+
fn deref(&self) -> &T {
63+
self.helper.helper_borrow()
64+
}
65+
}
66+
67+
pub fn check<T: MyEq>(x: T, y: T) -> bool {
68+
let d: DerefWithHelper<Option<T>, T> = DerefWithHelper { helper: Some(x) };
69+
d.eq(&y)
70+
}
71+
72+
pub fn main() {
73+
}

0 commit comments

Comments
 (0)