Skip to content

Commit 50d8057

Browse files
author
Michael Rosenberg
committed
Fix issue rust-lang#34792
1 parent bbfcb47 commit 50d8057

File tree

2 files changed

+72
-44
lines changed

2 files changed

+72
-44
lines changed

src/librustc/traits/select.rs

+45-44
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ enum SelectionCandidate<'tcx> {
206206

207207
/// This is a trait matching with a projected type as `Self`, and
208208
/// we found an applicable bound in the trait definition.
209-
ProjectionCandidate,
209+
ProjectionCandidate(ty::PolyTraitRef<'tcx>),
210210

211211
/// Implementation of a `Fn`-family trait by one of the anonymous types
212212
/// generated for a `||` expression. The ty::ClosureKind informs the
@@ -238,7 +238,9 @@ impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> {
238238
DefaultImplObjectCandidate(def_id) => {
239239
DefaultImplObjectCandidate(def_id)
240240
}
241-
ProjectionCandidate => ProjectionCandidate,
241+
ProjectionCandidate(ref bound) => {
242+
return tcx.lift(bound).map(ProjectionCandidate);
243+
}
242244
FnPointerCandidate => FnPointerCandidate,
243245
ObjectCandidate => ObjectCandidate,
244246
BuiltinObjectCandidate => BuiltinObjectCandidate,
@@ -1170,22 +1172,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
11701172
debug!("assemble_candidates_for_projected_tys: trait_def_id={:?}",
11711173
trait_def_id);
11721174

1173-
let result = self.probe(|this, snapshot| {
1175+
self.in_snapshot(|this, snapshot| {
11741176
this.match_projection_obligation_against_bounds_from_trait(obligation,
1175-
snapshot)
1177+
candidates,
1178+
snapshot);
11761179
});
1177-
1178-
if result {
1179-
candidates.vec.push(ProjectionCandidate);
1180-
}
11811180
}
11821181

11831182
fn match_projection_obligation_against_bounds_from_trait(
11841183
&mut self,
11851184
obligation: &TraitObligation<'tcx>,
1185+
candidates: &mut SelectionCandidateSet<'tcx>,
11861186
snapshot: &infer::CombinedSnapshot)
1187-
-> bool
11881187
{
1188+
11891189
let poly_trait_predicate =
11901190
self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
11911191
let (skol_trait_predicate, skol_map) =
@@ -1215,36 +1215,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
12151215
bounds={:?}",
12161216
bounds);
12171217

1218-
let matching_bound =
1218+
let matching_bounds =
12191219
util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec())
12201220
.filter_to_traits()
1221-
.find(
1221+
.filter(
12221222
|bound| self.probe(
12231223
|this, _| this.match_projection(obligation,
12241224
bound.clone(),
12251225
skol_trait_predicate.trait_ref.clone(),
12261226
&skol_map,
1227-
snapshot)));
1228-
1229-
debug!("match_projection_obligation_against_bounds_from_trait: \
1230-
matching_bound={:?}",
1231-
matching_bound);
1232-
match matching_bound {
1233-
None => false,
1234-
Some(bound) => {
1235-
// Repeat the successful match, if any, this time outside of a probe.
1236-
let result = self.match_projection(obligation,
1237-
bound,
1238-
skol_trait_predicate.trait_ref.clone(),
1239-
&skol_map,
1240-
snapshot);
1241-
1242-
self.infcx.pop_skolemized(skol_map, snapshot);
1227+
snapshot)))
1228+
.map(|bound| ProjectionCandidate(bound));
12431229

1244-
assert!(result);
1245-
true
1246-
}
1247-
}
1230+
candidates.vec.extend(matching_bounds);
12481231
}
12491232

12501233
fn match_projection(&mut self,
@@ -1684,7 +1667,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
16841667

16851668
match other.candidate {
16861669
ObjectCandidate |
1687-
ParamCandidate(_) | ProjectionCandidate => match victim.candidate {
1670+
ParamCandidate(_) | ProjectionCandidate(..) => match victim.candidate {
16881671
DefaultImplCandidate(..) => {
16891672
bug!(
16901673
"default implementations shouldn't be recorded \
@@ -1701,11 +1684,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
17011684
// for impls.
17021685
true
17031686
}
1704-
ObjectCandidate |
1705-
ProjectionCandidate => {
1706-
// Arbitrarily give param candidates priority
1707-
// over projection and object candidates.
1708-
true
1687+
// Arbitrarily give param candidates priority
1688+
// over projection and object candidates.
1689+
ObjectCandidate => true,
1690+
ProjectionCandidate(..) => {
1691+
if let ProjectionCandidate(..) = other.candidate {
1692+
// Not identical, since equality is checked at the start
1693+
false
1694+
} else {
1695+
true
1696+
}
17091697
},
17101698
ParamCandidate(..) => false,
17111699
},
@@ -2056,8 +2044,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
20562044
Ok(VtableFnPointer(data))
20572045
}
20582046

2059-
ProjectionCandidate => {
2060-
self.confirm_projection_candidate(obligation);
2047+
ProjectionCandidate(bound) => {
2048+
self.confirm_projection_candidate(obligation, bound);
20612049
Ok(VtableParam(Vec::new()))
20622050
}
20632051

@@ -2069,14 +2057,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
20692057
}
20702058

20712059
fn confirm_projection_candidate(&mut self,
2072-
obligation: &TraitObligation<'tcx>)
2060+
obligation: &TraitObligation<'tcx>,
2061+
matching_bound: ty::PolyTraitRef<'tcx>)
20732062
{
2063+
debug!("confirm_projection_candidate: matching_bound={:?}", matching_bound);
2064+
20742065
self.in_snapshot(|this, snapshot| {
2075-
let result =
2076-
this.match_projection_obligation_against_bounds_from_trait(obligation,
2077-
snapshot);
2066+
let poly_trait_predicate =
2067+
this.infcx().resolve_type_vars_if_possible(&obligation.predicate);
2068+
let (skol_trait_predicate, skol_map) =
2069+
this.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot);
2070+
2071+
// Repeat the successful match, if any, this time outside of a probe.
2072+
let result = this.match_projection(obligation,
2073+
matching_bound,
2074+
skol_trait_predicate.trait_ref.clone(),
2075+
&skol_map,
2076+
snapshot);
2077+
this.infcx.pop_skolemized(skol_map, snapshot);
2078+
20782079
assert!(result);
2079-
})
2080+
});
20802081
}
20812082

20822083
fn confirm_param_candidate(&mut self,

src/test/run-pass/issue-34792.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2016 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 correct type inference for projections when the associated
12+
// type has multiple trait bounds
13+
14+
struct A;
15+
struct B;
16+
17+
trait Foo {
18+
type T: PartialEq<A> + PartialEq<B>;
19+
}
20+
21+
fn generic<F: Foo>(t: F::T, a: A, b: B) -> bool {
22+
// Equivalent, but not as explicit: t == a && t == b
23+
<<F as Foo>::T as PartialEq<_>>::eq(&t, &a) &&
24+
<<F as Foo>::T as PartialEq<_>>::eq(&t, &b)
25+
}
26+
27+
fn main() {}

0 commit comments

Comments
 (0)