Skip to content

Commit 8fae9cc

Browse files
committed
Normalize bounds that we extract from where clauses. Fixes rust-lang#20765.
1 parent ac32974 commit 8fae9cc

File tree

6 files changed

+126
-29
lines changed

6 files changed

+126
-29
lines changed

src/librustc/middle/traits/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ pub enum Vtable<'tcx, N> {
222222

223223
/// Successful resolution to an obligation provided by the caller
224224
/// for some type parameter.
225-
VtableParam,
225+
VtableParam(Vec<N>),
226226

227227
/// Virtual calls through an object
228228
VtableObject(VtableObjectData<'tcx>),
@@ -446,7 +446,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
446446
VtableImpl(ref i) => i.iter_nested(),
447447
VtableFnPointer(..) => (&[]).iter(),
448448
VtableUnboxedClosure(..) => (&[]).iter(),
449-
VtableParam => (&[]).iter(),
449+
VtableParam(ref n) => n.iter(),
450450
VtableObject(_) => (&[]).iter(),
451451
VtableBuiltin(ref i) => i.iter_nested(),
452452
}
@@ -457,7 +457,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
457457
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
458458
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
459459
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
460-
VtableParam => VtableParam,
460+
VtableParam(ref n) => VtableParam(n.iter().map(op).collect()),
461461
VtableObject(ref p) => VtableObject(p.clone()),
462462
VtableBuiltin(ref b) => VtableBuiltin(b.map_nested(op)),
463463
}
@@ -470,7 +470,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
470470
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
471471
VtableFnPointer(sig) => VtableFnPointer(sig),
472472
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
473-
VtableParam => VtableParam,
473+
VtableParam(n) => VtableParam(n.into_iter().map(op).collect()),
474474
VtableObject(p) => VtableObject(p),
475475
VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
476476
}

src/librustc/middle/traits/select.rs

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
752752
}
753753

754754
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
755-
try!(self.assemble_candidates_from_caller_bounds(obligation, &mut candidates));
755+
try!(self.assemble_candidates_from_caller_bounds(stack, &mut candidates));
756756
debug!("candidate list size: {}", candidates.vec.len());
757757
Ok(candidates)
758758
}
@@ -889,13 +889,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
889889
/// supplied to find out whether it is listed among them.
890890
///
891891
/// Never affects inference environment.
892-
fn assemble_candidates_from_caller_bounds(&mut self,
893-
obligation: &TraitObligation<'tcx>,
894-
candidates: &mut SelectionCandidateSet<'tcx>)
895-
-> Result<(),SelectionError<'tcx>>
892+
fn assemble_candidates_from_caller_bounds<'o>(&mut self,
893+
stack: &TraitObligationStack<'o, 'tcx>,
894+
candidates: &mut SelectionCandidateSet<'tcx>)
895+
-> Result<(),SelectionError<'tcx>>
896896
{
897897
debug!("assemble_candidates_from_caller_bounds({})",
898-
obligation.repr(self.tcx()));
898+
stack.obligation.repr(self.tcx()));
899899

900900
let caller_trait_refs: Vec<_> =
901901
self.param_env().caller_bounds.predicates.iter()
@@ -908,8 +908,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
908908

909909
let matching_bounds =
910910
all_bounds.filter(
911-
|bound| self.infcx.probe(
912-
|_| self.match_poly_trait_ref(obligation, bound.clone())).is_ok());
911+
|bound| self.evaluate_where_clause(stack, bound.clone()).may_apply());
913912

914913
let param_candidates =
915914
matching_bounds.map(|bound| ParamCandidate(bound));
@@ -919,6 +918,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
919918
Ok(())
920919
}
921920

921+
fn evaluate_where_clause<'o>(&mut self,
922+
stack: &TraitObligationStack<'o, 'tcx>,
923+
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
924+
-> EvaluationResult<'tcx>
925+
{
926+
self.infcx().probe(move |_| {
927+
match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
928+
Ok(obligations) => {
929+
self.evaluate_predicates_recursively(Some(stack), obligations.iter())
930+
}
931+
Err(()) => {
932+
EvaluatedToErr(Unimplemented)
933+
}
934+
}
935+
})
936+
}
937+
922938
/// Check for the artificial impl that the compiler will create for an obligation like `X :
923939
/// FnMut<..>` where `X` is an unboxed closure type.
924940
///
@@ -1145,6 +1161,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11451161
candidate_j: &SelectionCandidate<'tcx>)
11461162
-> bool
11471163
{
1164+
if candidate_i == candidate_j {
1165+
return true;
1166+
}
1167+
11481168
match (candidate_i, candidate_j) {
11491169
(&ImplCandidate(impl_def_id), &ParamCandidate(ref bound)) => {
11501170
debug!("Considering whether to drop param {} in favor of impl {}",
@@ -1184,8 +1204,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11841204
// the where clauses are in scope.
11851205
true
11861206
}
1207+
(&ParamCandidate(ref bound1), &ParamCandidate(ref bound2)) => {
1208+
self.infcx.probe(|_| {
1209+
let bound1 =
1210+
project::normalize_with_depth(self,
1211+
stack.obligation.cause.clone(),
1212+
stack.obligation.recursion_depth+1,
1213+
bound1);
1214+
let bound2 =
1215+
project::normalize_with_depth(self,
1216+
stack.obligation.cause.clone(),
1217+
stack.obligation.recursion_depth+1,
1218+
bound2);
1219+
let origin =
1220+
infer::RelateOutputImplTypes(stack.obligation.cause.span);
1221+
self.infcx
1222+
.sub_poly_trait_refs(false, origin, bound1.value, bound2.value)
1223+
.is_ok()
1224+
})
1225+
}
11871226
_ => {
1188-
*candidate_i == *candidate_j
1227+
false
11891228
}
11901229
}
11911230
}
@@ -1567,8 +1606,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15671606
}
15681607

15691608
ParamCandidate(param) => {
1570-
self.confirm_param_candidate(obligation, param);
1571-
Ok(VtableParam)
1609+
let obligations = self.confirm_param_candidate(obligation, param);
1610+
Ok(VtableParam(obligations))
15721611
}
15731612

15741613
ImplCandidate(impl_def_id) => {
@@ -1595,7 +1634,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15951634

15961635
ProjectionCandidate => {
15971636
self.confirm_projection_candidate(obligation);
1598-
Ok(VtableParam)
1637+
Ok(VtableParam(Vec::new()))
15991638
}
16001639
}
16011640
}
@@ -1616,6 +1655,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16161655
fn confirm_param_candidate(&mut self,
16171656
obligation: &TraitObligation<'tcx>,
16181657
param: ty::PolyTraitRef<'tcx>)
1658+
-> Vec<PredicateObligation<'tcx>>
16191659
{
16201660
debug!("confirm_param_candidate({},{})",
16211661
obligation.repr(self.tcx()),
@@ -1625,11 +1665,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16251665
// where-clause trait-ref could be unified with the obligation
16261666
// trait-ref. Repeat that unification now without any
16271667
// transactional boundary; it should not fail.
1628-
match self.confirm_poly_trait_refs(obligation.cause.clone(),
1629-
obligation.predicate.to_poly_trait_ref(),
1630-
param.clone()) {
1631-
Ok(()) => { }
1632-
Err(_) => {
1668+
match self.match_where_clause_trait_ref(obligation, param.clone()) {
1669+
Ok(obligations) => obligations,
1670+
Err(()) => {
16331671
self.tcx().sess.bug(
16341672
format!("Where clause `{}` was applicable to `{}` but now is not",
16351673
param.repr(self.tcx()),
@@ -2056,19 +2094,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20562094
})
20572095
}
20582096

2097+
/// Normalize `where_clause_trait_ref` and try to match it against
2098+
/// `obligation`. If successful, return any predicates that
2099+
/// result from the normalization. Normalization is necessary
2100+
/// because where-clauses are stored in the parameter environment
2101+
/// unnormalized.
2102+
fn match_where_clause_trait_ref(&mut self,
2103+
obligation: &TraitObligation<'tcx>,
2104+
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
2105+
-> Result<Vec<PredicateObligation<'tcx>>,()>
2106+
{
2107+
let where_clause_trait_ref =
2108+
project::normalize_with_depth(self,
2109+
obligation.cause.clone(),
2110+
obligation.recursion_depth+1,
2111+
&where_clause_trait_ref);
2112+
2113+
let () =
2114+
try!(self.match_poly_trait_ref(obligation, where_clause_trait_ref.value.clone()));
2115+
2116+
Ok(where_clause_trait_ref.obligations)
2117+
}
2118+
2119+
/// Returns `Ok` if `poly_trait_ref` being true implies that the
2120+
/// obligation is satisfied.
20592121
fn match_poly_trait_ref(&mut self,
20602122
obligation: &TraitObligation<'tcx>,
2061-
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
2123+
poly_trait_ref: ty::PolyTraitRef<'tcx>)
20622124
-> Result<(),()>
20632125
{
2064-
debug!("match_poly_trait_ref: obligation={} where_clause_trait_ref={}",
2126+
debug!("match_poly_trait_ref: obligation={} poly_trait_ref={}",
20652127
obligation.repr(self.tcx()),
2066-
where_clause_trait_ref.repr(self.tcx()));
2128+
poly_trait_ref.repr(self.tcx()));
20672129

20682130
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
20692131
match self.infcx.sub_poly_trait_refs(false,
20702132
origin,
2071-
where_clause_trait_ref,
2133+
poly_trait_ref,
20722134
obligation.predicate.to_poly_trait_ref()) {
20732135
Ok(()) => Ok(()),
20742136
Err(_) => Err(()),

src/librustc/middle/traits/util.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,9 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
380380
format!("VtableObject({})",
381381
d.repr(tcx)),
382382

383-
super::VtableParam =>
384-
format!("VtableParam"),
383+
super::VtableParam(ref n) =>
384+
format!("VtableParam({})",
385+
n.repr(tcx)),
385386

386387
super::VtableBuiltin(ref d) =>
387388
d.repr(tcx)

src/librustc/middle/ty_fold.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
514514
traits::VtableFnPointer(ref d) => {
515515
traits::VtableFnPointer(d.fold_with(folder))
516516
}
517-
traits::VtableParam => traits::VtableParam,
517+
traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
518518
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
519519
traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
520520
}

src/librustc_trans/trans/meth.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
736736
format!("cannot get vtable for an object type: {}",
737737
data.repr(bcx.tcx())).as_slice());
738738
}
739-
traits::VtableParam => {
739+
traits::VtableParam(..) => {
740740
bcx.sess().bug(
741741
&format!("resolved vtable for {} to bad vtable {} in trans",
742742
trait_ref.repr(bcx.tcx()),
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
// Test a where clause that uses a non-normalized projection type.
12+
13+
trait Int
14+
{
15+
type T;
16+
}
17+
18+
trait NonZero
19+
{
20+
fn non_zero(self) -> bool;
21+
}
22+
23+
fn foo<I:Int<T=J>,J>(t: I) -> bool
24+
where <I as Int>::T : NonZero
25+
// ^~~~~~~~~~~~~ canonical form is just J
26+
{
27+
bar::<J>()
28+
}
29+
30+
fn bar<NZ:NonZero>() -> bool { true }
31+
32+
fn main ()
33+
{
34+
}

0 commit comments

Comments
 (0)