Skip to content

Commit daa0745

Browse files
committed
auto merge of #18749 : nikomatsakis/rust/builtin-bounds-like-other-traits, r=pcwalton
Treat builtin bounds like all other kinds of trait matches. Introduce a simple hashset in the fulfillment context to catch cases where we register the exact same obligation twice. This helps prevent duplicate error reports but also handles the recursive obligations created by builtin bounds. r? @pcwalton cc @flaper87
2 parents dbc379a + 931758c commit daa0745

20 files changed

+112
-54
lines changed

src/librustc/middle/traits/fulfill.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use middle::mem_categorization::Typer;
1212
use middle::ty;
1313
use middle::typeck::infer::InferCtxt;
14+
use std::collections::HashSet;
15+
use std::rc::Rc;
1416
use util::ppaux::Repr;
1517

1618
use super::CodeAmbiguity;
@@ -30,6 +32,13 @@ use super::select::SelectionContext;
3032
/// method `select_all_or_error` can be used to report any remaining
3133
/// ambiguous cases as errors.
3234
pub struct FulfillmentContext<'tcx> {
35+
// a simple cache that aims to cache *exact duplicate obligations*
36+
// and avoid adding them twice. This serves a different purpose
37+
// than the `SelectionCache`: it avoids duplicate errors and
38+
// permits recursive obligations, which are often generated from
39+
// traits like `Send` et al.
40+
duplicate_set: HashSet<Rc<ty::TraitRef<'tcx>>>,
41+
3342
// A list of all obligations that have been registered with this
3443
// fulfillment context.
3544
trait_obligations: Vec<Obligation<'tcx>>,
@@ -43,6 +52,7 @@ pub struct FulfillmentContext<'tcx> {
4352
impl<'tcx> FulfillmentContext<'tcx> {
4453
pub fn new() -> FulfillmentContext<'tcx> {
4554
FulfillmentContext {
55+
duplicate_set: HashSet::new(),
4656
trait_obligations: Vec::new(),
4757
attempted_mark: 0,
4858
}
@@ -52,9 +62,13 @@ impl<'tcx> FulfillmentContext<'tcx> {
5262
tcx: &ty::ctxt<'tcx>,
5363
obligation: Obligation<'tcx>)
5464
{
55-
debug!("register_obligation({})", obligation.repr(tcx));
56-
assert!(!obligation.trait_ref.has_escaping_regions());
57-
self.trait_obligations.push(obligation);
65+
if self.duplicate_set.insert(obligation.trait_ref.clone()) {
66+
debug!("register_obligation({})", obligation.repr(tcx));
67+
assert!(!obligation.trait_ref.has_escaping_regions());
68+
self.trait_obligations.push(obligation);
69+
} else {
70+
debug!("register_obligation({}) -- already seen, skip", obligation.repr(tcx));
71+
}
5872
}
5973

6074
pub fn select_all_or_error<'a>(&mut self,

src/librustc/middle/traits/select.rs

+12-22
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ pub enum MethodMatchedData {
113113
/// candidate is one that might match or might not, depending on how
114114
/// type variables wind up being resolved. This only occurs during inference.
115115
///
116-
/// For selection to suceed, there must be exactly one non-ambiguous
116+
/// For selection to succeed, there must be exactly one non-ambiguous
117117
/// candidate. Usually, it is not possible to have more than one
118118
/// definitive candidate, due to the coherence rules. However, there is
119119
/// one case where it could occur: if there is a blanket impl for a
@@ -1149,24 +1149,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11491149
candidates: &mut CandidateSet<'tcx>)
11501150
-> Result<(),SelectionError<'tcx>>
11511151
{
1152-
// FIXME -- To be more like a normal impl, we should just
1153-
// ignore the nested cases here, and instead generate nested
1154-
// obligations in `confirm_candidate`. However, this doesn't
1155-
// work because we require handling the recursive cases to
1156-
// avoid infinite cycles (that is, with recursive types,
1157-
// sometimes `Foo : Copy` only holds if `Foo : Copy`).
1158-
11591152
match self.builtin_bound(bound, stack.obligation.self_ty()) {
1160-
Ok(If(nested)) => {
1161-
debug!("builtin_bound: bound={} nested={}",
1162-
bound.repr(self.tcx()),
1163-
nested.repr(self.tcx()));
1164-
let data = self.vtable_builtin_data(stack.obligation, bound, nested);
1165-
match self.winnow_selection(Some(stack), VtableBuiltin(data)) {
1166-
EvaluatedToOk => { Ok(candidates.vec.push(BuiltinCandidate(bound))) }
1167-
EvaluatedToAmbig => { Ok(candidates.ambiguous = true) }
1168-
EvaluatedToErr => { Err(Unimplemented) }
1169-
}
1153+
Ok(If(_)) => {
1154+
debug!("builtin_bound: bound={}",
1155+
bound.repr(self.tcx()));
1156+
candidates.vec.push(BuiltinCandidate(bound));
1157+
Ok(())
11701158
}
11711159
Ok(ParameterBuiltin) => { Ok(()) }
11721160
Ok(AmbiguousBuiltin) => { Ok(candidates.ambiguous = true) }
@@ -1539,8 +1527,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15391527
candidate.repr(self.tcx()));
15401528

15411529
match candidate {
1542-
// FIXME -- see assemble_builtin_bound_candidates()
1543-
BuiltinCandidate(_) |
1530+
BuiltinCandidate(builtin_bound) => {
1531+
Ok(VtableBuiltin(
1532+
try!(self.confirm_builtin_candidate(obligation, builtin_bound))))
1533+
}
1534+
15441535
ErrorCandidate => {
15451536
Ok(VtableBuiltin(VtableBuiltinData { nested: VecPerParamSpace::empty() }))
15461537
}
@@ -1590,8 +1581,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15901581

15911582
match try!(self.builtin_bound(bound, obligation.self_ty())) {
15921583
If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)),
1593-
AmbiguousBuiltin |
1594-
ParameterBuiltin => {
1584+
AmbiguousBuiltin | ParameterBuiltin => {
15951585
self.tcx().sess.span_bug(
15961586
obligation.cause.span,
15971587
format!("builtin bound for {} was ambig",

src/librustc_trans/trans/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
965965

966966
pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
967967
llfn: ValueRef,
968-
llargs: Vec<ValueRef> ,
968+
llargs: &[ValueRef],
969969
fn_ty: Ty<'tcx>,
970970
call_info: Option<NodeInfo>,
971971
// FIXME(15064) is_lang_item is a horrible hack, please remove it

src/librustc_trans/trans/callee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
808808
// Invoke the actual rust fn and update bcx/llresult.
809809
let (llret, b) = base::invoke(bcx,
810810
llfn,
811-
llargs,
811+
llargs[],
812812
callee_ty,
813813
call_info,
814814
dest.is_none());

src/librustc_trans/trans/glue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
291291
let dtor_ty = ty::mk_ctor_fn(bcx.tcx(),
292292
&[get_drop_glue_type(bcx.ccx(), t)],
293293
ty::mk_nil(bcx.tcx()));
294-
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None, false);
294+
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args[], dtor_ty, None, false);
295295

296296
variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope);
297297
variant_cx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2013 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+
fn test<T: Sync>() {}
12+
13+
fn main() {
14+
test::<Receiver<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
15+
}

src/test/compile-fail/comm-not-freeze.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,5 @@
1111
fn test<T: Sync>() {}
1212

1313
fn main() {
14-
test::<Sender<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
15-
test::<Receiver<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
16-
test::<Sender<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
14+
test::<Sender<int>>(); //~ ERROR: `core::kinds::Sync` is not implemented
1715
}

src/test/compile-fail/dst-object-from-unsized-type.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,24 @@
1313
trait Foo for Sized? {}
1414
impl Foo for str {}
1515

16-
fn test<Sized? T: Foo>(t: &T) {
16+
fn test1<Sized? T: Foo>(t: &T) {
1717
let u: &Foo = t;
1818
//~^ ERROR `core::kinds::Sized` is not implemented for the type `T`
19+
}
1920

21+
fn test2<Sized? T: Foo>(t: &T) {
2022
let v: &Foo = t as &Foo;
2123
//~^ ERROR `core::kinds::Sized` is not implemented for the type `T`
2224
}
2325

24-
fn main() {
26+
fn test3() {
2527
let _: &[&Foo] = &["hi"];
2628
//~^ ERROR `core::kinds::Sized` is not implemented for the type `str`
29+
}
2730

31+
fn test4() {
2832
let _: &Foo = "hi" as &Foo;
2933
//~^ ERROR `core::kinds::Sized` is not implemented for the type `str`
3034
}
35+
36+
fn main() { }

src/test/compile-fail/issue-5883.rs

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ fn new_struct(r: A+'static)
1818
-> Struct { //~^ ERROR the trait `core::kinds::Sized` is not implemented
1919
//~^ ERROR the trait `core::kinds::Sized` is not implemented
2020
Struct { r: r }
21-
//~^ ERROR the trait `core::kinds::Sized` is not implemented
2221
}
2322

2423
trait Curve {}

src/test/compile-fail/issue-7013.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ struct A {
3232

3333
fn main() {
3434
let a = A {v: box B{v: None} as Box<Foo+Send>};
35-
//~^ ERROR the trait `core::kinds::Send` is not implemented for the type `B`
35+
//~^ ERROR the trait `core::kinds::Send` is not implemented
3636
}

src/test/compile-fail/issue-8727.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// error-pattern:reached the recursion limit during monomorphization
12+
1113
// Verify the compiler fails with an error on infinite function
1214
// recursions.
1315

14-
1516
struct Data(Box<Option<Data>>);
1617

1718
fn generic<T>( _ : Vec<(Data,T)> ) {
18-
//~^ ERROR reached the recursion limit during monomorphization
1919
let rec : Vec<(Data,(bool,T))> = Vec::new();
2020
generic( rec );
2121
}

src/test/compile-fail/kindck-copy.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct MyStruct {
2222
}
2323

2424
struct MyNoncopyStruct {
25-
x: Box<int>,
25+
x: Box<char>,
2626
}
2727

2828
fn test<'a,T,U:Copy>(_: &'a int) {

src/test/compile-fail/kindck-destructor-owned.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct Foo {
1616
}
1717

1818
impl Drop for Foo {
19-
//~^ ERROR the trait `core::kinds::Send` is not implemented for the type `Foo`
19+
//~^ ERROR the trait `core::kinds::Send` is not implemented
2020
//~^^ NOTE cannot implement a destructor on a structure or enumeration that does not satisfy Send
2121
fn drop(&mut self) {
2222
}

src/test/compile-fail/kindck-impl-type-params.rs

+10
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ fn f<T>(val: T) {
2222
let a = &t as &Gettable<T>;
2323
//~^ ERROR the trait `core::kinds::Send` is not implemented
2424
//~^^ ERROR the trait `core::kinds::Copy` is not implemented
25+
}
26+
27+
fn g<T>(val: T) {
28+
let t: S<T> = S;
2529
let a: &Gettable<T> = &t;
2630
//~^ ERROR the trait `core::kinds::Send` is not implemented
2731
//~^^ ERROR the trait `core::kinds::Copy` is not implemented
@@ -30,9 +34,15 @@ fn f<T>(val: T) {
3034
fn foo<'a>() {
3135
let t: S<&'a int> = S;
3236
let a = &t as &Gettable<&'a int>;
37+
}
38+
39+
fn foo2<'a>() {
3340
let t: Box<S<String>> = box S;
3441
let a = t as Box<Gettable<String>>;
3542
//~^ ERROR the trait `core::kinds::Copy` is not implemented
43+
}
44+
45+
fn foo3<'a>() {
3646
let t: Box<S<String>> = box S;
3747
let a: Box<Gettable<String>> = t;
3848
//~^ ERROR the trait `core::kinds::Copy` is not implemented

src/test/compile-fail/kindck-nonsendable-1.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ use std::rc::Rc;
1313

1414
fn foo(_x: Rc<uint>) {}
1515

16-
fn main() {
16+
fn bar() {
1717
let x = Rc::new(3u);
1818
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
19-
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
20-
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
19+
}
20+
21+
fn bar2() {
22+
let x = Rc::new(3u);
2123
let _: proc() = proc() foo(x);
2224
}
25+
26+
fn main() { }

src/test/compile-fail/unsendable-class.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ fn foo(i:int, j: Rc<String>) -> foo {
2929
fn main() {
3030
let cat = "kitty".to_string();
3131
let (tx, _) = channel(); //~ ERROR `core::kinds::Send` is not implemented
32-
tx.send(foo(42, Rc::new(cat))); //~ ERROR `core::kinds::Send` is not implemented
32+
tx.send(foo(42, Rc::new(cat)));
3333
}

src/test/compile-fail/unsized-enum.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,22 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
enum Foo<T> { FooSome(T), FooNone }
1211

13-
fn bar<T: Sized>() { }
14-
fn foo<Sized? T>() { bar::<Foo<T>>() }
12+
fn is_sized<T:Sized>() { }
13+
fn not_sized<Sized? T>() { }
14+
15+
enum Foo<U> { FooSome(U), FooNone }
16+
fn foo1<T>() { not_sized::<Foo<T>>() } // Hunky dory.
17+
fn foo2<Sized? T>() { not_sized::<Foo<T>>() }
18+
//~^ ERROR the trait `core::kinds::Sized` is not implemented
19+
//
20+
// Not OK: `T` is not sized.
21+
22+
enum Bar<Sized? U> { BarSome(U), BarNone }
23+
fn bar1<Sized? T>() { not_sized::<Bar<T>>() }
24+
fn bar2<Sized? T>() { is_sized::<Bar<T>>() }
1525
//~^ ERROR the trait `core::kinds::Sized` is not implemented
16-
//~^^ ERROR the trait `core::kinds::Sized` is not implemented
1726
//
18-
// One error is for T being provided to Foo<T>, the other is
19-
// for Foo<T> being provided to bar.
27+
// Not OK: `Bar<T>` is not sized, but it should be.
2028

2129
fn main() { }

src/test/compile-fail/unsized-struct.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
12+
fn is_sized<T:Sized>() { }
13+
fn not_sized<Sized? T>() { }
14+
1115
struct Foo<T> { data: T }
16+
fn foo1<T>() { not_sized::<Foo<T>>() } // Hunky dory.
17+
fn foo2<Sized? T>() { not_sized::<Foo<T>>() }
18+
//~^ ERROR the trait `core::kinds::Sized` is not implemented
19+
//
20+
// Not OK: `T` is not sized.
1221

13-
fn bar<T: Sized>() { }
14-
fn foo<Sized? T>() { bar::<Foo<T>>() }
22+
struct Bar<Sized? T> { data: T }
23+
fn bar1<Sized? T>() { not_sized::<Bar<T>>() }
24+
fn bar2<Sized? T>() { is_sized::<Bar<T>>() }
1525
//~^ ERROR the trait `core::kinds::Sized` is not implemented
16-
//~^^ ERROR the trait `core::kinds::Sized` is not implemented
17-
// One error is for the T in Foo<T>, the other is for Foo<T> as a value
18-
// for bar's type parameter.
26+
//
27+
// Not OK: `Bar<T>` is not sized, but it should be.
1928

2029
fn main() { }

src/test/compile-fail/unsized3.rs

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ fn f8<Sized? X>(x1: &S<X>, x2: &S<X>) {
5757
fn f9<Sized? X>(x1: Box<S<X>>, x2: Box<E<X>>) {
5858
f5(&(*x1, 34i));
5959
//~^ ERROR the trait `core::kinds::Sized` is not implemented
60+
}
61+
62+
fn f10<Sized? X>(x1: Box<S<X>>, x2: Box<E<X>>) {
6063
f5(&(32i, *x2));
6164
//~^ ERROR the trait `core::kinds::Sized` is not implemented
6265
}

src/test/compile-fail/unsized5.rs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ struct S4 {
2929
}
3030
enum E<Sized? X> {
3131
V1(X, int), //~ERROR `core::kinds::Sized` is not implemented
32+
}
33+
enum F<Sized? X> {
3234
V2{f1: X, f: int}, //~ERROR `core::kinds::Sized` is not implemented
3335
}
3436

0 commit comments

Comments
 (0)