diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index bf4273dbfd0..25c86be993f 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -11,6 +11,8 @@ use middle::mem_categorization::Typer; use middle::ty; use middle::typeck::infer::InferCtxt; +use std::collections::HashSet; +use std::rc::Rc; use util::ppaux::Repr; use super::CodeAmbiguity; @@ -30,6 +32,13 @@ use super::select::SelectionContext; /// method `select_all_or_error` can be used to report any remaining /// ambiguous cases as errors. pub struct FulfillmentContext<'tcx> { + // a simple cache that aims to cache *exact duplicate obligations* + // and avoid adding them twice. This serves a different purpose + // than the `SelectionCache`: it avoids duplicate errors and + // permits recursive obligations, which are often generated from + // traits like `Send` et al. + duplicate_set: HashSet>>, + // A list of all obligations that have been registered with this // fulfillment context. trait_obligations: Vec>, @@ -43,6 +52,7 @@ pub struct FulfillmentContext<'tcx> { impl<'tcx> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { + duplicate_set: HashSet::new(), trait_obligations: Vec::new(), attempted_mark: 0, } @@ -52,9 +62,13 @@ impl<'tcx> FulfillmentContext<'tcx> { tcx: &ty::ctxt<'tcx>, obligation: Obligation<'tcx>) { - debug!("register_obligation({})", obligation.repr(tcx)); - assert!(!obligation.trait_ref.has_escaping_regions()); - self.trait_obligations.push(obligation); + if self.duplicate_set.insert(obligation.trait_ref.clone()) { + debug!("register_obligation({})", obligation.repr(tcx)); + assert!(!obligation.trait_ref.has_escaping_regions()); + self.trait_obligations.push(obligation); + } else { + debug!("register_obligation({}) -- already seen, skip", obligation.repr(tcx)); + } } pub fn select_all_or_error<'a>(&mut self, diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 9ce6947731d..71a183b475c 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -113,7 +113,7 @@ pub enum MethodMatchedData { /// candidate is one that might match or might not, depending on how /// type variables wind up being resolved. This only occurs during inference. /// -/// For selection to suceed, there must be exactly one non-ambiguous +/// For selection to succeed, there must be exactly one non-ambiguous /// candidate. Usually, it is not possible to have more than one /// definitive candidate, due to the coherence rules. However, there is /// one case where it could occur: if there is a blanket impl for a @@ -1149,24 +1149,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - // FIXME -- To be more like a normal impl, we should just - // ignore the nested cases here, and instead generate nested - // obligations in `confirm_candidate`. However, this doesn't - // work because we require handling the recursive cases to - // avoid infinite cycles (that is, with recursive types, - // sometimes `Foo : Copy` only holds if `Foo : Copy`). - match self.builtin_bound(bound, stack.obligation.self_ty()) { - Ok(If(nested)) => { - debug!("builtin_bound: bound={} nested={}", - bound.repr(self.tcx()), - nested.repr(self.tcx())); - let data = self.vtable_builtin_data(stack.obligation, bound, nested); - match self.winnow_selection(Some(stack), VtableBuiltin(data)) { - EvaluatedToOk => { Ok(candidates.vec.push(BuiltinCandidate(bound))) } - EvaluatedToAmbig => { Ok(candidates.ambiguous = true) } - EvaluatedToErr => { Err(Unimplemented) } - } + Ok(If(_)) => { + debug!("builtin_bound: bound={}", + bound.repr(self.tcx())); + candidates.vec.push(BuiltinCandidate(bound)); + Ok(()) } Ok(ParameterBuiltin) => { Ok(()) } Ok(AmbiguousBuiltin) => { Ok(candidates.ambiguous = true) } @@ -1539,8 +1527,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate.repr(self.tcx())); match candidate { - // FIXME -- see assemble_builtin_bound_candidates() - BuiltinCandidate(_) | + BuiltinCandidate(builtin_bound) => { + Ok(VtableBuiltin( + try!(self.confirm_builtin_candidate(obligation, builtin_bound)))) + } + ErrorCandidate => { Ok(VtableBuiltin(VtableBuiltinData { nested: VecPerParamSpace::empty() })) } @@ -1590,8 +1581,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match try!(self.builtin_bound(bound, obligation.self_ty())) { If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)), - AmbiguousBuiltin | - ParameterBuiltin => { + AmbiguousBuiltin | ParameterBuiltin => { self.tcx().sess.span_bug( obligation.cause.span, format!("builtin bound for {} was ambig", diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 71439f5887b..23072dee3b6 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -965,7 +965,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn: ValueRef, - llargs: Vec , + llargs: &[ValueRef], fn_ty: Ty<'tcx>, call_info: Option, // FIXME(15064) is_lang_item is a horrible hack, please remove it diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 80a17465d78..50d2f885afa 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -808,7 +808,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Invoke the actual rust fn and update bcx/llresult. let (llret, b) = base::invoke(bcx, llfn, - llargs, + llargs[], callee_ty, call_info, dest.is_none()); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 4ed79837896..fbaf1e65810 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -291,7 +291,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), &[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil(bcx.tcx())); - let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None, false); + let (_, variant_cx) = invoke(variant_cx, dtor_addr, args[], dtor_ty, None, false); variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope); variant_cx diff --git a/src/test/compile-fail/comm-not-freeze-receiver.rs b/src/test/compile-fail/comm-not-freeze-receiver.rs new file mode 100644 index 00000000000..8cb4b6328c4 --- /dev/null +++ b/src/test/compile-fail/comm-not-freeze-receiver.rs @@ -0,0 +1,15 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn test() {} + +fn main() { + test::>(); //~ ERROR: `core::kinds::Sync` is not implemented +} diff --git a/src/test/compile-fail/comm-not-freeze.rs b/src/test/compile-fail/comm-not-freeze.rs index b6277a3e2bd..8c17895eb8a 100644 --- a/src/test/compile-fail/comm-not-freeze.rs +++ b/src/test/compile-fail/comm-not-freeze.rs @@ -11,7 +11,5 @@ fn test() {} fn main() { - test::>(); //~ ERROR: `core::kinds::Sync` is not implemented - test::>(); //~ ERROR: `core::kinds::Sync` is not implemented - test::>(); //~ ERROR: `core::kinds::Sync` is not implemented + test::>(); //~ ERROR: `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/dst-object-from-unsized-type.rs b/src/test/compile-fail/dst-object-from-unsized-type.rs index e40cc342c0b..99c63c3c6e9 100644 --- a/src/test/compile-fail/dst-object-from-unsized-type.rs +++ b/src/test/compile-fail/dst-object-from-unsized-type.rs @@ -13,18 +13,24 @@ trait Foo for Sized? {} impl Foo for str {} -fn test(t: &T) { +fn test1(t: &T) { let u: &Foo = t; //~^ ERROR `core::kinds::Sized` is not implemented for the type `T` +} +fn test2(t: &T) { let v: &Foo = t as &Foo; //~^ ERROR `core::kinds::Sized` is not implemented for the type `T` } -fn main() { +fn test3() { let _: &[&Foo] = &["hi"]; //~^ ERROR `core::kinds::Sized` is not implemented for the type `str` +} +fn test4() { let _: &Foo = "hi" as &Foo; //~^ ERROR `core::kinds::Sized` is not implemented for the type `str` } + +fn main() { } diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 96088052e91..e6ac30139c3 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -18,7 +18,6 @@ fn new_struct(r: A+'static) -> Struct { //~^ ERROR the trait `core::kinds::Sized` is not implemented //~^ ERROR the trait `core::kinds::Sized` is not implemented Struct { r: r } - //~^ ERROR the trait `core::kinds::Sized` is not implemented } trait Curve {} diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index 3d16ff0a3fa..bef8ca6b86c 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -32,5 +32,5 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR the trait `core::kinds::Send` is not implemented for the type `B` + //~^ ERROR the trait `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/issue-8727.rs b/src/test/compile-fail/issue-8727.rs index e2790eb7b39..d1a86d334cb 100644 --- a/src/test/compile-fail/issue-8727.rs +++ b/src/test/compile-fail/issue-8727.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern:reached the recursion limit during monomorphization + // Verify the compiler fails with an error on infinite function // recursions. - struct Data(Box>); fn generic( _ : Vec<(Data,T)> ) { - //~^ ERROR reached the recursion limit during monomorphization let rec : Vec<(Data,(bool,T))> = Vec::new(); generic( rec ); } diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index 202529c30b3..f0c4a4243ac 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -22,7 +22,7 @@ struct MyStruct { } struct MyNoncopyStruct { - x: Box, + x: Box, } fn test<'a,T,U:Copy>(_: &'a int) { diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs index 26b0c5503e3..1a82a2b3832 100644 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ b/src/test/compile-fail/kindck-destructor-owned.rs @@ -16,7 +16,7 @@ struct Foo { } impl Drop for Foo { -//~^ ERROR the trait `core::kinds::Send` is not implemented for the type `Foo` +//~^ ERROR the trait `core::kinds::Send` is not implemented //~^^ NOTE cannot implement a destructor on a structure or enumeration that does not satisfy Send fn drop(&mut self) { } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index c92887965c0..a430fe72333 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -22,6 +22,10 @@ fn f(val: T) { let a = &t as &Gettable; //~^ ERROR the trait `core::kinds::Send` is not implemented //~^^ ERROR the trait `core::kinds::Copy` is not implemented +} + +fn g(val: T) { + let t: S = S; let a: &Gettable = &t; //~^ ERROR the trait `core::kinds::Send` is not implemented //~^^ ERROR the trait `core::kinds::Copy` is not implemented @@ -30,9 +34,15 @@ fn f(val: T) { fn foo<'a>() { let t: S<&'a int> = S; let a = &t as &Gettable<&'a int>; +} + +fn foo2<'a>() { let t: Box> = box S; let a = t as Box>; //~^ ERROR the trait `core::kinds::Copy` is not implemented +} + +fn foo3<'a>() { let t: Box> = box S; let a: Box> = t; //~^ ERROR the trait `core::kinds::Copy` is not implemented diff --git a/src/test/compile-fail/kindck-nonsendable-1.rs b/src/test/compile-fail/kindck-nonsendable-1.rs index 6ca3f0174bb..d694fd2c795 100644 --- a/src/test/compile-fail/kindck-nonsendable-1.rs +++ b/src/test/compile-fail/kindck-nonsendable-1.rs @@ -13,10 +13,14 @@ use std::rc::Rc; fn foo(_x: Rc) {} -fn main() { +fn bar() { let x = Rc::new(3u); let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented - let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented - let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented +} + +fn bar2() { + let x = Rc::new(3u); let _: proc() = proc() foo(x); } + +fn main() { } diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs index 102cb636550..d988a245700 100644 --- a/src/test/compile-fail/unsendable-class.rs +++ b/src/test/compile-fail/unsendable-class.rs @@ -29,5 +29,5 @@ fn foo(i:int, j: Rc) -> foo { fn main() { let cat = "kitty".to_string(); let (tx, _) = channel(); //~ ERROR `core::kinds::Send` is not implemented - tx.send(foo(42, Rc::new(cat))); //~ ERROR `core::kinds::Send` is not implemented + tx.send(foo(42, Rc::new(cat))); } diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index edef3ae6492..0462a2025d2 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -8,14 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum Foo { FooSome(T), FooNone } -fn bar() { } -fn foo() { bar::>() } +fn is_sized() { } +fn not_sized() { } + +enum Foo { FooSome(U), FooNone } +fn foo1() { not_sized::>() } // Hunky dory. +fn foo2() { not_sized::>() } //~^ ERROR the trait `core::kinds::Sized` is not implemented -//~^^ ERROR the trait `core::kinds::Sized` is not implemented // -// One error is for T being provided to Foo, the other is -// for Foo being provided to bar. +// Not OK: `T` is not sized. + +enum Bar { BarSome(U), BarNone } +fn bar1() { not_sized::>() } +fn bar2() { is_sized::>() } +//~^ ERROR the trait `core::kinds::Sized` is not implemented +// +// Not OK: `Bar` is not sized, but it should be. fn main() { } diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs index 58aba1a2646..db2e9cb9328 100644 --- a/src/test/compile-fail/unsized-struct.rs +++ b/src/test/compile-fail/unsized-struct.rs @@ -8,13 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Foo { data: T } -fn bar() { } -fn foo() { bar::>() } +fn is_sized() { } +fn not_sized() { } + +struct Foo { data: T } +fn foo1() { not_sized::>() } // Hunky dory. +fn foo2() { not_sized::>() } //~^ ERROR the trait `core::kinds::Sized` is not implemented -//~^^ ERROR the trait `core::kinds::Sized` is not implemented -// One error is for the T in Foo, the other is for Foo as a value -// for bar's type parameter. +// +// Not OK: `T` is not sized. + +struct Bar { data: T } +fn bar1() { not_sized::>() } +fn bar2() { is_sized::>() } +//~^ ERROR the trait `core::kinds::Sized` is not implemented +// +// Not OK: `Bar` is not sized, but it should be. fn main() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index fba1237340f..0a75240f2d8 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -57,6 +57,9 @@ fn f8(x1: &S, x2: &S) { fn f9(x1: Box>, x2: Box>) { f5(&(*x1, 34i)); //~^ ERROR the trait `core::kinds::Sized` is not implemented +} + +fn f10(x1: Box>, x2: Box>) { f5(&(32i, *x2)); //~^ ERROR the trait `core::kinds::Sized` is not implemented } diff --git a/src/test/compile-fail/unsized5.rs b/src/test/compile-fail/unsized5.rs index 2f1eb35a426..d9d7a86889f 100644 --- a/src/test/compile-fail/unsized5.rs +++ b/src/test/compile-fail/unsized5.rs @@ -29,6 +29,8 @@ struct S4 { } enum E { V1(X, int), //~ERROR `core::kinds::Sized` is not implemented +} +enum F { V2{f1: X, f: int}, //~ERROR `core::kinds::Sized` is not implemented }