about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAaron Turon <aturon@mozilla.com>2016-03-11 12:15:28 -0800
committerAaron Turon <aturon@mozilla.com>2016-03-14 15:05:14 -0700
commitd80189d305ce24b6a1fd83a4f724d17506b64a13 (patch)
tree4902d58b47e5528809d91cbdb124b0ad95f9f78d
parent326201657a912d9a291da057d82ddd4576ae04f2 (diff)
downloadrust-d80189d305ce24b6a1fd83a4f724d17506b64a13.tar.gz
rust-d80189d305ce24b6a1fd83a4f724d17506b64a13.zip
Test fixes, added README for tests
-rw-r--r--src/librustc/middle/traits/specialize/mod.rs17
-rw-r--r--src/test/auxiliary/xcrate_associated_type_defaults.rs12
-rw-r--r--src/test/compile-fail/specialization/README.md21
-rw-r--r--src/test/compile-fail/specialization/specialization-default-projection.rs4
-rw-r--r--src/test/compile-fail/specialization/specialization-default-types.rs4
-rw-r--r--src/test/compile-fail/specialization/specialization-overlap.rs4
-rw-r--r--src/test/run-pass/default-associated-types.rs21
-rw-r--r--src/test/run-pass/specialization/README.md37
-rw-r--r--src/test/run-pass/specialization/specialization-assoc-fns.rs2
-rw-r--r--src/test/run-pass/specialization/specialization-cross-crate-defaults.rs12
-rw-r--r--src/test/run-pass/specialization/specialization-cross-crate-no-gate.rs29
-rw-r--r--src/test/run-pass/specialization/specialization-default-methods.rs2
-rw-r--r--src/test/run-pass/specialization/specialization-on-projection.rs2
-rw-r--r--src/test/run-pass/specialization/specialization-overlap-projection.rs33
-rw-r--r--src/test/run-pass/specialization/specialization-projection-alias.rs6
-rw-r--r--src/test/run-pass/specialization/specialization-projection.rs22
-rw-r--r--src/test/run-pass/specialization/specialization-translate-projections-with-params.rs4
-rw-r--r--src/test/run-pass/specialization/specialization-translate-projections.rs3
-rw-r--r--src/test/run-pass/xcrate-associated-type-defaults.rs22
19 files changed, 230 insertions, 27 deletions
diff --git a/src/librustc/middle/traits/specialize/mod.rs b/src/librustc/middle/traits/specialize/mod.rs
index a5b3c667fc0..624ebc545fe 100644
--- a/src/librustc/middle/traits/specialize/mod.rs
+++ b/src/librustc/middle/traits/specialize/mod.rs
@@ -25,7 +25,7 @@ use middle::def_id::DefId;
 use middle::infer::{self, InferCtxt, TypeOrigin};
 use middle::region;
 use middle::subst::{Subst, Substs};
-use middle::traits::ProjectionMode;
+use middle::traits::{self, ProjectionMode, ObligationCause, Normalized};
 use middle::ty::{self, TyCtxt};
 use syntax::codemap::DUMMY_SP;
 
@@ -149,14 +149,21 @@ pub fn specializes(tcx: &TyCtxt, impl1_def_id: DefId, impl2_def_id: DefId) -> bo
     // create a parameter environment corresponding to a (skolemized) instantiation of impl1
     let scheme = tcx.lookup_item_type(impl1_def_id);
     let predicates = tcx.lookup_predicates(impl1_def_id);
-    let penv = tcx.construct_parameter_environment(DUMMY_SP,
-                                                   &scheme.generics,
-                                                   &predicates,
-                                                   region::DUMMY_CODE_EXTENT);
+    let mut penv = tcx.construct_parameter_environment(DUMMY_SP,
+                                                       &scheme.generics,
+                                                       &predicates,
+                                                       region::DUMMY_CODE_EXTENT);
     let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
                              .unwrap()
                              .subst(tcx, &penv.free_substs);
 
+    // Normalize the trait reference, adding any obligations that arise into the impl1 assumptions
+    let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
+        let selcx = &mut SelectionContext::new(&infcx);
+        traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
+    };
+    penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| o.predicate));
+
     // Install the parameter environment, which means we take the predicates of impl1 as assumptions:
     infcx.parameter_environment = penv;
 
diff --git a/src/test/auxiliary/xcrate_associated_type_defaults.rs b/src/test/auxiliary/xcrate_associated_type_defaults.rs
index 43852a4e793..6779438c672 100644
--- a/src/test/auxiliary/xcrate_associated_type_defaults.rs
+++ b/src/test/auxiliary/xcrate_associated_type_defaults.rs
@@ -10,9 +10,13 @@
 
 #![feature(associated_type_defaults)]
 
-pub trait Foo {
-    type Input = usize;
-    fn bar(&self, _: Self::Input) {}
+pub trait Foo<T: Default + ToString> {
+    type Out: Default + ToString = T;
 }
 
-impl Foo for () {}
+impl Foo<u32> for () {
+}
+
+impl Foo<u64> for () {
+    type Out = bool;
+}
diff --git a/src/test/compile-fail/specialization/README.md b/src/test/compile-fail/specialization/README.md
new file mode 100644
index 00000000000..f2b4bf946c5
--- /dev/null
+++ b/src/test/compile-fail/specialization/README.md
@@ -0,0 +1,21 @@
+This directory contains the test for incorrect usage of specialization that
+should lead to compile failure. Those tests break down into a few categories:
+
+- Feature gating
+  - [On use of the `default` keyword](specialization-feature-gate-default.rs)
+  - [On overlapping impls](specialization-feature-gate-overlap.rs)
+
+- Overlap checking with specialization enabled
+  - [Basic overlap scenarios](specialization-overlap.rs)
+    - Includes purely structural overlap
+    - Includes purely trait-based overlap
+    - Includes mix
+  - [Overlap with differing polarity](specialization-overlap-negative.rs)
+
+- [Attempt to specialize without using `default`](specialization-no-default.rs)
+
+- [Attempt to change impl polarity in a specialization](specialization-polarity.rs)
+
+- Attempt to rely on projection of a `default` type
+  - [Rely on it externally in both generic and monomorphic contexts](specialization-default-projection.rs)
+  - [Rely on it both within an impl and outside it](specialization-default-types.rs)
diff --git a/src/test/compile-fail/specialization/specialization-default-projection.rs b/src/test/compile-fail/specialization/specialization-default-projection.rs
index 377838f2a08..96cbd7a4852 100644
--- a/src/test/compile-fail/specialization/specialization-default-projection.rs
+++ b/src/test/compile-fail/specialization/specialization-default-projection.rs
@@ -28,14 +28,14 @@ fn generic<T>() -> <T as Foo>::Assoc {
     // `T` could be some downstream crate type that specializes (or,
     // for that matter, `u8`).
 
-    () //~ ERROR E0308
+    () //~ ERROR mismatched types
 }
 
 fn monomorphic() -> () {
     // Even though we know that `()` is not specialized in a
     // downstream crate, typeck refuses to project here.
 
-    generic::<()>() //~ ERROR E0308
+    generic::<()>() //~ ERROR mismatched types
 }
 
 fn main() {
diff --git a/src/test/compile-fail/specialization/specialization-default-types.rs b/src/test/compile-fail/specialization/specialization-default-types.rs
index 3c2e3d5a36c..18acecb4229 100644
--- a/src/test/compile-fail/specialization/specialization-default-types.rs
+++ b/src/test/compile-fail/specialization/specialization-default-types.rs
@@ -22,7 +22,7 @@ trait Example {
 impl<T> Example for T {
     default type Output = Box<T>;
     default fn generate(self) -> Self::Output {
-        Box::new(self) //~ ERROR E0308
+        Box::new(self) //~ ERROR mismatched types
     }
 }
 
@@ -32,7 +32,7 @@ impl Example for bool {
 }
 
 fn trouble<T>(t: T) -> Box<T> {
-    Example::generate(t) //~ ERROR E0308
+    Example::generate(t) //~ ERROR mismatched types
 }
 
 fn weaponize() -> bool {
diff --git a/src/test/compile-fail/specialization/specialization-overlap.rs b/src/test/compile-fail/specialization/specialization-overlap.rs
index 57529d2ae42..f5798171001 100644
--- a/src/test/compile-fail/specialization/specialization-overlap.rs
+++ b/src/test/compile-fail/specialization/specialization-overlap.rs
@@ -22,4 +22,8 @@ trait Baz<U> {}
 impl<T> Baz<T> for u8 {}
 impl<T> Baz<u8> for T {} //~ ERROR E0119
 
+trait Qux {}
+impl<T: Clone> Qux for T {}
+impl<T: Eq> Qux for T {} //~ ERROR E0119
+
 fn main() {}
diff --git a/src/test/run-pass/default-associated-types.rs b/src/test/run-pass/default-associated-types.rs
index 3e6c72c993a..ed55d5c8b17 100644
--- a/src/test/run-pass/default-associated-types.rs
+++ b/src/test/run-pass/default-associated-types.rs
@@ -10,23 +10,22 @@
 
 #![feature(associated_type_defaults)]
 
-trait Foo<T> {
-    type Out = T;
-    fn foo(&self) -> Self::Out;
+trait Foo<T: Default + ToString> {
+    type Out: Default + ToString = T;
 }
 
 impl Foo<u32> for () {
-    fn foo(&self) -> u32 {
-        4u32
-    }
 }
 
-impl Foo<u64> for bool {
-    type Out = ();
-    fn foo(&self) {}
+impl Foo<u64> for () {
+    type Out = bool;
 }
 
 fn main() {
-    assert_eq!(<() as Foo<u32>>::foo(&()), 4u32);
-    assert_eq!(<bool as Foo<u64>>::foo(&true), ());
+    assert_eq!(
+        <() as Foo<u32>>::Out::default().to_string(),
+        "0");
+    assert_eq!(
+        <() as Foo<u64>>::Out::default().to_string(),
+        "false");
 }
diff --git a/src/test/run-pass/specialization/README.md b/src/test/run-pass/specialization/README.md
new file mode 100644
index 00000000000..1373a2cf81b
--- /dev/null
+++ b/src/test/run-pass/specialization/README.md
@@ -0,0 +1,37 @@
+Tests that specialization is working correctly:
+
+- Dispatch
+  - [On methods](specialization-basics.rs), includes:
+    - Specialization via adding a trait bound
+      - Including both remote and local traits
+    - Specialization via pure structure (e.g. `(T, U)` vs `(T, T)`)
+    - Specialization via concrete types vs unknown types
+      - In top level of the trait reference
+      - Embedded within another type (`Vec<T>` vs `Vec<i32>`)
+  - [Specialization based on super trait relationships](specialization-super-traits.rs)
+  - [On assoc fns](specialization-assoc-fns.rs)
+  - [Ensure that impl order doesn't matter](specialization-out-of-order.rs)
+
+- Item inheritance
+  - [Correct default cascading for methods](specialization-default-methods.rs)
+  - Inheritance works across impls with varying generics
+    - [With projections](specialization-translate-projections.rs)
+    - [With projections that involve input types](specialization-translate-projections-with-params.rs)
+
+- Normalization issues
+  - [Non-default assoc types can be projected](specialization-projection.rs)
+    - Including non-specialized cases
+    - Including specialized cases
+  - [Specialized Impls can happen on projections](specialization-on-projection.rs)
+  - [Projections and aliases play well together](specialization-projection-alias.rs)
+  - [Projections involving specialization allowed in the trait ref for impls, and overlap can still be determined](specialization-overlap-projection.rs)
+    - Only works for the simple case where the most specialized impl directly
+      provides a non-`default` associated type
+
+- Across crates
+  - [For traits defined in upstream crate](specialization-allowed-cross-crate.rs)
+  - [Full method dispatch tests, drawing from upstream crate](specialization-cross-crate.rs)
+    - Including *additional* local specializations
+  - [Full method dispatch tests, *without* turning on specialization in local crate](specialization-cross-crate-no-gate.rs)
+  - [Test that defaults cascade correctly from upstream crates](specialization-cross-crate-defaults.rs)
+    - Including *additional* local use of defaults
diff --git a/src/test/run-pass/specialization/specialization-assoc-fns.rs b/src/test/run-pass/specialization/specialization-assoc-fns.rs
index 683e0d55dc9..577f217862d 100644
--- a/src/test/run-pass/specialization/specialization-assoc-fns.rs
+++ b/src/test/run-pass/specialization/specialization-assoc-fns.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Test that non-method associated functions can be specialized
+
 #![feature(specialization)]
 
 trait Foo {
diff --git a/src/test/run-pass/specialization/specialization-cross-crate-defaults.rs b/src/test/run-pass/specialization/specialization-cross-crate-defaults.rs
index 750c3cf8b3e..bc695ea821d 100644
--- a/src/test/run-pass/specialization/specialization-cross-crate-defaults.rs
+++ b/src/test/run-pass/specialization/specialization-cross-crate-defaults.rs
@@ -16,10 +16,22 @@ extern crate specialization_cross_crate_defaults;
 
 use specialization_cross_crate_defaults::*;
 
+struct LocalDefault;
+struct LocalOverride;
+
+impl Foo for LocalDefault {}
+
+impl Foo for LocalOverride {
+    fn foo(&self) -> bool { true }
+}
+
 fn test_foo() {
     assert!(0i8.foo() == false);
     assert!(0i32.foo() == false);
     assert!(0i64.foo() == true);
+
+    assert!(LocalDefault.foo() == false);
+    assert!(LocalOverride.foo() == true);
 }
 
 fn test_bar() {
diff --git a/src/test/run-pass/specialization/specialization-cross-crate-no-gate.rs b/src/test/run-pass/specialization/specialization-cross-crate-no-gate.rs
new file mode 100644
index 00000000000..b9548539e16
--- /dev/null
+++ b/src/test/run-pass/specialization/specialization-cross-crate-no-gate.rs
@@ -0,0 +1,29 @@
+// Copyright 2015 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.
+
+// Test that specialization works even if only the upstream crate enables it
+
+// aux-build:specialization_cross_crate.rs
+
+extern crate specialization_cross_crate;
+
+use specialization_cross_crate::*;
+
+fn  main() {
+    assert!(0u8.foo() == "generic Clone");
+    assert!(vec![0u8].foo() == "generic Vec");
+    assert!(vec![0i32].foo() == "Vec<i32>");
+    assert!(0i32.foo() == "i32");
+    assert!(String::new().foo() == "String");
+    assert!(((), 0).foo() == "generic pair");
+    assert!(((), ()).foo() == "generic uniform pair");
+    assert!((0u8, 0u32).foo() == "(u8, u32)");
+    assert!((0u8, 0u8).foo() == "(u8, u8)");
+}
diff --git a/src/test/run-pass/specialization/specialization-default-methods.rs b/src/test/run-pass/specialization/specialization-default-methods.rs
index d662c5bfa28..b2fad9d171f 100644
--- a/src/test/run-pass/specialization/specialization-default-methods.rs
+++ b/src/test/run-pass/specialization/specialization-default-methods.rs
@@ -10,6 +10,8 @@
 
 #![feature(specialization)]
 
+// Test that default methods are cascaded correctly
+
 // First, test only use of explicit `default` items:
 
 trait Foo {
diff --git a/src/test/run-pass/specialization/specialization-on-projection.rs b/src/test/run-pass/specialization/specialization-on-projection.rs
index 65cbb31d221..acf78def1b9 100644
--- a/src/test/run-pass/specialization/specialization-on-projection.rs
+++ b/src/test/run-pass/specialization/specialization-on-projection.rs
@@ -10,6 +10,8 @@
 
 #![feature(specialization)]
 
+// Ensure that specialization works for impls defined directly on a projection
+
 trait Foo<T> {}
 
 trait Assoc {
diff --git a/src/test/run-pass/specialization/specialization-overlap-projection.rs b/src/test/run-pass/specialization/specialization-overlap-projection.rs
new file mode 100644
index 00000000000..20046ee66b0
--- /dev/null
+++ b/src/test/run-pass/specialization/specialization-overlap-projection.rs
@@ -0,0 +1,33 @@
+// Copyright 2016 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.
+
+// Test that impls on projected self types can resolve overlap, even when the
+// projections involve specialization, so long as the associated type is
+// provided by the most specialized impl.
+
+#![feature(specialization)]
+
+trait Assoc {
+    type Output;
+}
+
+impl<T> Assoc for T {
+    default type Output = bool;
+}
+
+impl Assoc for u8 { type Output = u8; }
+impl Assoc for u16 { type Output = u16; }
+
+trait Foo {}
+impl Foo for u32 {}
+impl Foo for <u8 as Assoc>::Output {}
+impl Foo for <u16 as Assoc>::Output {}
+
+fn main() {}
diff --git a/src/test/run-pass/specialization/specialization-projection-alias.rs b/src/test/run-pass/specialization/specialization-projection-alias.rs
index 2250d77e08e..7fce1cca582 100644
--- a/src/test/run-pass/specialization/specialization-projection-alias.rs
+++ b/src/test/run-pass/specialization/specialization-projection-alias.rs
@@ -23,6 +23,10 @@ impl<T> Id_ for T {
     default type Out = T;
 }
 
-fn main() {
+fn test_proection() {
     let x: Id<bool> = panic!();
 }
+
+fn main() {
+
+}
diff --git a/src/test/run-pass/specialization/specialization-projection.rs b/src/test/run-pass/specialization/specialization-projection.rs
index d26d59896a5..4e0bdec297f 100644
--- a/src/test/run-pass/specialization/specialization-projection.rs
+++ b/src/test/run-pass/specialization/specialization-projection.rs
@@ -13,6 +13,8 @@
 // Make sure we *can* project non-defaulted associated types
 // cf compile-fail/specialization-default-projection.rs
 
+// First, do so without any use of specialization
+
 trait Foo {
     type Assoc;
 }
@@ -21,9 +23,27 @@ impl<T> Foo for T {
     type Assoc = ();
 }
 
-fn generic<T>() -> <T as Foo>::Assoc {
+fn generic_foo<T>() -> <T as Foo>::Assoc {
     ()
 }
 
+// Next, allow for one layer of specialization
+
+trait Bar {
+    type Assoc;
+}
+
+impl<T> Bar for T {
+    default type Assoc = ();
+}
+
+impl<T: Clone> Bar for T {
+    type Assoc = u8;
+}
+
+fn generic_bar_clone<T: Clone>() -> <T as Bar>::Assoc {
+    0u8
+}
+
 fn main() {
 }
diff --git a/src/test/run-pass/specialization/specialization-translate-projections-with-params.rs b/src/test/run-pass/specialization/specialization-translate-projections-with-params.rs
index 3d90bc56f42..647d5523c37 100644
--- a/src/test/run-pass/specialization/specialization-translate-projections-with-params.rs
+++ b/src/test/run-pass/specialization/specialization-translate-projections-with-params.rs
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Ensure that provided items are inherited properly even when impls vary in
+// type parameters *and* rely on projections, and the type parameters are input
+// types on the trait.
+
 #![feature(specialization)]
 
 trait Trait<T> {
diff --git a/src/test/run-pass/specialization/specialization-translate-projections.rs b/src/test/run-pass/specialization/specialization-translate-projections.rs
index d224efe8c31..11e1d997fdd 100644
--- a/src/test/run-pass/specialization/specialization-translate-projections.rs
+++ b/src/test/run-pass/specialization/specialization-translate-projections.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Ensure that provided items are inherited properly even when impls vary in
+// type parameters *and* rely on projections.
+
 #![feature(specialization)]
 
 use std::convert::Into;
diff --git a/src/test/run-pass/xcrate-associated-type-defaults.rs b/src/test/run-pass/xcrate-associated-type-defaults.rs
index 1b6de3b2f7b..2dacbe0966e 100644
--- a/src/test/run-pass/xcrate-associated-type-defaults.rs
+++ b/src/test/run-pass/xcrate-associated-type-defaults.rs
@@ -13,6 +13,26 @@
 extern crate xcrate_associated_type_defaults;
 use xcrate_associated_type_defaults::Foo;
 
+struct LocalDefault;
+impl Foo<u32> for LocalDefault {}
+
+struct LocalOverride;
+impl Foo<u64> for LocalOverride {
+    type Out = bool;
+}
+
 fn main() {
-    ().bar(5);
+    assert_eq!(
+        <() as Foo<u32>>::Out::default().to_string(),
+        "0");
+    assert_eq!(
+        <() as Foo<u64>>::Out::default().to_string(),
+        "false");
+
+    assert_eq!(
+        <LocalDefault as Foo<u32>>::Out::default().to_string(),
+        "0");
+    assert_eq!(
+        <LocalOverride as Foo<u64>>::Out::default().to_string(),
+        "false");
 }