summaryrefslogtreecommitdiffstats
path: root/src/test/ui/coercion
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/coercion')
-rw-r--r--src/test/ui/coercion/auxiliary/issue-39823.rs7
-rw-r--r--src/test/ui/coercion/coerce-expect-unsized-ascribed.rs32
-rw-r--r--src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr129
-rw-r--r--src/test/ui/coercion/coerce-expect-unsized.rs43
-rw-r--r--src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr19
-rw-r--r--src/test/ui/coercion/coerce-issue-49593-box-never-windows.rs58
-rw-r--r--src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr19
-rw-r--r--src/test/ui/coercion/coerce-issue-49593-box-never.rs58
-rw-r--r--src/test/ui/coercion/coerce-mut.rs10
-rw-r--r--src/test/ui/coercion/coerce-mut.stderr19
-rw-r--r--src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs32
-rw-r--r--src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr46
-rw-r--r--src/test/ui/coercion/coerce-overloaded-autoderef.rs68
-rw-r--r--src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs17
-rw-r--r--src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs18
-rw-r--r--src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs19
-rw-r--r--src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs16
-rw-r--r--src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs6
-rw-r--r--src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr19
-rw-r--r--src/test/ui/coercion/coerce-reborrow-multi-arg.rs9
-rw-r--r--src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs25
-rw-r--r--src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs27
-rw-r--r--src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs18
-rw-r--r--src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs14
-rw-r--r--src/test/ui/coercion/coerce-to-bang-cast.rs12
-rw-r--r--src/test/ui/coercion/coerce-to-bang-cast.stderr15
-rw-r--r--src/test/ui/coercion/coerce-to-bang.rs79
-rw-r--r--src/test/ui/coercion/coerce-to-bang.stderr130
-rw-r--r--src/test/ui/coercion/coerce-unify-return.rs19
-rw-r--r--src/test/ui/coercion/coerce-unify.rs68
-rw-r--r--src/test/ui/coercion/coerce-unsize-subtype.rs40
-rw-r--r--src/test/ui/coercion/coercion-missing-tail-expected-type.fixed16
-rw-r--r--src/test/ui/coercion/coercion-missing-tail-expected-type.rs16
-rw-r--r--src/test/ui/coercion/coercion-missing-tail-expected-type.stderr26
-rw-r--r--src/test/ui/coercion/coercion-slice.rs7
-rw-r--r--src/test/ui/coercion/coercion-slice.stderr13
-rw-r--r--src/test/ui/coercion/issue-14589.rs24
-rw-r--r--src/test/ui/coercion/issue-37655.rs37
-rw-r--r--src/test/ui/coercion/issue-39823.rs25
-rw-r--r--src/test/ui/coercion/issue-53475.rs13
-rw-r--r--src/test/ui/coercion/issue-53475.stderr14
-rw-r--r--src/test/ui/coercion/issue-73886.rs6
-rw-r--r--src/test/ui/coercion/issue-73886.stderr17
-rw-r--r--src/test/ui/coercion/issue-88097.rs31
-rw-r--r--src/test/ui/coercion/retslot-cast.rs22
-rw-r--r--src/test/ui/coercion/retslot-cast.stderr15
-rw-r--r--src/test/ui/coercion/unsafe-coercion.rs17
47 files changed, 1390 insertions, 0 deletions
diff --git a/src/test/ui/coercion/auxiliary/issue-39823.rs b/src/test/ui/coercion/auxiliary/issue-39823.rs
new file mode 100644
index 000000000..3af9c68f2
--- /dev/null
+++ b/src/test/ui/coercion/auxiliary/issue-39823.rs
@@ -0,0 +1,7 @@
+#![crate_type="rlib"]
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteC(pub u32);
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteG<T>(pub T);
diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.rs b/src/test/ui/coercion/coerce-expect-unsized-ascribed.rs
new file mode 100644
index 000000000..c139e823c
--- /dev/null
+++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.rs
@@ -0,0 +1,32 @@
+// A version of coerce-expect-unsized that uses type ascription.
+// Doesn't work so far, but supposed to work eventually
+
+#![feature(box_syntax, type_ascription)]
+
+use std::fmt::Debug;
+
+pub fn main() {
+ let _ = box { [1, 2, 3] }: Box<[i32]>; //~ ERROR mismatched types
+ let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>; //~ ERROR mismatched types
+ let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[i32]>;
+ //~^ ERROR mismatched types
+ let _ = box { |x| (x as u8) }: Box<dyn Fn(i32) -> _>; //~ ERROR mismatched types
+ let _ = box if true { false } else { true }: Box<dyn Debug>; //~ ERROR mismatched types
+ let _ = box match true { true => 'a', false => 'b' }: Box<dyn Debug>; //~ ERROR mismatched types
+
+ let _ = &{ [1, 2, 3] }: &[i32]; //~ ERROR mismatched types
+ let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[i32]; //~ ERROR mismatched types
+ let _ = &match true { true => [1, 2, 3], false => [1, 3, 4] }: &[i32];
+ //~^ ERROR mismatched types
+ let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _; //~ ERROR mismatched types
+ let _ = &if true { false } else { true }: &dyn Debug; //~ ERROR mismatched types
+ let _ = &match true { true => 'a', false => 'b' }: &dyn Debug; //~ ERROR mismatched types
+
+ let _ = Box::new([1, 2, 3]): Box<[i32]>; //~ ERROR mismatched types
+ let _ = Box::new(|x| (x as u8)): Box<dyn Fn(i32) -> _>; //~ ERROR mismatched types
+
+ let _ = vec![
+ Box::new(|x| (x as u8)),
+ box |x| (x as i16 as u8),
+ ]: Vec<Box<dyn Fn(i32) -> _>>;
+}
diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
new file mode 100644
index 000000000..9d614e610
--- /dev/null
+++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
@@ -0,0 +1,129 @@
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:9:13
+ |
+LL | let _ = box { [1, 2, 3] }: Box<[i32]>;
+ | ^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+ |
+ = note: expected struct `Box<[i32]>`
+ found struct `Box<[i32; 3]>`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:10:13
+ |
+LL | let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+ |
+ = note: expected struct `Box<[i32]>`
+ found struct `Box<[i32; 3]>`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:11:13
+ |
+LL | let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[i32]>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+ |
+ = note: expected struct `Box<[i32]>`
+ found struct `Box<[i32; 3]>`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:13:13
+ |
+LL | let _ = box { |x| (x as u8) }: Box<dyn Fn(i32) -> _>;
+ | ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
+ |
+ = note: expected struct `Box<dyn Fn(i32) -> u8>`
+ found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:22]>`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:14:13
+ |
+LL | let _ = box if true { false } else { true }: Box<dyn Debug>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool`
+ |
+ = note: expected struct `Box<dyn Debug>`
+ found struct `Box<bool>`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:15:13
+ |
+LL | let _ = box match true { true => 'a', false => 'b' }: Box<dyn Debug>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char`
+ |
+ = note: expected struct `Box<dyn Debug>`
+ found struct `Box<char>`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:17:13
+ |
+LL | let _ = &{ [1, 2, 3] }: &[i32];
+ | ^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+ |
+ = note: expected reference `&[i32]`
+ found reference `&[i32; 3]`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:18:13
+ |
+LL | let _ = &if true { [1, 2, 3] } else { [1, 3, 4] }: &[i32];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+ |
+ = note: expected reference `&[i32]`
+ found reference `&[i32; 3]`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:19:13
+ |
+LL | let _ = &match true { true => [1, 2, 3], false => [1, 3, 4] }: &[i32];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+ |
+ = note: expected reference `&[i32]`
+ found reference `&[i32; 3]`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:21:13
+ |
+LL | let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _;
+ | ^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
+ |
+ = note: expected reference `&dyn Fn(i32) -> u8`
+ found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:19]`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:22:13
+ |
+LL | let _ = &if true { false } else { true }: &dyn Debug;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool`
+ |
+ = note: expected reference `&dyn Debug`
+ found reference `&bool`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:23:13
+ |
+LL | let _ = &match true { true => 'a', false => 'b' }: &dyn Debug;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char`
+ |
+ = note: expected reference `&dyn Debug`
+ found reference `&char`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:25:13
+ |
+LL | let _ = Box::new([1, 2, 3]): Box<[i32]>;
+ | ^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]`
+ |
+ = note: expected struct `Box<[i32]>`
+ found struct `Box<[i32; 3]>`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-expect-unsized-ascribed.rs:26:13
+ |
+LL | let _ = Box::new(|x| (x as u8)): Box<dyn Fn(i32) -> _>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
+ |
+ = note: expected struct `Box<dyn Fn(i32) -> u8>`
+ found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:25]>`
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-expect-unsized.rs b/src/test/ui/coercion/coerce-expect-unsized.rs
new file mode 100644
index 000000000..eeb8fe823
--- /dev/null
+++ b/src/test/ui/coercion/coerce-expect-unsized.rs
@@ -0,0 +1,43 @@
+// run-pass
+#![allow(unused_braces)]
+
+use std::cell::RefCell;
+use std::fmt::Debug;
+use std::rc::Rc;
+
+// Check that coercions apply at the pointer level and don't cause
+// rvalue expressions to be unsized. See #20169 for more information.
+
+pub fn main() {
+ let _: Box<[isize]> = Box::new({ [1, 2, 3] });
+ let _: Box<[isize]> = Box::new(if true { [1, 2, 3] } else { [1, 3, 4] });
+ let _: Box<[isize]> = Box::new(match true { true => [1, 2, 3], false => [1, 3, 4] });
+ let _: Box<dyn Fn(isize) -> _> = Box::new({ |x| (x as u8) });
+ let _: Box<dyn Debug> = Box::new(if true { false } else { true });
+ let _: Box<dyn Debug> = Box::new(match true { true => 'a', false => 'b' });
+
+ let _: &[isize] = &{ [1, 2, 3] };
+ let _: &[isize] = &if true { [1, 2, 3] } else { [1, 3, 4] };
+ let _: &[isize] = &match true { true => [1, 2, 3], false => [1, 3, 4] };
+ let _: &dyn Fn(isize) -> _ = &{ |x| (x as u8) };
+ let _: &dyn Debug = &if true { false } else { true };
+ let _: &dyn Debug = &match true { true => 'a', false => 'b' };
+
+ let _: &str = &{ String::new() };
+ let _: &str = &if true { String::from("...") } else { 5.to_string() };
+ let _: &str = &match true {
+ true => format!("{}", false),
+ false => ["x", "y"].join("+")
+ };
+
+ let _: Box<[isize]> = Box::new([1, 2, 3]);
+ let _: Box<dyn Fn(isize) -> _> = Box::new(|x| (x as u8));
+
+ let _: Rc<RefCell<[isize]>> = Rc::new(RefCell::new([1, 2, 3]));
+ let _: Rc<RefCell<dyn FnMut(isize) -> _>> = Rc::new(RefCell::new(|x| (x as u8)));
+
+ let _: Vec<Box<dyn Fn(isize) -> _>> = vec![
+ Box::new(|x| (x as u8)),
+ Box::new(|x| (x as i16 as u8)),
+ ];
+}
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr
new file mode 100644
index 000000000..980da5360
--- /dev/null
+++ b/src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `(): std::error::Error` is not satisfied
+ --> $DIR/coerce-issue-49593-box-never-windows.rs:18:53
+ |
+LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
+ |
+ = note: required for the cast from `()` to the object type `dyn std::error::Error`
+
+error[E0277]: the trait bound `(): std::error::Error` is not satisfied
+ --> $DIR/coerce-issue-49593-box-never-windows.rs:23:49
+ |
+LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
+ |
+ = note: required for the cast from `()` to the object type `(dyn std::error::Error + 'static)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never-windows.rs b/src/test/ui/coercion/coerce-issue-49593-box-never-windows.rs
new file mode 100644
index 000000000..95d3935ca
--- /dev/null
+++ b/src/test/ui/coercion/coerce-issue-49593-box-never-windows.rs
@@ -0,0 +1,58 @@
+// revisions: nofallback fallback
+// only-windows - the number of `Error` impls is platform-dependent
+//[fallback] check-pass
+//[nofallback] check-fail
+
+#![feature(never_type)]
+#![cfg_attr(fallback, feature(never_type_fallback))]
+#![allow(unreachable_code)]
+
+use std::error::Error;
+use std::mem;
+
+fn raw_ptr_box<T>(t: T) -> *mut T {
+ panic!()
+}
+
+fn foo(x: !) -> Box<dyn Error> {
+ /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
+ //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
+}
+
+fn foo_raw_ptr(x: !) -> *mut dyn Error {
+ /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
+ //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
+}
+
+fn no_coercion(d: *mut dyn Error) -> *mut dyn Error {
+ /* an unsize coercion won't compile here, and it is indeed not used
+ because there is nothing requiring the _ to be Sized */
+ d as *mut _
+}
+
+trait Xyz {}
+struct S;
+struct T;
+impl Xyz for S {}
+impl Xyz for T {}
+
+fn foo_no_never() {
+ let mut x /* : Option<S> */ = None;
+ let mut first_iter = false;
+ loop {
+ if !first_iter {
+ let y: Box<dyn Xyz>
+ = /* Box<$0> is coerced to Box<Xyz> here */ Box::new(x.unwrap());
+ }
+
+ x = Some(S);
+ first_iter = true;
+ }
+
+ let mut y : Option<S> = None;
+ // assert types are equal
+ mem::swap(&mut x, &mut y);
+}
+
+fn main() {
+}
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr
new file mode 100644
index 000000000..322681b97
--- /dev/null
+++ b/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `(): std::error::Error` is not satisfied
+ --> $DIR/coerce-issue-49593-box-never.rs:18:53
+ |
+LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
+ |
+ = note: required for the cast from `()` to the object type `dyn std::error::Error`
+
+error[E0277]: the trait bound `(): std::error::Error` is not satisfied
+ --> $DIR/coerce-issue-49593-box-never.rs:23:49
+ |
+LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
+ |
+ = note: required for the cast from `()` to the object type `(dyn std::error::Error + 'static)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs
new file mode 100644
index 000000000..16efb65ac
--- /dev/null
+++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs
@@ -0,0 +1,58 @@
+// revisions: nofallback fallback
+// ignore-windows - the number of `Error` impls is platform-dependent
+//[fallback] check-pass
+//[nofallback] check-fail
+
+#![feature(never_type)]
+#![cfg_attr(fallback, feature(never_type_fallback))]
+#![allow(unreachable_code)]
+
+use std::error::Error;
+use std::mem;
+
+fn raw_ptr_box<T>(t: T) -> *mut T {
+ panic!()
+}
+
+fn foo(x: !) -> Box<dyn Error> {
+ /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
+ //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
+}
+
+fn foo_raw_ptr(x: !) -> *mut dyn Error {
+ /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
+ //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied
+}
+
+fn no_coercion(d: *mut dyn Error) -> *mut dyn Error {
+ /* an unsize coercion won't compile here, and it is indeed not used
+ because there is nothing requiring the _ to be Sized */
+ d as *mut _
+}
+
+trait Xyz {}
+struct S;
+struct T;
+impl Xyz for S {}
+impl Xyz for T {}
+
+fn foo_no_never() {
+ let mut x /* : Option<S> */ = None;
+ let mut first_iter = false;
+ loop {
+ if !first_iter {
+ let y: Box<dyn Xyz>
+ = /* Box<$0> is coerced to Box<Xyz> here */ Box::new(x.unwrap());
+ }
+
+ x = Some(S);
+ first_iter = true;
+ }
+
+ let mut y : Option<S> = None;
+ // assert types are equal
+ mem::swap(&mut x, &mut y);
+}
+
+fn main() {
+}
diff --git a/src/test/ui/coercion/coerce-mut.rs b/src/test/ui/coercion/coerce-mut.rs
new file mode 100644
index 000000000..43f0b5585
--- /dev/null
+++ b/src/test/ui/coercion/coerce-mut.rs
@@ -0,0 +1,10 @@
+fn f(x: &mut i32) {}
+
+fn main() {
+ let x = 0;
+ f(&x);
+ //~^ ERROR mismatched types
+ //~| expected mutable reference `&mut i32`
+ //~| found reference `&{integer}`
+ //~| types differ in mutability
+}
diff --git a/src/test/ui/coercion/coerce-mut.stderr b/src/test/ui/coercion/coerce-mut.stderr
new file mode 100644
index 000000000..11a4f3101
--- /dev/null
+++ b/src/test/ui/coercion/coerce-mut.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+ --> $DIR/coerce-mut.rs:5:7
+ |
+LL | f(&x);
+ | - ^^ types differ in mutability
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected mutable reference `&mut i32`
+ found reference `&{integer}`
+note: function defined here
+ --> $DIR/coerce-mut.rs:1:4
+ |
+LL | fn f(x: &mut i32) {}
+ | ^ -----------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs
new file mode 100644
index 000000000..01d9c1e48
--- /dev/null
+++ b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs
@@ -0,0 +1,32 @@
+fn borrow_mut<T>(x: &mut T) -> &mut T { x }
+fn borrow<T>(x: &T) -> &T { x }
+
+fn borrow_mut2<T>(_: &mut T, _: &mut T) {}
+fn borrow2<T>(_: &mut T, _: &T) {}
+
+fn double_mut_borrow<T>(x: &mut Box<T>) {
+ let y = borrow_mut(x);
+ let z = borrow_mut(x);
+ //~^ ERROR cannot borrow `*x` as mutable more than once at a time
+ drop((y, z));
+}
+
+fn double_imm_borrow(x: &mut Box<i32>) {
+ let y = borrow(x);
+ let z = borrow(x);
+ **x += 1;
+ //~^ ERROR cannot assign to `**x` because it is borrowed
+ drop((y, z));
+}
+
+fn double_mut_borrow2<T>(x: &mut Box<T>) {
+ borrow_mut2(x, x);
+ //~^ ERROR cannot borrow `*x` as mutable more than once at a time
+}
+
+fn double_borrow2<T>(x: &mut Box<T>) {
+ borrow2(x, x);
+ //~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable
+}
+
+pub fn main() {}
diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr
new file mode 100644
index 000000000..d067c3b3a
--- /dev/null
+++ b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr
@@ -0,0 +1,46 @@
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+ --> $DIR/coerce-overloaded-autoderef-fail.rs:9:24
+ |
+LL | let y = borrow_mut(x);
+ | - first mutable borrow occurs here
+LL | let z = borrow_mut(x);
+ | ^ second mutable borrow occurs here
+LL |
+LL | drop((y, z));
+ | - first borrow later used here
+
+error[E0506]: cannot assign to `**x` because it is borrowed
+ --> $DIR/coerce-overloaded-autoderef-fail.rs:17:5
+ |
+LL | let y = borrow(x);
+ | - borrow of `**x` occurs here
+LL | let z = borrow(x);
+LL | **x += 1;
+ | ^^^^^^^^ assignment to borrowed `**x` occurs here
+LL |
+LL | drop((y, z));
+ | - borrow later used here
+
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+ --> $DIR/coerce-overloaded-autoderef-fail.rs:23:20
+ |
+LL | borrow_mut2(x, x);
+ | ----------- - ^ second mutable borrow occurs here
+ | | |
+ | | first mutable borrow occurs here
+ | first borrow later used by call
+
+error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
+ --> $DIR/coerce-overloaded-autoderef-fail.rs:28:5
+ |
+LL | borrow2(x, x);
+ | -------^^^^-^
+ | | |
+ | | immutable borrow occurs here
+ | mutable borrow occurs here
+ | immutable borrow later used by call
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0506.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.rs b/src/test/ui/coercion/coerce-overloaded-autoderef.rs
new file mode 100644
index 000000000..d5484607c
--- /dev/null
+++ b/src/test/ui/coercion/coerce-overloaded-autoderef.rs
@@ -0,0 +1,68 @@
+// run-pass
+#![allow(unused_braces)]
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+use std::rc::Rc;
+
+// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241.
+
+fn use_ref<T>(_: &T) {}
+fn use_mut<T>(_: &mut T) {}
+
+fn use_rc<T>(t: Rc<T>) {
+ use_ref(&*t); // what you have to write today
+ use_ref(&t); // what you'd be able to write
+ use_ref(&&&&&&t);
+ use_ref(&mut &&&&&t);
+ use_ref(&&&mut &&&t);
+}
+
+fn use_mut_box<T>(mut t: &mut Box<T>) {
+ use_mut(&mut *t); // what you have to write today
+ use_mut(t); // what you'd be able to write
+ use_mut(&mut &mut &mut t);
+
+ use_ref(&*t); // what you have to write today
+ use_ref(t); // what you'd be able to write
+ use_ref(&&&&&&t);
+ use_ref(&mut &&&&&t);
+ use_ref(&&&mut &&&t);
+}
+
+fn use_nested<T>(t: &Box<T>) {
+ use_ref(&**t); // what you have to write today
+ use_ref(t); // what you'd be able to write (note: recursive deref)
+ use_ref(&&&&&&t);
+ use_ref(&mut &&&&&t);
+ use_ref(&&&mut &&&t);
+}
+
+fn use_slice(_: &[u8]) {}
+fn use_slice_mut(_: &mut [u8]) {}
+
+fn use_vec(mut v: Vec<u8>) {
+ use_slice_mut(&mut v[..]); // what you have to write today
+ use_slice_mut(&mut v); // what you'd be able to write
+ use_slice_mut(&mut &mut &mut v);
+
+ use_slice(&v[..]); // what you have to write today
+ use_slice(&v); // what you'd be able to write
+ use_slice(&&&&&&v);
+ use_slice(&mut &&&&&v);
+ use_slice(&&&mut &&&v);
+}
+
+fn use_vec_ref(v: &Vec<u8>) {
+ use_slice(&v[..]); // what you have to write today
+ use_slice(v); // what you'd be able to write
+ use_slice(&&&&&&v);
+ use_slice(&mut &&&&&v);
+ use_slice(&&&mut &&&v);
+}
+
+fn use_op_rhs(s: &mut String) {
+ *s += {&String::from(" ")};
+}
+
+pub fn main() {}
diff --git a/src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs b/src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs
new file mode 100644
index 000000000..f033e1b5d
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+fn negate(x: &isize) -> isize {
+ -*x
+}
+
+fn negate_mut(y: &mut isize) -> isize {
+ negate(y)
+}
+
+fn negate_imm(y: &isize) -> isize {
+ negate(y)
+}
+
+pub fn main() {}
diff --git a/src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs
new file mode 100644
index 000000000..64a365229
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+struct SpeechMaker {
+ speeches: usize
+}
+
+impl SpeechMaker {
+ pub fn how_many(&self) -> usize { self.speeches }
+}
+
+fn foo(speaker: &SpeechMaker) -> usize {
+ speaker.how_many() + 33
+}
+
+pub fn main() {
+ let lincoln = SpeechMaker {speeches: 22};
+ assert_eq!(foo(&lincoln), 55);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs b/src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs
new file mode 100644
index 000000000..c2aaae1c7
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs
@@ -0,0 +1,19 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+fn sum(x: &[isize]) -> isize {
+ let mut sum = 0;
+ for y in x { sum += *y; }
+ return sum;
+}
+
+fn sum_mut(y: &mut [isize]) -> isize {
+ sum(y)
+}
+
+fn sum_imm(y: &[isize]) -> isize {
+ sum(y)
+}
+
+pub fn main() {}
diff --git a/src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs
new file mode 100644
index 000000000..9a5652acf
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+
+fn bar(v: &mut [usize]) -> Vec<usize> {
+ v.to_vec()
+}
+
+fn bip(v: &[usize]) -> Vec<usize> {
+ v.to_vec()
+}
+
+pub fn main() {
+ let mut the_vec = vec![1, 2, 3, 100];
+ assert_eq!(the_vec.clone(), bar(&mut the_vec));
+ assert_eq!(the_vec.clone(), bip(&the_vec));
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs
new file mode 100644
index 000000000..48be2d314
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs
@@ -0,0 +1,6 @@
+fn test<T>(_a: T, _b: T) {}
+
+fn main() {
+ test(&mut 7, &7);
+ //~^ mismatched types
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
new file mode 100644
index 000000000..36551e5af
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+ --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
+ |
+LL | test(&mut 7, &7);
+ | ---- ^^ types differ in mutability
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected mutable reference `&mut {integer}`
+ found reference `&{integer}`
+note: function defined here
+ --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4
+ |
+LL | fn test<T>(_a: T, _b: T) {}
+ | ^^^^ ----- -----
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg.rs b/src/test/ui/coercion/coerce-reborrow-multi-arg.rs
new file mode 100644
index 000000000..93cd0bb3e
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-multi-arg.rs
@@ -0,0 +1,9 @@
+// build-pass
+fn test<T>(_a: T, _b: T) {}
+
+fn main() {
+ test(&7, &7);
+ test(&7, &mut 7);
+ test::<&i32>(&mut 7, &7);
+ test::<&i32>(&mut 7, &mut 7);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs b/src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs
new file mode 100644
index 000000000..76cd6793b
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs
@@ -0,0 +1,25 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+struct SpeechMaker {
+ speeches: usize
+}
+
+fn talk(x: &mut SpeechMaker) {
+ x.speeches += 1;
+}
+
+fn give_a_few_speeches(speaker: &mut SpeechMaker) {
+
+ // Here speaker is reborrowed for each call, so we don't get errors
+ // about speaker being moved.
+
+ talk(speaker);
+ talk(speaker);
+ talk(speaker);
+}
+
+pub fn main() {
+ let mut lincoln = SpeechMaker {speeches: 22};
+ give_a_few_speeches(&mut lincoln);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs
new file mode 100644
index 000000000..e6e7c3a51
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs
@@ -0,0 +1,27 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+struct SpeechMaker {
+ speeches: usize
+}
+
+impl SpeechMaker {
+ pub fn talk(&mut self) {
+ self.speeches += 1;
+ }
+}
+
+fn give_a_few_speeches(speaker: &mut SpeechMaker) {
+
+ // Here speaker is reborrowed for each call, so we don't get errors
+ // about speaker being moved.
+
+ speaker.talk();
+ speaker.talk();
+ speaker.talk();
+}
+
+pub fn main() {
+ let mut lincoln = SpeechMaker {speeches: 22};
+ give_a_few_speeches(&mut lincoln);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs b/src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs
new file mode 100644
index 000000000..2635754f1
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+
+fn reverse(v: &mut [usize]) {
+ v.reverse();
+}
+
+fn bar(v: &mut [usize]) {
+ reverse(v);
+ reverse(v);
+ reverse(v);
+}
+
+pub fn main() {
+ let mut the_vec = vec![1, 2, 3, 100];
+ bar(&mut the_vec);
+ assert_eq!(the_vec, [100, 3, 2, 1]);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs
new file mode 100644
index 000000000..c03336ea3
--- /dev/null
+++ b/src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+
+fn bar(v: &mut [usize]) {
+ v.reverse();
+ v.reverse();
+ v.reverse();
+}
+
+pub fn main() {
+ let mut the_vec = vec![1, 2, 3, 100];
+ bar(&mut the_vec);
+ assert_eq!(the_vec, [100, 3, 2, 1]);
+}
diff --git a/src/test/ui/coercion/coerce-to-bang-cast.rs b/src/test/ui/coercion/coerce-to-bang-cast.rs
new file mode 100644
index 000000000..85598a42e
--- /dev/null
+++ b/src/test/ui/coercion/coerce-to-bang-cast.rs
@@ -0,0 +1,12 @@
+#![feature(never_type)]
+
+fn cast_a() {
+ let y = {return; 22} as !;
+ //~^ ERROR non-primitive cast
+}
+
+fn cast_b() {
+ let y = 22 as !; //~ ERROR non-primitive cast
+}
+
+fn main() { }
diff --git a/src/test/ui/coercion/coerce-to-bang-cast.stderr b/src/test/ui/coercion/coerce-to-bang-cast.stderr
new file mode 100644
index 000000000..50e009aa2
--- /dev/null
+++ b/src/test/ui/coercion/coerce-to-bang-cast.stderr
@@ -0,0 +1,15 @@
+error[E0605]: non-primitive cast: `i32` as `!`
+ --> $DIR/coerce-to-bang-cast.rs:4:13
+ |
+LL | let y = {return; 22} as !;
+ | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error[E0605]: non-primitive cast: `i32` as `!`
+ --> $DIR/coerce-to-bang-cast.rs:9:13
+ |
+LL | let y = 22 as !;
+ | ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0605`.
diff --git a/src/test/ui/coercion/coerce-to-bang.rs b/src/test/ui/coercion/coerce-to-bang.rs
new file mode 100644
index 000000000..1e06934d0
--- /dev/null
+++ b/src/test/ui/coercion/coerce-to-bang.rs
@@ -0,0 +1,79 @@
+#![feature(never_type)]
+
+fn foo(x: usize, y: !, z: usize) { }
+
+fn call_foo_a() {
+ foo(return, 22, 44);
+ //~^ ERROR mismatched types
+}
+
+fn call_foo_b() {
+ // Divergence happens in the argument itself, definitely ok.
+ foo(22, return, 44);
+}
+
+fn call_foo_c() {
+ // This test fails because the divergence happens **after** the
+ // coercion to `!`:
+ foo(22, 44, return); //~ ERROR mismatched types
+}
+
+fn call_foo_d() {
+ // This test passes because `a` has type `!`:
+ let a: ! = return;
+ let b = 22;
+ let c = 44;
+ foo(a, b, c); // ... and hence a reference to `a` is expected to diverge.
+ //~^ ERROR mismatched types
+}
+
+fn call_foo_e() {
+ // This test probably could pass but we don't *know* that `a`
+ // has type `!` so we don't let it work.
+ let a = return;
+ let b = 22;
+ let c = 44;
+ foo(a, b, c); //~ ERROR mismatched types
+}
+
+fn call_foo_f() {
+ // This fn fails because `a` has type `usize`, and hence a
+ // reference to is it **not** considered to diverge.
+ let a: usize = return;
+ let b = 22;
+ let c = 44;
+ foo(a, b, c); //~ ERROR mismatched types
+}
+
+fn array_a() {
+ // Return is coerced to `!` just fine, but `22` cannot be.
+ let x: [!; 2] = [return, 22]; //~ ERROR mismatched types
+}
+
+fn array_b() {
+ // Error: divergence has not yet occurred.
+ let x: [!; 2] = [22, return]; //~ ERROR mismatched types
+}
+
+fn tuple_a() {
+ // No divergence at all.
+ let x: (usize, !, usize) = (22, 44, 66); //~ ERROR mismatched types
+}
+
+fn tuple_b() {
+ // Divergence happens before coercion: OK
+ let x: (usize, !, usize) = (return, 44, 66);
+ //~^ ERROR mismatched types
+}
+
+fn tuple_c() {
+ // Divergence happens before coercion: OK
+ let x: (usize, !, usize) = (22, return, 66);
+}
+
+fn tuple_d() {
+ // Error: divergence happens too late
+ let x: (usize, !, usize) = (22, 44, return); //~ ERROR mismatched types
+}
+
+fn main() { }
diff --git a/src/test/ui/coercion/coerce-to-bang.stderr b/src/test/ui/coercion/coerce-to-bang.stderr
new file mode 100644
index 000000000..add8f14cf
--- /dev/null
+++ b/src/test/ui/coercion/coerce-to-bang.stderr
@@ -0,0 +1,130 @@
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:6:17
+ |
+LL | foo(return, 22, 44);
+ | --- ^^ expected `!`, found integer
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected type `!`
+ found type `{integer}`
+note: function defined here
+ --> $DIR/coerce-to-bang.rs:3:4
+ |
+LL | fn foo(x: usize, y: !, z: usize) { }
+ | ^^^ -------- ---- --------
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:18:13
+ |
+LL | foo(22, 44, return);
+ | --- ^^ expected `!`, found integer
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected type `!`
+ found type `{integer}`
+note: function defined here
+ --> $DIR/coerce-to-bang.rs:3:4
+ |
+LL | fn foo(x: usize, y: !, z: usize) { }
+ | ^^^ -------- ---- --------
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:26:12
+ |
+LL | foo(a, b, c); // ... and hence a reference to `a` is expected to diverge.
+ | --- ^ expected `!`, found integer
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected type `!`
+ found type `{integer}`
+note: function defined here
+ --> $DIR/coerce-to-bang.rs:3:4
+ |
+LL | fn foo(x: usize, y: !, z: usize) { }
+ | ^^^ -------- ---- --------
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:36:12
+ |
+LL | foo(a, b, c);
+ | --- ^ expected `!`, found integer
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected type `!`
+ found type `{integer}`
+note: function defined here
+ --> $DIR/coerce-to-bang.rs:3:4
+ |
+LL | fn foo(x: usize, y: !, z: usize) { }
+ | ^^^ -------- ---- --------
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:45:12
+ |
+LL | foo(a, b, c);
+ | --- ^ expected `!`, found integer
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected type `!`
+ found type `{integer}`
+note: function defined here
+ --> $DIR/coerce-to-bang.rs:3:4
+ |
+LL | fn foo(x: usize, y: !, z: usize) { }
+ | ^^^ -------- ---- --------
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:50:21
+ |
+LL | let x: [!; 2] = [return, 22];
+ | ------ ^^^^^^^^^^^^ expected `!`, found integer
+ | |
+ | expected due to this
+ |
+ = note: expected array `[!; 2]`
+ found array `[{integer}; 2]`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:55:22
+ |
+LL | let x: [!; 2] = [22, return];
+ | ^^ expected `!`, found integer
+ |
+ = note: expected type `!`
+ found type `{integer}`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:60:37
+ |
+LL | let x: (usize, !, usize) = (22, 44, 66);
+ | ^^ expected `!`, found integer
+ |
+ = note: expected type `!`
+ found type `{integer}`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:65:41
+ |
+LL | let x: (usize, !, usize) = (return, 44, 66);
+ | ^^ expected `!`, found integer
+ |
+ = note: expected type `!`
+ found type `{integer}`
+
+error[E0308]: mismatched types
+ --> $DIR/coerce-to-bang.rs:76:37
+ |
+LL | let x: (usize, !, usize) = (22, 44, return);
+ | ^^ expected `!`, found integer
+ |
+ = note: expected type `!`
+ found type `{integer}`
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-unify-return.rs b/src/test/ui/coercion/coerce-unify-return.rs
new file mode 100644
index 000000000..95a7ee8fe
--- /dev/null
+++ b/src/test/ui/coercion/coerce-unify-return.rs
@@ -0,0 +1,19 @@
+// run-pass
+// Check that coercions unify the expected return type of a polymorphic
+// function call, instead of leaving the type variables as they were.
+
+// pretty-expanded FIXME #23616
+
+struct Foo;
+impl Foo {
+ fn foo<T>(self, x: T) -> Option<T> { Some(x) }
+}
+
+pub fn main() {
+ let _: Option<fn()> = Some(main);
+ let _: Option<fn()> = Foo.foo(main);
+
+ // The same two cases, with implicit type variables made explicit.
+ let _: Option<fn()> = Some::<_>(main);
+ let _: Option<fn()> = Foo.foo::<_>(main);
+}
diff --git a/src/test/ui/coercion/coerce-unify.rs b/src/test/ui/coercion/coerce-unify.rs
new file mode 100644
index 000000000..f1818f9bb
--- /dev/null
+++ b/src/test/ui/coercion/coerce-unify.rs
@@ -0,0 +1,68 @@
+// run-pass
+// Check that coercions can unify if-else, match arms and array elements.
+
+// Try to construct if-else chains, matches and arrays out of given expressions.
+macro_rules! check {
+ ($last:expr $(, $rest:expr)+) => {
+ // Last expression comes first because of whacky ifs and matches.
+ let _ = $(if false { $rest })else+ else { $last };
+
+ let _ = match 0 { $(_ if false => $rest,)+ _ => $last };
+
+ let _ = [$($rest,)+ $last];
+ }
+}
+
+// Check all non-uniform cases of 2 and 3 expressions of 2 types.
+macro_rules! check2 {
+ ($a:expr, $b:expr) => {
+ check!($a, $b);
+ check!($b, $a);
+
+ check!($a, $a, $b);
+ check!($a, $b, $a);
+ check!($a, $b, $b);
+
+ check!($b, $a, $a);
+ check!($b, $a, $b);
+ check!($b, $b, $a);
+ }
+}
+
+// Check all non-uniform cases of 2 and 3 expressions of 3 types.
+macro_rules! check3 {
+ ($a:expr, $b:expr, $c:expr) => {
+ // Delegate to check2 for cases where a type repeats.
+ check2!($a, $b);
+ check2!($b, $c);
+ check2!($a, $c);
+
+ // Check the remaining cases, i.e., permutations of ($a, $b, $c).
+ check!($a, $b, $c);
+ check!($a, $c, $b);
+ check!($b, $a, $c);
+ check!($b, $c, $a);
+ check!($c, $a, $b);
+ check!($c, $b, $a);
+ }
+}
+
+use std::mem::size_of;
+
+fn foo() {}
+fn bar() {}
+
+pub fn main() {
+ check3!(foo, bar, foo as fn());
+ check3!(size_of::<u8>, size_of::<u16>, size_of::<usize> as fn() -> usize);
+
+ let s = String::from("bar");
+ check2!("foo", &s);
+
+ let a = [1, 2, 3];
+ let v = vec![1, 2, 3];
+ check2!(&a[..], &v);
+
+ // Make sure in-array coercion still works.
+ let _ = [("a", Default::default()), (Default::default(), "b"), (&s, &s)];
+}
diff --git a/src/test/ui/coercion/coerce-unsize-subtype.rs b/src/test/ui/coercion/coerce-unsize-subtype.rs
new file mode 100644
index 000000000..45b53300c
--- /dev/null
+++ b/src/test/ui/coercion/coerce-unsize-subtype.rs
@@ -0,0 +1,40 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+use std::rc::Rc;
+
+fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {}
+
+// The two arguments are a subtype of their LUB, after coercion.
+fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) {
+ lub_short(xs, ys);
+}
+
+// The argument coerces to a subtype of the return type.
+fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] {
+ xs
+}
+
+// Rc<T> is covariant over T just like &T.
+fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> {
+ xs
+}
+
+// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]`
+// to a subtype of the LUB of `xs` and `ys` (i.e., `&'b [&'a T]`),
+// regardless of the order they appear (in if-else/match/array).
+fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) {
+ let _order1 = [xs, ys];
+ let _order2 = [ys, xs];
+}
+
+// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]`
+// needs to be coerced, i.e., the resulting type is not &'b [&'static T], but
+// rather the `&'b [&'a T]` LUB.
+fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) {
+ let _order1 = [xs, ys];
+ let _order2 = [ys, xs];
+}
+
+fn main() {}
diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.fixed b/src/test/ui/coercion/coercion-missing-tail-expected-type.fixed
new file mode 100644
index 000000000..713e04774
--- /dev/null
+++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.fixed
@@ -0,0 +1,16 @@
+// #41425 -- error message "mismatched types" has wrong types
+// run-rustfix
+
+fn plus_one(x: i32) -> i32 { //~ ERROR mismatched types
+ x + 1
+}
+
+fn foo() -> Result<u8, u64> { //~ ERROR mismatched types
+ Ok(1)
+}
+
+fn main() {
+ let x = plus_one(5);
+ let _ = foo();
+ println!("X = {}", x);
+}
diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.rs b/src/test/ui/coercion/coercion-missing-tail-expected-type.rs
new file mode 100644
index 000000000..e14d79d8a
--- /dev/null
+++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.rs
@@ -0,0 +1,16 @@
+// #41425 -- error message "mismatched types" has wrong types
+// run-rustfix
+
+fn plus_one(x: i32) -> i32 { //~ ERROR mismatched types
+ x + 1;
+}
+
+fn foo() -> Result<u8, u64> { //~ ERROR mismatched types
+ Ok(1);
+}
+
+fn main() {
+ let x = plus_one(5);
+ let _ = foo();
+ println!("X = {}", x);
+}
diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr
new file mode 100644
index 000000000..a4843bca5
--- /dev/null
+++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr
@@ -0,0 +1,26 @@
+error[E0308]: mismatched types
+ --> $DIR/coercion-missing-tail-expected-type.rs:4:24
+ |
+LL | fn plus_one(x: i32) -> i32 {
+ | -------- ^^^ expected `i32`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+LL | x + 1;
+ | - help: remove this semicolon
+
+error[E0308]: mismatched types
+ --> $DIR/coercion-missing-tail-expected-type.rs:8:13
+ |
+LL | fn foo() -> Result<u8, u64> {
+ | --- ^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+LL | Ok(1);
+ | - help: remove this semicolon
+ |
+ = note: expected enum `Result<u8, u64>`
+ found unit type `()`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coercion-slice.rs b/src/test/ui/coercion/coercion-slice.rs
new file mode 100644
index 000000000..b756c8f82
--- /dev/null
+++ b/src/test/ui/coercion/coercion-slice.rs
@@ -0,0 +1,7 @@
+// Tests that we forbid coercion from `[T; n]` to `&[T]`
+
+fn main() {
+ let _: &[i32] = [0];
+ //~^ ERROR mismatched types
+ //~| expected `&[i32]`, found array `[{integer}; 1]`
+}
diff --git a/src/test/ui/coercion/coercion-slice.stderr b/src/test/ui/coercion/coercion-slice.stderr
new file mode 100644
index 000000000..42dc954ff
--- /dev/null
+++ b/src/test/ui/coercion/coercion-slice.stderr
@@ -0,0 +1,13 @@
+error[E0308]: mismatched types
+ --> $DIR/coercion-slice.rs:4:21
+ |
+LL | let _: &[i32] = [0];
+ | ------ ^^^
+ | | |
+ | | expected `&[i32]`, found array `[{integer}; 1]`
+ | | help: consider borrowing here: `&[0]`
+ | expected due to this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/issue-14589.rs b/src/test/ui/coercion/issue-14589.rs
new file mode 100644
index 000000000..d35ee5c73
--- /dev/null
+++ b/src/test/ui/coercion/issue-14589.rs
@@ -0,0 +1,24 @@
+// run-pass
+// All 3 expressions should work in that the argument gets
+// coerced to a trait object
+
+// pretty-expanded FIXME #23616
+
+fn main() {
+ send::<Box<dyn Foo>>(Box::new(Output(0)));
+ Test::<Box<dyn Foo>>::foo(Box::new(Output(0)));
+ Test::<Box<dyn Foo>>::new().send(Box::new(Output(0)));
+}
+
+fn send<T>(_: T) {}
+
+struct Test<T> { marker: std::marker::PhantomData<T> }
+impl<T> Test<T> {
+ fn new() -> Test<T> { Test { marker: ::std::marker::PhantomData } }
+ fn foo(_: T) {}
+ fn send(&self, _: T) {}
+}
+
+trait Foo { fn dummy(&self) { }}
+struct Output(#[allow(unused_tuple_struct_fields)] isize);
+impl Foo for Output {}
diff --git a/src/test/ui/coercion/issue-37655.rs b/src/test/ui/coercion/issue-37655.rs
new file mode 100644
index 000000000..416854d66
--- /dev/null
+++ b/src/test/ui/coercion/issue-37655.rs
@@ -0,0 +1,37 @@
+// check-pass
+// Regression test for #37655. The problem was a false edge created by
+// coercion that wound up requiring that `'a` (in `split()`) outlive
+// `'b`, which shouldn't be necessary.
+
+#![allow(warnings)]
+
+trait SliceExt<T> {
+ type Item;
+
+ fn get_me<I>(&self, index: I) -> &I::Output
+ where I: SliceIndex<Self::Item>;
+}
+
+impl<T> SliceExt<T> for [T] {
+ type Item = T;
+
+ fn get_me<I>(&self, index: I) -> &I::Output
+ where I: SliceIndex<T>
+ {
+ panic!()
+ }
+}
+
+pub trait SliceIndex<T> {
+ type Output: ?Sized;
+}
+
+impl<T> SliceIndex<T> for usize {
+ type Output = T;
+}
+
+fn foo<'a, 'b>(split: &'b [&'a [u8]]) -> &'a [u8] {
+ split.get_me(0)
+}
+
+fn main() { }
diff --git a/src/test/ui/coercion/issue-39823.rs b/src/test/ui/coercion/issue-39823.rs
new file mode 100644
index 000000000..148cf527e
--- /dev/null
+++ b/src/test/ui/coercion/issue-39823.rs
@@ -0,0 +1,25 @@
+// run-pass
+// aux-build:issue-39823.rs
+
+extern crate issue_39823;
+use issue_39823::{RemoteC, RemoteG};
+
+#[derive(Debug, PartialEq)]
+struct LocalC(u32);
+
+#[derive(Debug, PartialEq)]
+struct LocalG<T>(T);
+
+fn main() {
+ let virtual_localc : &dyn Fn(_) -> LocalC = &LocalC;
+ assert_eq!(virtual_localc(1), LocalC(1));
+
+ let virtual_localg : &dyn Fn(_) -> LocalG<u32> = &LocalG;
+ assert_eq!(virtual_localg(1), LocalG(1));
+
+ let virtual_remotec : &dyn Fn(_) -> RemoteC = &RemoteC;
+ assert_eq!(virtual_remotec(1), RemoteC(1));
+
+ let virtual_remoteg : &dyn Fn(_) -> RemoteG<u32> = &RemoteG;
+ assert_eq!(virtual_remoteg(1), RemoteG(1));
+}
diff --git a/src/test/ui/coercion/issue-53475.rs b/src/test/ui/coercion/issue-53475.rs
new file mode 100644
index 000000000..3770c024f
--- /dev/null
+++ b/src/test/ui/coercion/issue-53475.rs
@@ -0,0 +1,13 @@
+#![feature(coerce_unsized)]
+
+use std::any::Any;
+use std::ops::CoerceUnsized;
+
+struct Foo<T> {
+ data: Box<T>,
+}
+
+impl<T> CoerceUnsized<Foo<dyn Any>> for Foo<T> {}
+//~^ ERROR the parameter type `T` may not live long enough
+
+fn main() {}
diff --git a/src/test/ui/coercion/issue-53475.stderr b/src/test/ui/coercion/issue-53475.stderr
new file mode 100644
index 000000000..522c50dca
--- /dev/null
+++ b/src/test/ui/coercion/issue-53475.stderr
@@ -0,0 +1,14 @@
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/issue-53475.rs:10:1
+ |
+LL | impl<T> CoerceUnsized<Foo<dyn Any>> for Foo<T> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | impl<T: 'static> CoerceUnsized<Foo<dyn Any>> for Foo<T> {}
+ | +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/coercion/issue-73886.rs b/src/test/ui/coercion/issue-73886.rs
new file mode 100644
index 000000000..9c0c87a5c
--- /dev/null
+++ b/src/test/ui/coercion/issue-73886.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let _ = &&[0] as &[_];
+ //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]`
+ let _ = 7u32 as Option<_>;
+ //~^ ERROR non-primitive cast: `u32` as `Option<_>`
+}
diff --git a/src/test/ui/coercion/issue-73886.stderr b/src/test/ui/coercion/issue-73886.stderr
new file mode 100644
index 000000000..a6f8ba65a
--- /dev/null
+++ b/src/test/ui/coercion/issue-73886.stderr
@@ -0,0 +1,17 @@
+error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]`
+ --> $DIR/issue-73886.rs:2:13
+ |
+LL | let _ = &&[0] as &[_];
+ | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error[E0605]: non-primitive cast: `u32` as `Option<_>`
+ --> $DIR/issue-73886.rs:4:13
+ |
+LL | let _ = 7u32 as Option<_>;
+ | ^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `Option<_>::from(7u32)`
+ |
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0605`.
diff --git a/src/test/ui/coercion/issue-88097.rs b/src/test/ui/coercion/issue-88097.rs
new file mode 100644
index 000000000..e543e1bae
--- /dev/null
+++ b/src/test/ui/coercion/issue-88097.rs
@@ -0,0 +1,31 @@
+// In #88097, the compiler attempted to coerce a closure type to itself via
+// a function pointer, which caused an unnecessary error. Check that this
+// behavior has been fixed.
+
+// check-pass
+
+fn peculiar() -> impl Fn(u8) -> u8 {
+ return |x| x + 1
+}
+
+fn peculiar2() -> impl Fn(u8) -> u8 {
+ return |x| x + 1;
+}
+
+fn peculiar3() -> impl Fn(u8) -> u8 {
+ let f = |x| x + 1;
+ return f
+}
+
+fn peculiar4() -> impl Fn(u8) -> u8 {
+ let f = |x| x + 1;
+ f
+}
+
+fn peculiar5() -> impl Fn(u8) -> u8 {
+ let f = |x| x + 1;
+ let g = |x| x + 2;
+ return if true { f } else { g }
+}
+
+fn main() {}
diff --git a/src/test/ui/coercion/retslot-cast.rs b/src/test/ui/coercion/retslot-cast.rs
new file mode 100644
index 000000000..ae500cb15
--- /dev/null
+++ b/src/test/ui/coercion/retslot-cast.rs
@@ -0,0 +1,22 @@
+#![allow(warnings)]
+
+pub fn fail(x: Option<&(Iterator<Item=()>+Send)>)
+ -> Option<&Iterator<Item=()>> {
+ // This call used to trigger an LLVM assertion because the return
+ // slot had type "Option<&Iterator>"* instead of
+ // "Option<&(Iterator+Send)>"* -- but this now yields a
+ // compilation error and I'm not sure how to create a comparable
+ // test. To ensure that this PARTICULAR failure doesn't occur
+ // again, though, I've left this test here, so if this ever starts
+ // to compile again, we can adjust the test appropriately (clearly
+ // it should never ICE...). -nmatsakis
+ inner(x) //~ ERROR mismatched types
+}
+
+pub fn inner(x: Option<&(Iterator<Item=()>+Send)>)
+ -> Option<&(Iterator<Item=()>+Send)> {
+ x
+}
+
+
+fn main() {}
diff --git a/src/test/ui/coercion/retslot-cast.stderr b/src/test/ui/coercion/retslot-cast.stderr
new file mode 100644
index 000000000..798ce1199
--- /dev/null
+++ b/src/test/ui/coercion/retslot-cast.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+ --> $DIR/retslot-cast.rs:13:5
+ |
+LL | -> Option<&Iterator<Item=()>> {
+ | -------------------------- expected `Option<&dyn Iterator<Item = ()>>` because of return type
+...
+LL | inner(x)
+ | ^^^^^^^^ expected trait `Iterator<Item = ()>`, found trait `Iterator<Item = ()> + Send`
+ |
+ = note: expected enum `Option<&dyn Iterator<Item = ()>>`
+ found enum `Option<&dyn Iterator<Item = ()> + Send>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/unsafe-coercion.rs b/src/test/ui/coercion/unsafe-coercion.rs
new file mode 100644
index 000000000..2478deeab
--- /dev/null
+++ b/src/test/ui/coercion/unsafe-coercion.rs
@@ -0,0 +1,17 @@
+// run-pass
+// Check that safe fns are not a subtype of unsafe fns.
+
+
+fn foo(x: i32) -> i32 {
+ x * 22
+}
+
+fn bar(x: fn(i32) -> i32) -> unsafe fn(i32) -> i32 {
+ x // OK, coercion!
+}
+
+fn main() {
+ let f = bar(foo);
+ let x = unsafe { f(2) };
+ assert_eq!(x, 44);
+}