]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15087 : iliekturtles/rust/13810-make-install-mingw32, r=brson
authorbors <bors@rust-lang.org>
Thu, 3 Jul 2014 03:41:39 +0000 (03:41 +0000)
committerbors <bors@rust-lang.org>
Thu, 3 Jul 2014 03:41:39 +0000 (03:41 +0000)
Short-term fix per @brson's comment: https://github.com/rust-lang/rust/issues/13810#issuecomment-43562843. Tested on Win7 x64 and Linux.

One possible issue is that `install.sh` doesn't have a `need_cmd` definition like `configure` does. Should this be ported over as well?

Platform-detection code from `configure` copied over to `install.sh` in
order to special case the lib dir being `bin` on Windows instead of
`lib`.

Short-term fix for #13810.

.travis.yml
src/librustc/middle/typeck/check/mod.rs
src/test/compile-fail/trait-bounds-impl-comparison-1.rs [new file with mode: 0644]
src/test/compile-fail/trait-bounds-impl-comparison-2.rs [new file with mode: 0644]
src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs [new file with mode: 0644]

index e3cec33ad070d340397e66e7e6a2f6295f3da90a..dd62defa02039ad5934b688d94fe07980706b4df 100644 (file)
@@ -41,7 +41,7 @@ script: |
     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:
index 5e675242688afc435f02b86f6bbdf33bac92d93d..f5e34e9307764944b73ff9457acb678b2970fa36 100644 (file)
@@ -920,49 +920,6 @@ fn compare_impl_method(tcx: &ty::ctxt,
     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> {
@@ -1037,6 +994,70 @@ fn compare_impl_method(tcx: &ty::ctxt,
     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
diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs b/src/test/compile-fail/trait-bounds-impl-comparison-1.rs
new file mode 100644 (file)
index 0000000..eec1168
--- /dev/null
@@ -0,0 +1,78 @@
+// 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() {}
+
diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs b/src/test/compile-fail/trait-bounds-impl-comparison-2.rs
new file mode 100644 (file)
index 0000000..a970a86
--- /dev/null
@@ -0,0 +1,33 @@
+// 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() {}
+
diff --git a/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs b/src/test/run-pass/trait-bounds-impl-comparison-duplicates.rs
new file mode 100644 (file)
index 0000000..55ad22d
--- /dev/null
@@ -0,0 +1,25 @@
+// 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() {}
+
+