about summary refs log tree commit diff
path: root/src/test/ui/specialization
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-27 01:33:01 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-27 18:56:16 +0300
commit9be35f82c1abf2ecbab489bca9eca138ea648312 (patch)
tree69888506e34af447d9748c0d542de3ba1dd76210 /src/test/ui/specialization
parentca9faa52f5ada0054b1fa27d97aedf448afb059b (diff)
downloadrust-9be35f82c1abf2ecbab489bca9eca138ea648312.tar.gz
rust-9be35f82c1abf2ecbab489bca9eca138ea648312.zip
tests: Move run-pass tests without naming conflicts to ui
Diffstat (limited to 'src/test/ui/specialization')
-rw-r--r--src/test/ui/specialization/assoc-ty-graph-cycle.rs25
-rw-r--r--src/test/ui/specialization/auxiliary/cross_crates_defaults.rs38
-rw-r--r--src/test/ui/specialization/auxiliary/go_trait.rs43
-rw-r--r--src/test/ui/specialization/auxiliary/specialization_cross_crate.rs72
-rw-r--r--src/test/ui/specialization/cross-crate-defaults.rs41
-rw-r--r--src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs26
-rw-r--r--src/test/ui/specialization/defaultimpl/auxiliary/go_trait.rs43
-rw-r--r--src/test/ui/specialization/defaultimpl/out-of-order.rs19
-rw-r--r--src/test/ui/specialization/defaultimpl/overlap-projection.rs25
-rw-r--r--src/test/ui/specialization/defaultimpl/projection.rs42
-rw-r--r--src/test/ui/specialization/issue-50452.rs19
-rw-r--r--src/test/ui/specialization/specialization-allowed-cross-crate.rs26
-rw-r--r--src/test/ui/specialization/specialization-assoc-fns.rs29
-rw-r--r--src/test/ui/specialization/specialization-basics.rs98
-rw-r--r--src/test/ui/specialization/specialization-cross-crate-no-gate.rs21
-rw-r--r--src/test/ui/specialization/specialization-cross-crate.rs50
-rw-r--r--src/test/ui/specialization/specialization-default-methods.rs86
-rw-r--r--src/test/ui/specialization/specialization-on-projection.rs24
-rw-r--r--src/test/ui/specialization/specialization-out-of-order.rs19
-rw-r--r--src/test/ui/specialization/specialization-overlap-projection.rs25
-rw-r--r--src/test/ui/specialization/specialization-projection-alias.rs26
-rw-r--r--src/test/ui/specialization/specialization-projection.rs42
-rw-r--r--src/test/ui/specialization/specialization-super-traits.rs17
-rw-r--r--src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs33
-rw-r--r--src/test/ui/specialization/specialization-translate-projections-with-params.rs32
-rw-r--r--src/test/ui/specialization/specialization-translate-projections.rs33
26 files changed, 954 insertions, 0 deletions
diff --git a/src/test/ui/specialization/assoc-ty-graph-cycle.rs b/src/test/ui/specialization/assoc-ty-graph-cycle.rs
new file mode 100644
index 00000000000..54d51492ab3
--- /dev/null
+++ b/src/test/ui/specialization/assoc-ty-graph-cycle.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+// Make sure we don't crash with a cycle error during coherence.
+
+#![feature(specialization)]
+
+trait Trait<T> {
+    type Assoc;
+}
+
+impl<T> Trait<T> for Vec<T> {
+    default type Assoc = ();
+}
+
+impl Trait<u8> for Vec<u8> {
+    type Assoc = u8;
+}
+
+impl<T> Trait<T> for String {
+    type Assoc = ();
+}
+
+impl Trait<<Vec<u8> as Trait<u8>>::Assoc> for String {}
+
+fn main() {}
diff --git a/src/test/ui/specialization/auxiliary/cross_crates_defaults.rs b/src/test/ui/specialization/auxiliary/cross_crates_defaults.rs
new file mode 100644
index 00000000000..5cf975b5752
--- /dev/null
+++ b/src/test/ui/specialization/auxiliary/cross_crates_defaults.rs
@@ -0,0 +1,38 @@
+#![feature(specialization)]
+
+// First, test only use of explicit `default` items:
+
+pub trait Foo {
+    fn foo(&self) -> bool;
+}
+
+impl<T> Foo for T {
+    default fn foo(&self) -> bool { false }
+}
+
+impl Foo for i32 {}
+
+impl Foo for i64 {
+    fn foo(&self) -> bool { true }
+}
+
+// Next, test mixture of explicit `default` and provided methods:
+
+pub trait Bar {
+    fn bar(&self) -> i32 { 0 }
+}
+
+impl<T> Bar for T {} // use the provided method
+
+impl Bar for i32 {
+    fn bar(&self) -> i32 { 1 }
+}
+impl<'a> Bar for &'a str {}
+
+impl<T> Bar for Vec<T> {
+    default fn bar(&self) -> i32 { 2 }
+}
+impl Bar for Vec<i32> {}
+impl Bar for Vec<i64> {
+    fn bar(&self) -> i32 { 3 }
+}
diff --git a/src/test/ui/specialization/auxiliary/go_trait.rs b/src/test/ui/specialization/auxiliary/go_trait.rs
new file mode 100644
index 00000000000..aa0ec22896d
--- /dev/null
+++ b/src/test/ui/specialization/auxiliary/go_trait.rs
@@ -0,0 +1,43 @@
+#![feature(specialization)]
+
+// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy.
+
+pub trait Go {
+    fn go(&self, arg: isize);
+}
+
+pub fn go<G:Go>(this: &G, arg: isize) {
+    this.go(arg)
+}
+
+pub trait GoMut {
+    fn go_mut(&mut self, arg: isize);
+}
+
+pub fn go_mut<G:GoMut>(this: &mut G, arg: isize) {
+    this.go_mut(arg)
+}
+
+pub trait GoOnce {
+    fn go_once(self, arg: isize);
+}
+
+pub fn go_once<G:GoOnce>(this: G, arg: isize) {
+    this.go_once(arg)
+}
+
+impl<G> GoMut for G
+    where G : Go
+{
+    default fn go_mut(&mut self, arg: isize) {
+        go(&*self, arg)
+    }
+}
+
+impl<G> GoOnce for G
+    where G : GoMut
+{
+    default fn go_once(mut self, arg: isize) {
+        go_mut(&mut self, arg)
+    }
+}
diff --git a/src/test/ui/specialization/auxiliary/specialization_cross_crate.rs b/src/test/ui/specialization/auxiliary/specialization_cross_crate.rs
new file mode 100644
index 00000000000..8caa8524fb9
--- /dev/null
+++ b/src/test/ui/specialization/auxiliary/specialization_cross_crate.rs
@@ -0,0 +1,72 @@
+#![feature(specialization)]
+
+pub trait Foo {
+    fn foo(&self) -> &'static str;
+}
+
+impl<T> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic"
+    }
+}
+
+impl<T: Clone> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic Clone"
+    }
+}
+
+impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
+    default fn foo(&self) -> &'static str {
+        "generic pair"
+    }
+}
+
+impl<T: Clone> Foo for (T, T) {
+    default fn foo(&self) -> &'static str {
+        "generic uniform pair"
+    }
+}
+
+impl Foo for (u8, u32) {
+    default fn foo(&self) -> &'static str {
+        "(u8, u32)"
+    }
+}
+
+impl Foo for (u8, u8) {
+    default fn foo(&self) -> &'static str {
+        "(u8, u8)"
+    }
+}
+
+impl<T: Clone> Foo for Vec<T> {
+    default fn foo(&self) -> &'static str {
+        "generic Vec"
+    }
+}
+
+impl Foo for Vec<i32> {
+    fn foo(&self) -> &'static str {
+        "Vec<i32>"
+    }
+}
+
+impl Foo for String {
+    fn foo(&self) -> &'static str {
+        "String"
+    }
+}
+
+impl Foo for i32 {
+    fn foo(&self) -> &'static str {
+        "i32"
+    }
+}
+
+pub trait MyMarker {}
+impl<T: Clone + MyMarker> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic Clone + MyMarker"
+    }
+}
diff --git a/src/test/ui/specialization/cross-crate-defaults.rs b/src/test/ui/specialization/cross-crate-defaults.rs
new file mode 100644
index 00000000000..79cb6594397
--- /dev/null
+++ b/src/test/ui/specialization/cross-crate-defaults.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+// aux-build:cross_crates_defaults.rs
+
+#![feature(specialization)]
+
+extern crate cross_crates_defaults;
+
+use cross_crates_defaults::*;
+
+struct LocalDefault;
+struct LocalOverride;
+
+impl Foo for LocalDefault {}
+
+impl Foo for LocalOverride {
+    fn foo(&self) -> bool { true }
+}
+
+fn test_foo() {
+    assert!(!0i8.foo());
+    assert!(!0i32.foo());
+    assert!(0i64.foo());
+
+    assert!(!LocalDefault.foo());
+    assert!(LocalOverride.foo());
+}
+
+fn test_bar() {
+    assert!(0u8.bar() == 0);
+    assert!(0i32.bar() == 1);
+    assert!("hello".bar() == 0);
+    assert!(vec![()].bar() == 2);
+    assert!(vec![0i32].bar() == 2);
+    assert!(vec![0i64].bar() == 3);
+}
+
+fn main() {
+    test_foo();
+    test_bar();
+}
diff --git a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs
new file mode 100644
index 00000000000..15550bcce2a
--- /dev/null
+++ b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs
@@ -0,0 +1,26 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_imports)]
+
+// aux-build:go_trait.rs
+
+#![feature(specialization)]
+
+extern crate go_trait;
+
+use go_trait::{Go,GoMut};
+use std::fmt::Debug;
+use std::default::Default;
+
+struct MyThingy;
+
+impl Go for MyThingy {
+    fn go(&self, arg: isize) { }
+}
+
+impl GoMut for MyThingy {
+    fn go_mut(&mut self, arg: isize) { }
+}
+
+fn main() { }
diff --git a/src/test/ui/specialization/defaultimpl/auxiliary/go_trait.rs b/src/test/ui/specialization/defaultimpl/auxiliary/go_trait.rs
new file mode 100644
index 00000000000..c065593b432
--- /dev/null
+++ b/src/test/ui/specialization/defaultimpl/auxiliary/go_trait.rs
@@ -0,0 +1,43 @@
+#![feature(specialization)]
+
+// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy.
+
+pub trait Go {
+    fn go(&self, arg: isize);
+}
+
+pub fn go<G:Go>(this: &G, arg: isize) {
+    this.go(arg)
+}
+
+pub trait GoMut {
+    fn go_mut(&mut self, arg: isize);
+}
+
+pub fn go_mut<G:GoMut>(this: &mut G, arg: isize) {
+    this.go_mut(arg)
+}
+
+pub trait GoOnce {
+    fn go_once(self, arg: isize);
+}
+
+pub fn go_once<G:GoOnce>(this: G, arg: isize) {
+    this.go_once(arg)
+}
+
+default impl<G> GoMut for G
+    where G : Go
+{
+    fn go_mut(&mut self, arg: isize) {
+        go(&*self, arg)
+    }
+}
+
+default impl<G> GoOnce for G
+    where G : GoMut
+{
+    fn go_once(mut self, arg: isize) {
+        go_mut(&mut self, arg)
+    }
+}
diff --git a/src/test/ui/specialization/defaultimpl/out-of-order.rs b/src/test/ui/specialization/defaultimpl/out-of-order.rs
new file mode 100644
index 00000000000..f9c73a19cfa
--- /dev/null
+++ b/src/test/ui/specialization/defaultimpl/out-of-order.rs
@@ -0,0 +1,19 @@
+// run-pass
+
+// Test that you can list the more specific impl before the more general one.
+
+#![feature(specialization)]
+
+trait Foo {
+    type Out;
+}
+
+impl Foo for bool {
+    type Out = ();
+}
+
+default impl<T> Foo for T {
+    type Out = bool;
+}
+
+fn main() {}
diff --git a/src/test/ui/specialization/defaultimpl/overlap-projection.rs b/src/test/ui/specialization/defaultimpl/overlap-projection.rs
new file mode 100644
index 00000000000..ed38bb3fc3a
--- /dev/null
+++ b/src/test/ui/specialization/defaultimpl/overlap-projection.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+// 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;
+}
+
+default impl<T> Assoc for T {
+    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/ui/specialization/defaultimpl/projection.rs b/src/test/ui/specialization/defaultimpl/projection.rs
new file mode 100644
index 00000000000..897a7aade2f
--- /dev/null
+++ b/src/test/ui/specialization/defaultimpl/projection.rs
@@ -0,0 +1,42 @@
+// run-pass
+#![allow(dead_code)]
+
+#![feature(specialization)]
+
+// 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;
+}
+
+impl<T> Foo for T {
+    type Assoc = ();
+}
+
+fn generic_foo<T>() -> <T as Foo>::Assoc {
+    ()
+}
+
+// Next, allow for one layer of specialization
+
+trait Bar {
+    type Assoc;
+}
+
+default impl<T> Bar for T {
+    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/ui/specialization/issue-50452.rs b/src/test/ui/specialization/issue-50452.rs
new file mode 100644
index 00000000000..93f081d9558
--- /dev/null
+++ b/src/test/ui/specialization/issue-50452.rs
@@ -0,0 +1,19 @@
+// run-pass
+
+#![feature(specialization)]
+
+pub trait Foo {
+    fn foo();
+}
+
+impl Foo for i32 {}
+impl Foo for i64 {}
+impl<T> Foo for T {
+    fn foo() {}
+}
+
+fn main() {
+    i32::foo();
+    i64::foo();
+    u8::foo();
+}
diff --git a/src/test/ui/specialization/specialization-allowed-cross-crate.rs b/src/test/ui/specialization/specialization-allowed-cross-crate.rs
new file mode 100644
index 00000000000..15550bcce2a
--- /dev/null
+++ b/src/test/ui/specialization/specialization-allowed-cross-crate.rs
@@ -0,0 +1,26 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_imports)]
+
+// aux-build:go_trait.rs
+
+#![feature(specialization)]
+
+extern crate go_trait;
+
+use go_trait::{Go,GoMut};
+use std::fmt::Debug;
+use std::default::Default;
+
+struct MyThingy;
+
+impl Go for MyThingy {
+    fn go(&self, arg: isize) { }
+}
+
+impl GoMut for MyThingy {
+    fn go_mut(&mut self, arg: isize) { }
+}
+
+fn main() { }
diff --git a/src/test/ui/specialization/specialization-assoc-fns.rs b/src/test/ui/specialization/specialization-assoc-fns.rs
new file mode 100644
index 00000000000..b6a7a48972a
--- /dev/null
+++ b/src/test/ui/specialization/specialization-assoc-fns.rs
@@ -0,0 +1,29 @@
+// run-pass
+
+// Test that non-method associated functions can be specialized
+
+#![feature(specialization)]
+
+trait Foo {
+    fn mk() -> Self;
+}
+
+impl<T: Default> Foo for T {
+    default fn mk() -> T {
+        T::default()
+    }
+}
+
+impl Foo for Vec<u8> {
+    fn mk() -> Vec<u8> {
+        vec![0]
+    }
+}
+
+fn main() {
+    let v1: Vec<i32> = Foo::mk();
+    let v2: Vec<u8> = Foo::mk();
+
+    assert!(v1.len() == 0);
+    assert!(v2.len() == 1);
+}
diff --git a/src/test/ui/specialization/specialization-basics.rs b/src/test/ui/specialization/specialization-basics.rs
new file mode 100644
index 00000000000..6c359e51bc2
--- /dev/null
+++ b/src/test/ui/specialization/specialization-basics.rs
@@ -0,0 +1,98 @@
+// run-pass
+
+#![feature(specialization)]
+
+// Tests a variety of basic specialization scenarios and method
+// dispatch for them.
+
+trait Foo {
+    fn foo(&self) -> &'static str;
+}
+
+impl<T> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic"
+    }
+}
+
+impl<T: Clone> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic Clone"
+    }
+}
+
+impl<T, U> Foo for (T, U) where T: Clone, U: Clone {
+    default fn foo(&self) -> &'static str {
+        "generic pair"
+    }
+}
+
+impl<T: Clone> Foo for (T, T) {
+    default fn foo(&self) -> &'static str {
+        "generic uniform pair"
+    }
+}
+
+impl Foo for (u8, u32) {
+    default fn foo(&self) -> &'static str {
+        "(u8, u32)"
+    }
+}
+
+impl Foo for (u8, u8) {
+    default fn foo(&self) -> &'static str {
+        "(u8, u8)"
+    }
+}
+
+impl<T: Clone> Foo for Vec<T> {
+    default fn foo(&self) -> &'static str {
+        "generic Vec"
+    }
+}
+
+impl Foo for Vec<i32> {
+    fn foo(&self) -> &'static str {
+        "Vec<i32>"
+    }
+}
+
+impl Foo for String {
+    fn foo(&self) -> &'static str {
+        "String"
+    }
+}
+
+impl Foo for i32 {
+    fn foo(&self) -> &'static str {
+        "i32"
+    }
+}
+
+struct NotClone;
+
+trait MyMarker {}
+impl<T: Clone + MyMarker> Foo for T {
+    default fn foo(&self) -> &'static str {
+        "generic Clone + MyMarker"
+    }
+}
+
+#[derive(Clone)]
+struct MarkedAndClone;
+impl MyMarker for MarkedAndClone {}
+
+fn  main() {
+    assert!(NotClone.foo() == "generic");
+    assert!(0u8.foo() == "generic Clone");
+    assert!(vec![NotClone].foo() == "generic");
+    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)");
+    assert!(MarkedAndClone.foo() == "generic Clone + MyMarker");
+}
diff --git a/src/test/ui/specialization/specialization-cross-crate-no-gate.rs b/src/test/ui/specialization/specialization-cross-crate-no-gate.rs
new file mode 100644
index 00000000000..f744b16de7a
--- /dev/null
+++ b/src/test/ui/specialization/specialization-cross-crate-no-gate.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+// 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/ui/specialization/specialization-cross-crate.rs b/src/test/ui/specialization/specialization-cross-crate.rs
new file mode 100644
index 00000000000..fa63c866329
--- /dev/null
+++ b/src/test/ui/specialization/specialization-cross-crate.rs
@@ -0,0 +1,50 @@
+// run-pass
+
+// aux-build:specialization_cross_crate.rs
+
+#![feature(specialization)]
+
+extern crate specialization_cross_crate;
+
+use specialization_cross_crate::*;
+
+struct NotClone;
+
+#[derive(Clone)]
+struct MarkedAndClone;
+impl MyMarker for MarkedAndClone {}
+
+struct MyType<T>(T);
+impl<T> Foo for MyType<T> {
+    default fn foo(&self) -> &'static str {
+        "generic MyType"
+    }
+}
+
+impl Foo for MyType<u8> {
+    fn foo(&self) -> &'static str {
+        "MyType<u8>"
+    }
+}
+
+struct MyOtherType;
+impl Foo for MyOtherType {}
+
+fn  main() {
+    assert!(NotClone.foo() == "generic");
+    assert!(0u8.foo() == "generic Clone");
+    assert!(vec![NotClone].foo() == "generic");
+    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)");
+    assert!(MarkedAndClone.foo() == "generic Clone + MyMarker");
+
+    assert!(MyType(()).foo() == "generic MyType");
+    assert!(MyType(0u8).foo() == "MyType<u8>");
+    assert!(MyOtherType.foo() == "generic");
+}
diff --git a/src/test/ui/specialization/specialization-default-methods.rs b/src/test/ui/specialization/specialization-default-methods.rs
new file mode 100644
index 00000000000..5d65a0457e7
--- /dev/null
+++ b/src/test/ui/specialization/specialization-default-methods.rs
@@ -0,0 +1,86 @@
+// run-pass
+
+#![feature(specialization)]
+
+// Test that default methods are cascaded correctly
+
+// First, test only use of explicit `default` items:
+
+trait Foo {
+    fn foo(&self) -> bool;
+}
+
+// Specialization tree for Foo:
+//
+//        T
+//       / \
+//    i32   i64
+
+impl<T> Foo for T {
+    default fn foo(&self) -> bool { false }
+}
+
+impl Foo for i32 {}
+
+impl Foo for i64 {
+    fn foo(&self) -> bool { true }
+}
+
+fn test_foo() {
+    assert!(!0i8.foo());
+    assert!(!0i32.foo());
+    assert!(0i64.foo());
+}
+
+// Next, test mixture of explicit `default` and provided methods:
+
+trait Bar {
+    fn bar(&self) -> i32 { 0 }
+}
+
+// Specialization tree for Bar.
+// Uses of $ designate that method is provided
+//
+//           $Bar   (the trait)
+//             |
+//             T
+//            /|\
+//           / | \
+//          /  |  \
+//         /   |   \
+//        /    |    \
+//       /     |     \
+//     $i32   &str  $Vec<T>
+//                    /\
+//                   /  \
+//            Vec<i32>  $Vec<i64>
+
+// use the provided method
+impl<T> Bar for T {}
+
+impl Bar for i32 {
+    fn bar(&self) -> i32 { 1 }
+}
+impl<'a> Bar for &'a str {}
+
+impl<T> Bar for Vec<T> {
+    default fn bar(&self) -> i32 { 2 }
+}
+impl Bar for Vec<i32> {}
+impl Bar for Vec<i64> {
+    fn bar(&self) -> i32 { 3 }
+}
+
+fn test_bar() {
+    assert!(0u8.bar() == 0);
+    assert!(0i32.bar() == 1);
+    assert!("hello".bar() == 0);
+    assert!(vec![()].bar() == 2);
+    assert!(vec![0i32].bar() == 2);
+    assert!(vec![0i64].bar() == 3);
+}
+
+fn main() {
+    test_foo();
+    test_bar();
+}
diff --git a/src/test/ui/specialization/specialization-on-projection.rs b/src/test/ui/specialization/specialization-on-projection.rs
new file mode 100644
index 00000000000..5606eaea307
--- /dev/null
+++ b/src/test/ui/specialization/specialization-on-projection.rs
@@ -0,0 +1,24 @@
+// run-pass
+#![allow(dead_code)]
+
+#![feature(specialization)]
+
+// Ensure that specialization works for impls defined directly on a projection
+
+trait Foo<T> {}
+
+trait Assoc {
+    type Item;
+}
+
+impl<T: Assoc> Foo<T::Item> for T {}
+
+struct Struct;
+
+impl Assoc for Struct {
+    type Item = u8;
+}
+
+impl Foo<u8> for Struct {}
+
+fn main() {}
diff --git a/src/test/ui/specialization/specialization-out-of-order.rs b/src/test/ui/specialization/specialization-out-of-order.rs
new file mode 100644
index 00000000000..94e764f7636
--- /dev/null
+++ b/src/test/ui/specialization/specialization-out-of-order.rs
@@ -0,0 +1,19 @@
+// run-pass
+
+// Test that you can list the more specific impl before the more general one.
+
+#![feature(specialization)]
+
+trait Foo {
+    type Out;
+}
+
+impl Foo for bool {
+    type Out = ();
+}
+
+impl<T> Foo for T {
+    default type Out = bool;
+}
+
+fn main() {}
diff --git a/src/test/ui/specialization/specialization-overlap-projection.rs b/src/test/ui/specialization/specialization-overlap-projection.rs
new file mode 100644
index 00000000000..00b83c7e7a1
--- /dev/null
+++ b/src/test/ui/specialization/specialization-overlap-projection.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+// 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/ui/specialization/specialization-projection-alias.rs b/src/test/ui/specialization/specialization-projection-alias.rs
new file mode 100644
index 00000000000..0081ed455c9
--- /dev/null
+++ b/src/test/ui/specialization/specialization-projection-alias.rs
@@ -0,0 +1,26 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+#![feature(specialization)]
+
+// Regression test for ICE when combining specialized associated types and type
+// aliases
+
+trait Id_ {
+    type Out;
+}
+
+type Id<T> = <T as Id_>::Out;
+
+impl<T> Id_ for T {
+    default type Out = T;
+}
+
+fn test_proection() {
+    let x: Id<bool> = panic!();
+}
+
+fn main() {
+
+}
diff --git a/src/test/ui/specialization/specialization-projection.rs b/src/test/ui/specialization/specialization-projection.rs
new file mode 100644
index 00000000000..86cdccf131e
--- /dev/null
+++ b/src/test/ui/specialization/specialization-projection.rs
@@ -0,0 +1,42 @@
+// run-pass
+#![allow(dead_code)]
+
+#![feature(specialization)]
+
+// 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;
+}
+
+impl<T> Foo for T {
+    type 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/ui/specialization/specialization-super-traits.rs b/src/test/ui/specialization/specialization-super-traits.rs
new file mode 100644
index 00000000000..a0f71d87693
--- /dev/null
+++ b/src/test/ui/specialization/specialization-super-traits.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+#![feature(specialization)]
+
+// Test that you can specialize via an explicit trait hierarchy
+
+// FIXME: this doesn't work yet...
+
+trait Parent {}
+trait Child: Parent {}
+
+trait Foo {}
+
+impl<T: Parent> Foo for T {}
+impl<T: Child> Foo for T {}
+
+fn main() {}
diff --git a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs
new file mode 100644
index 00000000000..2e32e3ff02d
--- /dev/null
+++ b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs
@@ -0,0 +1,33 @@
+// run-pass
+
+#![feature(specialization)]
+
+trait Iterator {
+    fn next(&self);
+}
+
+trait WithAssoc {
+    type Item;
+}
+
+impl<'a> WithAssoc for &'a () {
+    type Item = &'a u32;
+}
+
+struct Cloned<I>(I);
+
+impl<'a, I, T: 'a> Iterator for Cloned<I>
+    where I: WithAssoc<Item=&'a T>, T: Clone
+{
+    fn next(&self) {}
+}
+
+impl<'a, I, T: 'a> Iterator for Cloned<I>
+    where I: WithAssoc<Item=&'a T>, T: Copy
+{
+
+}
+
+fn main() {
+    Cloned(&()).next();
+}
diff --git a/src/test/ui/specialization/specialization-translate-projections-with-params.rs b/src/test/ui/specialization/specialization-translate-projections-with-params.rs
new file mode 100644
index 00000000000..bdc6501df44
--- /dev/null
+++ b/src/test/ui/specialization/specialization-translate-projections-with-params.rs
@@ -0,0 +1,32 @@
+// run-pass
+
+// 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> {
+    fn convert(&self) -> T;
+}
+trait WithAssoc {
+    type Item;
+    fn as_item(&self) -> &Self::Item;
+}
+
+impl<T, U> Trait<U> for T where T: WithAssoc<Item=U>, U: Clone {
+    fn convert(&self) -> U {
+        self.as_item().clone()
+    }
+}
+
+impl WithAssoc for u8 {
+    type Item = u8;
+    fn as_item(&self) -> &u8 { self }
+}
+
+impl Trait<u8> for u8 {}
+
+fn main() {
+    assert!(3u8.convert() == 3u8);
+}
diff --git a/src/test/ui/specialization/specialization-translate-projections.rs b/src/test/ui/specialization/specialization-translate-projections.rs
new file mode 100644
index 00000000000..fcccb67902e
--- /dev/null
+++ b/src/test/ui/specialization/specialization-translate-projections.rs
@@ -0,0 +1,33 @@
+// run-pass
+
+// Ensure that provided items are inherited properly even when impls vary in
+// type parameters *and* rely on projections.
+
+#![feature(specialization)]
+
+use std::convert::Into;
+
+trait Trait {
+    fn to_u8(&self) -> u8;
+}
+trait WithAssoc {
+    type Item;
+    fn to_item(&self) -> Self::Item;
+}
+
+impl<T, U> Trait for T where T: WithAssoc<Item=U>, U: Into<u8> {
+    fn to_u8(&self) -> u8 {
+        self.to_item().into()
+    }
+}
+
+impl WithAssoc for u8 {
+    type Item = u8;
+    fn to_item(&self) -> u8 { *self }
+}
+
+impl Trait for u8 {}
+
+fn main() {
+    assert!(3u8.to_u8() == 3u8);
+}