if [[ $LLVM_VERSION != '3.4' ]]; then exit 0; fi
fi &&
make tidy &&
- travis_wait make -j4 rustc-stage1 &&
+ make -j4 rustc-stage1 RUSTFLAGS='-Z time-passes' &&
make check-stage1-std check-stage1-rpass check-stage1-cfail check-stage1-rfail check-stage1-doc
env:
let it = trait_m.generics.types.get_vec(subst::FnSpace).iter()
.zip(impl_m.generics.types.get_vec(subst::FnSpace).iter());
- for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
- // Check that the impl does not require any builtin-bounds
- // that the trait does not guarantee:
- let extra_bounds =
- impl_param_def.bounds.builtin_bounds -
- trait_param_def.bounds.builtin_bounds;
- if !extra_bounds.is_empty() {
- tcx.sess.span_err(
- impl_m_span,
- format!("in method `{}`, \
- type parameter {} requires `{}`, \
- which is not required by \
- the corresponding type parameter \
- in the trait declaration",
- token::get_ident(trait_m.ident),
- i,
- extra_bounds.user_string(tcx)).as_slice());
- return;
- }
-
- // FIXME(#2687)---we should be checking that the bounds of the
- // trait imply the bounds of the subtype, but it appears we
- // are...not checking this.
- if impl_param_def.bounds.trait_bounds.len() !=
- trait_param_def.bounds.trait_bounds.len()
- {
- let found = impl_param_def.bounds.trait_bounds.len();
- let expected = trait_param_def.bounds.trait_bounds.len();
- tcx.sess.span_err(
- impl_m_span,
- format!("in method `{}`, type parameter {} has {} trait \
- bound{}, but the corresponding type parameter in \
- the trait declaration has {} trait bound{}",
- token::get_ident(trait_m.ident),
- i,
- found,
- if found == 1 {""} else {"s"},
- expected,
- if expected == 1 {""} else {"s"}).as_slice());
- return;
- }
- }
-
// This code is best explained by example. Consider a trait:
//
// trait Trait<T> {
let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
+ // Check bounds.
+ for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
+ // Check that the impl does not require any builtin-bounds
+ // that the trait does not guarantee:
+ let extra_bounds =
+ impl_param_def.bounds.builtin_bounds -
+ trait_param_def.bounds.builtin_bounds;
+ if !extra_bounds.is_empty() {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("in method `{}`, \
+ type parameter {} requires `{}`, \
+ which is not required by \
+ the corresponding type parameter \
+ in the trait declaration",
+ token::get_ident(trait_m.ident),
+ i,
+ extra_bounds.user_string(tcx)).as_slice());
+ return;
+ }
+
+ // Check that the trait bounds of the trait imply the bounds of its
+ // implementation.
+ //
+ // FIXME(pcwalton): We could be laxer here regarding sub- and super-
+ // traits, but I doubt that'll be wanted often, so meh.
+ for impl_trait_bound in impl_param_def.bounds.trait_bounds.iter() {
+ let impl_trait_bound =
+ impl_trait_bound.subst(tcx, &impl_to_skol_substs);
+
+ let mut ok = false;
+ for trait_bound in trait_param_def.bounds.trait_bounds.iter() {
+ let trait_bound =
+ trait_bound.subst(tcx, &trait_to_skol_substs);
+ let infcx = infer::new_infer_ctxt(tcx);
+ match infer::mk_sub_trait_refs(&infcx,
+ true,
+ infer::Misc(impl_m_span),
+ trait_bound,
+ impl_trait_bound.clone()) {
+ Ok(_) => {
+ ok = true;
+ break
+ }
+ Err(_) => continue,
+ }
+ }
+
+ if !ok {
+ tcx.sess.span_err(impl_m_span,
+ format!("in method `{}`, type parameter {} \
+ requires bound `{}`, which is not \
+ required by the corresponding \
+ type parameter in the trait \
+ declaration",
+ token::get_ident(trait_m.ident),
+ i,
+ ppaux::trait_ref_to_str(
+ tcx,
+ &*impl_trait_bound)).as_slice())
+ }
+ }
+ }
+
// Check the impl method type IM is a subtype of the trait method
// type TM. To see why this makes sense, think of a vtable. The
// expected type of the function pointers in the vtable is the
--- /dev/null
+// Copyright 2014 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Make sure rustc checks the type parameter bounds in implementations of traits,
+// see #2687
+
+trait A {}
+
+trait B: A {}
+
+trait C: A {}
+
+trait Foo {
+ fn test_error1_fn<T: Eq>(&self);
+ fn test_error2_fn<T: Eq + Ord>(&self);
+ fn test_error3_fn<T: Eq + Ord>(&self);
+ fn test3_fn<T: Eq + Ord>(&self);
+ fn test4_fn<T: Eq + Ord>(&self);
+ fn test_error5_fn<T: A>(&self);
+ fn test6_fn<T: A + Eq>(&self);
+ fn test_error7_fn<T: A>(&self);
+ fn test_error8_fn<T: B>(&self);
+}
+
+impl Foo for int {
+ // invalid bound for T, was defined as Eq in trait
+ fn test_error1_fn<T: Ord>(&self) {}
+ //~^ ERROR in method `test_error1_fn`, type parameter 0 requires bound `core::cmp::Ord`
+
+ // invalid bound for T, was defined as Eq + Ord in trait
+ fn test_error2_fn<T: Eq + B>(&self) {}
+ //~^ ERROR in method `test_error2_fn`, type parameter 0 requires bound `B`
+
+ // invalid bound for T, was defined as Eq + Ord in trait
+ fn test_error3_fn<T: B + Eq>(&self) {}
+ //~^ ERROR in method `test_error3_fn`, type parameter 0 requires bound `B`
+
+ // multiple bounds, same order as in trait
+ fn test3_fn<T: Ord + Eq>(&self) {}
+
+ // multiple bounds, different order as in trait
+ fn test4_fn<T: Eq + Ord>(&self) {}
+
+ // parameters in impls must be equal or more general than in the defining trait
+ fn test_error5_fn<T: B>(&self) {}
+ //~^ ERROR in method `test_error5_fn`, type parameter 0 requires bound `B`
+
+ // bound `std::cmp::Eq` not enforced by this implementation, but this is OK
+ fn test6_fn<T: A>(&self) {}
+
+ fn test_error7_fn<T: A + Eq>(&self) {}
+ //~^ ERROR in method `test_error7_fn`, type parameter 0 requires bound `core::cmp::Eq`
+
+ fn test_error8_fn<T: C>(&self) {}
+ //~^ ERROR in method `test_error8_fn`, type parameter 0 requires bound `C`
+}
+
+
+trait Getter<T> { }
+
+trait Trait {
+ fn method<G:Getter<int>>();
+}
+
+impl Trait for uint {
+ fn method<G: Getter<uint>>() {}
+ //~^ ERROR in method `method`, type parameter 0 requires bound `Getter<uint>`
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2014 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue #5886: a complex instance of issue #2687.
+
+trait Iterator<A> {
+ fn next(&mut self) -> Option<A>;
+}
+
+trait IteratorUtil<A> {
+ fn zip<B, U: Iterator<U>>(self, other: U) -> ZipIterator<Self, U>;
+}
+
+impl<A, T: Iterator<A>> IteratorUtil<A> for T {
+ fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
+ //~^ ERROR in method `zip`, type parameter 1 requires bound `Iterator<B>`
+ ZipIterator{a: self, b: other}
+ }
+}
+
+struct ZipIterator<T, U> {
+ a: T, b: U
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2014 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that type parameter bounds on an implementation need not match the
+// trait exactly, as long as the implementation doesn't demand *more* bounds
+// than the trait.
+
+trait A {
+ fn foo<T: Eq + Ord>(&self);
+}
+
+impl A for int {
+ fn foo<T: Ord + Ord>(&self) {}
+}
+
+fn main() {}
+
+