diff options
Diffstat (limited to '')
58 files changed, 1297 insertions, 0 deletions
diff --git a/src/test/ui/never_type/adjust_never.rs b/src/test/ui/never_type/adjust_never.rs new file mode 100644 index 000000000..0d7d2c0ed --- /dev/null +++ b/src/test/ui/never_type/adjust_never.rs @@ -0,0 +1,10 @@ +// Test that a variable of type ! can coerce to another type. + +// check-pass + +#![feature(never_type)] + +fn main() { + let x: ! = panic!(); + let y: u32 = x; +} diff --git a/src/test/ui/never_type/auto-traits.rs b/src/test/ui/never_type/auto-traits.rs new file mode 100644 index 000000000..42ede708e --- /dev/null +++ b/src/test/ui/never_type/auto-traits.rs @@ -0,0 +1,18 @@ +// check-pass + +#![feature(auto_traits)] +#![feature(negative_impls)] +#![feature(never_type)] + +fn main() { + enum Void {} + + auto trait Auto {} + fn assert_auto<T: Auto>() {} + assert_auto::<Void>(); + assert_auto::<!>(); + + fn assert_send<T: Send>() {} + assert_send::<Void>(); + assert_send::<!>(); +} diff --git a/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs new file mode 100644 index 000000000..d06637e74 --- /dev/null +++ b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs @@ -0,0 +1,11 @@ +// Test that we can't pass other types for ! + +#![feature(never_type)] + +fn foo(x: !) -> ! { + x +} + +fn main() { + foo("wow"); //~ ERROR mismatched types +} diff --git a/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr b/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr new file mode 100644 index 000000000..fa3db33c9 --- /dev/null +++ b/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/call-fn-never-arg-wrong-type.rs:10:9 + | +LL | foo("wow"); + | --- ^^^^^ expected `!`, found `&str` + | | + | arguments to this function are incorrect + | + = note: expected type `!` + found reference `&'static str` +note: function defined here + --> $DIR/call-fn-never-arg-wrong-type.rs:5:4 + | +LL | fn foo(x: !) -> ! { + | ^^^ ---- + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/never_type/call-fn-never-arg.rs b/src/test/ui/never_type/call-fn-never-arg.rs new file mode 100644 index 000000000..9d355817e --- /dev/null +++ b/src/test/ui/never_type/call-fn-never-arg.rs @@ -0,0 +1,14 @@ +// Test that we can use a ! for an argument of type ! + +// check-pass + +#![feature(never_type)] +#![allow(unreachable_code)] + +fn foo(x: !) -> ! { + x +} + +fn main() { + foo(panic!("wowzers!")) +} diff --git a/src/test/ui/never_type/cast-never.rs b/src/test/ui/never_type/cast-never.rs new file mode 100644 index 000000000..0139ebe46 --- /dev/null +++ b/src/test/ui/never_type/cast-never.rs @@ -0,0 +1,10 @@ +// Test that we can explicitly cast ! to another type + +// check-pass + +#![feature(never_type)] + +fn main() { + let x: ! = panic!(); + let y: u32 = x as u32; +} diff --git a/src/test/ui/never_type/defaulted-never-note.fallback.stderr b/src/test/ui/never_type/defaulted-never-note.fallback.stderr new file mode 100644 index 000000000..4c8b49224 --- /dev/null +++ b/src/test/ui/never_type/defaulted-never-note.fallback.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied + --> $DIR/defaulted-never-note.rs:30:5 + | +LL | foo(_x); + | ^^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` + | + = help: the trait `ImplementedForUnitButNotNever` is implemented for `()` + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information) + = help: did you intend to use the type `()` here instead? +note: required by a bound in `foo` + --> $DIR/defaulted-never-note.rs:25:11 + | +LL | fn foo<T: ImplementedForUnitButNotNever>(_t: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/defaulted-never-note.rs b/src/test/ui/never_type/defaulted-never-note.rs new file mode 100644 index 000000000..aefc739a0 --- /dev/null +++ b/src/test/ui/never_type/defaulted-never-note.rs @@ -0,0 +1,40 @@ +// revisions: nofallback fallback +//[nofallback] run-pass +//[fallback] check-fail + +// We need to opt into the `never_type_fallback` feature +// to trigger the requirement that this is testing. +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] + +#![allow(unused)] + +trait Deserialize: Sized { + fn deserialize() -> Result<Self, String>; +} + +impl Deserialize for () { + fn deserialize() -> Result<(), String> { + Ok(()) + } +} + +trait ImplementedForUnitButNotNever {} + +impl ImplementedForUnitButNotNever for () {} + +fn foo<T: ImplementedForUnitButNotNever>(_t: T) {} +//[fallback]~^ NOTE required by this bound in `foo` +//[fallback]~| NOTE required by a bound in `foo` +fn smeg() { + let _x = return; + foo(_x); + //[fallback]~^ ERROR the trait bound + //[fallback]~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented + //[fallback]~| HELP trait `ImplementedForUnitButNotNever` is implemented for `()` + //[fallback]~| NOTE this error might have been caused + //[fallback]~| HELP did you intend +} + +fn main() { + smeg(); +} diff --git a/src/test/ui/never_type/dispatch_from_dyn_zst.rs b/src/test/ui/never_type/dispatch_from_dyn_zst.rs new file mode 100644 index 000000000..764f58ce9 --- /dev/null +++ b/src/test/ui/never_type/dispatch_from_dyn_zst.rs @@ -0,0 +1,51 @@ +// run-pass + +#![feature(unsize, dispatch_from_dyn, never_type)] + +#![allow(dead_code)] + +use std::{ + ops::DispatchFromDyn, + marker::{Unsize, PhantomData}, +}; + +struct Zst; +struct NestedZst(PhantomData<()>, Zst); + + +struct WithUnit<T: ?Sized>(Box<T>, ()); +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithUnit<U>> for WithUnit<T> + where T: Unsize<U> {} + +struct WithPhantom<T: ?Sized>(Box<T>, PhantomData<()>); +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithPhantom<U>> for WithPhantom<T> + where T: Unsize<U> {} + +struct WithNever<T: ?Sized>(Box<T>, !); +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithNever<U>> for WithNever<T> + where T: Unsize<U> {} + +struct WithZst<T: ?Sized>(Box<T>, Zst); +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithZst<U>> for WithZst<T> + where T: Unsize<U> {} + +struct WithNestedZst<T: ?Sized>(Box<T>, NestedZst); +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithNestedZst<U>> for WithNestedZst<T> + where T: Unsize<U> {} + + +struct Generic<T: ?Sized, A>(Box<T>, A); +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, ()>> for Generic<T, ()> + where T: Unsize<U> {} +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, PhantomData<()>>> + for Generic<T, PhantomData<()>> + where T: Unsize<U> {} +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, !>> for Generic<T, !> + where T: Unsize<U> {} +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, Zst>> for Generic<T, Zst> + where T: Unsize<U> {} +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, NestedZst>> for Generic<T, NestedZst> + where T: Unsize<U> {} + + +fn main() {} diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs new file mode 100644 index 000000000..45a3362fa --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs @@ -0,0 +1,100 @@ +// revisions: nofallback fallback +// run-pass + +#![allow(dead_code)] +#![allow(unused_assignments)] +#![allow(unused_variables)] +#![allow(unreachable_code)] +// Test various cases where we permit an unconstrained variable +// to fallback based on control-flow. In all of these cases, +// the type variable winds up being the target of both a `!` coercion +// and a coercion from a non-`!` variable, and hence falls back to `()`. +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] + +trait UnitDefault { + fn default() -> Self; +} + +impl UnitDefault for u32 { + fn default() -> Self { + 0 + } +} + +impl UnitDefault for () { + fn default() -> () { + panic!() + } +} + +fn assignment() { + let x; + + if true { + x = UnitDefault::default(); + } else { + x = return; + } +} + +fn assignment_rev() { + let x; + + if true { + x = return; + } else { + x = UnitDefault::default(); + } +} + +fn if_then_else() { + let _x = if true { + UnitDefault::default() + } else { + return; + }; +} + +fn if_then_else_rev() { + let _x = if true { + return; + } else { + UnitDefault::default() + }; +} + +fn match_arm() { + let _x = match Ok(UnitDefault::default()) { + Ok(v) => v, + Err(()) => return, + }; +} + +fn match_arm_rev() { + let _x = match Ok(UnitDefault::default()) { + Err(()) => return, + Ok(v) => v, + }; +} + +fn loop_break() { + let _x = loop { + if false { + break return; + } else { + break UnitDefault::default(); + } + }; +} + +fn loop_break_rev() { + let _x = loop { + if false { + break return; + } else { + break UnitDefault::default(); + } + }; +} + +fn main() {} diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr new file mode 100644 index 000000000..dee2b1d70 --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `!: Test` is not satisfied + --> $DIR/diverging-fallback-no-leak.rs:17:5 + | +LL | unconstrained_arg(return); + | ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!` + | + = help: the following other types implement trait `Test`: + () + i32 + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information) + = help: did you intend to use the type `()` here instead? +note: required by a bound in `unconstrained_arg` + --> $DIR/diverging-fallback-no-leak.rs:12:25 + | +LL | fn unconstrained_arg<T: Test>(_: T) {} + | ^^^^ required by this bound in `unconstrained_arg` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.rs b/src/test/ui/never_type/diverging-fallback-no-leak.rs new file mode 100644 index 000000000..03478e19d --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-no-leak.rs @@ -0,0 +1,19 @@ +// revisions: nofallback fallback +//[nofallback] check-pass + +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] + +fn make_unit() {} + +trait Test {} +impl Test for i32 {} +impl Test for () {} + +fn unconstrained_arg<T: Test>(_: T) {} + +fn main() { + // Here the type variable falls back to `!`, + // and hence we get a type error. + unconstrained_arg(return); + //[fallback]~^ ERROR trait bound `!: Test` is not satisfied +} diff --git a/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs new file mode 100644 index 000000000..7ea97126f --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -0,0 +1,37 @@ +// Variant of diverging-falllback-control-flow that tests +// the specific case of a free function with an unconstrained +// return type. This captures the pattern we saw in the wild +// in the objc crate, where changing the fallback from `!` to `()` +// resulted in unsoundness. +// +// check-pass + +// revisions: nofallback fallback + +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] + + +fn make_unit() {} + +trait UnitReturn {} +impl UnitReturn for i32 {} +impl UnitReturn for () {} + +fn unconstrained_return<T: UnitReturn>() -> T { + unsafe { + let make_unit_fn: fn() = make_unit; + let ffi: fn() -> T = std::mem::transmute(make_unit_fn); + ffi() + } +} + +fn main() { + // In Ye Olde Days, the `T` parameter of `unconstrained_return` + // winds up "entangled" with the `!` type that results from + // `panic!`, and hence falls back to `()`. This is kind of unfortunate + // and unexpected. When we introduced the `!` type, the original + // idea was to change that fallback to `!`, but that would have resulted + // in this code no longer compiling (or worse, in some cases it injected + // unsound results). + let _ = if true { unconstrained_return() } else { panic!() }; +} diff --git a/src/test/ui/never_type/diverging-tuple-parts-39485.rs b/src/test/ui/never_type/diverging-tuple-parts-39485.rs new file mode 100644 index 000000000..0cde61193 --- /dev/null +++ b/src/test/ui/never_type/diverging-tuple-parts-39485.rs @@ -0,0 +1,15 @@ +// After #39485, this test used to pass, but that change was reverted +// due to numerous inference failures like #39808, so it now fails +// again. #39485 made it so that diverging types never propagate +// upward; but we now do propagate such types upward in many more +// cases. + +fn g() { + &panic!() //~ ERROR mismatched types +} + +fn f() -> isize { + (return 1, return 2) //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/never_type/diverging-tuple-parts-39485.stderr b/src/test/ui/never_type/diverging-tuple-parts-39485.stderr new file mode 100644 index 000000000..52d07ae17 --- /dev/null +++ b/src/test/ui/never_type/diverging-tuple-parts-39485.stderr @@ -0,0 +1,32 @@ +error[E0308]: mismatched types + --> $DIR/diverging-tuple-parts-39485.rs:8:5 + | +LL | &panic!() + | ^^^^^^^^^ expected `()`, found reference + | + = note: expected unit type `()` + found reference `&_` +help: a return type might be missing here + | +LL | fn g() -> _ { + | ++++ +help: consider removing the borrow + | +LL - &panic!() +LL + panic!() + | + +error[E0308]: mismatched types + --> $DIR/diverging-tuple-parts-39485.rs:12:5 + | +LL | fn f() -> isize { + | ----- expected `isize` because of return type +LL | (return 1, return 2) + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple + | + = note: expected type `isize` + found tuple `(!, !)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/never_type/expr-empty-ret.rs b/src/test/ui/never_type/expr-empty-ret.rs new file mode 100644 index 000000000..ce8ffaf94 --- /dev/null +++ b/src/test/ui/never_type/expr-empty-ret.rs @@ -0,0 +1,15 @@ +// run-pass + +#![allow(dead_code)] +// Issue #521 + +// pretty-expanded FIXME #23616 + +fn f() { + let _x = match true { + true => { 10 } + false => { return } + }; +} + +pub fn main() { } diff --git a/src/test/ui/never_type/fallback-closure-ret.rs b/src/test/ui/never_type/fallback-closure-ret.rs new file mode 100644 index 000000000..5c8ce48cb --- /dev/null +++ b/src/test/ui/never_type/fallback-closure-ret.rs @@ -0,0 +1,23 @@ +// This test verifies that never type fallback preserves the following code in a +// compiling state. This pattern is fairly common in the wild, notably seen in +// wasmtime v0.16. Typically this is some closure wrapper that expects a +// collection of 'known' signatures, and -> ! is not included in that set. +// +// This test is specifically targeted by the unit type fallback when +// encountering a set of obligations like `?T: Foo` and `Trait::Projection = +// ?T`. In the code below, these are `R: Bar` and `Fn::Output = R`. +// +// revisions: nofallback fallback +// check-pass + +#![cfg_attr(fallback, feature(never_type_fallback))] + +trait Bar { } +impl Bar for () { } +impl Bar for u32 { } + +fn foo<R: Bar>(_: impl Fn() -> R) {} + +fn main() { + foo(|| panic!()); +} diff --git a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr new file mode 100644 index 000000000..2acf44432 --- /dev/null +++ b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -0,0 +1,17 @@ +error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()` + --> $DIR/fallback-closure-wrap.rs:18:31 + | +LL | let error = Closure::wrap(Box::new(move || { + | _______________________________^ +LL | | +LL | | panic!("Can't connect to server."); +LL | | }) as Box<dyn FnMut()>); + | |______^ expected `()`, found `!` + | + = note: expected unit type `()` + found type `!` + = note: required for the cast from `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to the object type `dyn FnMut()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/never_type/fallback-closure-wrap.rs b/src/test/ui/never_type/fallback-closure-wrap.rs new file mode 100644 index 000000000..af0577ac0 --- /dev/null +++ b/src/test/ui/never_type/fallback-closure-wrap.rs @@ -0,0 +1,30 @@ +// This is a minified example from Crater breakage observed when attempting to +// stabilize never type, nstoddard/webgl-gui @ 22f0169f. +// +// This particular test case currently fails as the inference to `()` rather +// than `!` happens as a result of an `as` cast, which is not currently tracked. +// Crater did not find many cases of this occuring, but it is included for +// awareness. +// +// revisions: nofallback fallback +//[nofallback] check-pass +//[fallback] check-fail + +#![cfg_attr(fallback, feature(never_type_fallback))] + +use std::marker::PhantomData; + +fn main() { + let error = Closure::wrap(Box::new(move || { + //[fallback]~^ ERROR type mismatch resolving + panic!("Can't connect to server."); + }) as Box<dyn FnMut()>); +} + +struct Closure<T: ?Sized>(PhantomData<T>); + +impl<T: ?Sized> Closure<T> { + fn wrap(data: Box<T>) -> Closure<T> { + todo!() + } +} diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.rs b/src/test/ui/never_type/feature-gate-never_type_fallback.rs new file mode 100644 index 000000000..7d0208411 --- /dev/null +++ b/src/test/ui/never_type/feature-gate-never_type_fallback.rs @@ -0,0 +1,13 @@ +// This is a feature gate test for `never_type_fallback`. +// It works by using a scenario where the type fall backs to `()` rather than ยด!` +// in the case where `#![feature(never_type_fallback)]` would change it to `!`. + +fn main() {} + +trait T {} + +fn should_ret_unit() { + foo(panic!()) //~ ERROR +} + +fn foo(_: impl T) {} diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr new file mode 100644 index 000000000..54abed383 --- /dev/null +++ b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): T` is not satisfied + --> $DIR/feature-gate-never_type_fallback.rs:10:5 + | +LL | foo(panic!()) + | ^^^ the trait `T` is not implemented for `()` + | +note: required by a bound in `foo` + --> $DIR/feature-gate-never_type_fallback.rs:13:16 + | +LL | fn foo(_: impl T) {} + | ^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/impl-for-never.rs b/src/test/ui/never_type/impl-for-never.rs new file mode 100644 index 000000000..9423f0885 --- /dev/null +++ b/src/test/ui/never_type/impl-for-never.rs @@ -0,0 +1,27 @@ +// run-pass + +#![feature(never_type)] + +// Test that we can call static methods on ! both directly and when it appears in a generic + +trait StringifyType { + fn stringify_type() -> &'static str; +} + +impl StringifyType for ! { + fn stringify_type() -> &'static str { + "!" + } +} + +fn maybe_stringify<T: StringifyType>(opt: Option<T>) -> &'static str { + match opt { + Some(_) => T::stringify_type(), + None => "none", + } +} + +fn main() { + println!("! is {}", <!>::stringify_type()); + println!("None is {}", maybe_stringify(None::<!>)); +} diff --git a/src/test/ui/never_type/impl_trait_fallback.rs b/src/test/ui/never_type/impl_trait_fallback.rs new file mode 100644 index 000000000..cc9520c1b --- /dev/null +++ b/src/test/ui/never_type/impl_trait_fallback.rs @@ -0,0 +1,10 @@ +// check-pass + +fn main() {} + +trait T {} +impl T for () {} + +fn should_ret_unit() -> impl T { + panic!() +} diff --git a/src/test/ui/never_type/impl_trait_fallback2.rs b/src/test/ui/never_type/impl_trait_fallback2.rs new file mode 100644 index 000000000..12c187b9e --- /dev/null +++ b/src/test/ui/never_type/impl_trait_fallback2.rs @@ -0,0 +1,22 @@ +#![feature(type_alias_impl_trait)] + +fn main() {} + +trait T {} +impl T for i32 {} + +fn should_ret_unit() -> impl T { + //~^ ERROR `(): T` is not satisfied + panic!() +} + +type Foo = impl T; + +fn a() -> Foo { + //~^ ERROR `(): T` is not satisfied + panic!() +} + +fn b() -> Foo { + 42 +} diff --git a/src/test/ui/never_type/impl_trait_fallback2.stderr b/src/test/ui/never_type/impl_trait_fallback2.stderr new file mode 100644 index 000000000..78cc83bdb --- /dev/null +++ b/src/test/ui/never_type/impl_trait_fallback2.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `(): T` is not satisfied + --> $DIR/impl_trait_fallback2.rs:8:25 + | +LL | fn should_ret_unit() -> impl T { + | ^^^^^^ the trait `T` is not implemented for `()` + | + = help: the trait `T` is implemented for `i32` + +error[E0277]: the trait bound `(): T` is not satisfied + --> $DIR/impl_trait_fallback2.rs:15:11 + | +LL | fn a() -> Foo { + | ^^^ the trait `T` is not implemented for `()` + | + = help: the trait `T` is implemented for `i32` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/impl_trait_fallback3.rs b/src/test/ui/never_type/impl_trait_fallback3.rs new file mode 100644 index 000000000..ed645b823 --- /dev/null +++ b/src/test/ui/never_type/impl_trait_fallback3.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +fn main() {} + +trait T { + type Assoc; +} + +type Foo = impl T; + +fn a() -> Foo { + //~^ ERROR the trait bound `(): T` is not satisfied + // This is not a defining use, it doesn't actually constrain the opaque type. + panic!() +} diff --git a/src/test/ui/never_type/impl_trait_fallback3.stderr b/src/test/ui/never_type/impl_trait_fallback3.stderr new file mode 100644 index 000000000..5d5d216fb --- /dev/null +++ b/src/test/ui/never_type/impl_trait_fallback3.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): T` is not satisfied + --> $DIR/impl_trait_fallback3.rs:11:11 + | +LL | fn a() -> Foo { + | ^^^ the trait `T` is not implemented for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/impl_trait_fallback4.rs b/src/test/ui/never_type/impl_trait_fallback4.rs new file mode 100644 index 000000000..fe62773fa --- /dev/null +++ b/src/test/ui/never_type/impl_trait_fallback4.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] + +trait T { + type Assoc: Cake; +} + +trait Cake: std::fmt::Display { + fn cake() -> Self; +} + +type Foo = impl T; + +fn foo() -> impl T { + //~^ ERROR `(): T` is not satisfied + panic!() +} + +fn a() -> Foo { + foo() +} + +fn main() { + println!("{}", <Foo as T>::Assoc::cake()); +} diff --git a/src/test/ui/never_type/impl_trait_fallback4.stderr b/src/test/ui/never_type/impl_trait_fallback4.stderr new file mode 100644 index 000000000..f2e216e90 --- /dev/null +++ b/src/test/ui/never_type/impl_trait_fallback4.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): T` is not satisfied + --> $DIR/impl_trait_fallback4.rs:13:13 + | +LL | fn foo() -> impl T { + | ^^^^^^ the trait `T` is not implemented for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/issue-10176.rs b/src/test/ui/never_type/issue-10176.rs new file mode 100644 index 000000000..6277aa05e --- /dev/null +++ b/src/test/ui/never_type/issue-10176.rs @@ -0,0 +1,9 @@ +fn f() -> isize { + (return 1, return 2) +//~^ ERROR mismatched types +//~| expected type `isize` +//~| found tuple `(!, !)` +//~| expected `isize`, found tuple +} + +fn main() {} diff --git a/src/test/ui/never_type/issue-10176.stderr b/src/test/ui/never_type/issue-10176.stderr new file mode 100644 index 000000000..cd5361ffa --- /dev/null +++ b/src/test/ui/never_type/issue-10176.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-10176.rs:2:5 + | +LL | fn f() -> isize { + | ----- expected `isize` because of return type +LL | (return 1, return 2) + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple + | + = note: expected type `isize` + found tuple `(!, !)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/never_type/issue-13352.rs b/src/test/ui/never_type/issue-13352.rs new file mode 100644 index 000000000..9c884a33c --- /dev/null +++ b/src/test/ui/never_type/issue-13352.rs @@ -0,0 +1,9 @@ +fn foo(_: Box<dyn FnMut()>) {} + +fn main() { + foo(loop { + std::process::exit(0); + }); + 2_usize + (loop {}); + //~^ ERROR E0277 +} diff --git a/src/test/ui/never_type/issue-13352.stderr b/src/test/ui/never_type/issue-13352.stderr new file mode 100644 index 000000000..fed780e68 --- /dev/null +++ b/src/test/ui/never_type/issue-13352.stderr @@ -0,0 +1,21 @@ +error[E0277]: cannot add `()` to `usize` + --> $DIR/issue-13352.rs:7:13 + | +LL | 2_usize + (loop {}); + | ^ no implementation for `usize + ()` + | + = help: the trait `Add<()>` is not implemented for `usize` + = help: the following other types implement trait `Add<Rhs>`: + <&'a f32 as Add<f32>> + <&'a f64 as Add<f64>> + <&'a i128 as Add<i128>> + <&'a i16 as Add<i16>> + <&'a i32 as Add<i32>> + <&'a i64 as Add<i64>> + <&'a i8 as Add<i8>> + <&'a isize as Add<isize>> + and 48 others + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/issue-2149.rs b/src/test/ui/never_type/issue-2149.rs new file mode 100644 index 000000000..d6426d2cf --- /dev/null +++ b/src/test/ui/never_type/issue-2149.rs @@ -0,0 +1,15 @@ +trait VecMonad<A> { + fn bind<B, F>(&self, f: F) where F: FnMut(A) -> Vec<B>; +} + +impl<A> VecMonad<A> for Vec<A> { + fn bind<B, F>(&self, mut f: F) where F: FnMut(A) -> Vec<B> { + let mut r = panic!(); + for elt in self { r = r + f(*elt); } + //~^ ERROR E0277 + } +} +fn main() { + ["hi"].bind(|x| [x] ); + //~^ ERROR no method named `bind` found +} diff --git a/src/test/ui/never_type/issue-2149.stderr b/src/test/ui/never_type/issue-2149.stderr new file mode 100644 index 000000000..58fe2edb1 --- /dev/null +++ b/src/test/ui/never_type/issue-2149.stderr @@ -0,0 +1,25 @@ +error[E0277]: cannot add `Vec<B>` to `()` + --> $DIR/issue-2149.rs:8:33 + | +LL | for elt in self { r = r + f(*elt); } + | ^ no implementation for `() + Vec<B>` + | + = help: the trait `Add<Vec<B>>` is not implemented for `()` + +error[E0599]: no method named `bind` found for array `[&str; 1]` in the current scope + --> $DIR/issue-2149.rs:13:12 + | +LL | ["hi"].bind(|x| [x] ); + | ^^^^ method not found in `[&str; 1]` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `VecMonad` defines an item `bind`, perhaps you need to implement it + --> $DIR/issue-2149.rs:1:1 + | +LL | trait VecMonad<A> { + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/issue-44402.rs b/src/test/ui/never_type/issue-44402.rs new file mode 100644 index 000000000..699e480df --- /dev/null +++ b/src/test/ui/never_type/issue-44402.rs @@ -0,0 +1,33 @@ +// check-pass + +#![allow(dead_code)] +#![feature(never_type)] +#![feature(exhaustive_patterns)] + +// Regression test for inhabitedness check. The old +// cache used to cause us to incorrectly decide +// that `test_b` was invalid. + +struct Foo { + field1: !, + field2: Option<&'static Bar>, +} + +struct Bar { + field1: &'static Foo +} + +fn test_a() { + let x: Option<Foo> = None; + match x { None => () } +} + +fn test_b() { + let x: Option<Bar> = None; + match x { + Some(_) => (), + None => () + } +} + +fn main() { } diff --git a/src/test/ui/never_type/issue-51506.rs b/src/test/ui/never_type/issue-51506.rs new file mode 100644 index 000000000..d0fe6a0f5 --- /dev/null +++ b/src/test/ui/never_type/issue-51506.rs @@ -0,0 +1,41 @@ +#![feature(never_type, specialization)] +#![allow(incomplete_features)] + +use std::iter::{self, Empty}; + +trait Trait { + type Out: Iterator<Item = u32>; + + fn f(&self) -> Option<Self::Out>; +} + +impl<T> Trait for T { + default type Out = !; //~ ERROR: `!` is not an iterator + + default fn f(&self) -> Option<Self::Out> { + None + } +} + +struct X; + +impl Trait for X { + type Out = Empty<u32>; + + fn f(&self) -> Option<Self::Out> { + Some(iter::empty()) + } +} + +fn f<T: Trait>(a: T) { + if let Some(iter) = a.f() { + println!("Some"); + for x in iter { + println!("x = {}", x); + } + } +} + +pub fn main() { + f(10); +} diff --git a/src/test/ui/never_type/issue-51506.stderr b/src/test/ui/never_type/issue-51506.stderr new file mode 100644 index 000000000..293ec3a72 --- /dev/null +++ b/src/test/ui/never_type/issue-51506.stderr @@ -0,0 +1,16 @@ +error[E0277]: `!` is not an iterator + --> $DIR/issue-51506.rs:13:24 + | +LL | default type Out = !; + | ^ `!` is not an iterator + | + = help: the trait `Iterator` is not implemented for `!` +note: required by a bound in `Trait::Out` + --> $DIR/issue-51506.rs:7:15 + | +LL | type Out: Iterator<Item = u32>; + | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::Out` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/issue-52443.rs b/src/test/ui/never_type/issue-52443.rs new file mode 100644 index 000000000..cebcca944 --- /dev/null +++ b/src/test/ui/never_type/issue-52443.rs @@ -0,0 +1,14 @@ +fn main() { + [(); & { loop { continue } } ]; //~ ERROR mismatched types + + [(); loop { break }]; //~ ERROR mismatched types + + [(); {while true {break}; 0}]; + //~^ WARN denote infinite loops with + + [(); { for _ in 0usize.. {}; 0}]; + //~^ ERROR `for` is not allowed in a `const` + //~| ERROR cannot convert + //~| ERROR mutable references are not allowed in constants + //~| ERROR cannot call non-const fn +} diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr new file mode 100644 index 000000000..3c0daa4c5 --- /dev/null +++ b/src/test/ui/never_type/issue-52443.stderr @@ -0,0 +1,74 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/issue-52443.rs:6:11 + | +LL | [(); {while true {break}; 0}]; + | ^^^^^^^^^^ help: use `loop` + | + = note: `#[warn(while_true)]` on by default + +error[E0658]: `for` is not allowed in a `const` + --> $DIR/issue-52443.rs:9:12 + | +LL | [(); { for _ in 0usize.. {}; 0}]; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information + = help: add `#![feature(const_for)]` to the crate attributes to enable + +error[E0308]: mismatched types + --> $DIR/issue-52443.rs:2:10 + | +LL | [(); & { loop { continue } } ]; + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference + | + = note: expected type `usize` + found reference `&_` +help: consider removing the borrow + | +LL - [(); & { loop { continue } } ]; +LL + [(); { loop { continue } } ]; + | + +error[E0308]: mismatched types + --> $DIR/issue-52443.rs:4:17 + | +LL | [(); loop { break }]; + | ^^^^^ + | | + | expected `usize`, found `()` + | help: give it a value of the expected type: `break 42` + +error[E0015]: cannot convert `RangeFrom<usize>` into an iterator in constants + --> $DIR/issue-52443.rs:9:21 + | +LL | [(); { for _ in 0usize.. {}; 0}]; + | ^^^^^^^^ + | +note: impl defined here, but it is not `const` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | impl<I: ~const Iterator> const IntoIterator for I { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error[E0658]: mutable references are not allowed in constants + --> $DIR/issue-52443.rs:9:21 + | +LL | [(); { for _ in 0usize.. {}; 0}]; + | ^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants + --> $DIR/issue-52443.rs:9:21 + | +LL | [(); { for _ in 0usize.. {}; 0}]; + | ^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 6 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0015, E0308, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/never_type/issue-96335.rs b/src/test/ui/never_type/issue-96335.rs new file mode 100644 index 000000000..411a7c9df --- /dev/null +++ b/src/test/ui/never_type/issue-96335.rs @@ -0,0 +1,5 @@ +fn main() { + 0.....{loop{}1}; + //~^ ERROR unexpected token + //~| ERROR mismatched types +} diff --git a/src/test/ui/never_type/issue-96335.stderr b/src/test/ui/never_type/issue-96335.stderr new file mode 100644 index 000000000..168cf2f83 --- /dev/null +++ b/src/test/ui/never_type/issue-96335.stderr @@ -0,0 +1,35 @@ +error: unexpected token: `...` + --> $DIR/issue-96335.rs:2:6 + | +LL | 0.....{loop{}1}; + | ^^^ + | +help: use `..` for an exclusive range + | +LL | 0....{loop{}1}; + | ~~ +help: or `..=` for an inclusive range + | +LL | 0..=..{loop{}1}; + | ~~~ + +error[E0308]: mismatched types + --> $DIR/issue-96335.rs:2:9 + | +LL | 0.....{loop{}1}; + | ----^^^^^^^^^^^ + | | | + | | expected integer, found struct `RangeTo` + | arguments to this function are incorrect + | + = note: expected type `{integer}` + found struct `RangeTo<{integer}>` +note: associated function defined here + --> $SRC_DIR/core/src/ops/range.rs:LL:COL + | +LL | pub const fn new(start: Idx, end: Idx) -> Self { + | ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/never_type/never-assign-dead-code.rs b/src/test/ui/never_type/never-assign-dead-code.rs new file mode 100644 index 000000000..7bb7c8709 --- /dev/null +++ b/src/test/ui/never_type/never-assign-dead-code.rs @@ -0,0 +1,12 @@ +// Test that an assignment of type ! makes the rest of the block dead code. + +// check-pass + +#![feature(never_type)] +#![warn(unused)] + +fn main() { + let x: ! = panic!("aah"); //~ WARN unused + drop(x); //~ WARN unreachable + //~^ WARN unreachable +} diff --git a/src/test/ui/never_type/never-assign-dead-code.stderr b/src/test/ui/never_type/never-assign-dead-code.stderr new file mode 100644 index 000000000..521b82023 --- /dev/null +++ b/src/test/ui/never_type/never-assign-dead-code.stderr @@ -0,0 +1,33 @@ +warning: unreachable statement + --> $DIR/never-assign-dead-code.rs:10:5 + | +LL | let x: ! = panic!("aah"); + | ------------- any code following this expression is unreachable +LL | drop(x); + | ^^^^^^^^ unreachable statement + | +note: the lint level is defined here + --> $DIR/never-assign-dead-code.rs:6:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]` + +warning: unreachable call + --> $DIR/never-assign-dead-code.rs:10:5 + | +LL | drop(x); + | ^^^^ - any code following this expression is unreachable + | | + | unreachable call + +warning: unused variable: `x` + --> $DIR/never-assign-dead-code.rs:9:9 + | +LL | let x: ! = panic!("aah"); + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: 3 warnings emitted + diff --git a/src/test/ui/never_type/never-assign-wrong-type.rs b/src/test/ui/never_type/never-assign-wrong-type.rs new file mode 100644 index 000000000..67e26f566 --- /dev/null +++ b/src/test/ui/never_type/never-assign-wrong-type.rs @@ -0,0 +1,8 @@ +// Test that we can't use another type in place of ! + +#![feature(never_type)] +#![deny(warnings)] + +fn main() { + let x: ! = "hello"; //~ ERROR mismatched types +} diff --git a/src/test/ui/never_type/never-assign-wrong-type.stderr b/src/test/ui/never_type/never-assign-wrong-type.stderr new file mode 100644 index 000000000..ce34d9483 --- /dev/null +++ b/src/test/ui/never_type/never-assign-wrong-type.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/never-assign-wrong-type.rs:7:16 + | +LL | let x: ! = "hello"; + | - ^^^^^^^ expected `!`, found `&str` + | | + | expected due to this + | + = note: expected type `!` + found reference `&'static str` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/never_type/never-associated-type.rs b/src/test/ui/never_type/never-associated-type.rs new file mode 100644 index 000000000..3bb917c93 --- /dev/null +++ b/src/test/ui/never_type/never-associated-type.rs @@ -0,0 +1,23 @@ +// Test that we can use ! as an associated type. + +// check-pass + +#![feature(never_type)] + +trait Foo { + type Wow; + + fn smeg(&self) -> Self::Wow; +} + +struct Blah; +impl Foo for Blah { + type Wow = !; + fn smeg(&self) -> ! { + panic!("kapow!"); + } +} + +fn main() { + Blah.smeg(); +} diff --git a/src/test/ui/never_type/never-from-impl-is-reserved.rs b/src/test/ui/never_type/never-from-impl-is-reserved.rs new file mode 100644 index 000000000..9d16015bd --- /dev/null +++ b/src/test/ui/never_type/never-from-impl-is-reserved.rs @@ -0,0 +1,12 @@ +// check that the `for<T> T: From<!>` impl is reserved + +#![feature(never_type)] + +pub struct MyFoo; +pub trait MyTrait {} + +impl MyTrait for MyFoo {} +// This will conflict with the first impl if we impl `for<T> T: From<!>`. +impl<T> MyTrait for T where T: From<!> {} //~ ERROR conflicting implementation + +fn main() {} diff --git a/src/test/ui/never_type/never-from-impl-is-reserved.stderr b/src/test/ui/never_type/never-from-impl-is-reserved.stderr new file mode 100644 index 000000000..f9f7c787e --- /dev/null +++ b/src/test/ui/never_type/never-from-impl-is-reserved.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo` + --> $DIR/never-from-impl-is-reserved.rs:10:1 + | +LL | impl MyTrait for MyFoo {} + | ---------------------- first implementation here +LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`. +LL | impl<T> MyTrait for T where T: From<!> {} + | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo` + | + = note: permitting this impl would forbid us from adding `impl<T> From<!> for T` later; see rust-lang/rust#64715 for details + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/never_type/never-result.rs b/src/test/ui/never_type/never-result.rs new file mode 100644 index 000000000..35af37910 --- /dev/null +++ b/src/test/ui/never_type/never-result.rs @@ -0,0 +1,21 @@ +// run-pass + +#![allow(unused_variables)] +#![allow(unreachable_code)] + +// Test that we can extract a ! through pattern matching then use it as several different types. + +#![feature(never_type)] + +fn main() { + let x: Result<u32, !> = Ok(123); + match x { + Ok(z) => (), + Err(y) => { + let q: u32 = y; + let w: i32 = y; + let e: String = y; + y + }, + } +} diff --git a/src/test/ui/never_type/never-type-arg.rs b/src/test/ui/never_type/never-type-arg.rs new file mode 100644 index 000000000..13cd59e6a --- /dev/null +++ b/src/test/ui/never_type/never-type-arg.rs @@ -0,0 +1,17 @@ +// Test that we can use ! as an argument to a trait impl. + +// check-pass + +#![feature(never_type)] + +struct Wub; + +impl PartialEq<!> for Wub { + fn eq(&self, other: &!) -> bool { + *other + } +} + +fn main() { + let _ = Wub == panic!("oh no!"); +} diff --git a/src/test/ui/never_type/never-type-rvalues.rs b/src/test/ui/never_type/never-type-rvalues.rs new file mode 100644 index 000000000..9ccc73dbf --- /dev/null +++ b/src/test/ui/never_type/never-type-rvalues.rs @@ -0,0 +1,38 @@ +// run-pass + +#![feature(never_type)] +#![allow(dead_code)] +#![allow(path_statements)] +#![allow(unreachable_patterns)] + +fn never_direct(x: !) { + x; +} + +fn never_ref_pat(ref x: !) { + *x; +} + +fn never_ref(x: &!) { + let &y = x; + y; +} + +fn never_pointer(x: *const !) { + unsafe { + *x; + } +} + +fn never_slice(x: &[!]) { + x[0]; +} + +fn never_match(x: Result<(), !>) { + match x { + Ok(_) => {}, + Err(_) => {}, + } +} + +pub fn main() { } diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr b/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr new file mode 100644 index 000000000..e20455913 --- /dev/null +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `E: From<()>` is not satisfied + --> $DIR/never-value-fallback-issue-66757.rs:28:5 + | +LL | <E as From<_>>::from(never); + | ^^^^^^^^^^^^^^^^^^^^ the trait `From<()>` is not implemented for `E` + | + = help: the trait `From<!>` is implemented for `E` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.rs b/src/test/ui/never_type/never-value-fallback-issue-66757.rs new file mode 100644 index 000000000..fc6fe6eb5 --- /dev/null +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.rs @@ -0,0 +1,31 @@ +// Regression test for #66757 +// +// Test than when you have a `!` value (e.g., the local variable +// never) and an uninferred variable (here the argument to `From`) it +// doesn't fallback to `()` but rather `!`. +// +// revisions: nofallback fallback +//[fallback] run-pass +//[nofallback] check-fail + +#![feature(never_type)] + +#![cfg_attr(fallback, feature(never_type_fallback))] + +struct E; + +impl From<!> for E { + fn from(_: !) -> E { + E + } +} + +#[allow(unreachable_code)] +#[allow(dead_code)] +#[allow(unused_must_use)] +fn foo(never: !) { + <E as From<!>>::from(never); // Ok + <E as From<_>>::from(never); //[nofallback]~ ERROR trait bound `E: From<()>` is not satisfied +} + +fn main() { } diff --git a/src/test/ui/never_type/never_coercions.rs b/src/test/ui/never_type/never_coercions.rs new file mode 100644 index 000000000..105c38635 --- /dev/null +++ b/src/test/ui/never_type/never_coercions.rs @@ -0,0 +1,12 @@ +// run-pass +// Test that having something of type ! doesn't screw up type-checking and that it coerces to the +// LUB type of the other match arms. + +fn main() { + let v: Vec<u32> = Vec::new(); + match 0u32 { + 0 => &v, + 1 => return, + _ => &v[..], + }; +} diff --git a/src/test/ui/never_type/never_transmute_never.rs b/src/test/ui/never_type/never_transmute_never.rs new file mode 100644 index 000000000..fce3ced9a --- /dev/null +++ b/src/test/ui/never_type/never_transmute_never.rs @@ -0,0 +1,23 @@ +// check-pass + +#![crate_type="lib"] + +#![feature(never_type)] +#![allow(dead_code)] +#![allow(unreachable_code)] +#![allow(unused_variables)] + +struct Foo; + +pub fn f(x: !) -> ! { + x +} + +pub fn ub() { + // This is completely undefined behaviour, + // but we still want to make sure it compiles. + let x: ! = unsafe { + std::mem::transmute::<Foo, !>(Foo) + }; + f(x) +} diff --git a/src/test/ui/never_type/return-never-coerce.rs b/src/test/ui/never_type/return-never-coerce.rs new file mode 100644 index 000000000..d615940ef --- /dev/null +++ b/src/test/ui/never_type/return-never-coerce.rs @@ -0,0 +1,18 @@ +// Test that ! coerces to other types. + +// run-fail +// error-pattern:aah! +// ignore-emscripten no processes + +fn call_another_fn<T, F: FnOnce() -> T>(f: F) -> T { + f() +} + +fn wub() -> ! { + panic!("aah!"); +} + +fn main() { + let x: i32 = call_another_fn(wub); + let y: u32 = wub(); +} diff --git a/src/test/ui/never_type/try_from.rs b/src/test/ui/never_type/try_from.rs new file mode 100644 index 000000000..50451576f --- /dev/null +++ b/src/test/ui/never_type/try_from.rs @@ -0,0 +1,37 @@ +// run-pass +// This test relies on `TryFrom` being blanket impl for all `T: Into` +// and `TryInto` being blanket impl for all `U: TryFrom` + +// This test was added to show the motivation for doing this +// over `TryFrom` being blanket impl for all `T: From` + +#![feature(never_type)] + +use std::convert::{TryInto, Infallible}; + +struct Foo<T> { + t: T, +} + +// This fails to compile due to coherence restrictions +// as of Rust version 1.32.x, therefore it could not be used +// instead of the `Into` version of the impl, and serves as +// motivation for a blanket impl for all `T: Into`, instead +// of a blanket impl for all `T: From` +/* +impl<T> From<Foo<T>> for Box<T> { + fn from(foo: Foo<T>) -> Box<T> { + Box::new(foo.t) + } +} +*/ + +impl<T> Into<Vec<T>> for Foo<T> { + fn into(self) -> Vec<T> { + vec![self.t] + } +} + +pub fn main() { + let _: Result<Vec<i32>, Infallible> = Foo { t: 10 }.try_into(); +} |