diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 181783441f3ff..a0b3df717672f 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -424,9 +424,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_extern(bare_fn_ty.ext); } - ast::TyKind::Never => { - gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); - } _ => {} } visit::walk_ty(self, ty) diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 4a8375afac3ce..97a3392d66dc3 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,14 +1,11 @@ -#![feature( - no_core, start, lang_items, box_syntax, never_type, linkage, - extern_types, thread_local -)] +#![feature(no_core, start, lang_items, box_syntax, linkage, extern_types, thread_local)] #![no_core] #![allow(dead_code, non_camel_case_types)] extern crate mini_core; -use mini_core::*; use mini_core::libc::*; +use mini_core::*; unsafe extern "C" fn my_puts(s: *const i8) { puts(s); @@ -74,15 +71,17 @@ enum Ordering { } #[lang = "start"] -fn start( - main: fn() -> T, - argc: isize, - argv: *const *const u8, -) -> isize { +fn start(main: fn() -> T, argc: isize, argv: *const *const u8) -> isize { if argc == 3 { - unsafe { puts(*argv as *const i8); } - unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const i8)); } - unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); } + unsafe { + puts(*argv as *const i8); + } + unsafe { + puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const i8)); + } + unsafe { + puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); + } } main().report(); @@ -95,7 +94,7 @@ static NUM_REF: &'static u8 = unsafe { &NUM }; macro_rules! assert { ($e:expr) => { if !$e { - panic(stringify!(! $e)); + panic(stringify!(!$e)); } }; } @@ -105,7 +104,7 @@ macro_rules! assert_eq { if $l != $r { panic(stringify!($l != $r)); } - } + }; } struct Unique { @@ -133,10 +132,7 @@ fn call_return_u128_pair() { } fn main() { - take_unique(Unique { - pointer: 0 as *const (), - _marker: PhantomData, - }); + take_unique(Unique { pointer: 0 as *const (), _marker: PhantomData }); take_f32(0.1); call_return_u128_pair(); @@ -179,15 +175,15 @@ fn main() { assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); assert_eq!(intrinsics::min_align_of::() as u8, 2); - assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8); + assert_eq!( + intrinsics::min_align_of_val(&a) as u8, + intrinsics::min_align_of::<&str>() as u8 + ); assert!(!intrinsics::needs_drop::()); assert!(intrinsics::needs_drop::()); - Unique { - pointer: 0 as *const &str, - _marker: PhantomData, - } as Unique; + Unique { pointer: 0 as *const &str, _marker: PhantomData } as Unique; struct MyDst(T); @@ -213,19 +209,17 @@ fn main() { } } - let _ = box NoisyDrop { - text: "Boxed outer got dropped!\0", - inner: NoisyDropInner, - } as Box; + let _ = box NoisyDrop { text: "Boxed outer got dropped!\0", inner: NoisyDropInner } + as Box; const FUNC_REF: Option = Some(main); match FUNC_REF { - Some(_) => {}, + Some(_) => {} None => assert!(false), } match Ordering::Less { - Ordering::Less => {}, + Ordering::Less => {} _ => assert!(false), } @@ -241,19 +235,21 @@ fn main() { #[cfg(not(jit))] { - extern { + extern "C" { #[linkage = "extern_weak"] static ABC: *const u8; } { - extern { + extern "C" { #[linkage = "extern_weak"] static ABC: *const u8; } } - unsafe { assert_eq!(ABC as usize, 0); } + unsafe { + assert_eq!(ABC as usize, 0); + } } &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>; @@ -337,13 +333,10 @@ extern "C" { native: *mut pthread_t, attr: *const pthread_attr_t, f: extern "C" fn(_: *mut c_void) -> *mut c_void, - value: *mut c_void + value: *mut c_void, ) -> c_int; - fn pthread_join( - native: pthread_t, - value: *mut *mut c_void - ) -> c_int; + fn pthread_join(native: pthread_t, value: *mut *mut c_void) -> c_int; } #[thread_local] @@ -352,7 +345,9 @@ static mut TLS: u8 = 42; #[cfg(not(jit))] extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void { - unsafe { TLS = 0; } + unsafe { + TLS = 0; + } 0 as *mut c_void } @@ -402,44 +397,267 @@ pub enum E1 { pub enum E2 { V1 { f: bool }, - /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X), - _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X), - _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X), - _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X), - _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X), - _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X), - _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X), - _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X), - _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X), - _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X), - _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X), - _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X), - _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X), - _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X), - _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X), - _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X), - _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X), - _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X), - _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X), - _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X), - _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X), - _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X), - _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X), - _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X), - _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X), - _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X), - _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X), - _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X), - _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X), - _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X), - _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X), - _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X), + /*_00*/ _01(X), + _02(X), + _03(X), + _04(X), + _05(X), + _06(X), + _07(X), + _08(X), + _09(X), + _0A(X), + _0B(X), + _0C(X), + _0D(X), + _0E(X), + _0F(X), + _10(X), + _11(X), + _12(X), + _13(X), + _14(X), + _15(X), + _16(X), + _17(X), + _18(X), + _19(X), + _1A(X), + _1B(X), + _1C(X), + _1D(X), + _1E(X), + _1F(X), + _20(X), + _21(X), + _22(X), + _23(X), + _24(X), + _25(X), + _26(X), + _27(X), + _28(X), + _29(X), + _2A(X), + _2B(X), + _2C(X), + _2D(X), + _2E(X), + _2F(X), + _30(X), + _31(X), + _32(X), + _33(X), + _34(X), + _35(X), + _36(X), + _37(X), + _38(X), + _39(X), + _3A(X), + _3B(X), + _3C(X), + _3D(X), + _3E(X), + _3F(X), + _40(X), + _41(X), + _42(X), + _43(X), + _44(X), + _45(X), + _46(X), + _47(X), + _48(X), + _49(X), + _4A(X), + _4B(X), + _4C(X), + _4D(X), + _4E(X), + _4F(X), + _50(X), + _51(X), + _52(X), + _53(X), + _54(X), + _55(X), + _56(X), + _57(X), + _58(X), + _59(X), + _5A(X), + _5B(X), + _5C(X), + _5D(X), + _5E(X), + _5F(X), + _60(X), + _61(X), + _62(X), + _63(X), + _64(X), + _65(X), + _66(X), + _67(X), + _68(X), + _69(X), + _6A(X), + _6B(X), + _6C(X), + _6D(X), + _6E(X), + _6F(X), + _70(X), + _71(X), + _72(X), + _73(X), + _74(X), + _75(X), + _76(X), + _77(X), + _78(X), + _79(X), + _7A(X), + _7B(X), + _7C(X), + _7D(X), + _7E(X), + _7F(X), + _80(X), + _81(X), + _82(X), + _83(X), + _84(X), + _85(X), + _86(X), + _87(X), + _88(X), + _89(X), + _8A(X), + _8B(X), + _8C(X), + _8D(X), + _8E(X), + _8F(X), + _90(X), + _91(X), + _92(X), + _93(X), + _94(X), + _95(X), + _96(X), + _97(X), + _98(X), + _99(X), + _9A(X), + _9B(X), + _9C(X), + _9D(X), + _9E(X), + _9F(X), + _A0(X), + _A1(X), + _A2(X), + _A3(X), + _A4(X), + _A5(X), + _A6(X), + _A7(X), + _A8(X), + _A9(X), + _AA(X), + _AB(X), + _AC(X), + _AD(X), + _AE(X), + _AF(X), + _B0(X), + _B1(X), + _B2(X), + _B3(X), + _B4(X), + _B5(X), + _B6(X), + _B7(X), + _B8(X), + _B9(X), + _BA(X), + _BB(X), + _BC(X), + _BD(X), + _BE(X), + _BF(X), + _C0(X), + _C1(X), + _C2(X), + _C3(X), + _C4(X), + _C5(X), + _C6(X), + _C7(X), + _C8(X), + _C9(X), + _CA(X), + _CB(X), + _CC(X), + _CD(X), + _CE(X), + _CF(X), + _D0(X), + _D1(X), + _D2(X), + _D3(X), + _D4(X), + _D5(X), + _D6(X), + _D7(X), + _D8(X), + _D9(X), + _DA(X), + _DB(X), + _DC(X), + _DD(X), + _DE(X), + _DF(X), + _E0(X), + _E1(X), + _E2(X), + _E3(X), + _E4(X), + _E5(X), + _E6(X), + _E7(X), + _E8(X), + _E9(X), + _EA(X), + _EB(X), + _EC(X), + _ED(X), + _EE(X), + _EF(X), + _F0(X), + _F1(X), + _F2(X), + _F3(X), + _F4(X), + _F5(X), + _F6(X), + _F7(X), + _F8(X), + _F9(X), + _FA(X), + _FB(X), + _FC(X), + _FD(X), + _FE(X), + _FF(X), V3, V4, } -fn check_niche_behavior () { +fn check_niche_behavior() { if let E1::V2 { .. } = (E1::V1 { f: true }) { intrinsics::abort(); } diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 1634c5863163b..64100fe176060 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -83,8 +83,58 @@ impl DepthFirstSearch<'graph, G> where G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, { - pub fn new(graph: &'graph G, start_node: G::Node) -> Self { - Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) } + pub fn new(graph: &'graph G) -> Self { + Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } + } + + /// Version of `push_start_node` that is convenient for chained + /// use. + pub fn with_start_node(mut self, start_node: G::Node) -> Self { + self.push_start_node(start_node); + self + } + + /// Pushes another start node onto the stack. If the node + /// has not already been visited, then you will be able to + /// walk its successors (and so forth) after the current + /// contents of the stack are drained. If multiple start nodes + /// are added into the walk, then their mutual successors + /// will all be walked. You can use this method once the + /// iterator has been completely drained to add additional + /// start nodes. + pub fn push_start_node(&mut self, start_node: G::Node) { + if self.visited.insert(start_node) { + self.stack.push(start_node); + } + } + + /// Searches all nodes reachable from the current start nodes. + /// This is equivalent to just invoke `next` repeatedly until + /// you get a `None` result. + pub fn complete_search(&mut self) { + while let Some(_) = self.next() {} + } + + /// Returns true if node has been visited thus far. + /// A node is considered "visited" once it is pushed + /// onto the internal stack; it may not yet have been yielded + /// from the iterator. This method is best used after + /// the iterator is completely drained. + pub fn visited(&self, node: G::Node) -> bool { + self.visited.contains(node) + } +} + +impl std::fmt::Debug for DepthFirstSearch<'_, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut f = fmt.debug_set(); + for n in self.visited.iter() { + f.entry(&n); + } + f.finish() } } diff --git a/compiler/rustc_data_structures/src/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs index 0e038e88b221d..fbdcb01b5f453 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/tests.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/tests.rs @@ -20,3 +20,19 @@ fn is_cyclic() { assert!(!is_cyclic(&diamond_acyclic)); assert!(is_cyclic(&diamond_cyclic)); } + +#[test] +fn dfs() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); + + let result: Vec = DepthFirstSearch::new(&graph).with_start_node(0).collect(); + assert_eq!(result, vec![0, 2, 3, 1]); +} + +#[test] +fn dfs_debug() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); + let mut dfs = DepthFirstSearch::new(&graph).with_start_node(0); + while let Some(_) = dfs.next() {} + assert_eq!(format!("{{0, 1, 2, 3}}"), format!("{:?}", dfs)); +} diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index e0903e4324124..684c1abe45cb9 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -32,7 +32,7 @@ where where Self: WithNumNodes, { - iterate::DepthFirstSearch::new(self, from) + iterate::DepthFirstSearch::new(self).with_start_node(from) } } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 4401ec0a04ea5..a9106eeb94eb0 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -273,6 +273,10 @@ declare_features! ( /// Allows patterns with concurrent by-move and by-ref bindings. /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. (accepted, move_ref_pattern, "1.48.0", Some(68354), None), + /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. + (accepted, never_type, "1.49.0", Some(35121), None), + /// Allows diverging expressions to fall back to `!` rather than `()`. + (accepted, never_type_fallback, "1.49.0", Some(65992), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index a035507924794..8fc28f61d956e 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -323,9 +323,6 @@ declare_features! ( /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. - (active, never_type, "1.13.0", Some(35121), None), - /// Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", Some(51085), None), @@ -510,9 +507,6 @@ declare_features! ( /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. (active, raw_ref_op, "1.41.0", Some(64490), None), - /// Allows diverging expressions to fall back to `!` rather than `()`. - (active, never_type_fallback, "1.41.0", Some(65992), None), - /// Allows using the `#[register_attr]` attribute. (active, register_attr, "1.41.0", Some(66080), None), diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 6a1715ef81899..c6ccd2fff8389 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -639,8 +639,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { .inner .borrow_mut() .type_variables() - .new_var(self.for_universe, false, origin); + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); + + // Record that we replaced `vid` with `new_var_id` as part of a generalization + // operation. This is needed to detect cyclic types. To see why, see the + // docs in the `type_variables` module. + self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); Ok(u) } @@ -856,11 +861,12 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { let origin = *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var( - self.for_universe, - false, - origin, - ); + let new_var_id = self + .infcx + .inner + .borrow_mut() + .type_variables() + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!( "ConstInferUnifier: replacing original vid={:?} with new={:?}", diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index c292b2bdb3040..c44f7a67c3ded 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { if self.type_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. - let idx = (vid.index - self.type_vars.0.start.index) as usize; + let idx = vid.as_usize() - self.type_vars.0.start.as_usize(); let origin = self.type_vars.1[idx]; self.infcx.next_ty_var(origin) } else { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6affe0e5463df..a11ff03311a8d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin use rustc_middle::mir; use rustc_middle::mir::interpret::EvalToConstValueResult; use rustc_middle::traits::select; -use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; @@ -641,39 +641,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { t.fold_with(&mut self.freshener()) } - pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { + /// Returns the origin of the type variable identified by `vid`, or `None` + /// if this is not a type variable. + /// + /// No attempt is made to resolve `ty`. + pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option { match *ty.kind() { - ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid), - _ => false, + ty::Infer(ty::TyVar(vid)) => { + Some(*self.inner.borrow_mut().type_variables().var_origin(vid)) + } + _ => None, } } pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { freshen::TypeFreshener::new(self) } - - pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric { - use rustc_middle::ty::error::UnconstrainedNumeric::Neither; - use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - match *ty.kind() { - ty::Infer(ty::IntVar(vid)) => { - if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() { - Neither - } else { - UnconstrainedInt - } - } - ty::Infer(ty::FloatVar(vid)) => { - if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() { - Neither - } else { - UnconstrainedFloat - } - } - _ => Neither, - } - } - pub fn unsolved_variables(&self) -> Vec> { let mut inner = self.inner.borrow_mut(); let mut vars: Vec> = inner @@ -926,29 +909,61 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } + /// Processes a `Coerce` predicate from the fulfillment context. + /// This is NOT the preferred way to handle coercion, which is to + /// invoke `FnCtxt::coerce` or a similar method (see `coercion.rs`). + /// + /// This method here is actually a fallback that winds up being + /// invoked when `FnCtxt::coerce` encounters unresolved type variables + /// and records a coercion predicate. Presently, this method is equivalent + /// to `subtype_predicate` -- that is, "coercing" `a` to `b` winds up + /// actually requiring `a <: b`. This is of course a valid coercion, + /// but it's not as flexible as `FnCtxt::coerce` would be. + /// + /// (We may refactor this in the future, but there are a number of + /// practical obstacles. Among other things, `FnCtxt::coerce` presently + /// records adjustments that are required on the HIR in order to perform + /// the coercion, and we don't currently have a way to manage that.) + pub fn coerce_predicate( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: ty::PolyCoercePredicate<'tcx>, + ) -> Option> { + let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate { + a_is_expected: false, // when coercing from `a` to `b`, `b` is expected + a: p.a, + b: p.b, + }); + self.subtype_predicate(cause, param_env, subtype_predicate) + } + pub fn subtype_predicate( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, predicate: ty::PolySubtypePredicate<'tcx>, ) -> Option> { - // Subtle: it's ok to skip the binder here and resolve because - // `shallow_resolve` just ignores anything that is not a type - // variable, and because type variable's can't (at present, at - // least) capture any of the things bound by this binder. + // Check for two unresolved inference variables, in which case we can + // make no progress. This is partly a micro-optimization, but it's + // also an opportunity to "sub-unify" the variables. This isn't + // *necessary* to prevent cycles, because they would eventually be sub-unified + // anyhow during generalization, but it helps with diagnostics (we can detect + // earlier that they are sub-unified). // - // NOTE(nmatsakis): really, there is no *particular* reason to do this - // `shallow_resolve` here except as a micro-optimization. - // Naturally I could not resist. - let two_unbound_type_vars = { - let a = self.shallow_resolve(predicate.skip_binder().a); - let b = self.shallow_resolve(predicate.skip_binder().b); - a.is_ty_var() && b.is_ty_var() - }; - - if two_unbound_type_vars { - // Two unbound type variables? Can't make progress. - return None; + // Note that we can just skip the binders here because + // type variables can't (at present, at + // least) capture any of the things bound by this binder. + { + let r_a = self.shallow_resolve(predicate.skip_binder().a); + let r_b = self.shallow_resolve(predicate.skip_binder().b); + match (r_a.kind(), r_b.kind()) { + (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { + self.inner.borrow_mut().type_variables().sub(a_vid, b_vid); + return None; + } + _ => {} + } } Some(self.commit_if_ok(|_snapshot| { @@ -977,12 +992,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } - pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin) + /// Number of type variables created so far. + pub fn num_ty_vars(&self) -> usize { + self.inner.borrow_mut().type_variables().num_vars() + } + + pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(self.universe(), origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(false, origin)) + self.tcx.mk_ty_var(self.next_ty_var_id(origin)) } pub fn next_ty_var_in_universe( @@ -990,14 +1010,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables().new_var(universe, false, origin); + let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin); self.tcx.mk_ty_var(vid) } - pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(true, origin)) - } - pub fn next_const_var( &self, ty: Ty<'tcx>, @@ -1109,7 +1125,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // as the substitutions for the default, `(T, U)`. let ty_var_id = self.inner.borrow_mut().type_variables().new_var( self.universe(), - false, TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition( param.name, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 0b2847658f71e..ac04494254658 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -898,7 +898,7 @@ where // Replacing with a new variable in the universe `self.universe`, // it will be unified later with the original type variable in // the universe `_universe`. - let new_var_id = variables.new_var(self.universe, false, origin); + let new_var_id = variables.new_var(self.universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index de98cccf25689..d6af58c2b7c3e 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -21,6 +21,7 @@ pub fn explicit_outlives_bounds<'tcx>( ty::PredicateAtom::Projection(..) | ty::PredicateAtom::Trait(..) | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::WellFormed(..) | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index a676c5e65a73b..a61c472494046 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -84,7 +84,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); match (a.kind(), b.kind()) { - (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { + (&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => { // Shouldn't have any LBR here, so we can safely put // this under a binder below without fear of accidental // capture. @@ -96,7 +96,6 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { // have to record in the `type_variables` tracker that // the two variables are equal modulo subtyping, which // is important to the occurs check later on. - infcx.inner.borrow_mut().type_variables().sub(a_vid, b_vid); self.fields.obligations.push(Obligation::new( self.fields.trace.cause.clone(), self.fields.param_env, diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 35b97fff3da1f..6919a8d75c4a6 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -75,14 +75,30 @@ pub struct TypeVariableStorage<'tcx> { /// ?1 <: ?3 /// Box <: ?1 /// - /// This works because `?1` and `?3` are unified in the - /// `sub_relations` relation (not in `eq_relations`). Then when we - /// process the `Box <: ?1` constraint, we do an occurs check - /// on `Box` and find a potential cycle. + /// Without this second table, what would happen in a case like + /// this is that we would instantiate `?1` with a generalized + /// type like `Box`. We would then relate `Box <: Box` + /// and infer that `?3 <: ?6`. Next, since `?1` was instantiated, + /// we would process `?1 <: ?3`, generalize `?1 = Box` to `Box`, + /// and instantiate `?3` with `Box`. Finally, we would relate + /// `?6 <: ?9`. But now that we instantiated `?3`, we can process + /// `?3 <: ?6`, which gives us `Box <: ?6`... and the cycle + /// continues. (This is `occurs-check-2.rs`.) + /// + /// What prevents this cycle is that when we generalize + /// `Box` to `Box`, we also sub-unify `?3` and `?6` + /// (in the generalizer). When we then process `Box <: ?3`, + /// the occurs check then fails because `?6` and `?3` are sub-unified, + /// and hence generalization fails. /// /// This is reasonable because, in Rust, subtypes have the same /// "skeleton" and hence there is no possible type such that /// (e.g.) `Box <: ?3` for any `?3`. + /// + /// In practice, we sometimes sub-unify variables in other spots, such + /// as when processing subtype predicates. This is not necessary but is + /// done to aid diagnostics, as it allows us to be more effective when + /// we guide the user towards where they should insert type hints. sub_relations: ut::UnificationTableStorage, } @@ -113,13 +129,16 @@ pub enum TypeVariableOriginKind { SubstitutionPlaceholder, AutoDeref, AdjustmentType, - DivergingFn, + + /// In type check, when we are type checking a function that + /// returns `-> dyn Foo`, we substitute a type variable for the + /// return type for diagnostic purposes. + DynReturnFn, LatticeVariable, } pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, - diverging: bool, } #[derive(Copy, Clone, Debug)] @@ -171,20 +190,12 @@ impl<'tcx> TypeVariableStorage<'tcx> { } impl<'tcx> TypeVariableTable<'_, 'tcx> { - /// Returns the diverges flag given when `vid` was created. - /// - /// Note that this function does not return care whether - /// `vid` has been unified with something else or not. - pub fn var_diverges(&self, vid: ty::TyVid) -> bool { - self.storage.values.get(vid.index as usize).diverging - } - /// Returns the origin that was given when `vid` was created. /// /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.storage.values.get(vid.index as usize).origin + &self.storage.values.get(vid.as_usize()).origin } /// Records that `a == b`, depending on `dir`. @@ -240,7 +251,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { pub fn new_var( &mut self, universe: ty::UniverseIndex, - diverging: bool, origin: TypeVariableOrigin, ) -> ty::TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); @@ -248,13 +258,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { let sub_key = self.sub_relations().new_key(()); assert_eq!(eq_key.vid, sub_key); - let index = self.values().push(TypeVariableData { origin, diverging }); - assert_eq!(eq_key.vid.index, index as u32); + let index = self.values().push(TypeVariableData { origin }); + assert_eq!(eq_key.vid.as_usize(), index); - debug!( - "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", - eq_key.vid, universe, diverging, origin, - ); + debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,); eq_key.vid } @@ -337,11 +344,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { &mut self, value_count: usize, ) -> (Range, Vec) { - let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 }; + let range = TyVid::from(value_count)..TyVid::from(self.num_vars()); ( range.start..range.end, - (range.start.index..range.end.index) - .map(|index| self.storage.values.get(index as usize).origin) + (range.start.as_usize()..range.end.as_usize()) + .map(|index| self.storage.values.get(index).origin) .collect(), ) } @@ -373,7 +380,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::Other( Instantiate { vid, .. }, ))) => { - if vid.index < new_elem_threshold { + if vid.as_u32() < new_elem_threshold { // quick check to see if this variable was // created since the snapshot started or not. let mut eq_relations = ut::UnificationTable::with_log( @@ -401,7 +408,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { pub fn unsolved_variables(&mut self) -> Vec { (0..self.storage.values.len()) .filter_map(|i| { - let vid = ty::TyVid { index: i as u32 }; + let vid = ty::TyVid::from(i); match self.probe(vid) { TypeVariableValue::Unknown { .. } => Some(vid), TypeVariableValue::Known { .. } => None, @@ -453,10 +460,10 @@ impl<'tcx> From for TyVidEqKey<'tcx> { impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { type Value = TypeVariableValue<'tcx>; fn index(&self) -> u32 { - self.vid.index + self.vid.as_u32() } fn from_index(i: u32) -> Self { - TyVidEqKey::from(ty::TyVid { index: i }) + TyVidEqKey::from(ty::TyVid::from(i)) } fn tag() -> &'static str { "TyVidEqKey" diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 3690a88c0d973..d1bdd5dc1a27d 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -19,7 +19,7 @@ #![feature(const_fn)] #![feature(const_panic)] #![feature(extend_one)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(or_patterns)] #![feature(in_band_lifetimes)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index b0b0e4372b8cd..751bf3a8e8cb7 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -162,6 +162,10 @@ impl Elaborator<'tcx> { // Currently, we do not "elaborate" predicates like `X <: Y`, // though conceivably we might. } + ty::PredicateAtom::Coerce(..) => { + // Currently, we do not "elaborate" predicates like `X -> Y`, + // though conceivably we might. + } ty::PredicateAtom::Projection(..) => { // Nothing to elaborate in a projection predicate. } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c65cf65b1c777..cc1872473e693 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1568,6 +1568,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ObjectSafe(..) | ClosureKind(..) | Subtype(..) | + Coerce(..) | ConstEvaluatable(..) | ConstEquate(..) | TypeWellFormedFromEnv(..) => continue, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 24bfdad970a1c..0c6f939ab051f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -32,7 +32,7 @@ #![feature(box_syntax)] #![feature(crate_visibility_modifier)] #![feature(iter_order_by)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(or_patterns)] #![feature(half_open_range_patterns)] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 77766be7397c7..fb95ca62ce37d 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -11,7 +11,7 @@ #![feature(min_specialization)] #![feature(stmt_expr_attributes)] #![feature(try_blocks)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![recursion_limit = "256"] extern crate proc_macro; diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 16e9aafb25a54..24ad3ab9ccdf6 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -20,10 +20,10 @@ pub trait ToType { impl UnifyKey for ty::TyVid { type Value = (); fn index(&self) -> u32 { - self.index + u32::from(*self) } fn from_index(i: u32) -> ty::TyVid { - ty::TyVid { index: i } + ty::TyVid::from(i) } fn tag() -> &'static str { "TyVid" diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index cdc5940d9baed..ddab25bdf13a2 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -34,7 +34,7 @@ #![feature(const_panic)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(extern_types)] #![feature(nll)] #![feature(once_cell)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 36cbd36a7705f..6924fa5760dfa 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2281,7 +2281,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.features().never_type_fallback { self.types.never } else { self.types.unit } + self.types.never } #[inline] diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 5ec0ec0c56ad6..7cf1d3b63adb1 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -67,12 +67,6 @@ pub enum TypeError<'tcx> { TargetFeatureCast(DefId), } -pub enum UnconstrainedNumeric { - UnconstrainedFloat, - UnconstrainedInt, - Neither, -} - /// Explains the source of a type err in a short, human readable way. This is meant to be placed /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` /// afterwards to present additional details, particularly when it comes to lifetime-related diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 8b97a87f214b8..30d342d65cf0a 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -236,6 +236,10 @@ impl FlagComputation { self.add_ty(a); self.add_ty(b); } + ty::PredicateAtom::Coerce(ty::CoercePredicate { a, b }) => { + self.add_ty(a); + self.add_ty(b); + } ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => { self.add_projection_ty(projection_ty); self.add_ty(ty); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6a67935cd98fe..b3366d0c69092 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1208,8 +1208,22 @@ pub enum PredicateAtom<'tcx> { ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind), /// `T1 <: T2` + /// + /// This obligation is created most often when we have two + /// unresolved type variables and hence don't have enough + /// information to process the subtyping obligation yet. Subtype(SubtypePredicate<'tcx>), + /// `T1` coerced to `T2` + /// + /// Like a subtyping obligation, thi sis created most often + /// when we have two unresolved type variables and hence + /// don't have enough information to process the coercion + /// obligation yet. At the moment, we actually process coercions + /// very much like subtyping and don't handle the full coercion + /// logic. + Coerce(CoercePredicate<'tcx>), + /// Constant initializer must evaluate successfully. ConstEvaluatable(ty::WithOptConstParam, SubstsRef<'tcx>), @@ -1362,6 +1376,9 @@ pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'t pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder>; pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder>; +/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates +/// whether the `a` type is the type that we should label as "expected" when +/// presenting user diagnostics. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] pub struct SubtypePredicate<'tcx> { @@ -1371,6 +1388,15 @@ pub struct SubtypePredicate<'tcx> { } pub type PolySubtypePredicate<'tcx> = ty::Binder>; +/// Encodes that we have to coerce *from* the `a` type to the `b` type. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable)] +pub struct CoercePredicate<'tcx> { + pub a: Ty<'tcx>, + pub b: Ty<'tcx>, +} +pub type PolyCoercePredicate<'tcx> = ty::Binder>; + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1508,6 +1534,7 @@ impl<'tcx> Predicate<'tcx> { PredicateAtom::Trait(t, _) => Some(ty::Binder::bind(t.trait_ref)), PredicateAtom::Projection(..) | PredicateAtom::Subtype(..) + | PredicateAtom::Coerce(..) | PredicateAtom::RegionOutlives(..) | PredicateAtom::WellFormed(..) | PredicateAtom::ObjectSafe(..) @@ -1525,6 +1552,7 @@ impl<'tcx> Predicate<'tcx> { PredicateAtom::Trait(..) | PredicateAtom::Projection(..) | PredicateAtom::Subtype(..) + | PredicateAtom::Coerce(..) | PredicateAtom::RegionOutlives(..) | PredicateAtom::WellFormed(..) | PredicateAtom::ObjectSafe(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 38f8e779f6a92..5587a25f16d21 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2003,6 +2003,10 @@ define_print_and_forward_display! { p!(print(self.a), " <: ", print(self.b)) } + ty::CoercePredicate<'tcx> { + p!(print(self.a), " -> ", print(self.b)) + } + ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": ", print(self.trait_ref.print_only_trait_path())) @@ -2040,6 +2044,7 @@ define_print_and_forward_display! { p!(print(data)) } ty::PredicateAtom::Subtype(predicate) => p!(print(predicate)), + ty::PredicateAtom::Coerce(predicate) => p!(print(predicate)), ty::PredicateAtom::RegionOutlives(predicate) => p!(print(predicate)), ty::PredicateAtom::TypeOutlives(predicate) => p!(print(predicate)), ty::PredicateAtom::Projection(predicate) => p!(print(predicate)), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 94e69a93a6b18..8a26a5171e27a 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -130,7 +130,7 @@ impl fmt::Debug for ty::FnSig<'tcx> { impl fmt::Debug for ty::TyVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}t", self.index) + write!(f, "_#{}t", u32::from(*self)) } } @@ -247,6 +247,7 @@ impl fmt::Debug for ty::PredicateAtom<'tcx> { a.fmt(f) } ty::PredicateAtom::Subtype(ref pair) => pair.fmt(f), + ty::PredicateAtom::Coerce(ref pair) => pair.fmt(f), ty::PredicateAtom::RegionOutlives(ref pair) => pair.fmt(f), ty::PredicateAtom::TypeOutlives(ref pair) => pair.fmt(f), ty::PredicateAtom::Projection(ref pair) => pair.fmt(f), @@ -447,6 +448,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> { + type Lifted = ty::CoercePredicate<'tcx>; + fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { + tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { a, b }) + } +} + impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate { type Lifted = ty::OutlivesPredicate; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { @@ -499,6 +507,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> { tcx.lift(data).map(|data| ty::PredicateAtom::Trait(data, constness)) } ty::PredicateAtom::Subtype(data) => tcx.lift(data).map(ty::PredicateAtom::Subtype), + ty::PredicateAtom::Coerce(data) => tcx.lift(data).map(ty::PredicateAtom::Coerce), ty::PredicateAtom::RegionOutlives(data) => { tcx.lift(data).map(ty::PredicateAtom::RegionOutlives) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 4bf16436855f4..708a498bfdae6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1489,9 +1489,10 @@ pub struct EarlyBoundRegion { pub name: Symbol, } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] -pub struct TyVid { - pub index: u32, +rustc_index::newtype_index! { + pub struct TyVid { + DEBUG_FORMAT = custom, + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] @@ -1901,6 +1902,14 @@ impl<'tcx> TyS<'tcx> { matches!(self.kind(), Infer(TyVar(_))) } + #[inline] + pub fn ty_vid(&self) -> Option { + match self.kind() { + &Infer(TyVar(vid)) => Some(vid), + _ => None, + } + } + #[inline] pub fn is_ty_infer(&self) -> bool { matches!(self.kind(), Infer(_)) diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 2ed115b12971c..8cd0463716ae4 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -17,7 +17,7 @@ Rust MIR: a lowered representation of Rust. #![feature(decl_macro)] #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(try_blocks)] diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index e4893044a1599..9a2a1307f99c2 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -397,8 +397,8 @@ impl Validator<'mir, 'tcx> { ty::PredicateAtom::ClosureKind(..) => { bug!("closure kind predicate on function: {:#?}", predicate) } - ty::PredicateAtom::Subtype(_) => { - bug!("subtype predicate on function: {:#?}", predicate) + ty::PredicateAtom::Subtype(_) | ty::PredicateAtom::Coerce(_) => { + bug!("subtype/coerce predicate on function: {:#?}", predicate) } ty::PredicateAtom::Trait(pred, constness) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index fab29f29e8730..0ac2425844aea 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -10,7 +10,7 @@ Core encoding and decoding interfaces. test(attr(allow(unused_variables), deny(warnings))) )] #![feature(box_syntax)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(associated_type_bounds)] #![feature(min_const_generics)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 10245d21b63a5..feddabaf28891 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -88,7 +88,7 @@ //! DefPaths which are much more robust in the face of changes to the code base. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(or_patterns)] #![feature(in_band_lifetimes)] diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index fb747dfcbd337..70d33fe82211a 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -12,7 +12,7 @@ #![feature(const_fn)] #![feature(const_panic)] #![feature(nll)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 42509cd897582..b7593c29a5c01 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -16,7 +16,7 @@ #![feature(box_patterns)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index ca547bf88b588..37112f6fd6b95 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -1265,6 +1265,7 @@ crate fn required_region_bounds( ty::PredicateAtom::Projection(..) | ty::PredicateAtom::Trait(..) | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::WellFormed(..) | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index fe4127fd4d8b9..d4a3a22b0b9cf 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -532,6 +532,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) } + ty::PredicateAtom::Coerce(predicate) => { + // Errors for Coerce predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate) + } + ty::PredicateAtom::RegionOutlives(predicate) => { let predicate = bound_predicate.rebind(predicate); let predicate = self.resolve_vars_if_possible(predicate); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 095483aa5a25d..a4936b7e48518 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1157,7 +1157,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let sig = if let ty::Tuple(inputs) = inputs.kind() { tcx.mk_fn_sig( inputs.iter().map(|k| k.expect_ty()), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from(0_u32))), false, hir::Unsafety::Normal, abi::Abi::Rust, @@ -1165,7 +1165,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } else { tcx.mk_fn_sig( std::iter::once(inputs), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from(0_u32))), false, hir::Unsafety::Normal, abi::Abi::Rust, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index a04f816b0f8a0..b6b3d4d94b6d3 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -373,6 +373,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { | ty::PredicateAtom::ObjectSafe(_) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(_) + | ty::PredicateAtom::Coerce(_) | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) => { let pred = infcx.replace_bound_vars_with_placeholders(binder); @@ -487,6 +488,31 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } + ty::PredicateAtom::Coerce(coerce) => { + match self.selcx.infcx().coerce_predicate( + &obligation.cause, + obligation.param_env, + Binder::dummy(coerce), + ) { + None => { + // None means that both are unresolved. + pending_obligation.stalled_on = vec![ + TyOrConstInferVar::maybe_from_ty(coerce.a).unwrap(), + TyOrConstInferVar::maybe_from_ty(coerce.b).unwrap(), + ]; + ProcessResult::Unchanged + } + Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Some(Err(err)) => { + let expected_found = ExpectedFound::new(false, coerce.a, coerce.b); + ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( + expected_found, + err, + )) + } + } + } + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { match const_evaluatable::is_const_evaluatable( self.selcx.infcx(), diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index d912a00d6b702..93dc49ff4a362 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -306,6 +306,7 @@ fn predicate_references_self( | ty::PredicateAtom::RegionOutlives(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, @@ -334,6 +335,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } ty::PredicateAtom::Projection(..) | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::RegionOutlives(..) | ty::PredicateAtom::WellFormed(..) | ty::PredicateAtom::ObjectSafe(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 05ff9a6fb9ca6..9fff65ae197d3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -474,6 +474,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::PredicateAtom::Coerce(p) => { + let p = bound_predicate.rebind(p); + // Does this code ever run? + match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { + Some(Ok(InferOk { mut obligations, .. })) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively( + previous_stack, + obligations.into_iter(), + ) + } + Some(Err(_)) => Ok(EvaluatedToErr), + None => Ok(EvaluatedToAmbig), + } + } + ty::PredicateAtom::WellFormed(arg) => match wf::obligations( self.infcx, obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index e5a792f229d19..535f17696061d 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -127,6 +127,10 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(a.into()); wf.compute(b.into()); } + ty::PredicateAtom::Coerce(ty::CoercePredicate { a, b }) => { + wf.compute(a.into()); + wf.compute(b.into()); + } ty::PredicateAtom::ConstEvaluatable(def, substs) => { let obligations = wf.nominal_obligations(def.did, substs); wf.out.extend(obligations); diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 9afb980f84d27..f685bfe2416f1 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -114,6 +114,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment bug!("unexpected predicate {}", predicate), }; @@ -201,6 +202,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi // some of these in terms of chalk operations. ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) @@ -604,6 +606,7 @@ impl<'tcx> LowerInto<'tcx, Option { @@ -727,6 +730,7 @@ impl<'tcx> LowerInto<'tcx, Option { diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 97017fbf2e56a..b9ec087025b06 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -99,6 +99,7 @@ fn compute_implied_outlives_bounds<'tcx>( &ty::PredicateKind::Atom(atom) => match atom { ty::PredicateAtom::Trait(..) | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::Projection(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ObjectSafe(..) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 750a0922be4d1..0600d1f820d53 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -48,6 +48,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool { | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index d5518dfc15a1b..5f30b8fc7094f 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -218,32 +218,16 @@ pub(super) fn check_fn<'a, 'tcx>( // we saw and assigning it to the expected return type. This isn't // really expected to fail, since the coercions would have failed // earlier when trying to find a LUB. - // - // However, the behavior around `!` is sort of complex. In the - // event that the `actual_return_ty` comes back as `!`, that - // indicates that the fn either does not return or "returns" only - // values of type `!`. In this case, if there is an expected - // return type that is *not* `!`, that should be ok. But if the - // return type is being inferred, we want to "fallback" to `!`: - // - // let x = move || panic!(); - // - // To allow for that, I am creating a type variable with diverging - // fallback. This was deemed ever so slightly better than unifying - // the return value with `!` because it allows for the caller to - // make more assumptions about the return type (e.g., they could do - // - // let y: Option = Some(x()); - // - // which would then cause this return type to become `u32`, not - // `!`). let coercion = fcx.ret_coercion.take().unwrap().into_inner(); let mut actual_return_ty = coercion.complete(&fcx); - if actual_return_ty.is_never() { - actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::DivergingFn, - span, - }); + debug!("actual_return_ty = {:?}", actual_return_ty); + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // We have special-cased the case where the function is declared + // `-> dyn Foo` and we don't actually relate it to the + // `fcx.ret_coercion`, so just substitute a type variable. + actual_return_ty = + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); + debug!("actual_return_ty replaced with {:?}", actual_return_ty); } fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 0f5f0ab026087..84a486250990b 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -40,16 +40,22 @@ use crate::check::FnCtxt; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; -use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, +use rustc_infer::{ + infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}, + traits::Obligation, }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TypeAndMut}; +use rustc_middle::ty::{ + adjustment::{ + Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, + }, + ToPredicate, +}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{self, BytePos, Span}; @@ -145,7 +151,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + // First, remove any resolved type variables (at the top level, at least): let a = self.shallow_resolve(a); + let b = self.shallow_resolve(b); debug!("Coerce.tys({:?} => {:?})", a, b); // Just ignore error types. @@ -153,26 +161,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return success(vec![], self.fcx.tcx.ty_error(), vec![]); } + // Coercing from `!` to any type is allowed: if a.is_never() { - // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound - // type variable, we want `?T` to fallback to `!` if not - // otherwise constrained. An example where this arises: - // - // let _: Option = Some({ return; }); - // - // here, we would coerce from `!` to `?T`. - let b = self.shallow_resolve(b); - return if self.shallow_resolve(b).is_ty_var() { - // Micro-optimization: no need for this if `b` is - // already resolved in some way. - let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::AdjustmentType, - span: self.cause.span, - }); - self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny)) - } else { - success(simple(Adjust::NeverToAny)(b), b, vec![]) - }; + return success(simple(Adjust::NeverToAny)(b), b, vec![]); + } + + // Coercing *from* an unresolved inference variable means that + // we have no information about the source type. This will always + // ultimately fall back to some form of subtyping. + if a.is_ty_var() { + return self.coerce_from_inference_variable(a, b, identity); } // Consider coercing the subtype to a DST @@ -195,9 +193,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { debug!("coerce: unsize failed"); // Examine the supertype and consider auto-borrowing. - // - // Note: does not attempt to resolve type variables we encounter. - // See above for details. match *b.kind() { ty::RawPtr(mt_b) => { return self.coerce_unsafe_ptr(a, b, mt_b.mutbl); @@ -235,6 +230,58 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } + /// Coercing *from* an inference variable. In this case, we have no information + /// about the source type, so we can't really do a true coercion and we always + /// fall back to subtyping (`unify_and`). + fn coerce_from_inference_variable( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec>, + ) -> CoerceResult<'tcx> { + debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b); + assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a); + assert!(self.infcx.shallow_resolve(b) == b); + + if b.is_ty_var() { + // Two unresolved type variables: create a `Coerce` predicate. + let target_ty = if self.use_lub { + self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::LatticeVariable, + span: self.cause.span, + }) + } else { + b + }; + + let mut obligations = Vec::with_capacity(2); + for &source_ty in &[a, b] { + if source_ty != target_ty { + obligations.push(Obligation::new( + self.cause.clone(), + self.param_env, + ty::PredicateAtom::Coerce(ty::CoercePredicate { + a: source_ty, + b: target_ty, + }) + .to_predicate(self.tcx()), + )); + } + } + + debug!( + "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}", + target_ty, obligations + ); + let adjustments = make_adjustments(target_ty); + InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations }) + } else { + // One unresolved type variable: just apply subtyping, we may be able + // to do something useful. + self.unify_and(a, b, make_adjustments) + } + } + /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index f7f9e607a7441..08fb9f6f26ceb 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id), "expression with never type wound up being adjusted" ); - let adj_ty = self.next_diverging_ty_var(TypeVariableOrigin { + let adj_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::AdjustmentType, span: expr.span, }); diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs new file mode 100644 index 0000000000000..cf04dbca1ab96 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -0,0 +1,384 @@ +use crate::check::FnCtxt; +use rustc_data_structures::{ + fx::FxHashMap, + graph::WithSuccessors, + graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + stable_set::FxHashSet, +}; +use rustc_middle::ty::{self, Ty}; + +impl<'tcx> FnCtxt<'_, 'tcx> { + pub(super) fn type_inference_fallback(&self) { + // All type checking constraints were added, try to fallback unsolved variables. + self.select_obligations_where_possible(false, |_| {}); + let mut fallback_has_occurred = false; + + // Check if we have any unsolved varibales. If not, no need for fallback. + let unsolved_variables = self.unsolved_variables(); + if unsolved_variables.is_empty() { + return; + } + + let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables); + + // We do fallback in two passes, to try to generate + // better error messages. + // The first time, we do *not* replace opaque types. + for ty in unsolved_variables { + debug!("unsolved_variable = {:?}", ty); + fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback); + } + + // We now see if we can make progress. This might cause us to + // unify inference variables for opaque types, since we may + // have unified some other type variables during the first + // phase of fallback. This means that we only replace + // inference variables with their underlying opaque types as a + // last resort. + // + // In code like this: + // + // ```rust + // type MyType = impl Copy; + // fn produce() -> MyType { true } + // fn bad_produce() -> MyType { panic!() } + // ``` + // + // we want to unify the opaque inference variable in `bad_produce` + // with the diverging fallback for `panic!` (e.g. `()` or `!`). + // This will produce a nice error message about conflicting concrete + // types for `MyType`. + // + // If we had tried to fallback the opaque inference variable to `MyType`, + // we will generate a confusing type-check error that does not explicitly + // refer to opaque types. + self.select_obligations_where_possible(fallback_has_occurred, |_| {}); + + // We now run fallback again, but this time we allow it to replace + // unconstrained opaque type variables, in addition to performing + // other kinds of fallback. + for ty in &self.unsolved_variables() { + fallback_has_occurred |= self.fallback_opaque_type_vars(ty); + } + + // See if we can make any more progress. + self.select_obligations_where_possible(fallback_has_occurred, |_| {}); + } + + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // + // - Unconstrained ints are replaced with `i32`. + // + // - Unconstrained floats are replaced with with `f64`. + // + // - Non-numerics may get replaced with `()` or `!`, depending on + // how they were categorized by `calculate_diverging_fallback`. + // + // Fallback becomes very dubious if we have encountered + // type-checking errors. In that case, fallback to Error. + // + // The return value indicates whether fallback has occurred. + fn fallback_if_possible( + &self, + ty: Ty<'tcx>, + diverging_fallback: &FxHashMap, Ty<'tcx>>, + ) -> bool { + // Careful: we do NOT shallow-resolve `ty`. We know that `ty` + // is an unsolved variable, and we determine its fallback + // based solely on how it was created, not what other type + // variables it may have been unified with since then. + // + // The reason this matters is that other attempts at fallback + // may (in principle) conflict with this fallback, and we wish + // to generate a type error in that case. (However, this + // actually isn't true right now, because we're only using the + // builtin fallback rules. This would be true if we were using + // user-supplied fallbacks. But it's still useful to write the + // code to detect bugs.) + // + // (Note though that if we have a general type variable `?T` + // that is then unified with an integer type variable `?I` + // that ultimately never gets resolved to a special integral + // type, `?T` is not considered unsolved, but `?I` is. The + // same is true for float variables.) + let fallback = match ty.kind() { + _ if self.is_tainted_by_errors() => self.tcx.ty_error(), + ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, + ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, + _ => match diverging_fallback.get(&ty) { + Some(&fallback_ty) => fallback_ty, + None => return false, + }, + }; + debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); + + let span = self + .infcx + .type_var_origin(ty) + .map(|origin| origin.span) + .unwrap_or(rustc_span::DUMMY_SP); + self.demand_eqtype(span, ty, fallback); + true + } + + /// Second round of fallback: Unconstrained type variables created + /// from the instantiation of an opaque type fall back to the + /// opaque type itself. This is a somewhat incomplete attempt to + /// manage "identity passthrough" for `impl Trait` types. + /// + /// For example, in this code: + /// + ///``` + /// type MyType = impl Copy; + /// fn defining_use() -> MyType { true } + /// fn other_use() -> MyType { defining_use() } + /// ``` + /// + /// `defining_use` will constrain the instantiated inference + /// variable to `bool`, while `other_use` will constrain + /// the instantiated inference variable to `MyType`. + /// + /// When we process opaque types during writeback, we + /// will handle cases like `other_use`, and not count + /// them as defining usages + /// + /// However, we also need to handle cases like this: + /// + /// ```rust + /// pub type Foo = impl Copy; + /// fn produce() -> Option { + /// None + /// } + /// ``` + /// + /// In the above snippet, the inference variable created by + /// instantiating `Option` will be completely unconstrained. + /// We treat this as a non-defining use by making the inference + /// variable fall back to the opaque type itself. + fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool { + let span = self + .infcx + .type_var_origin(ty) + .map(|origin| origin.span) + .unwrap_or(rustc_span::DUMMY_SP); + if let Some(&opaque_ty) = self.opaque_types_vars.borrow().get(ty) { + debug!( + "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}", + ty, opaque_ty + ); + self.demand_eqtype(span, ty, opaque_ty); + true + } else { + return false; + } + } + + /// The "diverging fallback" system is rather complicated. This is + /// a result of our need to balance 'do the right thing' with + /// backwards compatibility. + /// + /// "Diverging" type variables are variables created when we + /// coerce a `!` type into an unbound type variable `?X`. If they + /// never wind up being constrained, the "right and natural" thing + /// is that `?X` should "fallback" to `!`. This means that e.g. an + /// expression like `Some(return)` will ultimately wind up with a + /// type like `Option` (presuming it is not assigned or + /// constrained to have some other type). + /// + /// However, the fallback used to be `()` (before the `!` type was + /// added). Moreover, there are cases where the `!` type 'leaks + /// out' from dead code into type variables that affect live + /// code. The most common case is something like this: + /// + /// ```rust + /// match foo() { + /// 22 => Default::default(), // call this type `?D` + /// _ => return, // return has type `!` + /// } // call the type of this match `?M` + /// ``` + /// + /// Here, coercing the type `!` into `?M` will create a diverging + /// type variable `?X` where `?X <: ?M`. We also have that `?D <: + /// ?M`. If `?M` winds up unconstrained, then `?X` will + /// fallback. If it falls back to `!`, then all the type variables + /// will wind up equal to `!` -- this includes the type `?D` + /// (since `!` doesn't implement `Default`, we wind up a "trait + /// not implemented" error in code like this). But since the + /// original fallback was `()`, this code used to compile with `?D + /// = ()`. This is somewhat surprising, since `Default::default()` + /// on its own would give an error because the types are + /// insufficiently constrained. + /// + /// Our solution to this dilemma is to modify diverging variables + /// so that they can *either* fallback to `!` (the default) or to + /// `()` (the backwards compatibility case). We decide which + /// fallback to use based on whether there is a coercion pattern + /// like this: + /// + /// ``` + /// ?Diverging -> ?V + /// ?NonDiverging -> ?V + /// ?V != ?NonDiverging + /// ``` + /// + /// Here `?Diverging` represents some diverging type variable and + /// `?NonDiverging` represents some non-diverging type + /// variable. `?V` can be any type variable (diverging or not), so + /// long as it is not equal to `?NonDiverging`. + /// + /// Intuitively, what we are looking for is a case where a + /// "non-diverging" type variable (like `?M` in our example above) + /// is coerced *into* some variable `?V` that would otherwise + /// fallback to `!`. In that case, we make `?V` fallback to `!`, + /// along with anything that would flow into `?V`. + /// + /// The algorithm we use: + /// * Identify all variables that are coerced *into* by a + /// diverging variable. Do this by iterating over each + /// diverging, unsolved variable and finding all variables + /// reachable from there. Call that set `D`. + /// * Walk over all unsolved, non-diverging variables, and find + /// any variable that has an edge into `D`. + fn calculate_diverging_fallback( + &self, + unsolved_variables: &[Ty<'tcx>], + ) -> FxHashMap, Ty<'tcx>> { + debug!("calculate_diverging_fallback({:?})", unsolved_variables); + + // Construct a coercion graph where an edge `A -> B` indicates + // a type variable is that is coerced + let coercion_graph = self.create_coercion_graph(); + + // Extract the unsolved type inference variable vids; note that some + // unsolved variables are integer/float variables and are excluded. + let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid()); + + // Compute the diverging root vids D -- that is, the root vid of + // those type variables that (a) are the target of a coercion from + // a `!` type and (b) have not yet been solved. + // + // These variables are the ones that are targets for fallback to + // either `!` or `()`. + let diverging_roots: FxHashSet = self + .diverging_type_vars + .borrow() + .iter() + .map(|&ty| self.infcx.shallow_resolve(ty)) + .filter_map(|ty| ty.ty_vid()) + .map(|vid| self.infcx.root_var(vid)) + .collect(); + debug!( + "calculate_diverging_fallback: diverging_type_vars={:?}", + self.diverging_type_vars.borrow() + ); + debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots); + + // Find all type variables that are reachable from a diverging + // type variable. These will typically default to `!`, unless + // we find later that they are *also* reachable from some + // other type variable outside this set. + let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph); + let mut diverging_vids = vec![]; + let mut non_diverging_vids = vec![]; + for unsolved_vid in unsolved_vids { + let root_vid = self.infcx.root_var(unsolved_vid); + debug!( + "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}", + unsolved_vid, + root_vid, + diverging_roots.contains(&root_vid), + ); + if diverging_roots.contains(&root_vid) { + diverging_vids.push(unsolved_vid); + roots_reachable_from_diverging.push_start_node(root_vid); + + debug!( + "calculate_diverging_fallback: root_vid={:?} reaches {:?}", + root_vid, + coercion_graph.depth_first_search(root_vid).collect::>() + ); + + // drain the iterator to visit all nodes reachable from this node + roots_reachable_from_diverging.complete_search(); + } else { + non_diverging_vids.push(unsolved_vid); + } + } + + debug!( + "calculate_diverging_fallback: roots_reachable_from_diverging={:?}", + roots_reachable_from_diverging, + ); + + // Find all type variables N0 that are not reachable from a + // diverging variable, and then compute the set reachable from + // N0, which we call N. These are the *non-diverging* type + // variables. (Note that this set consists of "root variables".) + let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph); + for &non_diverging_vid in &non_diverging_vids { + let root_vid = self.infcx.root_var(non_diverging_vid); + if roots_reachable_from_diverging.visited(root_vid) { + continue; + } + roots_reachable_from_non_diverging.push_start_node(root_vid); + roots_reachable_from_non_diverging.complete_search(); + } + debug!( + "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}", + roots_reachable_from_non_diverging, + ); + + // For each diverging variable, figure out whether it can + // reach a member of N. If so, it falls back to `()`. Else + // `!`. + let mut diverging_fallback = FxHashMap::default(); + for &diverging_vid in &diverging_vids { + let diverging_ty = self.tcx.mk_ty_var(diverging_vid); + let root_vid = self.infcx.root_var(diverging_vid); + let can_reach_non_diverging = coercion_graph + .depth_first_search(root_vid) + .any(|n| roots_reachable_from_non_diverging.visited(n)); + if can_reach_non_diverging { + debug!("fallback to (): {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else { + debug!("fallback to !: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default()); + } + } + + diverging_fallback + } + + /// Returns a graph whose nodes are (unresolved) inference variables and where + /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. + fn create_coercion_graph(&self) -> VecGraph { + let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations(); + debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations); + let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations + .into_iter() + .filter_map(|obligation| { + // The predicates we are looking for look like `Coerce(?A -> ?B)`. + // They will have no bound variables. + obligation.predicate.bound_atom().no_bound_vars() + }) + .filter_map(|atom| { + if let ty::PredicateAtom::Coerce(ty::CoercePredicate { a, b }) = atom { + let a_vid = self.root_vid(a)?; + let b_vid = self.root_vid(b)?; + Some((a_vid, b_vid)) + } else { + None + } + }) + .collect(); + debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges); + let num_ty_vars = self.infcx.num_ty_vars(); + VecGraph::new(num_ty_vars, coercion_edges) + } + + /// If `ty` is an unresolved type variable, returns its root vid. + fn root_vid(&self, ty: Ty<'tcx>) -> Option { + Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?)) + } +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index e1a2f593b8d9b..af510d6d9f74e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -4,7 +4,7 @@ use crate::astconv::{ }; use crate::check::callee::{self, DeferredCallResolution}; use crate::check::method::{self, MethodCallee, SelfSource}; -use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy}; +use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; @@ -273,6 +273,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + for a in &adj { + if let Adjust::NeverToAny = a.kind { + if a.target.is_ty_var() { + self.diverging_type_vars.borrow_mut().insert(a.target); + debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target); + } + } + } + let autoborrow_mut = adj.iter().any(|adj| { matches!(adj, &Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), @@ -609,83 +618,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // Tries to apply a fallback to `ty` if it is an unsolved variable. - // - // - Unconstrained ints are replaced with `i32`. - // - // - Unconstrained floats are replaced with with `f64`. - // - // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` - // is enabled. Otherwise, they are replaced with `()`. - // - // Fallback becomes very dubious if we have encountered type-checking errors. - // In that case, fallback to Error. - // The return value indicates whether fallback has occurred. - pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { - use rustc_middle::ty::error::UnconstrainedNumeric::Neither; - use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - - assert!(ty.is_ty_infer()); - let fallback = match self.type_is_unconstrained_numeric(ty) { - _ if self.is_tainted_by_errors() => self.tcx().ty_error(), - UnconstrainedInt => self.tcx.types.i32, - UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), - Neither => { - // This type variable was created from the instantiation of an opaque - // type. The fact that we're attempting to perform fallback for it - // means that the function neither constrained it to a concrete - // type, nor to the opaque type itself. - // - // For example, in this code: - // - //``` - // type MyType = impl Copy; - // fn defining_use() -> MyType { true } - // fn other_use() -> MyType { defining_use() } - // ``` - // - // `defining_use` will constrain the instantiated inference - // variable to `bool`, while `other_use` will constrain - // the instantiated inference variable to `MyType`. - // - // When we process opaque types during writeback, we - // will handle cases like `other_use`, and not count - // them as defining usages - // - // However, we also need to handle cases like this: - // - // ```rust - // pub type Foo = impl Copy; - // fn produce() -> Option { - // None - // } - // ``` - // - // In the above snippet, the inference variable created by - // instantiating `Option` will be completely unconstrained. - // We treat this as a non-defining use by making the inference - // variable fall back to the opaque type itself. - if let FallbackMode::All = mode { - if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { - debug!( - "fallback_if_possible: falling back opaque type var {:?} to {:?}", - ty, opaque_ty - ); - *opaque_ty - } else { - return false; - } - } else { - return false; - } - } - }; - debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); - self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback); - true - } - pub(in super::super) fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { @@ -772,6 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) } ty::PredicateAtom::Subtype(..) => None, + ty::PredicateAtom::Coerce(..) => None, ty::PredicateAtom::RegionOutlives(..) => None, ty::PredicateAtom::TypeOutlives(..) => None, ty::PredicateAtom::WellFormed(..) => None, diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 0011a3fc71b59..5cee8d1f5d9fa 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -1,7 +1,7 @@ use super::callee::DeferredCallResolution; use super::MaybeInProgressTables; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet}; use rustc_hir as hir; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::HirIdMap; @@ -68,6 +68,11 @@ pub struct Inherited<'a, 'tcx> { pub(super) opaque_types_vars: RefCell, Ty<'tcx>>>, pub(super) body_id: Option, + + /// Whenever we introduce an adjustment from `!` into a type variable, + /// we record that type variable here. This is later used to inform + /// fallback. See the `fallback` module for details. + pub(super) diverging_type_vars: RefCell>>, } impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { @@ -125,6 +130,7 @@ impl Inherited<'a, 'tcx> { deferred_generator_interiors: RefCell::new(Vec::new()), opaque_types: RefCell::new(Default::default()), opaque_types_vars: RefCell::new(Default::default()), + diverging_type_vars: RefCell::new(Default::default()), body_id, } } diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 478f8a16169ed..52e9f0d08cc47 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -807,6 +807,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::Projection(..) | ty::PredicateAtom::RegionOutlives(..) | ty::PredicateAtom::WellFormed(..) diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 1479eadf1b067..943ca1cbefc3a 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -75,6 +75,7 @@ mod diverges; pub mod dropck; mod expectation; mod expr; +mod fallback; mod fn_ctxt; mod gather_locals; mod generator_interior; @@ -562,50 +563,7 @@ fn typeck_with_fallback<'tcx>( fcx }; - // All type checking constraints were added, try to fallback unsolved variables. - fcx.select_obligations_where_possible(false, |_| {}); - let mut fallback_has_occurred = false; - - // We do fallback in two passes, to try to generate - // better error messages. - // The first time, we do *not* replace opaque types. - for ty in &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque); - } - // We now see if we can make progress. This might - // cause us to unify inference variables for opaque types, - // since we may have unified some other type variables - // during the first phase of fallback. - // This means that we only replace inference variables with their underlying - // opaque types as a last resort. - // - // In code like this: - // - // ```rust - // type MyType = impl Copy; - // fn produce() -> MyType { true } - // fn bad_produce() -> MyType { panic!() } - // ``` - // - // we want to unify the opaque inference variable in `bad_produce` - // with the diverging fallback for `panic!` (e.g. `()` or `!`). - // This will produce a nice error message about conflicting concrete - // types for `MyType`. - // - // If we had tried to fallback the opaque inference variable to `MyType`, - // we will generate a confusing type-check error that does not explicitly - // refer to opaque types. - fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); - - // We now run fallback again, but this time we allow it to replace - // unconstrained opaque type variables, in addition to performing - // other kinds of fallback. - for ty in &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All); - } - - // See if we can make any more progress. - fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); + fcx.type_inference_fallback(); // Even though coercion casts provide type hints, we check casts after fallback for // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. @@ -1088,16 +1046,6 @@ enum TupleArgumentsFlag { TupleArguments, } -/// Controls how we perform fallback for unconstrained -/// type variables. -enum FallbackMode { - /// Do not fallback type variables to opaque types. - NoOpaque, - /// Perform all possible kinds of fallback, including - /// turning type variables to opaque types. - All, -} - /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. #[derive(Copy, Clone)] struct MaybeInProgressTables<'a, 'tcx> { diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 5db9ff9524de0..d4615f5d35a03 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -403,6 +403,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateAtom::Projection(_) | ty::PredicateAtom::WellFormed(_) | ty::PredicateAtom::Subtype(_) + | ty::PredicateAtom::Coerce(_) | ty::PredicateAtom::ObjectSafe(_) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ConstEvaluatable(..) diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 929c88455f041..896367bb2cad2 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -65,7 +65,7 @@ This API is completely unstable and subject to change. #![feature(nll)] #![feature(or_patterns)] #![feature(try_blocks)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(slice_partition_dedup)] #![feature(control_flow_enum)] #![recursion_limit = "256"] diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs index ae336ccca457d..fc8bd66ba78a2 100644 --- a/compiler/rustc_typeck/src/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -56,6 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (), diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f21fc8854d05e..76f8512f87bbf 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -109,7 +109,7 @@ #![feature(layout_for_ptr)] #![feature(maybe_uninit_ref)] #![feature(negative_impls)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(optin_builtin_traits)] diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index a953a3a4182bc..de8bb15495bb7 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -193,7 +193,7 @@ mod impls { bool char } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.49.0")] impl Clone for ! { #[inline] fn clone(&self) -> Self { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index bbb3a3dea435e..e70d6d814ce5d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1189,24 +1189,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.49.0")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.49.0")] impl Eq for ! {} - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.49.0")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.49.0")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 3f7110b34cc67..827221d28e436 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -34,9 +34,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::fmt; -use crate::hash::{Hash, Hasher}; - mod num; #[unstable(feature = "convert_float_to_int", issue = "67057")] @@ -675,64 +672,4 @@ impl AsRef for str { /// /// [never]: ../../std/primitive.never.html #[stable(feature = "convert_infallible", since = "1.34.0")] -#[derive(Copy)] -pub enum Infallible {} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl Clone for Infallible { - fn clone(&self) -> Infallible { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl fmt::Debug for Infallible { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl fmt::Display for Infallible { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl PartialEq for Infallible { - fn eq(&self, _: &Infallible) -> bool { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl Eq for Infallible {} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl PartialOrd for Infallible { - fn partial_cmp(&self, _other: &Self) -> Option { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl Ord for Infallible { - fn cmp(&self, _other: &Self) -> crate::cmp::Ordering { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl From for Infallible { - fn from(x: !) -> Self { - x - } -} - -#[stable(feature = "convert_infallible_hash", since = "1.44.0")] -impl Hash for Infallible { - fn hash(&self, _: &mut H) { - match *self {} - } -} +pub type Infallible = !; diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 506d778068682..03db55306453b 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1991,14 +1991,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.49.0")] impl Debug for ! { fn fmt(&self, _: &mut Formatter<'_>) -> Result { *self } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.49.0")] impl Display for ! { fn fmt(&self, _: &mut Formatter<'_>) -> Result { *self diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d67f9c15a1916..cfae920e9c793 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -115,7 +115,7 @@ #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] #![feature(negative_impls)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(exhaustive_patterns)] #![feature(no_core)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index cdf742057b7b6..ee46d78e6ad53 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -815,7 +815,7 @@ mod copy_impls { bool char } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.49.0")] impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index e84014c68a676..c6d4703205e1c 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1018,7 +1018,6 @@ pub const fn discriminant(v: &T) -> Discriminant { /// # Examples /// /// ``` -/// # #![feature(never_type)] /// # #![feature(variant_count)] /// /// use std::mem; diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 9d8c8c862911c..ce768c950453e 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -1,6 +1,5 @@ //! Error types for conversion to integral types. -use crate::convert::Infallible; use crate::fmt; /// The error type returned when a checked integral type conversion fails. @@ -28,14 +27,7 @@ impl fmt::Display for TryFromIntError { } } -#[stable(feature = "try_from", since = "1.34.0")] -impl From for TryFromIntError { - fn from(x: Infallible) -> TryFromIntError { - match x {} - } -} - -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.49.0")] impl From for TryFromIntError { fn from(never: !) -> TryFromIntError { // Match rather than coerce to make sure that code like diff --git a/library/core/src/result.rs b/library/core/src/result.rs index b6d9f13d881e3..f439b7c32ec4b 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1086,7 +1086,6 @@ impl> Result { /// Basic usage: /// /// ``` - /// # #![feature(never_type)] /// # #![feature(unwrap_infallible)] /// /// fn only_good_news() -> Result { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 14ef03fd53eba..a0a1d74eb3f94 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -52,7 +52,7 @@ #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(unwrap_infallible)] #![feature(option_unwrap_none)] #![feature(peekable_next_if)] diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 0044e59d697e3..edeaa012ebeb7 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -17,7 +17,6 @@ mod tests; use core::array; -use core::convert::Infallible; use crate::alloc::{AllocError, LayoutError}; use crate::any::TypeId; @@ -379,7 +378,7 @@ impl<'a> From> for Box { } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.49.0")] impl Error for ! {} #[unstable( @@ -456,13 +455,6 @@ impl Error for string::FromUtf16Error { } } -#[stable(feature = "str_parse_error2", since = "1.8.0")] -impl Error for Infallible { - fn description(&self) -> &str { - match *self {} - } -} - #[stable(feature = "decode_utf16", since = "1.9.0")] impl Error for char::DecodeUtf16Error { #[allow(deprecated)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index db523f05e01a5..ce6a604c191dc 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -284,7 +284,7 @@ #![feature(min_specialization)] #![feature(needs_panic_runtime)] #![feature(negative_impls)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(once_cell)] diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 83a282c8cd6b5..a86058b914069 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -69,7 +69,6 @@ mod prim_bool {} /// write: /// /// ``` -/// #![feature(never_type)] /// # fn foo() -> u32 { /// let x: ! = { /// return 123 @@ -231,7 +230,6 @@ mod prim_bool {} /// for example: /// /// ``` -/// #![feature(never_type)] /// # use std::fmt; /// # trait Debug { /// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; @@ -267,7 +265,7 @@ mod prim_bool {} /// [`Debug`]: fmt::Debug /// [`default()`]: Default::default /// -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.49.0")] mod prim_never {} #[doc(primitive = "char")] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9d84089eb405c..063831e86d500 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -499,6 +499,7 @@ impl<'a> Clean> for ty::Predicate<'a> { ty::PredicateAtom::Projection(pred) => Some(pred.clean(cx)), ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Coerce(..) | ty::PredicateAtom::WellFormed(..) | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a88efba77b41c..6e274e1d6e891 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -12,7 +12,7 @@ #![feature(peekable_next_if)] #![feature(test)] #![feature(crate_visibility_modifier)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/src/test/codegen/enum-debug-niche-2.rs b/src/test/codegen/enum-debug-niche-2.rs index 0f78234d9774d..cd6207ab7eefa 100644 --- a/src/test/codegen/enum-debug-niche-2.rs +++ b/src/test/codegen/enum-debug-niche-2.rs @@ -10,8 +10,6 @@ // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i64 4294967295{{[,)].*}} // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i64 0{{[,)].*}} -#![feature(never_type)] - #[derive(Copy, Clone)] pub struct Entity { private: std::num::NonZeroU32, diff --git a/src/test/mir-opt/issue-72181-1.rs b/src/test/mir-opt/issue-72181-1.rs index 91e98adbe8049..336a21a3a83e3 100644 --- a/src/test/mir-opt/issue-72181-1.rs +++ b/src/test/mir-opt/issue-72181-1.rs @@ -1,7 +1,6 @@ // compile-flags: -Z mir-opt-level=1 // Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags. -#![feature(never_type)] #![allow(unused, invalid_value)] enum Void {} @@ -13,9 +12,7 @@ fn f(v: Void) -> ! { // EMIT_MIR issue_72181_1.main.mir_map.0.mir fn main() { - let v: Void = unsafe { - std::mem::transmute::<(), Void>(()) - }; + let v: Void = unsafe { std::mem::transmute::<(), Void>(()) }; f(v); } diff --git a/src/test/mir-opt/remove-never-const.rs b/src/test/mir-opt/remove-never-const.rs index 1673f14b45ce4..fddbbd5965358 100644 --- a/src/test/mir-opt/remove-never-const.rs +++ b/src/test/mir-opt/remove-never-const.rs @@ -6,7 +6,6 @@ // compile-flags: --emit mir,link #![feature(const_panic)] -#![feature(never_type)] #![warn(const_err)] struct PrintName(T); diff --git a/src/test/mir-opt/uninhabited-enum.rs b/src/test/mir-opt/uninhabited-enum.rs index 97c6e8cd53111..b7aa029004b9a 100644 --- a/src/test/mir-opt/uninhabited-enum.rs +++ b/src/test/mir-opt/uninhabited-enum.rs @@ -1,19 +1,17 @@ -#![feature(never_type)] - pub enum Void {} // EMIT_MIR uninhabited_enum.process_never.SimplifyLocals.after.mir #[no_mangle] pub fn process_never(input: *const !) { - let _input = unsafe { &*input }; + let _input = unsafe { &*input }; } // EMIT_MIR uninhabited_enum.process_void.SimplifyLocals.after.mir #[no_mangle] pub fn process_void(input: *const Void) { - let _input = unsafe { &*input }; - // In the future, this should end with `unreachable`, but we currently only do - // unreachability analysis for `!`. + let _input = unsafe { &*input }; + // In the future, this should end with `unreachable`, but we currently only do + // unreachability analysis for `!`. } fn main() {} diff --git a/src/test/ui/borrowck/assign-never-type.rs b/src/test/ui/borrowck/assign-never-type.rs index 4f30ea1467023..3309a72ff1d6f 100644 --- a/src/test/ui/borrowck/assign-never-type.rs +++ b/src/test/ui/borrowck/assign-never-type.rs @@ -2,13 +2,11 @@ // check-pass -#![feature(never_type)] - pub fn main() { loop { match None { None => return, Some(val) => val, }; - }; + } } diff --git a/src/test/ui/break-diverging-value.rs b/src/test/ui/break-diverging-value.rs index d070fddaffc19..ea86971ea813a 100644 --- a/src/test/ui/break-diverging-value.rs +++ b/src/test/ui/break-diverging-value.rs @@ -1,19 +1,29 @@ -#![feature(never_type)] - fn loop_break_return() -> i32 { - let loop_value = loop { break return 0 }; // ok + let loop_value = loop { + break return 0; + }; // ok } fn loop_break_loop() -> i32 { - let loop_value = loop { break loop {} }; // ok + let loop_value = loop { + break loop {}; + }; // ok } -fn loop_break_break() -> i32 { //~ ERROR mismatched types - let loop_value = loop { break break }; +fn loop_break_break() -> i32 { + //~ ERROR mismatched types + let loop_value = loop { + break break; + }; } fn loop_break_return_2() -> i32 { - let loop_value = loop { break { return 0; () } }; // ok + let loop_value = loop { + break { + return 0; + () + }; + }; // ok } enum Void {} @@ -22,8 +32,11 @@ fn get_void() -> Void { panic!() } -fn loop_break_void() -> i32 { //~ ERROR mismatched types - let loop_value = loop { break get_void() }; +fn loop_break_void() -> i32 { + //~ ERROR mismatched types + let loop_value = loop { + break get_void(); + }; } fn get_never() -> ! { @@ -31,7 +44,9 @@ fn get_never() -> ! { } fn loop_break_never() -> i32 { - let loop_value = loop { break get_never() }; // ok + let loop_value = loop { + break get_never(); + }; // ok } fn main() {} diff --git a/src/test/ui/break-while-condition.rs b/src/test/ui/break-while-condition.rs index 6064e6ab00235..06a611d752309 100644 --- a/src/test/ui/break-while-condition.rs +++ b/src/test/ui/break-while-condition.rs @@ -1,28 +1,29 @@ -#![feature(never_type)] - fn main() { // The `if false` expressions are simply to // make sure we don't avoid checking everything // simply because a few expressions are unreachable. if false { - let _: ! = { //~ ERROR mismatched types - 'a: while break 'a {}; + let _: ! = { + //~ ERROR mismatched types + 'a: while break 'a {} }; } if false { let _: ! = { - while false { //~ ERROR mismatched types - break + while false { + //~ ERROR mismatched types + break; } }; } if false { let _: ! = { - while false { //~ ERROR mismatched types - return + while false { + //~ ERROR mismatched types + return; } }; } diff --git a/src/test/ui/coercion/coerce-to-bang-cast.rs b/src/test/ui/coercion/coerce-to-bang-cast.rs index 85598a42eccd9..9ec72c46d88be 100644 --- a/src/test/ui/coercion/coerce-to-bang-cast.rs +++ b/src/test/ui/coercion/coerce-to-bang-cast.rs @@ -1,7 +1,8 @@ -#![feature(never_type)] - fn cast_a() { - let y = {return; 22} as !; + let y = { + return; + 22 + } as !; //~^ ERROR non-primitive cast } @@ -9,4 +10,4 @@ fn cast_b() { let y = 22 as !; //~ ERROR non-primitive cast } -fn main() { } +fn main() {} diff --git a/src/test/ui/coercion/coerce-to-bang.rs b/src/test/ui/coercion/coerce-to-bang.rs index 1e06934d09f9e..d52f79fbb7a98 100644 --- a/src/test/ui/coercion/coerce-to-bang.rs +++ b/src/test/ui/coercion/coerce-to-bang.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - fn foo(x: usize, y: !, z: usize) { } fn call_foo_a() { diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.rs b/src/test/ui/const-generics/min_const_generics/complex-types.rs index 2aaf2c3987558..29f58c29dfb48 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-types.rs +++ b/src/test/ui/const-generics/min_const_generics/complex-types.rs @@ -1,5 +1,4 @@ #![feature(min_const_generics)] -#![feature(never_type)] struct Foo; //~^ ERROR `[u8; 0]` is forbidden @@ -18,11 +17,15 @@ struct Faz; struct Fiz; //~^ ERROR `!` is forbidden -enum Goo { A, B } +enum Goo { + A, + B, +} //~^ ERROR `()` is forbidden -union Boo { a: () } +union Boo { + a: (), +} //~^ ERROR `()` is forbidden - fn main() {} diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs index 795c5154f8155..d3ade5a08b230 100644 --- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs @@ -2,14 +2,15 @@ // Regression test for #66975 #![warn(const_err, unconditional_panic)] -#![feature(never_type)] struct PrintName(T); impl PrintName { - const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; + const VOID: ! = { + let x = 0 * std::mem::size_of::(); + [][x] + }; //~^ WARN any use of this value will cause an error - } fn f() { diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs index 21ee64fa6d937..8c0ac868d4392 100644 --- a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs @@ -3,7 +3,6 @@ // Regression test for #66975 #![warn(const_err)] #![feature(const_panic)] -#![feature(never_type)] struct PrintName; diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs index 3b28b2fdd247e..f248a787ededa 100644 --- a/src/test/ui/consts/const-eval/panic-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-never-type.rs @@ -3,7 +3,6 @@ // Regression test for #66975 #![warn(const_err)] #![feature(const_panic)] -#![feature(never_type)] const VOID: ! = panic!(); //~^ WARN any use of this value will cause an error diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index dc94f2368c9b6..fab021c1c1293 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -1,5 +1,4 @@ // normalize-stderr-64bit "0x0000000000" -> "0x00" -#![feature(never_type)] #![allow(const_err)] // make sure we cannot allow away the errors tested here use std::mem; @@ -53,7 +52,7 @@ union MaybeUninit { uninit: (), init: T, } -const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; +const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR is undefined behavior // Pointer value in an enum with a niche that is not just 0. @@ -94,5 +93,4 @@ const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem: const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; //~^ ERROR is undefined behavior -fn main() { -} +fn main() {} diff --git a/src/test/ui/consts/const-variant-count.rs b/src/test/ui/consts/const-variant-count.rs index 455419d2c7f1d..f21f6e9c29168 100644 --- a/src/test/ui/consts/const-variant-count.rs +++ b/src/test/ui/consts/const-variant-count.rs @@ -1,7 +1,6 @@ // run-pass #![allow(dead_code)] #![feature(variant_count)] -#![feature(never_type)] use std::mem::variant_count; diff --git a/src/test/ui/empty/empty-never-array.rs b/src/test/ui/empty/empty-never-array.rs index 01b99134a445f..a5024449d91d9 100644 --- a/src/test/ui/empty/empty-never-array.rs +++ b/src/test/ui/empty/empty-never-array.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - enum Helper { T(T, [!; 0]), #[allow(dead_code)] diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs index f0cc9ea70550e..c27089d2a0590 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - fn foo() -> Result { Ok(123) } diff --git a/src/test/ui/feature-gates/feature-gate-never_type.rs b/src/test/ui/feature-gates/feature-gate-never_type.rs deleted file mode 100644 index be8c27dbb1b02..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-never_type.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Test that ! errors when used in illegal positions with feature(never_type) disabled - -trait Foo { - type Wub; -} - -type Ma = (u32, !, i32); //~ ERROR type is experimental -type Meeshka = Vec; //~ ERROR type is experimental -type Mow = &'static fn(!) -> !; //~ ERROR type is experimental -type Skwoz = &'static mut !; //~ ERROR type is experimental - -impl Foo for Meeshka { - type Wub = !; //~ ERROR type is experimental -} - -fn main() { -} diff --git a/src/test/ui/feature-gates/feature-gate-never_type.stderr b/src/test/ui/feature-gates/feature-gate-never_type.stderr deleted file mode 100644 index 0a59cae9c8c46..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-never_type.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:7:17 - | -LL | type Ma = (u32, !, i32); - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:8:20 - | -LL | type Meeshka = Vec; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:9:24 - | -LL | type Mow = &'static fn(!) -> !; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:10:27 - | -LL | type Skwoz = &'static mut !; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:13:16 - | -LL | type Wub = !; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/for-loop-while/loop-break-value.rs b/src/test/ui/for-loop-while/loop-break-value.rs index d7209fc4de867..eee214406bf33 100644 --- a/src/test/ui/for-loop-while/loop-break-value.rs +++ b/src/test/ui/for-loop-while/loop-break-value.rs @@ -1,7 +1,6 @@ // run-pass #![allow(unreachable_code)] -#![feature(never_type)] #[allow(unused)] fn never_returns() { @@ -18,7 +17,7 @@ pub fn main() { let _never: ! = loop { break loop { break 'outer panic!(); - } + }; }; } }; @@ -38,29 +37,21 @@ pub fn main() { assert_eq!(coerced, &[17u32]); let trait_unified = loop { - break if true { - break Default::default() - } else { - break [13, 14] - }; + break if true { break Default::default() } else { break [13, 14] }; }; assert_eq!(trait_unified, [0, 0]); let trait_unified_2 = loop { if false { - break [String::from("Hello")] + break [String::from("Hello")]; } else { - break Default::default() + break Default::default(); }; }; assert_eq!(trait_unified_2, [""]); let trait_unified_3 = loop { - break if false { - break [String::from("Hello")] - } else { - ["Yes".into()] - }; + break if false { break [String::from("Hello")] } else { ["Yes".into()] }; }; assert_eq!(trait_unified_3, ["Yes"]); @@ -87,7 +78,7 @@ pub fn main() { Default::default() } else { break; - } + }; }; assert_eq!(regular_break_3, ()); diff --git a/src/test/ui/lint/must_use-unit.rs b/src/test/ui/lint/must_use-unit.rs index 4dd4798abb7ce..8f59bab26d3ef 100644 --- a/src/test/ui/lint/must_use-unit.rs +++ b/src/test/ui/lint/must_use-unit.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![deny(unused_must_use)] #[must_use] diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs index 6c4160c36aa39..219c7604c8c50 100644 --- a/src/test/ui/loops/loop-break-value.rs +++ b/src/test/ui/loops/loop-break-value.rs @@ -1,7 +1,7 @@ -#![feature(never_type)] - fn main() { - let val: ! = loop { break break; }; + let val: ! = loop { + break break; + }; //~^ ERROR mismatched types loop { @@ -10,7 +10,7 @@ fn main() { } else { break 123; //~ ERROR mismatched types } - }; + } let _: i32 = loop { break "asdf"; //~ ERROR mismatched types @@ -20,10 +20,11 @@ fn main() { loop { break 'outer_loop "nope"; //~ ERROR mismatched types break "ok"; - }; + } }; - 'while_loop: while true { //~ WARN denote infinite loops with + 'while_loop: while true { + //~ WARN denote infinite loops with break; break (); //~ ERROR `break` with value from a `while` loop loop { @@ -31,7 +32,7 @@ fn main() { //~^ ERROR `break` with value from a `while` loop break 456; break 789; - }; + } } while let Some(_) = Some(()) { @@ -49,21 +50,21 @@ fn main() { break 'while_let_loop "nope"; //~^ ERROR `break` with value from a `while` loop break 33; - }; + } } - for _ in &[1,2,3] { + for _ in &[1, 2, 3] { break (); //~ ERROR `break` with value from a `for` loop break [()]; //~^ ERROR `break` with value from a `for` loop } - 'for_loop: for _ in &[1,2,3] { + 'for_loop: for _ in &[1, 2, 3] { loop { break Some(3); break 'for_loop Some(17); //~^ ERROR `break` with value from a `for` loop - }; + } } let _: i32 = 'a: loop { @@ -78,16 +79,16 @@ fn main() { loop { break (break, break); //~ ERROR mismatched types - }; + } loop { break; break 2; //~ ERROR mismatched types - }; + } loop { break 2; break; //~ ERROR mismatched types break 4; - }; + } } diff --git a/src/test/ui/mir/mir_calls_to_shims.rs b/src/test/ui/mir/mir_calls_to_shims.rs index 6f13d5612ce51..189fa87601d18 100644 --- a/src/test/ui/mir/mir_calls_to_shims.rs +++ b/src/test/ui/mir/mir_calls_to_shims.rs @@ -2,15 +2,19 @@ // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] -#![feature(never_type)] use std::panic; -fn foo(x: u32, y: u32) -> u32 { x/y } -fn foo_diverges() -> ! { panic!() } +fn foo(x: u32, y: u32) -> u32 { + x / y +} +fn foo_diverges() -> ! { + panic!() +} fn test_fn_ptr(mut t: T) - where T: Fn(u32, u32) -> u32, +where + T: Fn(u32, u32) -> u32, { let as_fn = >::call; assert_eq!(as_fn(&t, (9, 3)), 3); @@ -20,18 +24,20 @@ fn test_fn_ptr(mut t: T) assert_eq!(as_fn_once(t, (24, 3)), 8); } -fn assert_panics(f: F) where F: FnOnce() { +fn assert_panics(f: F) +where + F: FnOnce(), +{ let f = panic::AssertUnwindSafe(f); - let result = panic::catch_unwind(move || { - f.0() - }); + let result = panic::catch_unwind(move || f.0()); if let Ok(..) = result { panic!("diverging function returned"); } } fn test_fn_ptr_panic(mut t: T) - where T: Fn() -> ! +where + T: Fn() -> !, { let as_fn = >::call; assert_panics(|| as_fn(&t, ())); diff --git a/src/test/ui/never_type/adjust_never.rs b/src/test/ui/never_type/adjust_never.rs index 0d7d2c0ed3fa9..e4d15c8a17dfa 100644 --- a/src/test/ui/never_type/adjust_never.rs +++ b/src/test/ui/never_type/adjust_never.rs @@ -2,8 +2,6 @@ // 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 index 84c8db4053e4f..ee801e1c5bf60 100644 --- a/src/test/ui/never_type/auto-traits.rs +++ b/src/test/ui/never_type/auto-traits.rs @@ -2,7 +2,6 @@ #![feature(optin_builtin_traits)] #![feature(negative_impls)] -#![feature(never_type)] fn main() { enum Void {} 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 index d06637e74a2f2..a2b44e91f1141 100644 --- 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 @@ -1,7 +1,5 @@ // Test that we can't pass other types for ! -#![feature(never_type)] - fn foo(x: !) -> ! { x } diff --git a/src/test/ui/never_type/call-fn-never-arg.rs b/src/test/ui/never_type/call-fn-never-arg.rs index 9d355817ee80d..55a7b79157a82 100644 --- a/src/test/ui/never_type/call-fn-never-arg.rs +++ b/src/test/ui/never_type/call-fn-never-arg.rs @@ -2,7 +2,6 @@ // check-pass -#![feature(never_type)] #![allow(unreachable_code)] fn foo(x: !) -> ! { diff --git a/src/test/ui/never_type/cast-never.rs b/src/test/ui/never_type/cast-never.rs index 0139ebe4640be..fbba114ab3274 100644 --- a/src/test/ui/never_type/cast-never.rs +++ b/src/test/ui/never_type/cast-never.rs @@ -2,8 +2,6 @@ // check-pass -#![feature(never_type)] - fn main() { let x: ! = panic!(); let y: u32 = x as u32; diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs index ea4881049d792..f323f40ba31c6 100644 --- a/src/test/ui/never_type/diverging-fallback-control-flow.rs +++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs @@ -4,27 +4,24 @@ #![allow(unused_assignments)] #![allow(unused_variables)] #![allow(unreachable_code)] - // Test various cases where we permit an unconstrained variable -// to fallback based on control-flow. -// -// These represent current behavior, but are pretty dubious. I would -// like to revisit these and potentially change them. --nmatsakis - +// 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 `()`. #![feature(never_type, never_type_fallback)] -trait BadDefault { +trait UnitDefault { fn default() -> Self; } -impl BadDefault for u32 { +impl UnitDefault for u32 { fn default() -> Self { 0 } } -impl BadDefault for ! { - fn default() -> ! { +impl UnitDefault for () { + fn default() -> () { panic!() } } @@ -33,7 +30,7 @@ fn assignment() { let x; if true { - x = BadDefault::default(); + x = UnitDefault::default(); } else { x = return; } @@ -45,13 +42,13 @@ fn assignment_rev() { if true { x = return; } else { - x = BadDefault::default(); + x = UnitDefault::default(); } } fn if_then_else() { let _x = if true { - BadDefault::default() + UnitDefault::default() } else { return; }; @@ -61,19 +58,19 @@ fn if_then_else_rev() { let _x = if true { return; } else { - BadDefault::default() + UnitDefault::default() }; } fn match_arm() { - let _x = match Ok(BadDefault::default()) { + let _x = match Ok(UnitDefault::default()) { Ok(v) => v, Err(()) => return, }; } fn match_arm_rev() { - let _x = match Ok(BadDefault::default()) { + let _x = match Ok(UnitDefault::default()) { Err(()) => return, Ok(v) => v, }; @@ -84,7 +81,7 @@ fn loop_break() { if false { break return; } else { - break BadDefault::default(); + break UnitDefault::default(); } }; } @@ -94,9 +91,9 @@ fn loop_break_rev() { if false { break return; } else { - break BadDefault::default(); + break UnitDefault::default(); } }; } -fn main() { } +fn main() {} 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 0000000000000..a3a15f0ed885d --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-no-leak.rs @@ -0,0 +1,15 @@ +#![feature(never_type_fallback)] + +fn make_unit() {} + +trait Test {} +impl Test for i32 {} +impl Test for () {} + +fn unconstrained_arg(_: T) {} + +fn main() { + // Here the type variable falls back to `!`, + // and hence we get a type error: + unconstrained_arg(return); //~ ERROR trait bound `!: Test` is not satisfied +} diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.stderr b/src/test/ui/never_type/diverging-fallback-no-leak.stderr new file mode 100644 index 0000000000000..9fcddc654610e --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-no-leak.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `!: Test` is not satisfied + --> $DIR/diverging-fallback-no-leak.rs:14:5 + | +LL | fn unconstrained_arg(_: T) {} + | ---- required by this bound in `unconstrained_arg` +... +LL | unconstrained_arg(return); + | ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!` + | + = note: the trait is implemented for `()`. Possibly this error has been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information). Consider whether you meant to use the type `()` here instead. + +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-unconstrained-return.rs b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs new file mode 100644 index 0000000000000..9a6c965cefb09 --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -0,0 +1,34 @@ +// 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 + +#![feature(never_type_fallback)] + +fn make_unit() {} + +trait UnitReturn {} +impl UnitReturn for i32 {} +impl UnitReturn for () {} + +fn unconstrained_return() -> 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/impl-for-never.rs b/src/test/ui/never_type/impl-for-never.rs index 9423f08858b9b..cbfda9a2cc00a 100644 --- a/src/test/ui/never_type/impl-for-never.rs +++ b/src/test/ui/never_type/impl-for-never.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(never_type)] - // Test that we can call static methods on ! both directly and when it appears in a generic trait StringifyType { diff --git a/src/test/ui/never_type/issue-44402.rs b/src/test/ui/never_type/issue-44402.rs index 699e480dfe7e5..f63974b465c5f 100644 --- a/src/test/ui/never_type/issue-44402.rs +++ b/src/test/ui/never_type/issue-44402.rs @@ -1,7 +1,6 @@ // check-pass #![allow(dead_code)] -#![feature(never_type)] #![feature(exhaustive_patterns)] // Regression test for inhabitedness check. The old @@ -14,20 +13,22 @@ struct Foo { } struct Bar { - field1: &'static Foo + field1: &'static Foo, } fn test_a() { let x: Option = None; - match x { None => () } + match x { + None => (), + } } fn test_b() { let x: Option = None; match x { Some(_) => (), - None => () + None => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/never_type/never-assign-dead-code.rs b/src/test/ui/never_type/never-assign-dead-code.rs index 7bb7c87097c50..5c1300c715128 100644 --- a/src/test/ui/never_type/never-assign-dead-code.rs +++ b/src/test/ui/never_type/never-assign-dead-code.rs @@ -2,7 +2,6 @@ // check-pass -#![feature(never_type)] #![warn(unused)] fn main() { diff --git a/src/test/ui/never_type/never-assign-wrong-type.rs b/src/test/ui/never_type/never-assign-wrong-type.rs index 67e26f5663f41..9ca1ac7462d4d 100644 --- a/src/test/ui/never_type/never-assign-wrong-type.rs +++ b/src/test/ui/never_type/never-assign-wrong-type.rs @@ -1,6 +1,5 @@ // Test that we can't use another type in place of ! -#![feature(never_type)] #![deny(warnings)] fn main() { diff --git a/src/test/ui/never_type/never-associated-type.rs b/src/test/ui/never_type/never-associated-type.rs index 3bb917c931635..45e54b9bf7c18 100644 --- a/src/test/ui/never_type/never-associated-type.rs +++ b/src/test/ui/never_type/never-associated-type.rs @@ -2,8 +2,6 @@ // check-pass -#![feature(never_type)] - trait Foo { type Wow; 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 index 9d16015bdc129..df74b6a53f888 100644 --- a/src/test/ui/never_type/never-from-impl-is-reserved.rs +++ b/src/test/ui/never_type/never-from-impl-is-reserved.rs @@ -1,7 +1,5 @@ // check that the `for T: From` impl is reserved -#![feature(never_type)] - pub struct MyFoo; pub trait MyTrait {} diff --git a/src/test/ui/never_type/never-result.rs b/src/test/ui/never_type/never-result.rs index 35af37910ef3e..c168a6ff71526 100644 --- a/src/test/ui/never_type/never-result.rs +++ b/src/test/ui/never_type/never-result.rs @@ -5,8 +5,6 @@ // Test that we can extract a ! through pattern matching then use it as several different types. -#![feature(never_type)] - fn main() { let x: Result = Ok(123); match x { @@ -16,6 +14,6 @@ fn main() { 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 index 13cd59e6aa9f1..3cbb114f43b94 100644 --- a/src/test/ui/never_type/never-type-arg.rs +++ b/src/test/ui/never_type/never-type-arg.rs @@ -2,8 +2,6 @@ // check-pass -#![feature(never_type)] - struct Wub; impl PartialEq for Wub { diff --git a/src/test/ui/never_type/never-type-rvalues.rs b/src/test/ui/never_type/never-type-rvalues.rs index 9ccc73dbf92d4..48fb9465138ee 100644 --- a/src/test/ui/never_type/never-type-rvalues.rs +++ b/src/test/ui/never_type/never-type-rvalues.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(never_type)] #![allow(dead_code)] #![allow(path_statements)] #![allow(unreachable_patterns)] @@ -30,9 +29,9 @@ fn never_slice(x: &[!]) { fn never_match(x: Result<(), !>) { match x { - Ok(_) => {}, - Err(_) => {}, + Ok(_) => {} + Err(_) => {} } } -pub fn main() { } +pub fn main() {} 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 index f2e9e087307db..36491bf7cb305 100644 --- a/src/test/ui/never_type/never-value-fallback-issue-66757.rs +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.rs @@ -6,8 +6,6 @@ // // run-pass -#![feature(never_type)] - // FIXME(#67225) -- this should be true even without the fallback gate. #![feature(never_type_fallback)] @@ -22,8 +20,8 @@ impl From for E { #[allow(unreachable_code)] #[allow(dead_code)] fn foo(never: !) { - >::from(never); // Ok - >::from(never); // Inference fails here + >::from(never); // Ok + >::from(never); // Inference fails here } -fn main() { } +fn main() {} diff --git a/src/test/ui/never_type/never_transmute_never.rs b/src/test/ui/never_type/never_transmute_never.rs index fce3ced9aac7f..3c850bfdb5755 100644 --- a/src/test/ui/never_type/never_transmute_never.rs +++ b/src/test/ui/never_type/never_transmute_never.rs @@ -1,8 +1,6 @@ // check-pass -#![crate_type="lib"] - -#![feature(never_type)] +#![crate_type = "lib"] #![allow(dead_code)] #![allow(unreachable_code)] #![allow(unused_variables)] @@ -16,8 +14,6 @@ pub fn f(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) - }; + let x: ! = unsafe { std::mem::transmute::(Foo) }; f(x) } diff --git a/src/test/ui/never_type/try_from.rs b/src/test/ui/never_type/try_from.rs index 50451576f9c97..d2aacf4c4be65 100644 --- a/src/test/ui/never_type/try_from.rs +++ b/src/test/ui/never_type/try_from.rs @@ -5,9 +5,7 @@ // 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}; +use std::convert::{Infallible, TryInto}; struct Foo { t: T, diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs index 7d1cac8a442f5..a909a784c9e4b 100644 --- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs +++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs @@ -2,8 +2,6 @@ // undecided. This test file currently checks a conservative choice. #![feature(exhaustive_patterns)] -#![feature(never_type)] - #![allow(dead_code)] #![allow(unreachable_code)] diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs index c5c3a214f9aff..a17e19e35b7e1 100644 --- a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs +++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs @@ -1,6 +1,4 @@ // aux-build:empty.rs -#![feature(never_type)] -#![feature(never_type_fallback)] #![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] @@ -9,19 +7,23 @@ extern crate empty; enum EmptyEnum {} struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here -union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here +union NonEmptyUnion1 { + //~ `NonEmptyUnion1` defined here foo: (), } -union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here +union NonEmptyUnion2 { + //~ `NonEmptyUnion2` defined here foo: (), bar: (), } -enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here +enum NonEmptyEnum1 { + //~ `NonEmptyEnum1` defined here Foo(bool), //~^ not covered //~| not covered } -enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here +enum NonEmptyEnum2 { + //~ `NonEmptyEnum2` defined here Foo(bool), //~^ not covered //~| not covered @@ -29,8 +31,13 @@ enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here //~^ not covered //~| not covered } -enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here - V1, V2, V3, V4, V5, +enum NonEmptyEnum5 { + //~ `NonEmptyEnum5` defined here + V1, + V2, + V3, + V4, + V5, } macro_rules! match_empty { @@ -49,30 +56,30 @@ macro_rules! match_false { fn empty_enum(x: EmptyEnum) { match x {} // ok match x { - _ => {}, //~ ERROR unreachable pattern + _ => {} //~ ERROR unreachable pattern } match x { - _ if false => {}, //~ ERROR unreachable pattern + _ if false => {} //~ ERROR unreachable pattern } } fn empty_foreign_enum(x: empty::EmptyForeignEnum) { match x {} // ok match x { - _ => {}, //~ ERROR unreachable pattern + _ => {} //~ ERROR unreachable pattern } match x { - _ if false => {}, //~ ERROR unreachable pattern + _ if false => {} //~ ERROR unreachable pattern } } fn never(x: !) { match x {} // ok match x { - _ => {}, //~ ERROR unreachable pattern + _ => {} //~ ERROR unreachable pattern } match x { - _ if false => {}, //~ ERROR unreachable pattern + _ if false => {} //~ ERROR unreachable pattern } } diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs index 10ea2a10406e3..968ef04bec031 100644 --- a/src/test/ui/pattern/usefulness/match-empty.rs +++ b/src/test/ui/pattern/usefulness/match-empty.rs @@ -1,6 +1,4 @@ // aux-build:empty.rs -#![feature(never_type)] -#![feature(never_type_fallback)] #![deny(unreachable_patterns)] extern crate empty; @@ -8,19 +6,23 @@ extern crate empty; enum EmptyEnum {} struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here -union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here +union NonEmptyUnion1 { + //~ `NonEmptyUnion1` defined here foo: (), } -union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here +union NonEmptyUnion2 { + //~ `NonEmptyUnion2` defined here foo: (), bar: (), } -enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here +enum NonEmptyEnum1 { + //~ `NonEmptyEnum1` defined here Foo(bool), //~^ not covered //~| not covered } -enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here +enum NonEmptyEnum2 { + //~ `NonEmptyEnum2` defined here Foo(bool), //~^ not covered //~| not covered @@ -28,8 +30,13 @@ enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here //~^ not covered //~| not covered } -enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here - V1, V2, V3, V4, V5, +enum NonEmptyEnum5 { + //~ `NonEmptyEnum5` defined here + V1, + V2, + V3, + V4, + V5, } macro_rules! match_empty { @@ -48,30 +55,30 @@ macro_rules! match_false { fn empty_enum(x: EmptyEnum) { match x {} // ok match x { - _ => {}, //~ ERROR unreachable pattern + _ => {} //~ ERROR unreachable pattern } match x { - _ if false => {}, //~ ERROR unreachable pattern + _ if false => {} //~ ERROR unreachable pattern } } fn empty_foreign_enum(x: empty::EmptyForeignEnum) { match x {} // ok match x { - _ => {}, //~ ERROR unreachable pattern + _ => {} //~ ERROR unreachable pattern } match x { - _ if false => {}, //~ ERROR unreachable pattern + _ if false => {} //~ ERROR unreachable pattern } } fn never(x: !) { match x {} // ok match x { - _ => {}, //~ ERROR unreachable pattern + _ => {} //~ ERROR unreachable pattern } match x { - _ if false => {}, //~ ERROR unreachable pattern + _ if false => {} //~ ERROR unreachable pattern } } diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.rs b/src/test/ui/pattern/usefulness/match-privately-empty.rs index 315eb03d16564..520df830f0291 100644 --- a/src/test/ui/pattern/usefulness/match-privately-empty.rs +++ b/src/test/ui/pattern/usefulness/match-privately-empty.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![feature(exhaustive_patterns)] mod private { @@ -11,11 +10,8 @@ mod private { fn main() { match private::DATA { - //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered + //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered None => {} - Some(private::Private { - misc: false, - .. - }) => {} + Some(private::Private { misc: false, .. }) => {} } } diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index c234547bd14b1..55c2121247d8b 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -4,7 +4,6 @@ // ^-- needed because `--pass check` does not emit the output needed. // FIXME: consider using an attribute instead of side-effects. -#![feature(never_type)] #![feature(start)] #[start] diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs index b45e5daf42c8d..640c2a2cf8fcc 100644 --- a/src/test/ui/reachable/expr_add.rs +++ b/src/test/ui/reachable/expr_add.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![deny(unreachable_code)] diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs index e547f75e2697b..293af24ce9008 100644 --- a/src/test/ui/reachable/expr_assign.rs +++ b/src/test/ui/reachable/expr_assign.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] @@ -23,7 +22,10 @@ fn bar() { fn baz() { let mut i = 0; - *{return; &mut i} = 22; //~ ERROR unreachable + *{ + return; + &mut i + } = 22; //~ ERROR unreachable } -fn main() { } +fn main() {} diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs index 1eaa96c3ce773..88c21a9198003 100644 --- a/src/test/ui/reachable/expr_call.rs +++ b/src/test/ui/reachable/expr_call.rs @@ -1,12 +1,11 @@ -#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -fn foo(x: !, y: usize) { } +fn foo(x: !, y: usize) {} -fn bar(x: !) { } +fn bar(x: !) {} fn a() { // the `22` is unreachable: @@ -18,4 +17,4 @@ fn b() { bar(return); //~ ERROR unreachable } -fn main() { } +fn main() {} diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs index d917df05b3c3d..07b2042725750 100644 --- a/src/test/ui/reachable/expr_method.rs +++ b/src/test/ui/reachable/expr_method.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] @@ -7,8 +6,8 @@ struct Foo; impl Foo { - fn foo(&self, x: !, y: usize) { } - fn bar(&self, x: !) { } + fn foo(&self, x: !, y: usize) {} + fn bar(&self, x: !) {} } fn a() { @@ -21,4 +20,4 @@ fn b() { Foo.bar(return); //~ ERROR unreachable } -fn main() { } +fn main() {} diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index e229d22ebc798..6f221c360cb17 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/unwarned-match-on-never.rs b/src/test/ui/reachable/unwarned-match-on-never.rs index 71f8fe3a783e2..2ed51a2a7a6f3 100644 --- a/src/test/ui/reachable/unwarned-match-on-never.rs +++ b/src/test/ui/reachable/unwarned-match-on-never.rs @@ -1,8 +1,6 @@ #![deny(unreachable_code)] #![allow(dead_code)] -#![feature(never_type)] - fn foo(x: !) -> bool { // Explicit matches on the never type are unwarned. match x {} @@ -12,13 +10,14 @@ fn foo(x: !) -> bool { fn bar() { match (return) { - () => () //~ ERROR unreachable arm + () => (), //~ ERROR unreachable arm } } fn main() { return; - match () { //~ ERROR unreachable expression + match () { + //~ ERROR unreachable expression () => (), } } diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs index a2735d4cbfb29..905a59fd3408d 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs @@ -1,9 +1,7 @@ #![crate_type = "rlib"] -#![feature(never_type)] #[non_exhaustive] -pub enum UninhabitedEnum { -} +pub enum UninhabitedEnum {} #[non_exhaustive] pub struct UninhabitedStruct { @@ -14,13 +12,18 @@ pub struct UninhabitedStruct { pub struct UninhabitedTupleStruct(!); pub enum UninhabitedVariants { - #[non_exhaustive] Tuple(!), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Tuple(!), + #[non_exhaustive] + Struct { x: ! }, } pub enum PartiallyInhabitedVariants { Tuple(u8), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Struct { + x: !, + }, } pub struct IndirectUninhabitedEnum(UninhabitedEnum); diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs index 80b9dc4c1c338..b5f4357229d3e 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs @@ -1,13 +1,9 @@ // aux-build:uninhabited.rs -#![feature(never_type)] extern crate uninhabited; use uninhabited::{ - UninhabitedEnum, - UninhabitedStruct, - UninhabitedTupleStruct, - UninhabitedVariants, + UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct, UninhabitedVariants, }; // This test checks that uninhabited non-exhaustive types cannot coerce to any type, as the never diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs index 6b911dd989cc5..b7591d8a3d059 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs @@ -1,8 +1,5 @@ -#![feature(never_type)] - #[non_exhaustive] -pub enum UninhabitedEnum { -} +pub enum UninhabitedEnum {} #[non_exhaustive] pub struct UninhabitedTupleStruct(!); @@ -13,8 +10,10 @@ pub struct UninhabitedStruct { } pub enum UninhabitedVariants { - #[non_exhaustive] Tuple(!), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Tuple(!), + #[non_exhaustive] + Struct { x: ! }, } struct A; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs index 98a7fdbc5049a..c07b09c735dd3 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs @@ -1,12 +1,9 @@ // aux-build:uninhabited.rs -#![feature(never_type)] extern crate uninhabited; use uninhabited::{ - IndirectUninhabitedEnum, - IndirectUninhabitedStruct, - IndirectUninhabitedTupleStruct, + IndirectUninhabitedEnum, IndirectUninhabitedStruct, IndirectUninhabitedTupleStruct, IndirectUninhabitedVariants, }; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs index 8f090fe886a00..e46ac84e8afb4 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs @@ -1,8 +1,5 @@ -#![feature(never_type)] - #[non_exhaustive] -pub enum UninhabitedEnum { -} +pub enum UninhabitedEnum {} #[non_exhaustive] pub struct UninhabitedStruct { @@ -13,8 +10,10 @@ pub struct UninhabitedStruct { pub struct UninhabitedTupleStruct(!); pub enum UninhabitedVariants { - #[non_exhaustive] Tuple(!), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Tuple(!), + #[non_exhaustive] + Struct { x: ! }, } pub struct IndirectUninhabitedEnum(UninhabitedEnum); diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs index be86519ecb159..f82b851ceca9d 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs @@ -1,14 +1,11 @@ // aux-build:uninhabited.rs #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] extern crate uninhabited; use uninhabited::{ - IndirectUninhabitedEnum, - IndirectUninhabitedStruct, - IndirectUninhabitedTupleStruct, + IndirectUninhabitedEnum, IndirectUninhabitedStruct, IndirectUninhabitedTupleStruct, IndirectUninhabitedVariants, }; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs index 60289aa780378..d7b237b672d24 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs @@ -2,11 +2,9 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] #[non_exhaustive] -pub enum UninhabitedEnum { -} +pub enum UninhabitedEnum {} #[non_exhaustive] pub struct UninhabitedStruct { @@ -17,8 +15,10 @@ pub struct UninhabitedStruct { pub struct UninhabitedTupleStruct(!); pub enum UninhabitedVariants { - #[non_exhaustive] Tuple(!), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Tuple(!), + #[non_exhaustive] + Struct { x: ! }, } pub struct IndirectUninhabitedEnum(UninhabitedEnum); diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs index 230ac75298e72..2eb063d57545f 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs @@ -1,6 +1,5 @@ // aux-build:uninhabited.rs #![deny(unreachable_patterns)] -#![feature(never_type)] extern crate uninhabited; @@ -11,11 +10,11 @@ use uninhabited::PartiallyInhabitedVariants; pub fn foo(x: PartiallyInhabitedVariants) { match x { - PartiallyInhabitedVariants::Struct { .. } => {}, - PartiallyInhabitedVariants::Struct { .. } => {}, + PartiallyInhabitedVariants::Struct { .. } => {} + PartiallyInhabitedVariants::Struct { .. } => {} //~^ ERROR unreachable pattern - _ => {}, + _ => {} } } -fn main() { } +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs index e54098d4d48b9..fc19a64ff105b 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs @@ -1,13 +1,9 @@ // aux-build:uninhabited.rs -#![feature(never_type)] extern crate uninhabited; use uninhabited::{ - UninhabitedEnum, - UninhabitedStruct, - UninhabitedTupleStruct, - UninhabitedVariants, + UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct, UninhabitedVariants, }; struct A; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs index ebbdfba15f3a3..7608f0e3db00c 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs @@ -1,8 +1,5 @@ -#![feature(never_type)] - #[non_exhaustive] -pub enum UninhabitedEnum { -} +pub enum UninhabitedEnum {} #[non_exhaustive] pub struct UninhabitedStruct { @@ -13,8 +10,10 @@ pub struct UninhabitedStruct { pub struct UninhabitedTupleStruct(!); pub enum UninhabitedVariants { - #[non_exhaustive] Tuple(!), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Tuple(!), + #[non_exhaustive] + Struct { x: ! }, } struct A; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs index 900dfff652ea6..8265265e292f2 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs @@ -1,15 +1,11 @@ // aux-build:uninhabited.rs #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] extern crate uninhabited; use uninhabited::{ - UninhabitedEnum, - UninhabitedStruct, - UninhabitedTupleStruct, - UninhabitedVariants, + UninhabitedEnum, UninhabitedStruct, UninhabitedTupleStruct, UninhabitedVariants, }; struct A; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs index de5530485f3e6..884d092f1372e 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs @@ -2,11 +2,9 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] #[non_exhaustive] -pub enum UninhabitedEnum { -} +pub enum UninhabitedEnum {} #[non_exhaustive] pub struct UninhabitedStruct { @@ -17,8 +15,10 @@ pub struct UninhabitedStruct { pub struct UninhabitedTupleStruct(!); pub enum UninhabitedVariants { - #[non_exhaustive] Tuple(!), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Tuple(!), + #[non_exhaustive] + Struct { x: ! }, } struct A; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs index ffc496a975ecf..01e9f86d5564f 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs @@ -1,10 +1,8 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] #[non_exhaustive] -pub enum UninhabitedEnum { -} +pub enum UninhabitedEnum {} #[non_exhaustive] pub struct UninhabitedTupleStruct(!); @@ -15,13 +13,18 @@ pub struct UninhabitedStruct { } pub enum UninhabitedVariants { - #[non_exhaustive] Tuple(!), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Tuple(!), + #[non_exhaustive] + Struct { x: ! }, } pub enum PartiallyInhabitedVariants { Tuple(u8), - #[non_exhaustive] Struct { x: ! } + #[non_exhaustive] + Struct { + x: !, + }, } fn uninhabited_enum() -> Option { diff --git a/src/test/ui/statics/uninhabited-static.rs b/src/test/ui/statics/uninhabited-static.rs index cc78f6cfa53f7..8b459f26139db 100644 --- a/src/test/ui/statics/uninhabited-static.rs +++ b/src/test/ui/statics/uninhabited-static.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![deny(uninhabited_static)] enum Void {} diff --git a/src/test/ui/type-sizes.rs b/src/test/ui/type-sizes.rs index 73a11a5e743f6..6eab3b9782ef4 100644 --- a/src/test/ui/type-sizes.rs +++ b/src/test/ui/type-sizes.rs @@ -2,35 +2,62 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -#![feature(never_type)] use std::mem::size_of; use std::num::NonZeroU8; -struct t {a: u8, b: i8} -struct u {a: u8, b: i8, c: u8} -struct v {a: u8, b: i8, c: v2, d: u32} -struct v2 {u: char, v: u8} -struct w {a: isize, b: ()} -struct x {a: isize, b: (), c: ()} -struct y {x: isize} +struct t { + a: u8, + b: i8, +} +struct u { + a: u8, + b: i8, + c: u8, +} +struct v { + a: u8, + b: i8, + c: v2, + d: u32, +} +struct v2 { + u: char, + v: u8, +} +struct w { + a: isize, + b: (), +} +struct x { + a: isize, + b: (), + c: (), +} +struct y { + x: isize, +} enum e1 { - a(u8, u32), b(u32), c + a(u8, u32), + b(u32), + c, } enum e2 { - a(u32), b + a(u32), + b, } #[repr(C, u8)] enum e3 { - a([u16; 0], u8), b + a([u16; 0], u8), + b, } struct ReorderedStruct { a: u8, b: u16, - c: u8 + c: u8, } enum ReorderedEnum { @@ -43,22 +70,262 @@ enum ReorderedEnum2 { B(u16, u8, u16, u8), // 0x100 niche variants. - _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F, - _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F, - _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F, - _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F, - _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F, - _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F, - _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F, - _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F, - _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F, - _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F, - _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF, - _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF, - _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF, - _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF, - _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF, - _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF, + _00, + _01, + _02, + _03, + _04, + _05, + _06, + _07, + _08, + _09, + _0A, + _0B, + _0C, + _0D, + _0E, + _0F, + _10, + _11, + _12, + _13, + _14, + _15, + _16, + _17, + _18, + _19, + _1A, + _1B, + _1C, + _1D, + _1E, + _1F, + _20, + _21, + _22, + _23, + _24, + _25, + _26, + _27, + _28, + _29, + _2A, + _2B, + _2C, + _2D, + _2E, + _2F, + _30, + _31, + _32, + _33, + _34, + _35, + _36, + _37, + _38, + _39, + _3A, + _3B, + _3C, + _3D, + _3E, + _3F, + _40, + _41, + _42, + _43, + _44, + _45, + _46, + _47, + _48, + _49, + _4A, + _4B, + _4C, + _4D, + _4E, + _4F, + _50, + _51, + _52, + _53, + _54, + _55, + _56, + _57, + _58, + _59, + _5A, + _5B, + _5C, + _5D, + _5E, + _5F, + _60, + _61, + _62, + _63, + _64, + _65, + _66, + _67, + _68, + _69, + _6A, + _6B, + _6C, + _6D, + _6E, + _6F, + _70, + _71, + _72, + _73, + _74, + _75, + _76, + _77, + _78, + _79, + _7A, + _7B, + _7C, + _7D, + _7E, + _7F, + _80, + _81, + _82, + _83, + _84, + _85, + _86, + _87, + _88, + _89, + _8A, + _8B, + _8C, + _8D, + _8E, + _8F, + _90, + _91, + _92, + _93, + _94, + _95, + _96, + _97, + _98, + _99, + _9A, + _9B, + _9C, + _9D, + _9E, + _9F, + _A0, + _A1, + _A2, + _A3, + _A4, + _A5, + _A6, + _A7, + _A8, + _A9, + _AA, + _AB, + _AC, + _AD, + _AE, + _AF, + _B0, + _B1, + _B2, + _B3, + _B4, + _B5, + _B6, + _B7, + _B8, + _B9, + _BA, + _BB, + _BC, + _BD, + _BE, + _BF, + _C0, + _C1, + _C2, + _C3, + _C4, + _C5, + _C6, + _C7, + _C8, + _C9, + _CA, + _CB, + _CC, + _CD, + _CE, + _CF, + _D0, + _D1, + _D2, + _D3, + _D4, + _D5, + _D6, + _D7, + _D8, + _D9, + _DA, + _DB, + _DC, + _DD, + _DE, + _DF, + _E0, + _E1, + _E2, + _E3, + _E4, + _E5, + _E6, + _E7, + _E8, + _E9, + _EA, + _EB, + _EC, + _ED, + _EE, + _EF, + _F0, + _F1, + _F2, + _F3, + _F4, + _F5, + _F6, + _F7, + _F8, + _F9, + _FA, + _FB, + _FC, + _FD, + _FE, + _FF, } enum EnumEmpty {} @@ -100,7 +367,7 @@ enum NicheFilledEnumWithAbsentVariant { enum Option2 { Some(A, B), - None + None, } // Two layouts are considered for `CanBeNicheFilledButShouldnt`: @@ -113,11 +380,11 @@ enum Option2 { // allowing types like `Option>` to fit into 8 bytes. pub enum CanBeNicheFilledButShouldnt { A(NonZeroU8, u32), - B + B, } pub enum AlwaysTaggedBecauseItHasNoNiche { A(u8, u32), - B + B, } pub fn main() { @@ -130,8 +397,7 @@ pub fn main() { assert_eq!(size_of::(), 3 as usize); // Alignment causes padding before the char and the u32. - assert_eq!(size_of::(), - 16 as usize); + assert_eq!(size_of::(), 16 as usize); assert_eq!(size_of::(), size_of::()); assert_eq!(size_of::(), size_of::()); assert_eq!(size_of::(), size_of::()); @@ -147,7 +413,6 @@ pub fn main() { assert_eq!(size_of::(), 6); assert_eq!(size_of::(), 8); - assert_eq!(size_of::(), 0); assert_eq!(size_of::(), 0); assert_eq!(size_of::(), 0); @@ -155,8 +420,10 @@ pub fn main() { assert_eq!(size_of::(), 1); assert_eq!(size_of::(), 1); - assert_eq!(size_of::>(), - size_of::>()); + assert_eq!( + size_of::>(), + size_of::>() + ); assert_eq!(size_of::(), size_of::<&'static ()>()); assert_eq!(size_of::>>(), size_of::<(bool, &())>()); diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.rs b/src/test/ui/uninhabited/uninhabited-irrefutable.rs index 48cd92719b49a..84daa35484f81 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.rs +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![feature(exhaustive_patterns)] mod foo { diff --git a/src/test/ui/uninhabited/uninhabited-patterns.rs b/src/test/ui/uninhabited/uninhabited-patterns.rs index 58c726d2185c4..13369ba9517a4 100644 --- a/src/test/ui/uninhabited/uninhabited-patterns.rs +++ b/src/test/ui/uninhabited/uninhabited-patterns.rs @@ -1,8 +1,6 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(never_type)] #![feature(exhaustive_patterns)] - #![deny(unreachable_patterns)] mod foo { @@ -23,22 +21,22 @@ fn main() { let x: &[!] = &[]; match x { - &[] => (), - &[..] => (), //~ ERROR unreachable pattern + &[] => (), + &[..] => (), //~ ERROR unreachable pattern }; let x: Result, &[Result]> = Err(&[]); match x { - Ok(box _) => (), //~ ERROR unreachable pattern + Ok(box _) => (), //~ ERROR unreachable pattern Err(&[]) => (), - Err(&[..]) => (), //~ ERROR unreachable pattern + Err(&[..]) => (), //~ ERROR unreachable pattern } let x: Result> = Err(Err(123)); match x { Ok(_y) => (), Err(Err(_y)) => (), - Err(Ok(_y)) => (), //~ ERROR unreachable pattern + Err(Ok(_y)) => (), //~ ERROR unreachable pattern } while let Some(_y) = foo() { diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index a249117d182fa..07df43b76deb6 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -27,8 +27,6 @@ declare_clippy_lint! { /// /// Good: /// ```rust - /// #![feature(never_type)] - /// /// struct Test(!); /// ``` pub EMPTY_ENUM, diff --git a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs index 7cb7d0a26b65e..449531380fff4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs @@ -1,8 +1,8 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ - Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, + Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, + Terminator, TerminatorKind, }; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; @@ -27,9 +27,18 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult { | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue, - ty::PredicateAtom::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate), - ty::PredicateAtom::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate), - ty::PredicateAtom::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate), + ty::PredicateAtom::ObjectSafe(_) => { + panic!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::ClosureKind(..) => { + panic!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Subtype(_) => { + panic!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Coerce(_) => { + panic!("coerce predicate on function: {:#?}", predicate) + } ty::PredicateAtom::Trait(pred, _) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; @@ -45,12 +54,12 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult { on const fn parameters are unstable" .into(), )); - }, + } // other kinds of bounds are either tautologies // or cause errors in other passes _ => continue, } - }, + } } } match predicates.parent { @@ -91,22 +100,23 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { match ty.kind() { ty::Ref(_, _, hir::Mutability::Mut) => { return Err((span, "mutable references in const fn are unstable".into())); - }, + } ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { return Err((span, "function pointers in const fn are unstable".into())); - }, + } ty::Dynamic(preds, _) => { for pred in preds.iter() { match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { + ty::ExistentialPredicate::AutoTrait(_) + | ty::ExistentialPredicate::Projection(_) => { return Err(( span, "trait bounds other than `Sized` \ on const fn parameters are unstable" .into(), )); - }, + } ty::ExistentialPredicate::Trait(trait_ref) => { if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { return Err(( @@ -116,23 +126,34 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { .into(), )); } - }, + } } } - }, - _ => {}, + } + _ => {} } } Ok(()) } -fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span) -> McfResult { +fn check_rvalue( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + def_id: DefId, + rvalue: &Rvalue<'tcx>, + span: Span, +) -> McfResult { match rvalue { - Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), - Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body), - Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - check_place(tcx, *place, span, body) - }, + Rvalue::ThreadLocalRef(_) => { + Err((span, "cannot access thread local storage in const fn".into())) + } + Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { + check_operand(tcx, operand, span, body) + } + Rvalue::Len(place) + | Rvalue::Discriminant(place) + | Rvalue::Ref(_, _, place) + | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc_middle::ty::cast::CastTy; let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast"); @@ -140,16 +161,20 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv match (cast_in, cast_out) { (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { Err((span, "casting pointers to ints is unstable in const fn".into())) - }, + } _ => check_operand(tcx, operand, span, body), } - }, - Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => { - check_operand(tcx, operand, span, body) - }, + } + Rvalue::Cast( + CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), + operand, + _, + ) => check_operand(tcx, operand, span, body), Rvalue::Cast( CastKind::Pointer( - PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, + PointerCast::UnsafeFnPointer + | PointerCast::ClosureFnPointer(_) + | PointerCast::ReifyFnPointer, ), _, _, @@ -159,7 +184,10 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv deref_ty.ty } else { // We cannot allow this for now. - return Err((span, "unsizing casts are only allowed for references right now".into())); + return Err(( + span, + "unsizing casts are only allowed for references right now".into(), + )); }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { @@ -170,7 +198,7 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv // We just can't allow trait objects until we have figured out trait method calls. Err((span, "unsizing casts are not allowed in const fn".into())) } - }, + } // binops are fine on integers Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { check_operand(tcx, lhs, span, body)?; @@ -179,14 +207,13 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { - Err(( - span, - "only int, `bool` and `char` operations are stable in const fn".into(), - )) + Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) } - }, + } Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()), - Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())), + Rvalue::NullaryOp(NullOp::Box, _) => { + Err((span, "heap allocations are not allowed in const fn".into())) + } Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { @@ -194,17 +221,22 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } - }, + } Rvalue::Aggregate(_, operands) => { for operand in operands { check_operand(tcx, operand, span, body)?; } Ok(()) - }, + } } } -fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>) -> McfResult { +fn check_statement( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + def_id: DefId, + statement: &Statement<'tcx>, +) -> McfResult { let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(box (place, rval)) => { @@ -228,7 +260,12 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen } } -fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { +fn check_operand( + tcx: TyCtxt<'tcx>, + operand: &Operand<'tcx>, + span: Span, + body: &Body<'tcx>, +) -> McfResult { match operand { Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { @@ -251,19 +288,23 @@ fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'t return Err((span, "accessing union fields is unstable".into())); } } - }, + } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref - | ProjectionElem::Index(_) => {}, + | ProjectionElem::Index(_) => {} } } Ok(()) } -fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Terminator<'tcx>) -> McfResult { +fn check_terminator( + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + terminator: &Terminator<'tcx>, +) -> McfResult { let span = terminator.source_info.span; match &terminator.kind { TerminatorKind::FalseEdge { .. } @@ -277,18 +318,16 @@ fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Termin TerminatorKind::DropAndReplace { place, value, .. } => { check_place(tcx, *place, span, body)?; check_operand(tcx, value, span, body) - }, + } - TerminatorKind::SwitchInt { - discr, - switch_ty: _, - targets: _, - } => check_operand(tcx, discr, span, body), + TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => { + check_operand(tcx, discr, span, body) + } TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) - }, + } TerminatorKind::Call { func, @@ -316,7 +355,9 @@ fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Termin // within const fns. `transmute` is allowed in all other const contexts. // This won't really scale to more intrinsics or functions. Let's allow const // transmutes in const fn before we add more hacks to this. - if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute { + if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic + && tcx.item_name(fn_def_id) == sym::transmute + { return Err(( span, "can only call `transmute` from const items, not `const fn`".into(), @@ -332,16 +373,14 @@ fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Termin } else { Err((span, "can only call other const fns within const fn".into())) } - }, + } - TerminatorKind::Assert { - cond, - expected: _, - msg: _, - target: _, - cleanup: _, - } => check_operand(tcx, cond, span, body), + TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { + check_operand(tcx, cond, span, body) + } - TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), + TerminatorKind::InlineAsm { .. } => { + Err((span, "cannot use inline assembly in const fn".into())) + } } } diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed index 9556f6f82cc63..db4142f19262c 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.fixed +++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed @@ -1,5 +1,4 @@ // run-rustfix -#![feature(never_type)] #![allow(unused_mut, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs index 3732422017104..99426384fabee 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.rs +++ b/src/tools/clippy/tests/ui/must_use_candidates.rs @@ -1,5 +1,4 @@ // run-rustfix -#![feature(never_type)] #![allow(unused_mut, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs index b197c609d7bfc..c00bd437588c4 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs @@ -1,5 +1,4 @@ #![warn(clippy::result_map_unit_fn)] -#![feature(never_type)] #![allow(unused)] struct HasResult {