Skip to content

Commit 703364f

Browse files
committed
Rollup merge of rust-lang#21968 - nikomatsakis:issue-21965-duplicate-preds-in-env, r=pnkfelix
We were already building a hashset to check for duplicates, but we assumed that the initial vector had no duplicates. Fixes rust-lang#21965. r? @pnkfelix
2 parents dfc9265 + bbf0898 commit 703364f

File tree

5 files changed

+125
-28
lines changed

5 files changed

+125
-28
lines changed

Diff for: src/librustc/middle/traits/select.rs

-19
Original file line numberDiff line numberDiff line change
@@ -1335,25 +1335,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13351335
// the where clauses are in scope.
13361336
true
13371337
}
1338-
(&ParamCandidate(ref bound1), &ParamCandidate(ref bound2)) => {
1339-
self.infcx.probe(|_| {
1340-
let bound1 =
1341-
project::normalize_with_depth(self,
1342-
stack.obligation.cause.clone(),
1343-
stack.obligation.recursion_depth+1,
1344-
bound1);
1345-
let bound2 =
1346-
project::normalize_with_depth(self,
1347-
stack.obligation.cause.clone(),
1348-
stack.obligation.recursion_depth+1,
1349-
bound2);
1350-
let origin =
1351-
infer::RelateOutputImplTypes(stack.obligation.cause.span);
1352-
self.infcx
1353-
.sub_poly_trait_refs(false, origin, bound1.value, bound2.value)
1354-
.is_ok()
1355-
})
1356-
}
13571338
_ => {
13581339
false
13591340
}

Diff for: src/librustc/middle/traits/util.rs

+47-9
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,58 @@
1111
use middle::subst::{Substs, VecPerParamSpace};
1212
use middle::infer::InferCtxt;
1313
use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef};
14-
use std::collections::HashSet;
1514
use std::fmt;
1615
use std::rc::Rc;
1716
use syntax::ast;
1817
use syntax::codemap::Span;
1918
use util::common::ErrorReported;
19+
use util::nodemap::FnvHashSet;
2020
use util::ppaux::Repr;
2121

2222
use super::{Obligation, ObligationCause, PredicateObligation,
2323
VtableImpl, VtableParam, VtableImplData};
2424

25+
struct PredicateSet<'a,'tcx:'a> {
26+
tcx: &'a ty::ctxt<'tcx>,
27+
set: FnvHashSet<ty::Predicate<'tcx>>,
28+
}
29+
30+
impl<'a,'tcx> PredicateSet<'a,'tcx> {
31+
fn new(tcx: &'a ty::ctxt<'tcx>) -> PredicateSet<'a,'tcx> {
32+
PredicateSet { tcx: tcx, set: FnvHashSet() }
33+
}
34+
35+
fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
36+
// We have to be careful here because we want
37+
//
38+
// for<'a> Foo<&'a int>
39+
//
40+
// and
41+
//
42+
// for<'b> Foo<&'b int>
43+
//
44+
// to be considered equivalent. So normalize all late-bound
45+
// regions before we throw things into the underlying set.
46+
let normalized_pred = match *pred {
47+
ty::Predicate::Trait(ref data) =>
48+
ty::Predicate::Trait(ty::anonymize_late_bound_regions(self.tcx, data)),
49+
50+
ty::Predicate::Equate(ref data) =>
51+
ty::Predicate::Equate(ty::anonymize_late_bound_regions(self.tcx, data)),
52+
53+
ty::Predicate::RegionOutlives(ref data) =>
54+
ty::Predicate::RegionOutlives(ty::anonymize_late_bound_regions(self.tcx, data)),
55+
56+
ty::Predicate::TypeOutlives(ref data) =>
57+
ty::Predicate::TypeOutlives(ty::anonymize_late_bound_regions(self.tcx, data)),
58+
59+
ty::Predicate::Projection(ref data) =>
60+
ty::Predicate::Projection(ty::anonymize_late_bound_regions(self.tcx, data)),
61+
};
62+
self.set.insert(normalized_pred)
63+
}
64+
}
65+
2566
///////////////////////////////////////////////////////////////////////////
2667
// `Elaboration` iterator
2768
///////////////////////////////////////////////////////////////////////////
@@ -36,7 +77,7 @@ use super::{Obligation, ObligationCause, PredicateObligation,
3677
pub struct Elaborator<'cx, 'tcx:'cx> {
3778
tcx: &'cx ty::ctxt<'tcx>,
3879
stack: Vec<StackEntry<'tcx>>,
39-
visited: HashSet<ty::Predicate<'tcx>>,
80+
visited: PredicateSet<'cx,'tcx>,
4081
}
4182

4283
struct StackEntry<'tcx> {
@@ -65,14 +106,11 @@ pub fn elaborate_trait_refs<'cx, 'tcx>(
65106

66107
pub fn elaborate_predicates<'cx, 'tcx>(
67108
tcx: &'cx ty::ctxt<'tcx>,
68-
predicates: Vec<ty::Predicate<'tcx>>)
109+
mut predicates: Vec<ty::Predicate<'tcx>>)
69110
-> Elaborator<'cx, 'tcx>
70111
{
71-
let visited: HashSet<ty::Predicate<'tcx>> =
72-
predicates.iter()
73-
.map(|b| (*b).clone())
74-
.collect();
75-
112+
let mut visited = PredicateSet::new(tcx);
113+
predicates.retain(|pred| visited.insert(pred));
76114
let entry = StackEntry { position: 0, predicates: predicates };
77115
Elaborator { tcx: tcx, stack: vec![entry], visited: visited }
78116
}
@@ -94,7 +132,7 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
94132
// recursion in some cases. One common case is when
95133
// people define `trait Sized: Sized { }` rather than `trait
96134
// Sized { }`.
97-
predicates.retain(|r| self.visited.insert(r.clone()));
135+
predicates.retain(|r| self.visited.insert(r));
98136

99137
self.stack.push(StackEntry { position: 0,
100138
predicates: predicates });

Diff for: src/test/compile-fail/issue-21974.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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 (for now) we report an ambiguity error here, because
12+
// specific trait relationships are ignored for the purposes of trait
13+
// matching. This behavior should likely be improved such that this
14+
// test passes. See #21974 for more details.
15+
16+
trait Foo {
17+
fn foo(self);
18+
}
19+
20+
fn foo<'a,'b,T>(x: &'a T, y: &'b T)
21+
where &'a T : Foo,
22+
&'b T : Foo
23+
{
24+
x.foo(); //~ ERROR type annotations required
25+
y.foo();
26+
}
27+
28+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 we do not report ambiguities when equivalent predicates
12+
// (modulo bound lifetime names) appears in the environment
13+
// twice. Issue #21965.
14+
15+
fn foo<T>(t: T) -> i32
16+
where T : for<'a> Fn(&'a u8) -> i32,
17+
T : for<'b> Fn(&'b u8) -> i32,
18+
{
19+
t(&3)
20+
}
21+
22+
fn main() {
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 we do not report ambiguities when the same predicate
12+
// appears in the environment twice. Issue #21965.
13+
14+
trait Foo {
15+
type B;
16+
17+
fn get() -> Self::B;
18+
}
19+
20+
fn foo<T>() -> ()
21+
where T : Foo<B=()>, T : Foo<B=()>
22+
{
23+
<T as Foo>::get()
24+
}
25+
26+
fn main() {
27+
}

0 commit comments

Comments
 (0)