]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #35162 - canndrew:bang_type_coerced, r=nikomatsakis
authorbors <bors@rust-lang.org>
Tue, 16 Aug 2016 07:12:12 +0000 (00:12 -0700)
committerGitHub <noreply@github.com>
Tue, 16 Aug 2016 07:12:12 +0000 (00:12 -0700)
Implement the `!` type

This implements the never type (`!`) and hides it behind the feature gate `#[feature(never_type)]`. With the feature gate off, things should build as normal (although some error messages may be different). With the gate on, `!` is usable as a type and diverging type variables (ie. types that are unconstrained by anything in the code) will default to `!` instead of `()`.

138 files changed:
src/libcore/cmp.rs
src/libcore/fmt/mod.rs
src/libcore/lib.rs
src/librustc/cfg/construct.rs
src/librustc/hir/fold.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc/infer/error_reporting.rs
src/librustc/infer/freshen.rs
src/librustc/infer/mod.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/intrinsicck.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/mir/repr.rs
src/librustc/mir/tcx.rs
src/librustc/mir/visit.rs
src/librustc/traits/coherence.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/object_safety.rs
src/librustc/traits/select.rs
src/librustc/traits/util.rs
src/librustc/ty/adjustment.rs
src/librustc/ty/contents.rs
src/librustc/ty/context.rs
src/librustc/ty/error.rs
src/librustc/ty/fast_reject.rs
src/librustc/ty/flags.rs
src/librustc/ty/fold.rs
src/librustc/ty/item_path.rs
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc/ty/outlives.rs
src/librustc/ty/relate.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/sty.rs
src/librustc/ty/util.rs
src/librustc/ty/walk.rs
src/librustc/ty/wf.rs
src/librustc/util/ppaux.rs
src/librustc_borrowck/borrowck/mir/gather_moves.rs
src/librustc_const_eval/check_match.rs
src/librustc_driver/test.rs
src/librustc_lint/builtin.rs
src/librustc_lint/types.rs
src/librustc_lint/unused.rs
src/librustc_metadata/astencode.rs
src/librustc_metadata/tydecode.rs
src/librustc_metadata/tyencode.rs
src/librustc_mir/build/expr/as_lvalue.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/expr/category.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/graphviz.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/mod.rs
src/librustc_mir/pretty.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/type_check.rs
src/librustc_passes/consts.rs
src/librustc_privacy/lib.rs
src/librustc_save_analysis/lib.rs
src/librustc_trans/_match.rs
src/librustc_trans/abi.rs
src/librustc_trans/base.rs
src/librustc_trans/callee.rs
src/librustc_trans/closure.rs
src/librustc_trans/collector.rs
src/librustc_trans/common.rs
src/librustc_trans/consts.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/debuginfo/mod.rs
src/librustc_trans/debuginfo/type_names.rs
src/librustc_trans/declare.rs
src/librustc_trans/expr.rs
src/librustc_trans/intrinsic.rs
src/librustc_trans/mir/analyze.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/mod.rs
src/librustc_trans/trans_item.rs
src/librustc_trans/type_of.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustc_typeck/lib.rs
src/librustc_typeck/variance/constraints.rs
src/librustdoc/clean/mod.rs
src/librustdoc/html/format.rs
src/libsyntax/ast.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/compile-fail/E0166.rs [deleted file]
src/test/compile-fail/bad-bang-ann-3.rs [deleted file]
src/test/compile-fail/bad-bang-ann.rs [deleted file]
src/test/compile-fail/bang-tailexpr.rs [deleted file]
src/test/compile-fail/call-fn-never-arg-wrong-type.rs [new file with mode: 0644]
src/test/compile-fail/issue-20105.rs [deleted file]
src/test/compile-fail/issue-897-2.rs [deleted file]
src/test/compile-fail/issue-897.rs [deleted file]
src/test/compile-fail/liveness-bad-bang-2.rs [deleted file]
src/test/compile-fail/loop-does-not-diverge.rs [deleted file]
src/test/compile-fail/loop-properly-diverging.rs [deleted file]
src/test/compile-fail/never-assign-dead-code.rs [new file with mode: 0644]
src/test/compile-fail/never-assign-wrong-type.rs [new file with mode: 0644]
src/test/compile-fail/never-disabled.rs [new file with mode: 0644]
src/test/compile-fail/never-fallback.rs [new file with mode: 0644]
src/test/compile-fail/return-from-diverging.rs [new file with mode: 0644]
src/test/compile-fail/return-unit-from-diverging.rs [new file with mode: 0644]
src/test/run-fail/adjust_never.rs [new file with mode: 0644]
src/test/run-fail/call-fn-never-arg.rs [new file with mode: 0644]
src/test/run-fail/cast-never.rs [new file with mode: 0644]
src/test/run-fail/never-associated-type.rs [new file with mode: 0644]
src/test/run-fail/never-type-arg.rs [new file with mode: 0644]
src/test/run-fail/return-never-coerce.rs [new file with mode: 0644]
src/test/run-pass/impl-for-never.rs [new file with mode: 0644]
src/test/run-pass/issue-10714.rs [deleted file]
src/test/run-pass/never-result.rs [new file with mode: 0644]
src/test/run-pass/never_coercions.rs [new file with mode: 0644]
src/test/run-pass/unit-fallback.rs [new file with mode: 0644]

index 8764766b2ef8675a04ea69be0b5bc3209fa162c1..bb7c971111853e2b612158d4a772835f5cbc7b8a 100644 (file)
@@ -699,6 +699,39 @@ fn cmp(&self, other: &bool) -> Ordering {
 
     ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
 
+    // Note: This macro is a temporary hack that can be remove once we are building with a compiler
+    // that supports `!`
+    macro_rules! not_stage0 {
+        () => {
+            #[unstable(feature = "never_type", issue = "35121")]
+            impl PartialEq for ! {
+                fn eq(&self, _: &!) -> bool {
+                    *self
+                }
+            }
+
+            #[unstable(feature = "never_type", issue = "35121")]
+            impl Eq for ! {}
+
+            #[unstable(feature = "never_type", issue = "35121")]
+            impl PartialOrd for ! {
+                fn partial_cmp(&self, _: &!) -> Option<Ordering> {
+                    *self
+                }
+            }
+
+            #[unstable(feature = "never_type", issue = "35121")]
+            impl Ord for ! {
+                fn cmp(&self, _: &!) -> Ordering {
+                    *self
+                }
+            }
+        }
+    }
+
+    #[cfg(not(stage0))]
+    not_stage0!();
+
     // & pointers
 
     #[stable(feature = "rust1", since = "1.0.0")]
index 173c55e35d51e5a680cd62c84929e22caa798193..dbd715c722e13ebd4111aeb53ef2af8d70b2276a 100644 (file)
@@ -1363,6 +1363,29 @@ fn fmt(&self, f: &mut Formatter) -> Result { $tr::fmt(&**self, f) }
 
 fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
 
+// Note: This macro is a temporary hack that can be remove once we are building with a compiler
+// that supports `!`
+macro_rules! not_stage0 {
+    () => {
+        #[unstable(feature = "never_type", issue = "35121")]
+        impl Debug for ! {
+            fn fmt(&self, _: &mut Formatter) -> Result {
+                *self
+            }
+        }
+
+        #[unstable(feature = "never_type", issue = "35121")]
+        impl Display for ! {
+            fn fmt(&self, _: &mut Formatter) -> Result {
+                *self
+            }
+        }
+    }
+}
+
+#[cfg(not(stage0))]
+not_stage0!();
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Debug for bool {
     fn fmt(&self, f: &mut Formatter) -> Result {
index fabb3900ec6483be59ef239c86eed6202c15d68b..7831464756b940d91cee040e4e0f400b1ca035ce 100644 (file)
@@ -88,6 +88,9 @@
 #![feature(unboxed_closures)]
 #![feature(question_mark)]
 
+// NOTE: remove the cfg_attr next snapshot
+#![cfg_attr(not(stage0), feature(never_type))]
+
 #[macro_use]
 mod macros;
 
index 601d3866b02d452be8808bcb3db6c936fa03d771..232db76a6d175ac34394a9dcd118ccd2d92627b8 100644 (file)
@@ -379,7 +379,8 @@ fn call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
 
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
         let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
-        if fn_ty.fn_ret().diverges() {
+        // FIXME(canndrew): This is_never should probably be an is_uninhabited.
+        if fn_ty.fn_ret().0.is_never() {
             self.add_unreachable_node()
         } else {
             ret
index dd79e14f077e831c5949797dd4b62c4fc08c7bef..0edfd16bdfd1b7ca07d9e3af5d222e5a44e796d0 100644 (file)
@@ -353,6 +353,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
                         }
                     }))
                 }
+                TyNever => node,
                 TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))),
                 TyPath(qself, path) => {
                     let qself = qself.map(|QSelf { ty, position }| {
@@ -515,7 +516,6 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
             output: match output {
                 Return(ty) => Return(fld.fold_ty(ty)),
                 DefaultReturn(span) => DefaultReturn(span),
-                NoReturn(span) => NoReturn(span),
             },
             variadic: variadic,
         }
index 1162c290f9cfca675f63b14bb52fef53e050e59e..92b956788860ee1058d4c7fb9b773f72b2d70e19 100644 (file)
@@ -403,6 +403,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             walk_list!(visitor, visit_lifetime, opt_lifetime);
             visitor.visit_ty(&mutable_type.ty)
         }
+        TyNever => {},
         TyTup(ref tuple_element_types) => {
             walk_list!(visitor, visit_ty, tuple_element_types);
         }
index eb98ed77da703df241719e57999b9c37a460930d..c2b211238b2f1d1262ac1c812fa8a3667b6eac83 100644 (file)
@@ -270,6 +270,7 @@ fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
                         decl: self.lower_fn_decl(&f.decl),
                     }))
                 }
+                Never => hir::TyNever,
                 Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()),
                 Paren(ref ty) => {
                     return self.lower_ty(ty);
@@ -402,7 +403,6 @@ fn lower_fn_decl(&mut self, decl: &FnDecl) -> P<hir::FnDecl> {
             output: match decl.output {
                 FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
                 FunctionRetTy::Default(span) => hir::DefaultReturn(span),
-                FunctionRetTy::None(span) => hir::NoReturn(span),
             },
             variadic: decl.variadic,
         })
index 707ef987c2c06e1518c466bccad774f5a9765732..d41cdfabdf4c04a55b841385bb6dccadd131cd39 100644 (file)
@@ -1112,6 +1112,7 @@ pub struct BareFnTy {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 /// The different kinds of types recognized by the compiler
 pub enum Ty_ {
+    /// A variable length array (`[T]`)
     TyVec(P<Ty>),
     /// A fixed length array (`[T; n]`)
     TyFixedLengthVec(P<Ty>, P<Expr>),
@@ -1121,6 +1122,8 @@ pub enum Ty_ {
     TyRptr(Option<Lifetime>, MutTy),
     /// A bare function (e.g. `fn(usize) -> bool`)
     TyBareFn(P<BareFnTy>),
+    /// The never type (`!`)
+    TyNever,
     /// A tuple (`(A, B, C, D,...)`)
     TyTup(HirVec<P<Ty>>),
     /// A path (`module::module::...::Type`), optionally
@@ -1283,9 +1286,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum FunctionRetTy {
-    /// Functions with return type `!`that always
-    /// raise an error or exit (i.e. never return to the caller)
-    NoReturn(Span),
     /// Return type is not specified.
     ///
     /// Functions default to `()` and
@@ -1299,7 +1299,6 @@ pub enum FunctionRetTy {
 impl FunctionRetTy {
     pub fn span(&self) -> Span {
         match *self {
-            NoReturn(span) => span,
             DefaultReturn(span) => span,
             Return(ref ty) => ty.span,
         }
index 6dedae5ccd75d2761321976ae5a260c343ab7315..66c1bc7642c56b682ce9da0b33d4844483f4fedc 100644 (file)
@@ -504,6 +504,9 @@ pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
                 self.print_opt_lifetime(lifetime)?;
                 self.print_mt(mt)?;
             }
+            hir::TyNever => {
+                word(&mut self.s, "!")?;
+            },
             hir::TyTup(ref elts) => {
                 self.popen()?;
                 self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&ty))?;
@@ -1959,10 +1962,6 @@ pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
                 self.maybe_print_comment(ty.span.lo)
             }
             hir::DefaultReturn(..) => unreachable!(),
-            hir::NoReturn(span) => {
-                self.word_nbsp("!")?;
-                self.maybe_print_comment(span.lo)
-            }
         }
     }
 
@@ -2195,7 +2194,6 @@ pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
         self.ibox(indent_unit)?;
         self.word_space("->")?;
         match decl.output {
-            hir::NoReturn(_) => self.word_nbsp("!")?,
             hir::DefaultReturn(..) => unreachable!(),
             hir::Return(ref ty) => self.print_type(&ty)?,
         }
index 3ad5ef1e0ff6d438720898027ddbed945692dcde..b0dec3277a9967686ddaf937e825947a26267000 100644 (file)
@@ -1326,7 +1326,6 @@ fn rebuild_output(&self, ty: &hir::FunctionRetTy,
                 self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names)
             ),
             hir::DefaultReturn(span) => hir::DefaultReturn(span),
-            hir::NoReturn(span) => hir::NoReturn(span)
         }
     }
 
index 1fb4e59e13189ff07fc14de61e81f58142d9ecff..ecd9759c721b2f11062386e08b259c9249737f4c 100644 (file)
@@ -168,6 +168,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             ty::TyTrait(..) |
             ty::TyStruct(..) |
             ty::TyClosure(..) |
+            ty::TyNever |
             ty::TyTuple(..) |
             ty::TyProjection(..) |
             ty::TyParam(..) |
index 697478015cb7b65a496d0b88ec48555f25fa7e37..24fadc549fafc221e748cdaff099c9781863b5d4 100644 (file)
@@ -607,7 +607,6 @@ fn trans_normalize<'a, 'tcx>(&self,
     Ty<'gcx>,
     &'gcx Substs<'gcx>,
     ty::FnSig<'gcx>,
-    ty::FnOutput<'gcx>,
     &'gcx ty::BareFnTy<'gcx>,
     ty::ClosureSubsts<'gcx>,
     ty::PolyTraitRef<'gcx>
index 18b80a9636b45e0c2d91a605167bb4b127f2df96..87463055a276a76748f939b8d59e2aaa51c6f50f 100644 (file)
@@ -717,6 +717,7 @@ fn walk_adjustment(&mut self, expr: &hir::Expr) {
         let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone());
         if let Some(adjustment) = adj {
             match adjustment {
+                adjustment::AdjustNeverToAny(..) |
                 adjustment::AdjustReifyFnPointer |
                 adjustment::AdjustUnsafeFnPointer |
                 adjustment::AdjustMutToConstPointer => {
index 15f2f21ef25291b2c4df292dada02a9bcd701d19..a1a4f15b9f78edde483daf7e1dc857a613e66b09 100644 (file)
@@ -161,10 +161,9 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                     let typ = self.infcx.tcx.node_id_to_type(expr.id);
                     match typ.sty {
                         ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
-                            if let ty::FnConverging(to) = bare_fn_ty.sig.0.output {
-                                let from = bare_fn_ty.sig.0.inputs[0];
-                                self.check_transmute(expr.span, from, to, expr.id);
-                            }
+                            let from = bare_fn_ty.sig.0.inputs[0];
+                            let to = bare_fn_ty.sig.0.output;
+                            self.check_transmute(expr.span, from, to, expr.id);
                         }
                         _ => {
                             span_bug!(expr.span, "transmute wasn't a bare fn?!");
index f62c9a5d8823e7586b9d90b77aa420e62f80549c..74d29b273ff2b40c9d619275a163aadbddfd4978 100644 (file)
 use dep_graph::DepNode;
 use hir::def::*;
 use hir::pat_util;
-use ty::{self, TyCtxt, ParameterEnvironment};
+use ty::{self, Ty, TyCtxt, ParameterEnvironment};
 use traits::{self, Reveal};
 use ty::subst::Subst;
 use lint;
@@ -1111,8 +1111,9 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           }
 
           hir::ExprCall(ref f, ref args) => {
+            // FIXME(canndrew): This is_never should really be an is_uninhabited
             let diverges = !self.ir.tcx.is_method_call(expr.id) &&
-                self.ir.tcx.expr_ty_adjusted(&f).fn_ret().diverges();
+                self.ir.tcx.expr_ty_adjusted(&f).fn_ret().0.is_never();
             let succ = if diverges {
                 self.s.exit_ln
             } else {
@@ -1125,7 +1126,8 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           hir::ExprMethodCall(_, _, ref args) => {
             let method_call = ty::MethodCall::expr(expr.id);
             let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
-            let succ = if method_ty.fn_ret().diverges() {
+            // FIXME(canndrew): This is_never should really be an is_uninhabited
+            let succ = if method_ty.fn_ret().0.is_never() {
                 self.s.exit_ln
             } else {
                 succ
@@ -1454,7 +1456,7 @@ fn check_fn(_v: &Liveness,
 }
 
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
-    fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
+    fn fn_ret(&self, id: NodeId) -> ty::Binder<Ty<'tcx>> {
         let fn_ty = self.ir.tcx.node_id_to_type(id);
         match fn_ty.sty {
             ty::TyClosure(closure_def_id, substs) =>
@@ -1477,55 +1479,44 @@ fn check_ret(&self,
                 self.ir.tcx.region_maps.call_site_extent(id, body.id),
                 &self.fn_ret(id));
 
-        match fn_ret {
-            ty::FnConverging(t_ret)
-                    if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() => {
-
-                let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
-                let t_ret_subst = t_ret.subst(self.ir.tcx, &param_env.free_substs);
-                let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
-                                                    Reveal::All).enter(|infcx| {
-                    let cause = traits::ObligationCause::dummy();
-                    traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
-                });
-
-                // for nil return types, it is ok to not return a value expl.
-                if !is_nil {
-                    let ends_with_stmt = match body.expr {
-                        None if !body.stmts.is_empty() =>
-                            match body.stmts.last().unwrap().node {
-                                hir::StmtSemi(ref e, _) => {
-                                    self.ir.tcx.expr_ty(&e) == t_ret
-                                },
-                                _ => false
+        if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
+            let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
+            let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
+            let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
+                                                Reveal::All).enter(|infcx| {
+                let cause = traits::ObligationCause::dummy();
+                traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
+            });
+
+            // for nil return types, it is ok to not return a value expl.
+            if !is_nil {
+                let ends_with_stmt = match body.expr {
+                    None if !body.stmts.is_empty() =>
+                        match body.stmts.last().unwrap().node {
+                            hir::StmtSemi(ref e, _) => {
+                                self.ir.tcx.expr_ty(&e) == fn_ret
                             },
-                        _ => false
+                            _ => false
+                        },
+                    _ => false
+                };
+                let mut err = struct_span_err!(self.ir.tcx.sess,
+                                               sp,
+                                               E0269,
+                                               "not all control paths return a value");
+                if ends_with_stmt {
+                    let last_stmt = body.stmts.last().unwrap();
+                    let original_span = original_sp(self.ir.tcx.sess.codemap(),
+                                                    last_stmt.span, sp);
+                    let span_semicolon = Span {
+                        lo: original_span.hi - BytePos(1),
+                        hi: original_span.hi,
+                        expn_id: original_span.expn_id
                     };
-                    let mut err = struct_span_err!(self.ir.tcx.sess,
-                                                   sp,
-                                                   E0269,
-                                                   "not all control paths return a value");
-                    if ends_with_stmt {
-                        let last_stmt = body.stmts.last().unwrap();
-                        let original_span = original_sp(self.ir.tcx.sess.codemap(),
-                                                        last_stmt.span, sp);
-                        let span_semicolon = Span {
-                            lo: original_span.hi - BytePos(1),
-                            hi: original_span.hi,
-                            expn_id: original_span.expn_id
-                        };
-                        err.span_help(span_semicolon, "consider removing this semicolon:");
-                    }
-                    err.emit();
+                    err.span_help(span_semicolon, "consider removing this semicolon:");
                 }
+                err.emit();
             }
-            ty::FnDiverging
-                if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() => {
-                    span_err!(self.ir.tcx.sess, sp, E0270,
-                        "computation may converge in a function marked as diverging");
-                }
-
-            _ => {}
         }
     }
 
index 0bc3c1ae899dd267d235e507c18eaded12278d50..676e456dcea94e2ecaf96fe984b50d1dec27dd47 100644 (file)
@@ -451,6 +451,7 @@ pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
                         self.cat_expr_autoderefd(expr, autoderefs)
                     }
 
+                    adjustment::AdjustNeverToAny(..) |
                     adjustment::AdjustReifyFnPointer |
                     adjustment::AdjustUnsafeFnPointer |
                     adjustment::AdjustMutToConstPointer |
@@ -922,7 +923,7 @@ fn cat_deref<N:ast_node>(&self,
         let base_cmt = match method_ty {
             Some(method_ty) => {
                 let ref_ty =
-                    self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
+                    self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
                 self.cat_rvalue_node(node.id(), node.span(), ref_ty)
             }
             None => base_cmt
@@ -1244,7 +1245,6 @@ fn overloaded_method_return_ty(&self,
         // to skip past the binder.
         self.tcx().no_late_bound_regions(&method_ty.fn_ret())
            .unwrap()
-           .unwrap() // overloaded ops do not diverge, either
     }
 }
 
index 454c1ff816753cbcbc955048cd111e504891318c..2bde3d6554feef4400767c15037e19aa4e2955b6 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_data_structures::control_flow_graph::ControlFlowGraph;
 use hir::def_id::DefId;
 use ty::subst::Substs;
-use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
+use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
 use util::ppaux;
 use rustc_back::slice;
 use hir::InlineAsm;
@@ -74,7 +74,7 @@ pub struct Mir<'tcx> {
     pub promoted: IndexVec<Promoted, Mir<'tcx>>,
 
     /// Return type of the function.
-    pub return_ty: FnOutput<'tcx>,
+    pub return_ty: Ty<'tcx>,
 
     /// Variables: these are stack slots corresponding to user variables. They may be
     /// assigned many times.
@@ -107,7 +107,7 @@ impl<'tcx> Mir<'tcx> {
     pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
                visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
                promoted: IndexVec<Promoted, Mir<'tcx>>,
-               return_ty: FnOutput<'tcx>,
+               return_ty: Ty<'tcx>,
                var_decls: IndexVec<Var, VarDecl<'tcx>>,
                arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
                temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
index 534bb2c0b2b2a1fde84d4067c3376f7f21f759f3..cf91229f1c713afa07c4baf714e51d161baa4df7 100644 (file)
@@ -125,7 +125,7 @@ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Lval
             &Lvalue::Static(def_id) =>
                 LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
             &Lvalue::ReturnPointer =>
-                LvalueTy::Ty { ty: mir.return_ty.unwrap() },
+                LvalueTy::Ty { ty: mir.return_ty },
             &Lvalue::Projection(ref proj) =>
                 proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem),
         }
index d3526f618a904e142675f76838412ce1ed6523ea..ead8de86dbae4094f555d09068fde43057d6a0cf 100644 (file)
@@ -11,7 +11,7 @@
 use middle::const_val::ConstVal;
 use hir::def_id::DefId;
 use ty::subst::Substs;
-use ty::{ClosureSubsts, FnOutput, Region, Ty};
+use ty::{ClosureSubsts, Region, Ty};
 use mir::repr::*;
 use rustc_const_math::ConstUsize;
 use rustc_data_structures::tuple_slice::TupleSlice;
@@ -38,9 +38,7 @@
 //
 // For the most part, we do not destructure things external to the
 // MIR, e.g. types, spans, etc, but simply visit them and stop. This
-// avoids duplication with other visitors like `TypeFoldable`. But
-// there is one exception: we do destructure the `FnOutput` to reach
-// the type within. Just because.
+// avoids duplication with other visitors like `TypeFoldable`.
 //
 // ## Updating
 //
@@ -192,11 +190,6 @@ fn visit_source_info(&mut self,
                 self.super_source_info(source_info);
             }
 
-            fn visit_fn_output(&mut self,
-                               fn_output: & $($mutability)* FnOutput<'tcx>) {
-                self.super_fn_output(fn_output);
-            }
-
             fn visit_ty(&mut self,
                         ty: & $($mutability)* Ty<'tcx>) {
                 self.super_ty(ty);
@@ -261,7 +254,7 @@ fn super_mir(&mut self,
                     self.visit_visibility_scope_data(scope);
                 }
 
-                self.visit_fn_output(&$($mutability)* mir.return_ty);
+                self.visit_ty(&$($mutability)* mir.return_ty);
 
                 for var_decl in &$($mutability)* mir.var_decls {
                     self.visit_var_decl(var_decl);
@@ -708,16 +701,6 @@ fn super_source_info(&mut self, source_info: & $($mutability)* SourceInfo) {
                 self.visit_visibility_scope(scope);
             }
 
-            fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) {
-                match *fn_output {
-                    FnOutput::FnConverging(ref $($mutability)* ty) => {
-                        self.visit_ty(ty);
-                    }
-                    FnOutput::FnDiverging => {
-                    }
-                }
-            }
-
             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
             }
 
index 37193d45e68852245a523c298b94e01689ce8164..b38f5f96de4484c385f18c22b6ef4b4e420fc290 100644 (file)
@@ -253,6 +253,7 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)->
         ty::TySlice(..) |
         ty::TyRawPtr(..) |
         ty::TyRef(..) |
+        ty::TyNever |
         ty::TyTuple(..) |
         ty::TyParam(..) |
         ty::TyProjection(..) => {
index 09b5a34fdf33722cb048348fe8e70b16d6c13a3b..cf004767b2aaca0e11fc6d68664561c46ed3a8e4 100644 (file)
@@ -212,6 +212,7 @@ fn type_category<'tcx>(t: Ty<'tcx>) -> Option<u32> {
                 ty::TyProjection(..) => Some(13),
                 ty::TyParam(..) => Some(14),
                 ty::TyAnon(..) => Some(15),
+                ty::TyNever => Some(16),
                 ty::TyInfer(..) | ty::TyError => None
             }
         }
index 93c6dd09e07b83d2c450f2b97f223b6d8c828b29..4889895860129144dc323c6ce52ebde00b364c89 100644 (file)
@@ -269,10 +269,8 @@ fn virtual_call_violation_for_method(self,
                 return Some(MethodViolationCode::ReferencesSelf);
             }
         }
-        if let ty::FnConverging(result_type) = sig.0.output {
-            if self.contains_illegal_self_type_reference(trait_def_id, result_type) {
-                return Some(MethodViolationCode::ReferencesSelf);
-            }
+        if self.contains_illegal_self_type_reference(trait_def_id, sig.0.output) {
+            return Some(MethodViolationCode::ReferencesSelf);
         }
 
         // We can't monomorphize things like `fn foo<A>(...)`.
index 2df492e507bdcd5ea0b7757370201b18a997206c..b61cb0d3eee7217c17243564bee61a911ae706d9 100644 (file)
@@ -1388,7 +1388,7 @@ fn assemble_fn_pointer_candidates(&mut self,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
                     inputs: _,
-                    output: ty::FnConverging(_),
+                    output: _,
                     variadic: false
                 })
             }) |
@@ -1397,7 +1397,7 @@ fn assemble_fn_pointer_candidates(&mut self,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
                     inputs: _,
-                    output: ty::FnConverging(_),
+                    output: _,
                     variadic: false
                 })
             }) => {
@@ -1772,7 +1772,7 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
             ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
             ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
             ty::TyChar | ty::TyBox(_) | ty::TyRef(..) |
-            ty::TyArray(..) | ty::TyClosure(..) |
+            ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever |
             ty::TyError => {
                 // safe for everything
                 Where(ty::Binder(Vec::new()))
@@ -1820,7 +1820,7 @@ fn copy_conditions(&mut self, obligation: &TraitObligation<'tcx>)
             ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
             ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
             ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
-            ty::TyRawPtr(..) | ty::TyError |
+            ty::TyRawPtr(..) | ty::TyError | ty::TyNever |
             ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
                 Where(ty::Binder(Vec::new()))
             }
@@ -1886,6 +1886,7 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
             ty::TyError |
             ty::TyInfer(ty::IntVar(_)) |
             ty::TyInfer(ty::FloatVar(_)) |
+            ty::TyNever |
             ty::TyChar => {
                 Vec::new()
             }
index a097c0093b2e116ec470f8f8f270b74b6f67fdd9..818eb4eb2fb1e3cf1d30ce81d91d8f98852d67d5 100644 (file)
@@ -515,7 +515,7 @@ pub fn closure_trait_ref_and_return_type(self,
             def_id: fn_trait_def_id,
             substs: self.mk_substs(trait_substs),
         };
-        ty::Binder((trait_ref, sig.0.output.unwrap_or(self.mk_nil())))
+        ty::Binder((trait_ref, sig.0.output))
     }
 }
 
index 47ca7d335ab822b0c8b1a1bd40f1083c278fba3a..ae9fd5ab5bc87f79bef77f744f2f11632ce2ab59 100644 (file)
 
 #[derive(Copy, Clone)]
 pub enum AutoAdjustment<'tcx> {
-    AdjustReifyFnPointer,    // go from a fn-item type to a fn-pointer type
-    AdjustUnsafeFnPointer,   // go from a safe fn pointer to an unsafe fn pointer
-    AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer
+    AdjustNeverToAny(Ty<'tcx>), // go from ! to any type
+    AdjustReifyFnPointer,       // go from a fn-item type to a fn-pointer type
+    AdjustUnsafeFnPointer,      // go from a safe fn pointer to an unsafe fn pointer
+    AdjustMutToConstPointer,    // go from a mut raw pointer to a const raw pointer
     AdjustDerefRef(AutoDerefRef<'tcx>),
 }
 
@@ -106,6 +107,7 @@ pub struct AutoDerefRef<'tcx> {
 impl<'tcx> AutoAdjustment<'tcx> {
     pub fn is_identity(&self) -> bool {
         match *self {
+            AdjustNeverToAny(ty) => ty.is_never(),
             AdjustReifyFnPointer |
             AdjustUnsafeFnPointer |
             AdjustMutToConstPointer => false,
@@ -154,6 +156,8 @@ pub fn adjust<F>(&'tcx self,
         return match adjustment {
             Some(adjustment) => {
                 match *adjustment {
+                    AdjustNeverToAny(ref ty) => ty,
+
                     AdjustReifyFnPointer => {
                         match self.sty {
                             ty::TyFnDef(_, _, f) => tcx.mk_fn_ptr(f),
@@ -227,8 +231,7 @@ pub fn adjust_for_autoderef<F>(&'tcx self,
         if let Some(method_ty) = method_type(method_call) {
             // Method calls always have all late-bound regions
             // fully instantiated.
-            let fn_ret = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
-            adjusted_ty = fn_ret.unwrap();
+            adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
         }
         match adjusted_ty.builtin_deref(true, NoPreference) {
             Some(mt) => mt.ty,
index 8da7568c558a70b6d16b7fbcc8854122fd02c983..53bf046d6b597ed74acdb37792d5afd7c79f1492 100644 (file)
@@ -185,7 +185,7 @@ fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
                 // Scalar and unique types are sendable, and durable
                 ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
-                ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
+                ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever |
                 ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => {
                     TC::None
                 }
index 13401e91265eb9ac8db3f4ae39490b01ec67d0fd..4056fb01aa2c26fe73c4061f0d7b0b4fa18bd6c9 100644 (file)
@@ -190,6 +190,7 @@ pub struct CommonTypes<'tcx> {
     pub u64: Ty<'tcx>,
     pub f32: Ty<'tcx>,
     pub f64: Ty<'tcx>,
+    pub never: Ty<'tcx>,
     pub err: Ty<'tcx>,
 }
 
@@ -256,6 +257,7 @@ fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
         CommonTypes {
             bool: mk(TyBool),
             char: mk(TyChar),
+            never: mk(TyNever),
             err: mk(TyError),
             isize: mk(TyInt(ast::IntTy::Is)),
             i8: mk(TyInt(ast::IntTy::I8)),
@@ -975,7 +977,7 @@ pub fn go(tcx: TyCtxt) {
                 for &Interned(t) in tcx.interners.type_.borrow().iter() {
                     let variant = match t.sty {
                         ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
-                            ty::TyFloat(..) | ty::TyStr => continue,
+                            ty::TyFloat(..) | ty::TyStr | ty::TyNever => continue,
                         ty::TyError => /* unimportant */ continue,
                         $(ty::$variant(..) => &mut $variant,)*
                     };
@@ -1264,6 +1266,14 @@ pub fn mk_nil(self) -> Ty<'tcx> {
         self.mk_tup(Vec::new())
     }
 
+    pub fn mk_diverging_default(self) -> Ty<'tcx> {
+        if self.sess.features.borrow().never_type {
+            self.types.never
+        } else {
+            self.mk_nil()
+        }
+    }
+
     pub fn mk_bool(self) -> Ty<'tcx> {
         self.mk_ty(TyBool)
     }
index 6b34c0a21988dd81ecf6246b1aeee854cab71888..42d5788568f1c246ac72ae746c74452ffe0d1f2d 100644 (file)
@@ -214,7 +214,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
     fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String {
         match self.sty {
             ty::TyBool | ty::TyChar | ty::TyInt(_) |
-            ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr => self.to_string(),
+            ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(),
             ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(),
 
             ty::TyEnum(def, _) => format!("enum `{}`", tcx.item_path_str(def.did)),
index e6f2ba8b650f1c77851ceb6c3eeaaeee93489295..9bf2daeb5f49bfa38be179145515d2193c08e92d 100644 (file)
@@ -26,6 +26,7 @@ pub enum SimplifiedType {
     StrSimplifiedType,
     VecSimplifiedType,
     PtrSimplifiedType,
+    NeverSimplifiedType,
     TupleSimplifiedType(usize),
     TraitSimplifiedType(DefId),
     StructSimplifiedType(DefId),
@@ -81,6 +82,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyClosure(def_id, _) => {
             Some(ClosureSimplifiedType(def_id))
         }
+        ty::TyNever => Some(NeverSimplifiedType),
         ty::TyTuple(ref tys) => {
             Some(TupleSimplifiedType(tys.len()))
         }
index 85b7d66a2eb085e8a1740d66d87387479277f602..0997d6c1a7562e6b2055847f3c767e2e1ba35216 100644 (file)
@@ -60,6 +60,7 @@ fn add_sty(&mut self, st: &ty::TypeVariants) {
             &ty::TyInt(_) |
             &ty::TyFloat(_) |
             &ty::TyUint(_) |
+            &ty::TyNever |
             &ty::TyStr => {
             }
 
@@ -171,10 +172,7 @@ fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) {
         let mut computation = FlagComputation::new();
 
         computation.add_tys(&fn_sig.0.inputs);
-
-        if let ty::FnConverging(output) = fn_sig.0.output {
-            computation.add_ty(output);
-        }
+        computation.add_ty(fn_sig.0.output);
 
         self.add_bound_computation(&computation);
     }
index 3580013c2a9129aa973bf308a31b5bded98fb2a2..3eeff6ee5792fe716d07d61691d10e750a2692ee 100644 (file)
@@ -160,12 +160,6 @@ fn fold_fn_sig(&mut self,
         sig.super_fold_with(self)
     }
 
-    fn fold_output(&mut self,
-                      output: &ty::FnOutput<'tcx>)
-                      -> ty::FnOutput<'tcx> {
-        output.super_fold_with(self)
-    }
-
     fn fold_bare_fn_ty(&mut self,
                        fty: &'tcx ty::BareFnTy<'tcx>)
                        -> &'tcx ty::BareFnTy<'tcx>
index bfe6303d8a328a7bf8793d78a0c9a95853475a72..8ddd8bef36a6f7f006b9e3f95e5008f3348a439f 100644 (file)
@@ -349,6 +349,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
         ty::TyAnon(..) |
         ty::TyInfer(_) |
         ty::TyError |
+        ty::TyNever |
         ty::TyFloat(_) => None,
     }
 }
index d73e412f55f267c7b1e40d5c18ccb5890aa209ff..195cece6bc4e008eb125087a9bc94d063cad0844 100644 (file)
@@ -795,6 +795,9 @@ pub fn compute_uncached(ty: Ty<'gcx>,
             ty::TyFloat(FloatTy::F64) => Scalar { value: F64, non_zero: false },
             ty::TyFnPtr(_) => Scalar { value: Pointer, non_zero: true },
 
+            // The never type.
+            ty::TyNever => Univariant { variant: Struct::new(dl, false), non_zero: false },
+
             // Potentially-fat pointers.
             ty::TyBox(pointee) |
             ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
index 8e89b3c60879f4555d8f95d57493e61b44d2d38a..cfc2e89f9d5a126e10e22681c00076fb29710007 100644 (file)
@@ -55,7 +55,7 @@
 
 pub use self::sty::{Binder, DebruijnIndex};
 pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds};
-pub use self::sty::{BareFnTy, FnSig, PolyFnSig, FnOutput, PolyFnOutput};
+pub use self::sty::{BareFnTy, FnSig, PolyFnSig};
 pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy};
 pub use self::sty::{ClosureSubsts, TypeAndMut};
 pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
@@ -63,7 +63,6 @@
 pub use self::sty::Issue32330;
 pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
 pub use self::sty::BoundRegion::*;
-pub use self::sty::FnOutput::*;
 pub use self::sty::InferTy::*;
 pub use self::sty::Region::*;
 pub use self::sty::TypeVariants::*;
@@ -1854,7 +1853,7 @@ fn sized_constraint_for_ty(
         let result = match ty.sty {
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
             TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
-            TyArray(..) | TyClosure(..) => {
+            TyArray(..) | TyClosure(..) | TyNever => {
                 vec![]
             }
 
index df907c26f71420b3e091c36ab02c96d5e5df394a..ee431681ad100488cb8c49f63d5f9c89766ce529 100644 (file)
@@ -171,6 +171,7 @@ fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec<Component<'tcx>>) {
             ty::TyInt(..) |         // OutlivesScalar
             ty::TyUint(..) |        // OutlivesScalar
             ty::TyFloat(..) |       // OutlivesScalar
+            ty::TyNever |           // ...
             ty::TyEnum(..) |        // OutlivesNominalType
             ty::TyStruct(..) |      // OutlivesNominalType
             ty::TyBox(..) |         // OutlivesNominalType (ish)
index f9263947c0379c099562fc55c35046ffc025dd0e..05a9b8111570dd5830287269b8f957b914493379 100644 (file)
@@ -256,20 +256,11 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
         let inputs = relate_arg_vecs(relation,
                                      &a.inputs,
                                      &b.inputs)?;
+        let output = relation.relate(&a.output, &b.output)?;
 
-        let output = match (a.output, b.output) {
-            (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
-                Ok(ty::FnConverging(relation.relate(&a_ty, &b_ty)?)),
-            (ty::FnDiverging, ty::FnDiverging) =>
-                Ok(ty::FnDiverging),
-            (a, b) =>
-                Err(TypeError::ConvergenceMismatch(
-                    expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))),
-        }?;
-
-        return Ok(ty::FnSig {inputs: inputs,
-                             output: output,
-                             variadic: a.variadic});
+        Ok(ty::FnSig {inputs: inputs,
+                      output: output,
+                      variadic: a.variadic})
     }
 }
 
@@ -462,6 +453,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             Ok(tcx.types.err)
         }
 
+        (&ty::TyNever, _) |
         (&ty::TyChar, _) |
         (&ty::TyBool, _) |
         (&ty::TyInt(_), _) |
index 8c10806fda768a46c0e31a9103470d5273f939e5..83413d16ffb3ff448b02c8ec138ac04ec6b06524 100644 (file)
@@ -220,18 +220,6 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lif
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for ty::FnOutput<'a> {
-    type Lifted = ty::FnOutput<'tcx>;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        match *self {
-            ty::FnConverging(ty) => {
-                tcx.lift(&ty).map(ty::FnConverging)
-            }
-            ty::FnDiverging => Some(ty::FnDiverging)
-        }
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> {
     type Lifted = ty::FnSig<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@@ -498,7 +486,7 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
             ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)),
             ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
             ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
-            ty::TyParam(..) => self.sty.clone(),
+            ty::TyParam(..) | ty::TyNever => self.sty.clone(),
         };
         folder.tcx().mk_ty(sty)
     }
@@ -527,7 +515,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
             ty::TyAnon(_, ref substs) => substs.visit_with(visitor),
             ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
             ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
-            ty::TyParam(..) => false,
+            ty::TyParam(..) | ty::TyNever => false,
         }
     }
 
@@ -587,26 +575,6 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            ty::FnConverging(ref ty) => ty::FnConverging(ty.fold_with(folder)),
-            ty::FnDiverging => ty::FnDiverging
-        }
-    }
-
-    fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_output(self)
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match *self {
-            ty::FnConverging(ref ty) => ty.visit_with(visitor),
-            ty::FnDiverging => false,
-        }
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::FnSig { inputs: self.inputs.fold_with(folder),
index 912cb39face0a6d9ec910ce33194618826999551..9680632ec4dcc59cb901cc3822e025f511660940 100644 (file)
@@ -29,7 +29,6 @@
 
 use hir;
 
-use self::FnOutput::*;
 use self::InferTy::*;
 use self::TypeVariants::*;
 
@@ -159,6 +158,9 @@ pub enum TypeVariants<'tcx> {
     /// `|a| a`.
     TyClosure(DefId, ClosureSubsts<'tcx>),
 
+    /// The never type `!`
+    TyNever,
+
     /// A tuple type.  For example, `(i32, bool)`.
     TyTuple(&'tcx [Ty<'tcx>]),
 
@@ -474,47 +476,6 @@ pub struct ClosureTy<'tcx> {
     pub sig: PolyFnSig<'tcx>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub enum FnOutput<'tcx> {
-    FnConverging(Ty<'tcx>),
-    FnDiverging
-}
-
-impl<'tcx> FnOutput<'tcx> {
-    pub fn diverges(&self) -> bool {
-        *self == FnDiverging
-    }
-
-    pub fn unwrap(self) -> Ty<'tcx> {
-        match self {
-            ty::FnConverging(t) => t,
-            ty::FnDiverging => bug!()
-        }
-    }
-
-    pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> {
-        match self {
-            ty::FnConverging(t) => t,
-            ty::FnDiverging => def
-        }
-    }
-
-    pub fn maybe_converging(self) -> Option<Ty<'tcx>> {
-        match self {
-            ty::FnConverging(t) => Some(t),
-            ty::FnDiverging => None
-        }
-    }
-}
-
-pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
-
-impl<'tcx> PolyFnOutput<'tcx> {
-    pub fn diverges(&self) -> bool {
-        self.0.diverges()
-    }
-}
-
 /// Signature of a function type, which I have arbitrarily
 /// decided to use to refer to the input/output types.
 ///
@@ -524,7 +485,7 @@ pub fn diverges(&self) -> bool {
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct FnSig<'tcx> {
     pub inputs: Vec<Ty<'tcx>>,
-    pub output: FnOutput<'tcx>,
+    pub output: Ty<'tcx>,
     pub variadic: bool
 }
 
@@ -537,7 +498,7 @@ pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
     pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
         self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
     }
-    pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
+    pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
         self.map_bound_ref(|fn_sig| fn_sig.output.clone())
     }
     pub fn variadic(&self) -> bool {
@@ -933,11 +894,27 @@ pub fn is_nil(&self) -> bool {
         }
     }
 
-    pub fn is_empty(&self, _cx: TyCtxt) -> bool {
-        // FIXME(#24885): be smarter here
+    pub fn is_never(&self) -> bool {
+        match self.sty {
+            TyNever => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_uninhabited(&self, _cx: TyCtxt) -> bool {
+        // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made
+        // more complete.
         match self.sty {
             TyEnum(def, _) | TyStruct(def, _) => def.is_empty(),
-            _ => false
+
+            // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested
+            // and they don't break anything. But I'm keeping my changes small for now.
+            //TyNever => true,
+            //TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited(cx)),
+
+            // FIXME(canndrew): this line breaks core::fmt
+            //TyRef(_, ref tm) => tm.ty.is_uninhabited(cx),
+            _ => false,
         }
     }
 
@@ -1195,7 +1172,7 @@ pub fn fn_args(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
         self.fn_sig().inputs()
     }
 
-    pub fn fn_ret(&self) -> Binder<FnOutput<'tcx>> {
+    pub fn fn_ret(&self) -> Binder<Ty<'tcx>> {
         self.fn_sig().output()
     }
 
@@ -1260,6 +1237,7 @@ pub fn regions(&self) -> Vec<ty::Region> {
             TyArray(_, _) |
             TySlice(_) |
             TyRawPtr(_) |
+            TyNever |
             TyTuple(_) |
             TyParam(_) |
             TyInfer(_) |
index e7bcfbfd823453dd2893fae3044744e7a8ee4b5c..d7bb8ff2995aa17e359a97d15bc2879d7e795140 100644 (file)
@@ -485,6 +485,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
                 self.def_id(data.trait_ref.def_id);
                 self.hash(data.item_name.as_str());
             }
+            TyNever |
             TyBool |
             TyChar |
             TyStr |
@@ -550,7 +551,7 @@ pub fn moves_by_default(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         // Fast-path for primitive types
         let result = match self.sty {
-            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyNever |
             TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut {
                 mutbl: hir::MutImmutable, ..
             }) => Some(false),
@@ -596,7 +597,7 @@ fn is_sized_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let result = match self.sty {
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
             TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
-            TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true),
+            TyArray(..) | TyTuple(..) | TyClosure(..) | TyNever => Some(true),
 
             TyStr | TyTrait(..) | TySlice(_) => Some(false),
 
index ebc2642678bfd80bb3b9d0a794dd0704dc88c263..9c1f9d9537a4f2e7e8e2e3715312b0b36df08818 100644 (file)
@@ -70,7 +70,7 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter<Ty<'tcx>> {
 fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
     match parent_ty.sty {
         ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
-        ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyError => {
+        ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => {
         }
         ty::TyBox(ty) | ty::TyArray(ty, _) | ty::TySlice(ty) => {
             stack.push(ty);
@@ -110,10 +110,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
 }
 
 fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, sig: &ty::PolyFnSig<'tcx>) {
-    match sig.0.output {
-        ty::FnConverging(output) => { stack.push(output); }
-        ty::FnDiverging => { }
-    }
+    stack.push(sig.0.output);
     push_reversed(stack, &sig.0.inputs);
 }
 
index f6ddfe60d40e6804c7ffee6f72b0276a303bcbe6..bfc2e11d9fbcef7a56c49859ff3494f6be64fea8 100644 (file)
@@ -321,6 +321,7 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
                 ty::TyFloat(..) |
                 ty::TyError |
                 ty::TyStr |
+                ty::TyNever |
                 ty::TyParam(_) => {
                     // WfScalar, WfParameter, etc
                 }
index a17c01068139a376cd6c5b1aaa83d1a16e1fb57a..896ef49de6f05240d1bc2749effa35e262ddd9d9 100644 (file)
@@ -14,7 +14,7 @@
 use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
 use ty::{TyBool, TyChar, TyStruct, TyEnum};
 use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
-use ty::{TyParam, TyRawPtr, TyRef, TyTuple};
+use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
 use ty::TyClosure;
 use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -34,7 +34,7 @@ pub fn verbose() -> bool {
 fn fn_sig(f: &mut fmt::Formatter,
           inputs: &[Ty],
           variadic: bool,
-          output: ty::FnOutput)
+          output: Ty)
           -> fmt::Result {
     write!(f, "(")?;
     let mut inputs = inputs.iter();
@@ -48,18 +48,11 @@ fn fn_sig(f: &mut fmt::Formatter,
         }
     }
     write!(f, ")")?;
-
-    match output {
-        ty::FnConverging(ty) => {
-            if !ty.is_nil() {
-                write!(f, " -> {}", ty)?;
-            }
-            Ok(())
-        }
-        ty::FnDiverging => {
-            write!(f, " -> !")
-        }
+    if !output.is_nil() {
+        write!(f, " -> {}", output)?;
     }
+
+    Ok(())
 }
 
 /// Namespace of the path given to parameterized to print.
@@ -135,7 +128,7 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
     if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
         let projection_ty = projections[0].ty;
         if let TyTuple(ref args) = substs.types.get_slice(subst::TypeSpace)[0].sty {
-            return fn_sig(f, args, false, ty::FnConverging(projection_ty));
+            return fn_sig(f, args, false, projection_ty);
         }
     }
 
@@ -429,6 +422,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
+            ty::adjustment::AdjustNeverToAny(ref target) => {
+                write!(f, "AdjustNeverToAny({:?})", target)
+            }
             ty::adjustment::AdjustReifyFnPointer => {
                 write!(f, "AdjustReifyFnPointer")
             }
@@ -847,6 +843,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 }
                 write!(f, "{}", tm)
             }
+            TyNever => write!(f, "!"),
             TyTuple(ref tys) => {
                 write!(f, "(")?;
                 let mut tys = tys.iter();
index d2ef3356afb9d69973c508ecb2924bca70b7ea7a..8ae40e71bee58a6eac20fc76e55c66938aceab60 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 
-use rustc::ty::{FnOutput, TyCtxt};
+use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
 use rustc::util::nodemap::FnvHashMap;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@ -231,8 +231,7 @@ fn index(&self, i: MovePathIndex) -> &MovePath<'tcx> {
     }
 }
 
-struct MovePathDataBuilder<'a, 'tcx: 'a> {
-    mir: &'a Mir<'tcx>,
+struct MovePathDataBuilder<'tcx> {
     pre_move_paths: Vec<PreMovePath<'tcx>>,
     rev_lookup: MovePathLookup<'tcx>,
 }
@@ -412,7 +411,7 @@ pub fn find(&self, lval: &Lvalue<'tcx>) -> MovePathIndex {
     }
 }
 
-impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> {
+impl<'tcx> MovePathDataBuilder<'tcx> {
     fn lookup(&mut self, lval: &Lvalue<'tcx>) -> Lookup<MovePathIndex> {
         let proj = match *lval {
             Lvalue::Var(var_idx) =>
@@ -528,7 +527,6 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
     // BlockContexts constructed on each iteration. (Moving is more
     // straight-forward than mutable borrows in this instance.)
     let mut builder = MovePathDataBuilder {
-        mir: mir,
         pre_move_paths: Vec::new(),
         rev_lookup: MovePathLookup::new(mir),
     };
@@ -634,13 +632,8 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
             TerminatorKind::Return => {
                 let source = Location { block: bb,
                                         index: bb_data.statements.len() };
-                if let FnOutput::FnConverging(_) = bb_ctxt.builder.mir.return_ty {
-                    debug!("gather_moves Return on_move_out_lval return {:?}", source);
-                    bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source);
-                } else {
-                    debug!("gather_moves Return on_move_out_lval \
-                            assuming unreachable return {:?}", source);
-                }
+                debug!("gather_moves Return on_move_out_lval return {:?}", source);
+                bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source);
             }
 
             TerminatorKind::If { ref cond, targets: _ } => {
@@ -751,15 +744,15 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
     }
 }
 
-struct BlockContext<'b, 'a: 'b, 'tcx: 'a> {
+struct BlockContext<'b, 'tcx: 'b> {
     _tcx: TyCtxt<'b, 'tcx, 'tcx>,
     moves: &'b mut Vec<MoveOut>,
-    builder: MovePathDataBuilder<'a, 'tcx>,
+    builder: MovePathDataBuilder<'tcx>,
     path_map: &'b mut Vec<Vec<MoveOutIndex>>,
     loc_map_bb: &'b mut Vec<Vec<MoveOutIndex>>,
 }
 
-impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> {
+impl<'b, 'tcx: 'b> BlockContext<'b, 'tcx> {
     fn on_move_out_lval(&mut self,
                         stmt_kind: StmtKind,
                         lval: &Lvalue<'tcx>,
index 20673dc1e181addb0148222acba2c7c3edec2d24..bf6ebcb5efefb6e02bc4fb86281082299b4b11fd 100644 (file)
@@ -215,7 +215,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
             // Check for empty enum, because is_useful only works on inhabited types.
             let pat_ty = cx.tcx.node_id_to_type(scrut.id);
             if inlined_arms.is_empty() {
-                if !pat_ty.is_empty(cx.tcx) {
+                if !pat_ty.is_uninhabited(cx.tcx) {
                     // We know the type is inhabited, so this must be wrong
                     let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002,
                                                    "non-exhaustive patterns: type {} is non-empty",
@@ -225,7 +225,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
                          possibly adding wildcards or more match arms.");
                     err.emit();
                 }
-                // If the type *is* empty, it's vacuously exhaustive
+                // If the type *is* uninhabited, it's vacuously exhaustive
                 return;
             }
 
index 30fe38a0603a563f71791bc8ac58fa7124d80c5e..7711091685d3848d4cd43ed0d3c8dd94951c5cf7 100644 (file)
@@ -262,7 +262,7 @@ pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
             abi: Abi::Rust,
             sig: ty::Binder(ty::FnSig {
                 inputs: input_args,
-                output: ty::FnConverging(output_ty),
+                output: output_ty,
                 variadic: false,
             }),
         }))
index d8ec79fb0609680de5be956ab554eadc2335d468..ed17f3533d49f785750ff73ea7bac3b9aa63f098 100644 (file)
@@ -1110,10 +1110,9 @@ fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr)
                 let typ = cx.tcx.node_id_to_type(expr.id);
                 match typ.sty {
                     ty::TyFnDef(_, _, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
-                        if let ty::FnConverging(to) = bare_fn.sig.0.output {
-                            let from = bare_fn.sig.0.inputs[0];
-                            return Some((&from.sty, &to.sty));
-                        }
+                        let from = bare_fn.sig.0.inputs[0];
+                        let to = bare_fn.sig.0.output;
+                        return Some((&from.sty, &to.sty));
                     },
                     _ => ()
                 }
index b9861c309dbec985d3e467eb9c9032219ecbf336..99df5c6e5f95e591b7592d807862781e3f9a2974 100644 (file)
@@ -523,7 +523,7 @@ fn check_type_for_ffi(&self,
 
             // Primitive types with a stable representation.
             ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
-            ty::TyFloat(..) => FfiSafe,
+            ty::TyFloat(..) | ty::TyNever => FfiSafe,
 
             ty::TyBox(..) => {
                 FfiUnsafe("found Rust type Box<_> in foreign module, \
@@ -573,16 +573,11 @@ fn check_type_for_ffi(&self,
                 }
 
                 let sig = cx.erase_late_bound_regions(&bare_fn.sig);
-                match sig.output {
-                    ty::FnDiverging => {}
-                    ty::FnConverging(output) => {
-                        if !output.is_nil() {
-                            let r = self.check_type_for_ffi(cache, output);
-                            match r {
-                                FfiSafe => {}
-                                _ => { return r; }
-                            }
-                        }
+                if !sig.output.is_nil() {
+                    let r = self.check_type_for_ffi(cache, sig.output);
+                    match r {
+                        FfiSafe => {}
+                        _ => { return r; }
                     }
                 }
                 for arg in sig.inputs {
@@ -641,7 +636,7 @@ fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) {
         }
 
         if let hir::Return(ref ret_hir) = decl.output {
-            let ret_ty = sig.output.unwrap();
+            let ret_ty = sig.output;
             if !ret_ty.is_nil() {
                 self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
             }
index 4dc1a5e4f5e9f6dda3e8bc63fa9ffab1af28c15e..57705301aab4e55b27a5edb884c7ad1d9d2e0f5e 100644 (file)
@@ -133,6 +133,7 @@ fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
         let t = cx.tcx.expr_ty(&expr);
         let warned = match t.sty {
             ty::TyTuple(ref tys) if tys.is_empty() => return,
+            ty::TyNever => return,
             ty::TyBool => return,
             ty::TyStruct(def, _) |
             ty::TyEnum(def, _) => {
index f03c432c0917791c4a9ca8531517090785b32787..b8e66530ea1533c0e6299bc9b551a731efe30e0e 100644 (file)
@@ -644,6 +644,12 @@ fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
                             |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref)))
                     })
                 }
+
+                adjustment::AdjustNeverToAny(ref ty) => {
+                    this.emit_enum_variant("AdjustNeverToAny", 5, 1, |this| {
+                        this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, ty)))
+                    })
+                }
             }
         });
     }
@@ -1017,7 +1023,8 @@ fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
                                     -> adjustment::AutoAdjustment<'tcx> {
         self.read_enum("AutoAdjustment", |this| {
             let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer",
-                            "AdjustMutToConstPointer", "AdjustDerefRef"];
+                            "AdjustMutToConstPointer", "AdjustDerefRef",
+                            "AdjustNeverToAny"];
             this.read_enum_variant(&variants, |this, i| {
                 Ok(match i {
                     1 => adjustment::AdjustReifyFnPointer,
@@ -1030,6 +1037,13 @@ fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
 
                         adjustment::AdjustDerefRef(auto_deref_ref)
                     }
+                    5 => {
+                        let ty: Ty<'tcx> = this.read_enum_variant_arg(0, |this| {
+                            Ok(this.read_ty(dcx))
+                        }).unwrap();
+
+                        adjustment::AdjustNeverToAny(ty)
+                    }
                     _ => bug!("bad enum variant for adjustment::AutoAdjustment")
                 })
             })
index 1dcec35adb285554642a41712abcc6265d736166..7b4919bb4773be39e41447b8a37b47e299e8a0d4 100644 (file)
@@ -311,6 +311,7 @@ pub fn parse_ty(&mut self) -> Ty<'tcx> {
         let tcx = self.tcx;
         match self.next() {
             'b' => return tcx.types.bool,
+            '!' => return tcx.types.never,
             'i' => { /* eat the s of is */ self.next(); return tcx.types.isize },
             'u' => { /* eat the s of us */ self.next(); return tcx.types.usize },
             'M' => {
@@ -539,13 +540,7 @@ fn parse_sig(&mut self) -> ty::PolyFnSig<'tcx> {
             'N' => false,
             r => bug!("bad variadic: {}", r),
         };
-        let output = match self.peek() {
-            'z' => {
-                self.pos += 1;
-                ty::FnDiverging
-            }
-            _ => ty::FnConverging(self.parse_ty())
-        };
+        let output = self.parse_ty();
         ty::Binder(ty::FnSig {inputs: inputs,
                               output: output,
                               variadic: variadic})
index c2e91eba0d2523a600d322ccf35f1d548375958a..15bafcdd3c99e9e5d61378be03509da0d264a640 100644 (file)
@@ -74,6 +74,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
     match t.sty {
         ty::TyBool => { write!(w, "b"); }
         ty::TyChar => { write!(w, "c"); }
+        ty::TyNever => { write!(w, "!"); }
         ty::TyInt(t) => {
             match t {
                 ast::IntTy::Is => write!(w, "is"),
@@ -382,14 +383,7 @@ fn enc_fn_sig<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
     } else {
         write!(w, "N");
     }
-    match fsig.0.output {
-        ty::FnConverging(result_type) => {
-            enc_ty(w, cx, result_type);
-        }
-        ty::FnDiverging => {
-            write!(w, "z");
-        }
-    }
+    enc_ty(w, cx, fsig.0.output);
 }
 
 pub fn enc_builtin_bounds(w: &mut Cursor<Vec<u8>>, _cx: &ctxt, bs: &ty::BuiltinBounds) {
index dd6c9c02f56446e802a792f5490ba0cc1faf504b..ae5ccbfd820996f8c1b582e66a501032f538797f 100644 (file)
@@ -96,6 +96,7 @@ fn expr_as_lvalue(&mut self,
             ExprKind::LogicalOp { .. } |
             ExprKind::Box { .. } |
             ExprKind::Cast { .. } |
+            ExprKind::NeverToAny { .. } |
             ExprKind::ReifyFnPointer { .. } |
             ExprKind::UnsafeFnPointer { .. } |
             ExprKind::Unsize { .. } |
index f1487992cb52285365e549e458484be1765592ce..dafc53d3c154208e518295b293d0a51d42a3105f 100644 (file)
@@ -219,6 +219,7 @@ fn expr_as_rvalue(&mut self,
             ExprKind::Block { .. } |
             ExprKind::Match { .. } |
             ExprKind::If { .. } |
+            ExprKind::NeverToAny { .. } |
             ExprKind::Loop { .. } |
             ExprKind::LogicalOp { .. } |
             ExprKind::Call { .. } |
index 658b7779b44a947f1bf8b7be40a983bcc14cff6f..c19ea0f445ac0ce8b60b7fb83dcc2f2297f59d9f 100644 (file)
@@ -56,6 +56,7 @@ pub fn of<'tcx>(ek: &ExprKind<'tcx>) -> Option<Category> {
             ExprKind::LogicalOp { .. } |
             ExprKind::If { .. } |
             ExprKind::Match { .. } |
+            ExprKind::NeverToAny { .. } |
             ExprKind::Call { .. } =>
                 Some(Category::Rvalue(RvalueFunc::Into)),
 
index fd9ddc05ab5c4cfb3533fc42aadc4b2fce37d07d..e5930f5a62df6da0c240e2459d2ef1e37bdb9576 100644 (file)
@@ -45,6 +45,25 @@ pub fn into_expr(&mut self,
             ExprKind::Match { discriminant, arms } => {
                 this.match_expr(destination, expr_span, block, discriminant, arms)
             }
+            ExprKind::NeverToAny { source } => {
+                let source = this.hir.mirror(source);
+                let is_call = match source.kind {
+                    ExprKind::Call { .. } => true,
+                    _ => false,
+                };
+
+                unpack!(block = this.as_rvalue(block, source));
+
+                // This is an optimization. If the expression was a call then we already have an
+                // unreachable block. Don't bother to terminate it and create a new one.
+                if is_call {
+                    block.unit()
+                } else {
+                    this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
+                    let end_block = this.cfg.start_new_block();
+                    end_block.unit()
+                }
+            }
             ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
                 let operand = unpack!(block = this.as_operand(block, cond_expr));
 
@@ -190,7 +209,8 @@ pub fn into_expr(&mut self,
             ExprKind::Call { ty, fun, args } => {
                 let diverges = match ty.sty {
                     ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
-                        f.sig.0.output.diverges()
+                        // FIXME(canndrew): This is_never should probably be an is_uninhabited
+                        f.sig.0.output.is_never()
                     }
                     _ => false
                 };
index 814d56f44ac30430b4a63035824b807b6c60a537..26eb782a73b0031c656e5353801828d421726502 100644 (file)
@@ -162,7 +162,7 @@ macro_rules! unpack {
 pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                        fn_id: ast::NodeId,
                                        arguments: A,
-                                       return_ty: ty::FnOutput<'gcx>,
+                                       return_ty: Ty<'gcx>,
                                        ast_block: &'gcx hir::Block)
                                        -> (Mir<'tcx>, ScopeAuxiliaryVec)
     where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
@@ -256,7 +256,7 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
     });
 
     let ty = tcx.expr_ty_adjusted(ast_expr);
-    builder.finish(vec![], IndexVec::new(), ty::FnConverging(ty))
+    builder.finish(vec![], IndexVec::new(), ty)
 }
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -288,7 +288,7 @@ fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> {
     fn finish(self,
               upvar_decls: Vec<UpvarDecl>,
               arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
-              return_ty: ty::FnOutput<'tcx>)
+              return_ty: Ty<'tcx>)
               -> (Mir<'tcx>, ScopeAuxiliaryVec) {
         for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
             if block.terminator.is_none() {
@@ -310,7 +310,7 @@ fn finish(self,
 
     fn args_and_body<A>(&mut self,
                         mut block: BasicBlock,
-                        return_ty: ty::FnOutput<'tcx>,
+                        return_ty: Ty<'tcx>,
                         arguments: A,
                         argument_extent: CodeExtent,
                         ast_block: &'gcx hir::Block)
@@ -351,11 +351,7 @@ fn args_and_body<A>(&mut self,
         }
 
         // FIXME(#32959): temporary hack for the issue at hand
-        let return_is_unit = if let ty::FnConverging(t) = return_ty {
-            t.is_nil()
-        } else {
-            false
-        };
+        let return_is_unit = return_ty.is_nil();
         // start the first basic block and translate the body
         unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block));
 
index d986d88dafc94c8b7c507457e3d74ce6d51fe953..72b6d7f0e5aa514605252addab0cc268760c4650 100644 (file)
@@ -12,7 +12,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir::repr::*;
 use rustc::mir::mir_map::MirMap;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 use std::fmt::Debug;
 use std::io::{self, Write};
 use syntax::ast::NodeId;
@@ -143,14 +143,7 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?;
     }
 
-    write!(w, ") -&gt; ")?;
-
-    // fn return type.
-    match mir.return_ty {
-        ty::FnOutput::FnConverging(ty) => write!(w, "{}", escape(ty))?,
-        ty::FnOutput::FnDiverging => write!(w, "!")?,
-    }
-
+    write!(w, ") -&gt; {}", escape(mir.return_ty))?;
     write!(w, r#"<br align="left"/>"#)?;
 
     // User variable types (including the user's name in a comment).
index 88fb65d8eea03569d41c13958d524a7e6cf5fe48..a61fdb79df822588fb61ca54dbd456f686ea4ff0 100644 (file)
@@ -60,6 +60,14 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
                     kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
                 };
             }
+            Some(&ty::adjustment::AdjustNeverToAny(adjusted_ty)) => {
+                expr = Expr {
+                    temp_lifetime: temp_lifetime,
+                    ty: adjusted_ty,
+                    span: self.span,
+                    kind: ExprKind::NeverToAny { source: expr.to_ref() },
+                };
+            }
             Some(&ty::adjustment::AdjustMutToConstPointer) => {
                 let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
                 expr = Expr {
@@ -88,9 +96,9 @@ fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
 
                         let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
                         let (region, mutbl) = match ref_ty {
-                            Some(ty::FnConverging(&ty::TyS {
+                            Some(&ty::TyS {
                                 sty: ty::TyRef(region, mt), ..
-                            })) => (region, mt.mutbl),
+                            }) => (region, mt.mutbl),
                             _ => span_bug!(expr.span, "autoderef returned bad type")
                         };
 
@@ -946,10 +954,8 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     let tables = cx.tcx.tables.borrow();
     let callee = &tables.method_map[&method_call];
     let ref_ty = callee.ty.fn_ret();
-    let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap().unwrap();
-    //                                              1~~~~~   2~~~~~
-    // (1) callees always have all late-bound regions fully instantiated,
-    // (2) overloaded methods don't return `!`
+    let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
+    // callees always have all late-bound regions fully instantiated,
 
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
index a2746bf30c91f7020702f6bd15f94f243c59c27a..2a5b7d0fb29024950cc727c92a407532a4810324 100644 (file)
@@ -139,6 +139,9 @@ pub enum ExprKind<'tcx> {
     Cast {
         source: ExprRef<'tcx>,
     },
+    NeverToAny {
+        source: ExprRef<'tcx>,
+    },
     ReifyFnPointer {
         source: ExprRef<'tcx>,
     },
index 55e7408b0fd5d4ec881c2387fa94023abc2e938b..c58491096b94f0d3957442e3738f9c14c19e3b80 100644 (file)
@@ -14,7 +14,7 @@
 use rustc::mir::repr::*;
 use rustc::mir::mir_map::MirMap;
 use rustc::mir::transform::MirSource;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv::FnvHashMap;
 use rustc_data_structures::indexed_vec::{Idx};
 use std::fmt::Display;
@@ -320,16 +320,10 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
             write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
         }
 
-        write!(w, ") -> ")?;
-
-        // fn return type.
-        match mir.return_ty {
-            ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty),
-            ty::FnOutput::FnDiverging => write!(w, "!"),
-        }
+        write!(w, ") -> {}", mir.return_ty)
     } else {
         assert!(mir.arg_decls.is_empty());
-        write!(w, ": {} =", mir.return_ty.unwrap())
+        write!(w, ": {} =", mir.return_ty)
     }
 }
 
index 17dd85abd64e371a9fe0289ac668f09e7e51989a..21b406c3bf5c99ba1e26d2822d62a3d356c1760e 100644 (file)
@@ -25,7 +25,7 @@
 use rustc::mir::repr::*;
 use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
 use rustc::mir::traversal::ReversePostorder;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 use syntax_pos::Span;
 
 use build::Location;
@@ -303,7 +303,7 @@ fn promote_candidate(mut self, candidate: Candidate) {
         let span = self.promoted.span;
         let new_operand = Operand::Constant(Constant {
             span: span,
-            ty: self.promoted.return_ty.unwrap(),
+            ty: self.promoted.return_ty,
             literal: Literal::Promoted {
                 index: Promoted::new(self.source.promoted.len())
             }
@@ -391,7 +391,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                     parent_scope: None
                 }).into_iter().collect(),
                 IndexVec::new(),
-                ty::FnConverging(ty),
+                ty,
                 IndexVec::new(),
                 IndexVec::new(),
                 IndexVec::new(),
index 87a10f1bb5bfc749fe808975fa699fb60d882d48..103a15dadb61cfcc9481049a9eb28d804445bbb3 100644 (file)
@@ -416,7 +416,7 @@ fn qualify_const(&mut self) -> Qualif {
             }
         }
 
-        let return_ty = mir.return_ty.unwrap();
+        let return_ty = mir.return_ty;
         self.qualif = self.return_qualif.unwrap_or(Qualif::NOT_CONST);
 
         match self.mode {
@@ -1001,7 +1001,7 @@ fn run_pass<'a>(&mut self,
 
             // Statics must be Sync.
             if mode == Mode::Static {
-                let ty = mir.return_ty.unwrap();
+                let ty = mir.return_ty;
                 tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
                     let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
                     let mut fulfillment_cx = traits::FulfillmentContext::new();
index 79e31167f2f7f5b542bb35b8623b8aed9986701a..bbd2a93659b0aff480d70a5ba03d7113c597083c 100644 (file)
@@ -85,9 +85,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
     }
 
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
-        if let ty::FnConverging(t) = mir.return_ty {
-            self.sanitize_type(&"return type", t);
-        }
+        self.sanitize_type(&"return type", mir.return_ty);
         for var_decl in &mir.var_decls {
             self.sanitize_type(var_decl, var_decl.ty);
         }
@@ -135,14 +133,7 @@ fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> {
             Lvalue::Static(def_id) =>
                 LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
             Lvalue::ReturnPointer => {
-                if let ty::FnConverging(return_ty) = self.mir.return_ty {
-                    LvalueTy::Ty { ty: return_ty }
-                } else {
-                    LvalueTy::Ty {
-                        ty: span_mirbug_and_err!(
-                            self, lvalue, "return in diverging function")
-                    }
-                }
+                LvalueTy::Ty { ty: self.mir.return_ty }
             }
             Lvalue::Projection(ref proj) => {
                 let base_ty = self.sanitize_lvalue(&proj.base);
@@ -500,22 +491,21 @@ fn check_call_dest(&self,
                        sig: &ty::FnSig<'tcx>,
                        destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
         let tcx = self.tcx();
-        match (destination, sig.output) {
-            (&Some(..), ty::FnDiverging) => {
-                span_mirbug!(self, term, "call to diverging function {:?} with dest", sig);
-            }
-            (&Some((ref dest, _)), ty::FnConverging(ty)) => {
+        match *destination {
+            Some((ref dest, _)) => {
                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
-                if let Err(terr) = self.sub_types(self.last_span, ty, dest_ty) {
+                if let Err(terr) = self.sub_types(self.last_span, sig.output, dest_ty) {
                     span_mirbug!(self, term,
                                  "call dest mismatch ({:?} <- {:?}): {:?}",
-                                 dest_ty, ty, terr);
+                                 dest_ty, sig.output, terr);
                 }
-            }
-            (&None, ty::FnDiverging) => {}
-            (&None, ty::FnConverging(..)) => {
-                span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
-             }
+            },
+            None => {
+                // FIXME(canndrew): This is_never should probably be an is_uninhabited
+                if !sig.output.is_never() {
+                    span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
+                }
+            },
         }
     }
 
index 37e42cdea1bf84b6f6b690efeb9bd92b28a4afa4..0c54f20fe76676bfd19c71405c3799a1752e0595 100644 (file)
@@ -632,6 +632,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
 fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
     match v.tcx.tables.borrow().adjustments.get(&e.id) {
         None |
+        Some(&ty::adjustment::AdjustNeverToAny(..)) |
         Some(&ty::adjustment::AdjustReifyFnPointer) |
         Some(&ty::adjustment::AdjustUnsafeFnPointer) |
         Some(&ty::adjustment::AdjustMutToConstPointer) => {}
index d8f39358411a19ef181adb25129038766bc1183a..de9ddcd934216e4cbcecf16de4c0cbdffc8a6d05 100644 (file)
@@ -440,7 +440,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                     let expr_ty = self.tcx.expr_ty(expr);
                     let def = match expr_ty.sty {
                         ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
-                            output: ty::FnConverging(ty), ..
+                            output: ty, ..
                         }), ..}) => ty,
                         _ => expr_ty
                     }.ty_adt_def().unwrap();
index 0580c51d9a17a745db2140e59ef8b3885624849c..16cd9186ce9bb43e251b29c5c66d61c799256457 100644 (file)
@@ -671,7 +671,6 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
     sig.push_str(&decl.inputs.iter().map(arg_to_string).collect::<Vec<_>>().join(", "));
     sig.push(')');
     match decl.output {
-        ast::FunctionRetTy::None(_) => sig.push_str(" -> !"),
         ast::FunctionRetTy::Default(_) => {}
         ast::FunctionRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))),
     }
index 29b3f6ce52fb2b8368f17d2fcbea1193273aac20..27a8c1f1df47686e3b0d6f66a127ab80685c831d 100644 (file)
@@ -1593,7 +1593,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>,
     }
 
     let t = node_id_type(bcx, discr_expr.id);
-    let chk = if t.is_empty(tcx) {
+    let chk = if t.is_uninhabited(tcx) {
         Unreachable
     } else {
         Infallible
index 587c03af3abb6d6eaae9fbdd1c73a2650912049e..3a7fde6a36bad02e6629ef9c27ea297b148b2d0e 100644 (file)
@@ -326,10 +326,7 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             }
         };
 
-        let ret_ty = match sig.output {
-            ty::FnConverging(ret_ty) => ret_ty,
-            ty::FnDiverging => ccx.tcx().mk_nil()
-        };
+        let ret_ty = sig.output;
         let mut ret = arg_of(ret_ty, true);
 
         if !type_is_fat_ptr(ccx.tcx(), ret_ty) {
@@ -470,7 +467,7 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self,
             };
             // Fat pointers are returned by-value.
             if !self.ret.is_ignore() {
-                if !type_is_fat_ptr(ccx.tcx(), sig.output.unwrap()) {
+                if !type_is_fat_ptr(ccx.tcx(), sig.output) {
                     fixup(&mut self.ret);
                 }
             }
index 30618ff37273569ba6251f5780d76ae3dae1ad51..c78cda75e820e548d5a585c1b5e2d1736745f3d0 100644 (file)
@@ -1972,7 +1972,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
     let sig = ccx.tcx().normalize_associated_type(&sig);
-    let result_ty = sig.output.unwrap();
+    let result_ty = sig.output;
 
     // Get location to store the result. If the user does not care about
     // the result, just make a stack slot
@@ -2054,7 +2054,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     if !fcx.fn_ty.ret.is_ignore() {
         let dest = fcx.get_ret_slot(bcx, "eret_slot");
         let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value
-        let repr = adt::represent_type(ccx, sig.output.unwrap());
+        let repr = adt::represent_type(ccx, sig.output);
         let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
         let mut arg_idx = 0;
         for (i, arg_ty) in sig.inputs.into_iter().enumerate() {
index 983ee564c35b1051fcc447b514d4719d05578707..aaec2a47025a2e2a7d788e57ac96c817f8a4596b 100644 (file)
@@ -641,10 +641,7 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let opt_llretslot = dest.and_then(|dest| match dest {
         expr::SaveIn(dst) => Some(dst),
         expr::Ignore => {
-            let needs_drop = || match output {
-                ty::FnConverging(ret_ty) => bcx.fcx.type_needs_drop(ret_ty),
-                ty::FnDiverging => false
-            };
+            let needs_drop = || bcx.fcx.type_needs_drop(output);
             if fn_ty.ret.is_indirect() || fn_ty.ret.cast.is_some() || needs_drop() {
                 // Push the out-pointer if we use an out-pointer for this
                 // return type, otherwise push "undef".
@@ -706,16 +703,17 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     // If the caller doesn't care about the result of this fn call,
     // drop the temporary slot we made.
-    match (dest, opt_llretslot, output) {
-        (Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => {
+    match (dest, opt_llretslot) {
+        (Some(expr::Ignore), Some(llretslot)) => {
             // drop the value if it is not being saved.
-            bcx = glue::drop_ty(bcx, llretslot, ret_ty, debug_loc);
+            bcx = glue::drop_ty(bcx, llretslot, output, debug_loc);
             call_lifetime_end(bcx, llretslot);
         }
         _ => {}
     }
 
-    if output == ty::FnDiverging {
+    // FIXME(canndrew): This is_never should really be an is_uninhabited
+    if output.is_never() {
         Unreachable(bcx);
     }
 
index e53a5edfc668519f2f305e8f63687419c7ebb83a..77b2c43167cfd280b20122f7c4bc233740141c4d 100644 (file)
@@ -201,7 +201,11 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     trans_closure_expr(Dest::Ignore(ccx),
                        &hir::FnDecl {
                            inputs: P::new(),
-                           output: hir::NoReturn(DUMMY_SP),
+                           output: hir::Return(P(hir::Ty {
+                               id: DUMMY_NODE_ID,
+                               span: DUMMY_SP,
+                               node: hir::Ty_::TyNever,
+                           })),
                            variadic: false
                        },
                        &hir::Block {
index 794da0d1473bd12b900d0aad7d842074f52c2dc8..acc302430aee68383513650f15f2db85cf1b3aa2 100644 (file)
@@ -791,6 +791,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         ty::TyRef(..)   |
         ty::TyFnDef(..) |
         ty::TyFnPtr(_)  |
+        ty::TyNever     |
         ty::TyTrait(_)  => {
             /* nothing to do */
         }
index dea5a1560e15b0564f94aaf8b29bb16a5cdc80fc..79cf77cd9d35d534c8434dc1dac8b5dd4d444d3a 100644 (file)
@@ -558,7 +558,7 @@ pub fn eh_unwind_resume(&self) -> Callee<'tcx> {
             abi: Abi::C,
             sig: ty::Binder(ty::FnSig {
                 inputs: vec![tcx.mk_mut_ptr(tcx.types.u8)],
-                output: ty::FnDiverging,
+                output: tcx.types.never,
                 variadic: false
             }),
         }));
@@ -1240,8 +1240,8 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            inlined_vid);
     let adt_def = match ctor_ty.sty {
         ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
-            output: ty::FnConverging(ty), ..
-        }), ..}) => ty,
+            output, ..
+        }), ..}) => output,
         _ => ctor_ty
     }.ty_adt_def().unwrap();
     let variant_def_id = if ccx.tcx().map.is_inlined_node_id(inlined_vid) {
index 769dd008af8f495c3602737f04e7b99e2187f7ed..3ecba3691d279d22dd994b002a66de89e556db4b 100644 (file)
@@ -34,7 +34,7 @@
 use value::Value;
 use Disr;
 use rustc::ty::subst::Substs;
-use rustc::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
+use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer};
 use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::cast::{CastTy,IntTy};
@@ -348,6 +348,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                                             &cx.tcx().expr_ty_adjusted(e));
     let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned();
     match opt_adj {
+        Some(AdjustNeverToAny(..)) => span_bug!(e.span, "const expression of type ! encountered"),
         Some(AdjustReifyFnPointer) => {
             match ety.sty {
                 ty::TyFnDef(def_id, substs, _) => {
index ee13af80b2ba0aeff7741bb4a5a687305b0bbb50..3fe8b2b66791a8c65b3db77cca77596c7b167a9d 100644 (file)
@@ -171,6 +171,7 @@ fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>,
         unique_type_id.push('{');
 
         match type_.sty {
+            ty::TyNever    |
             ty::TyBool     |
             ty::TyChar     |
             ty::TyStr      |
@@ -278,16 +279,9 @@ fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>,
                 }
 
                 unique_type_id.push_str(")->");
-                match sig.output {
-                    ty::FnConverging(ret_ty) => {
-                        let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty);
-                        let return_type_id = self.get_unique_type_id_as_string(return_type_id);
-                        unique_type_id.push_str(&return_type_id[..]);
-                    }
-                    ty::FnDiverging => {
-                        unique_type_id.push_str("!");
-                    }
-                }
+                let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
+                let return_type_id = self.get_unique_type_id_as_string(return_type_id);
+                unique_type_id.push_str(&return_type_id[..]);
             },
             ty::TyClosure(_, substs) if substs.upvar_tys.is_empty() => {
                 push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
@@ -595,12 +589,9 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
 
     // return type
-    signature_metadata.push(match signature.output {
-        ty::FnConverging(ret_ty) => match ret_ty.sty {
-            ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
-            _ => type_metadata(cx, ret_ty, span)
-        },
-        ty::FnDiverging => diverging_type_metadata(cx)
+    signature_metadata.push(match signature.output.sty {
+        ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
+        _ => type_metadata(cx, signature.output, span)
     });
 
     // regular arguments
@@ -704,6 +695,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     let sty = &t.sty;
     let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty {
+        ty::TyNever    |
         ty::TyBool     |
         ty::TyChar     |
         ty::TyInt(_)   |
@@ -914,23 +906,13 @@ pub fn scope_metadata(fcx: &FunctionContext,
     }
 }
 
-pub fn diverging_type_metadata(cx: &CrateContext) -> DIType {
-    unsafe {
-        llvm::LLVMRustDIBuilderCreateBasicType(
-            DIB(cx),
-            "!\0".as_ptr() as *const _,
-            bytes_to_bits(0),
-            bytes_to_bits(0),
-            DW_ATE_unsigned)
-    }
-}
-
 fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                  t: Ty<'tcx>) -> DIType {
 
     debug!("basic_type_metadata: {:?}", t);
 
     let (name, encoding) = match t.sty {
+        ty::TyNever => ("!", DW_ATE_unsigned),
         ty::TyTuple(ref elements) if elements.is_empty() =>
             ("()", DW_ATE_unsigned),
         ty::TyBool => ("bool", DW_ATE_boolean),
index f2c7068565ee90d482bfb7471f6f5b0e7f879cbf..d6a4ce3c43a4ecc9b9ec67e0c1522daf93ed5889 100644 (file)
@@ -17,8 +17,7 @@
 use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
 use self::namespace::mangled_name_of_item;
 use self::type_names::compute_debuginfo_type_name;
-use self::metadata::{type_metadata, diverging_type_metadata};
-use self::metadata::{file_metadata, TypeMap};
+use self::metadata::{type_metadata, file_metadata, TypeMap};
 use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
 
 use llvm;
@@ -325,12 +324,9 @@ fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         let mut signature = Vec::with_capacity(sig.inputs.len() + 1);
 
         // Return type -- llvm::DIBuilder wants this at index 0
-        signature.push(match sig.output {
-            ty::FnConverging(ret_ty) => match ret_ty.sty {
-                ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
-                _ => type_metadata(cx, ret_ty, syntax_pos::DUMMY_SP)
-            },
-            ty::FnDiverging => diverging_type_metadata(cx)
+        signature.push(match sig.output.sty {
+            ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
+            _ => type_metadata(cx, sig.output, syntax_pos::DUMMY_SP)
         });
 
         let inputs = if abi == Abi::RustCall {
index bee2667c71f9db974660ff39bde162776e9379b3..73b1c828663e1b660751578045a2dce73b28e956 100644 (file)
@@ -40,6 +40,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ty::TyBool => output.push_str("bool"),
         ty::TyChar => output.push_str("char"),
         ty::TyStr => output.push_str("str"),
+        ty::TyNever => output.push_str("!"),
         ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()),
         ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
         ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()),
@@ -133,15 +134,9 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             output.push(')');
 
-            match sig.output {
-                ty::FnConverging(result_type) if result_type.is_nil() => {}
-                ty::FnConverging(result_type) => {
-                    output.push_str(" -> ");
-                    push_debuginfo_type_name(cx, result_type, true, output);
-                }
-                ty::FnDiverging => {
-                    output.push_str(" -> !");
-                }
+            if !sig.output.is_nil() {
+                output.push_str(" -> ");
+                push_debuginfo_type_name(cx, sig.output, true, output);
             }
         },
         ty::TyClosure(..) => {
index 324e8697ecae695ab61e3a6e550cdf085fa85fd2..4d9ee187ac50c36ddad54d98548175e874b4c26f 100644 (file)
@@ -111,7 +111,8 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
     let fty = FnType::new(ccx, abi, &sig, &[]);
     let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx));
 
-    if sig.output == ty::FnDiverging {
+    // FIXME(canndrew): This is_never should really be an is_uninhabited
+    if sig.output.is_never() {
         llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
     }
 
index 2a60dd17446717eae78d1a971c48dc81e6ee541a..6c894ddad1a94981559d56da9aef60ad564f84e7 100644 (file)
@@ -69,7 +69,7 @@
 use type_of;
 use value::Value;
 use Disr;
-use rustc::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
+use rustc::ty::adjustment::{AdjustNeverToAny, AdjustDerefRef, AdjustReifyFnPointer};
 use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
 use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -348,6 +348,7 @@ fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 
     match adjustment {
+        AdjustNeverToAny(..) => true,
         AdjustReifyFnPointer => true,
         AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
             // purely a type-level thing
@@ -380,6 +381,12 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     debug!("unadjusted datum for expr {:?}: {:?} adjustment={:?}",
            expr, datum, adjustment);
     match adjustment {
+        AdjustNeverToAny(ref target) => {
+            let mono_target = bcx.monomorphize(target);
+            let llty = type_of::type_of(bcx.ccx(), mono_target);
+            let dummy = C_undef(llty.ptr_to());
+            datum = Datum::new(dummy, mono_target, Lvalue::new("never")).to_expr_datum();
+        }
         AdjustReifyFnPointer => {
             match datum.ty.sty {
                 ty::TyFnDef(def_id, substs, _) => {
@@ -796,7 +803,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
 
             let ref_ty = // invoked methods have LB regions instantiated:
-                bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
+                bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
             let elt_ty = match ref_ty.builtin_deref(true, ty::NoPreference) {
                 None => {
                     span_bug!(index_expr.span,
@@ -2053,7 +2060,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             };
 
             let ref_ty = // invoked methods have their LB regions instantiated
-                ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
+                ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
 
             bcx = Callee::method(bcx, method)
index 4980fad0cc37e676f3605bbcfdd667166e1681a7..7be173d17b487ded0132b7408c214a96becb84e5 100644 (file)
@@ -132,7 +132,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     // For `transmute` we can just trans the input expr directly into dest
     if name == "transmute" {
-        let llret_ty = type_of::type_of(ccx, ret_ty.unwrap());
+        let llret_ty = type_of::type_of(ccx, ret_ty);
         match args {
             callee::ArgExprs(arg_exprs) => {
                 assert_eq!(arg_exprs.len(), 1);
@@ -315,11 +315,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         return Result::new(bcx, C_nil(ccx));
     }
 
-    let ret_ty = match ret_ty {
-        ty::FnConverging(ret_ty) => ret_ty,
-        ty::FnDiverging => bug!()
-    };
-
     let llret_ty = type_of::type_of(ccx, ret_ty);
 
     // Get location to store the result. If the user does
@@ -1226,7 +1221,7 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
                     name: &str,
                     inputs: Vec<Ty<'tcx>>,
-                    output: ty::FnOutput<'tcx>,
+                    output: Ty<'tcx>,
                     trans: &mut for<'b> FnMut(Block<'b, 'tcx>))
                     -> ValueRef {
     let ccx = fcx.ccx;
@@ -1272,11 +1267,11 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
         abi: Abi::Rust,
         sig: ty::Binder(ty::FnSig {
             inputs: vec![i8p],
-            output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+            output: tcx.mk_nil(),
             variadic: false,
         }),
     }));
-    let output = ty::FnOutput::FnConverging(tcx.types.i32);
+    let output = tcx.types.i32;
     let rust_try = gen_fn(fcx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
     ccx.rust_try_fn().set(Some(rust_try));
     return rust_try
index de5581af2912d2edda55462de68b85f8d4ab6026..e0d959f4774a64e3a2952f85bb6dcf081f931025 100644 (file)
@@ -19,6 +19,7 @@
 use rustc::mir::traversal;
 use common::{self, Block, BlockAndBuilder};
 use glue;
+use std::iter;
 use super::rvalue;
 
 pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
@@ -31,7 +32,7 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
     let local_types = mir.arg_decls.iter().map(|a| a.ty)
                .chain(mir.var_decls.iter().map(|v| v.ty))
                .chain(mir.temp_decls.iter().map(|t| t.ty))
-               .chain(mir.return_ty.maybe_converging());
+               .chain(iter::once(mir.return_ty));
     for (index, ty) in local_types.enumerate() {
         let ty = bcx.monomorphize(&ty);
         debug!("local {} has type {:?}", index, ty);
index b1fd3e88d75f00c8d579f8e0feb9fa45773b7adf..56d02fa1fac4fbc02bdfe337ff48f77607b2e7dd 100644 (file)
@@ -525,7 +525,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                             // Make a fake operand for store_return
                             let op = OperandRef {
                                 val: Ref(dst),
-                                ty: sig.output.unwrap()
+                                ty: sig.output,
                             };
                             self.store_return(&bcx, ret_dest, fn_ty.ret, op);
                         }
@@ -563,7 +563,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                             debug_loc.apply_to_bcx(ret_bcx);
                             let op = OperandRef {
                                 val: Immediate(invokeret),
-                                ty: sig.output.unwrap()
+                                ty: sig.output,
                             };
                             self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
                         });
@@ -574,7 +574,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                     if let Some((_, target)) = *destination {
                         let op = OperandRef {
                             val: Immediate(llret),
-                            ty: sig.output.unwrap()
+                            ty: sig.output,
                         };
                         self.store_return(&bcx, ret_dest, fn_ty.ret, op);
                         funclet_br(self, bcx, target);
index 8f723d288c9eb4718cb4bb77580396bbf122b4ac..727b680541dd7cf81579f2ce97e17982009beb0f 100644 (file)
@@ -26,6 +26,7 @@
 
 use std::ops::Deref;
 use std::rc::Rc;
+use std::iter;
 
 use basic_block::BasicBlock;
 
@@ -183,7 +184,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
 
         let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| {
             (mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty)
-        }).chain(mir.return_ty.maybe_converging().map(|ty| (mir::Lvalue::ReturnPointer, ty)));
+        }).chain(iter::once((mir::Lvalue::ReturnPointer, mir.return_ty)));
 
         args.into_iter().chain(vars).chain(locals.map(|(lvalue, ty)| {
             let ty = bcx.monomorphize(&ty);
index 187ffe353fdcb5f596bd87dbfb0994feaa8e8c79..90058f0b8329a30afdc3f0d694c9438599fffd7a 100644 (file)
@@ -233,7 +233,7 @@ fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>,
 
         let sig = ty::FnSig {
             inputs: vec![tcx.mk_mut_ptr(tcx.types.i8)],
-            output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+            output: tcx.mk_nil(),
             variadic: false,
         };
 
@@ -412,6 +412,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ty::TyBool              => output.push_str("bool"),
         ty::TyChar              => output.push_str("char"),
         ty::TyStr               => output.push_str("str"),
+        ty::TyNever             => output.push_str("!"),
         ty::TyInt(ast::IntTy::Is)    => output.push_str("isize"),
         ty::TyInt(ast::IntTy::I8)    => output.push_str("i8"),
         ty::TyInt(ast::IntTy::I16)   => output.push_str("i16"),
@@ -515,15 +516,9 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             output.push(')');
 
-            match sig.output {
-                ty::FnConverging(result_type) if result_type.is_nil() => {}
-                ty::FnConverging(result_type) => {
-                    output.push_str(" -> ");
-                    push_unique_type_name(tcx, result_type, output);
-                }
-                ty::FnDiverging => {
-                    output.push_str(" -> !");
-                }
+            if !sig.output.is_nil() {
+                output.push_str(" -> ");
+                push_unique_type_name(tcx, sig.output, output);
             }
         },
         ty::TyClosure(def_id, ref closure_substs) => {
index cde53f6fa899cb9c89a33977e8e42070764b6f19..e6794149fcb3b5b7088dc476b7aa6b1977d6abcd 100644 (file)
@@ -64,6 +64,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
         ty::TyInt(t) => Type::int_from_ty(cx, t),
         ty::TyUint(t) => Type::uint_from_ty(cx, t),
         ty::TyFloat(t) => Type::float_from_ty(cx, t),
+        ty::TyNever => Type::nil(cx),
 
         ty::TyBox(ty) |
         ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
@@ -249,6 +250,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TyInt(t) => Type::int_from_ty(cx, t),
       ty::TyUint(t) => Type::uint_from_ty(cx, t),
       ty::TyFloat(t) => Type::float_from_ty(cx, t),
+      ty::TyNever => Type::nil(cx),
       ty::TyEnum(def, ref substs) => {
           // Only create the named struct, but don't fill it in. We
           // fill it in *after* placing it into the type cache. This
index ad61b5b0b513eb355d664e7e4695e1c40de36cf2..ed67c9fbe30bee94e3f7ebeb94dc8a0831e28bfe 100644 (file)
@@ -1700,6 +1700,9 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
                 let t = self.ast_ty_to_ty(rscope1, &mt.ty);
                 tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
             }
+            hir::TyNever => {
+                tcx.types.never
+            },
             hir::TyTup(ref fields) => {
                 let flds = fields.iter()
                                  .map(|t| self.ast_ty_to_ty(rscope, &t))
@@ -1920,11 +1923,10 @@ fn ty_of_method_or_bare_fn(&self,
 
         let output_ty = match decl.output {
             hir::Return(ref output) =>
-                ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region,
-                                                                       &output,
-                                                                       ret_anon_scope)),
-            hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()),
-            hir::NoReturn(..) => ty::FnDiverging
+                self.convert_ty_with_lifetime_elision(implied_output_region,
+                                                      &output,
+                                                      ret_anon_scope),
+            hir::DefaultReturn(..) => self.tcx().mk_nil(),
         };
 
         (self.tcx().mk_bare_fn(ty::BareFnTy {
@@ -2067,11 +2069,10 @@ pub fn ty_of_closure(&self,
             _ if is_infer && expected_ret_ty.is_some() =>
                 expected_ret_ty.unwrap(),
             _ if is_infer =>
-                ty::FnConverging(self.ty_infer(None, None, None, decl.output.span())),
+                self.ty_infer(None, None, None, decl.output.span()),
             hir::Return(ref output) =>
-                ty::FnConverging(self.ast_ty_to_ty(&rb, &output)),
+                self.ast_ty_to_ty(&rb, &output),
             hir::DefaultReturn(..) => bug!(),
-            hir::NoReturn(..) => ty::FnDiverging
         };
 
         debug!("ty_of_closure: input_tys={:?}", input_tys);
index 5f255cc1fb730112b1df500d28a65b18fec18dfb..04f22b195110f59b6bb7306695bc77808b98c8ab 100644 (file)
@@ -610,7 +610,7 @@ fn check_pat_tuple_struct(&self,
         let scheme = tcx.lookup_item_type(def.def_id());
         let scheme = if scheme.ty.is_fn() {
             // Replace constructor type with constructed type for tuple struct patterns.
-            let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap().unwrap();
+            let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap();
             ty::TypeScheme { ty: fn_ret, generics: scheme.generics }
         } else {
             // Leave the type as is for unit structs (backward compatibility).
index e73c3aa352b5605beec6fe6d8b1f164554360fbf..985c3be149617dc388a08a2e932b92f41f1eeef9 100644 (file)
@@ -213,7 +213,7 @@ fn confirm_builtin_call(&self,
                 // set up all the node type bindings.
                 error_fn_sig = ty::Binder(ty::FnSig {
                     inputs: self.err_args(arg_exprs.len()),
-                    output: ty::FnConverging(self.tcx.types.err),
+                    output: self.tcx.types.err,
                     variadic: false
                 });
 
@@ -345,10 +345,9 @@ fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
                     fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty);
                 }
 
-                let nilty = fcx.tcx.mk_nil();
                 fcx.demand_eqtype(self.call_expr.span,
-                                  method_sig.output.unwrap_or(nilty),
-                                  self.fn_sig.output.unwrap_or(nilty));
+                                  method_sig.output,
+                                  self.fn_sig.output);
 
                 fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
             }
index d3396eb4c1baf480236e9298302cda45101628ac..3acb8017eec509acaadd09ef48ed36c343095c2d 100644 (file)
@@ -221,7 +221,7 @@ fn deduce_sig_from_projection(&self,
 
         let fn_sig = ty::FnSig {
             inputs: input_tys,
-            output: ty::FnConverging(ret_param_ty),
+            output: ret_param_ty,
             variadic: false
         };
         debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
index 9dd737f3a6168af9ae99a35b6e081089f7a8aaba..4a0d529812891f48049e128824b5cec7cf8b1ece 100644 (file)
@@ -68,6 +68,7 @@
 use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
 use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
 use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
+use rustc::ty::adjustment::AdjustNeverToAny;
 use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
@@ -167,6 +168,10 @@ fn coerce<'a, E, I>(&self,
             return self.identity(b);
         }
 
+        if a.is_never() {
+            return Ok((b, AdjustNeverToAny(b)));
+        }
+
         // Consider coercing the subtype to a DST
         let unsize = self.coerce_unsized(a, b);
         if unsize.is_ok() {
@@ -637,7 +642,10 @@ pub fn try_coerce(&self,
                 apply(&mut coerce, &|| Some(expr), source, target)?;
             if !adjustment.is_identity() {
                 debug!("Success, coerced with {:?}", adjustment);
-                assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
+                match self.tables.borrow().adjustments.get(&expr.id) {
+                    None | Some(&AdjustNeverToAny(..)) => (),
+                    _ => bug!("expr already has an adjustment on it!"),
+                };
                 self.write_adjustment(expr.id, adjustment);
             }
             Ok(ty)
@@ -741,6 +749,7 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
                     }
                     _ => false
                 },
+                Some(&AdjustNeverToAny(_)) => true,
                 Some(_) => false,
                 None => true
             };
@@ -776,7 +785,12 @@ pub fn try_find_coercion_lub<'b, E, I>(&self,
             Ok((ty, adjustment)) => {
                 if !adjustment.is_identity() {
                     for expr in exprs() {
-                        self.write_adjustment(expr.id, adjustment);
+                        let previous = self.tables.borrow().adjustments.get(&expr.id).cloned();
+                        if let Some(AdjustNeverToAny(_)) = previous {
+                            self.write_adjustment(expr.id, AdjustNeverToAny(ty));
+                        } else {
+                            self.write_adjustment(expr.id, adjustment);
+                        }
                     }
                 }
                 Ok(ty)
index f65e15430daf75c7de17357c61f1bab01cc2d49a..f3a01ef7409fa48fa7a86b600b963d7f9a59e4da 100644 (file)
@@ -433,7 +433,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
     // We still need to ensure all referenced data is safe.
     match ty.sty {
         ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
-        ty::TyFloat(_) | ty::TyStr => {
+        ty::TyFloat(_) | ty::TyStr | ty::TyNever => {
             // primitive - definitely safe
             Ok(())
         }
index 084bbff338346e72440513840f729ebbcae09f81..4334f043772e361962a409b94e1ec0e7c6a82a0c 100644 (file)
@@ -30,8 +30,8 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                    it: &hir::ForeignItem,
                                    n_tps: usize,
                                    abi: Abi,
-                                   inputs: Vec<ty::Ty<'tcx>>,
-                                   output: ty::FnOutput<'tcx>) {
+                                   inputs: Vec<Ty<'tcx>>,
+                                   output: Ty<'tcx>) {
     let tcx = ccx.tcx;
     let def_id = tcx.map.local_def_id(it.id);
     let i_ty = tcx.lookup_item_type(def_id);
@@ -106,9 +106,9 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
                 return;
             }
         };
-        (n_tps, inputs, ty::FnConverging(output))
+        (n_tps, inputs, output)
     } else if &name[..] == "abort" || &name[..] == "unreachable" {
-        (0, Vec::new(), ty::FnDiverging)
+        (0, Vec::new(), tcx.types.never)
     } else {
         let (n_tps, inputs, output) = match &name[..] {
             "breakpoint" => (0, Vec::new(), tcx.mk_nil()),
@@ -293,7 +293,7 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
                     abi: Abi::Rust,
                     sig: ty::Binder(FnSig {
                         inputs: vec![mut_u8],
-                        output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+                        output: tcx.mk_nil(),
                         variadic: false,
                     }),
                 });
@@ -306,7 +306,7 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
                 return;
             }
         };
-        (n_tps, inputs, ty::FnConverging(output))
+        (n_tps, inputs, output)
     };
     equate_intrinsic_type(ccx, it, n_tps, Abi::RustIntrinsic, inputs, output)
 }
@@ -379,7 +379,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
                     }
                     match_intrinsic_type_to_type(ccx, "return value", it.span,
                                                  &mut structural_to_nomimal,
-                                                 &intr.output, sig.output.unwrap());
+                                                 &intr.output, sig.output);
                     return
                 }
                 None => {
@@ -392,7 +392,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
     };
 
     equate_intrinsic_type(ccx, it, n_tps, Abi::PlatformIntrinsic,
-                          inputs, ty::FnConverging(output))
+                          inputs, output)
 }
 
 // walk the expected type and the actual type in lock step, checking they're
index e99a95e4135196402f67893163a191e7d8ca79db..d985d3ccbea89751909d018202a7cc999f6086df 100644 (file)
@@ -372,7 +372,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // expects the types within the function to be consistent.
     err_count_on_creation: usize,
 
-    ret_ty: ty::FnOutput<'tcx>,
+    ret_ty: Ty<'tcx>,
 
     ps: RefCell<UnsafetyState>,
 
@@ -676,14 +676,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id);
     *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
 
-    fn_sig.output = match fcx.ret_ty {
-        ty::FnConverging(orig_ret_ty) => {
-            fcx.require_type_is_sized(orig_ret_ty, decl.output.span(), traits::ReturnType);
-            ty::FnConverging(fcx.instantiate_anon_types(&orig_ret_ty))
-        }
-        ty::FnDiverging => ty::FnDiverging
-    };
-    fcx.ret_ty = fn_sig.output;
+    fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType);
+    fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty);
+    fn_sig.output = fcx.ret_ty;
 
     {
         let mut visit = GatherLocalsVisitor { fcx: &fcx, };
@@ -714,10 +709,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
 
     inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
 
-    fcx.check_block_with_expected(body, match fcx.ret_ty {
-        ty::FnConverging(result_type) => ExpectHasType(result_type),
-        ty::FnDiverging => NoExpectation
-    });
+    fcx.check_block_with_expected(body, ExpectHasType(fcx.ret_ty));
 
     fcx
 }
@@ -1168,7 +1160,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
                                    expected_type: Ty<'tcx>,
                                    id: ast::NodeId) {
     ccx.inherited(id).enter(|inh| {
-        let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id);
+        let fcx = FnCtxt::new(&inh, expected_type, expr.id);
         fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
 
         // Gather locals in statics (because of block expressions).
@@ -1465,7 +1457,7 @@ enum TupleArgumentsFlag {
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
-               rty: ty::FnOutput<'tcx>,
+               rty: Ty<'tcx>,
                body_id: ast::NodeId)
                -> FnCtxt<'a, 'gcx, 'tcx> {
         FnCtxt {
@@ -1559,6 +1551,14 @@ pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
         self.tables.borrow_mut().node_types.insert(node_id, ty);
+
+        // Add adjustments to !-expressions
+        if ty.is_never() {
+            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) {
+                let adj = adjustment::AdjustNeverToAny(self.next_diverging_ty_var());
+                self.write_adjustment(node_id, adj);
+            }
+        }
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1704,7 +1704,7 @@ pub fn instantiate_type_path(&self,
         let mut type_scheme = self.tcx.lookup_item_type(did);
         if type_scheme.ty.is_fn() {
             // Tuple variants have fn type even in type namespace, extract true variant type from it
-            let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap().unwrap();
+            let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap();
             type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics }
         }
         let type_predicates = self.tcx.lookup_predicates(did);
@@ -1731,6 +1731,11 @@ pub fn instantiate_type_path(&self,
     pub fn write_nil(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.mk_nil());
     }
+
+    pub fn write_never(&self, node_id: ast::NodeId) {
+        self.write_ty(node_id, self.tcx.types.never);
+    }
+
     pub fn write_error(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.types.err);
     }
@@ -1788,6 +1793,10 @@ pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
     }
 
     pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
+        if let Some(&adjustment::AdjustNeverToAny(ref t))
+                = self.tables.borrow().adjustments.get(&ex.id) {
+            return t;
+        }
         match self.tables.borrow().node_types.get(&ex.id) {
             Some(&t) => t,
             None => {
@@ -1966,9 +1975,10 @@ fn default_type_parameters(&self) {
         for ty in &self.unsolved_variables() {
             let resolved = self.resolve_type_vars_if_possible(ty);
             if self.type_var_diverges(resolved) {
-                debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges",
+                debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges",
                        resolved);
-                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                                   self.tcx.mk_diverging_default());
             } else {
                 match self.type_is_unconstrained_numeric(resolved) {
                     UnconstrainedInt => {
@@ -2042,7 +2052,8 @@ fn new_select_all_obligations_and_apply_defaults(&self) {
             for ty in &unsolved_variables {
                 let resolved = self.resolve_type_vars_if_possible(ty);
                 if self.type_var_diverges(resolved) {
-                    self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                    self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                                       self.tcx.mk_diverging_default());
                 } else {
                     match self.type_is_unconstrained_numeric(resolved) {
                         UnconstrainedInt | UnconstrainedFloat => {
@@ -2100,7 +2111,8 @@ fn new_select_all_obligations_and_apply_defaults(&self) {
             let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| {
                 for ty in &unbound_tyvars {
                     if self.type_var_diverges(ty) {
-                        self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                        self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                                           self.tcx.mk_diverging_default());
                     } else {
                         match self.type_is_unconstrained_numeric(ty) {
                             UnconstrainedInt => {
@@ -2196,7 +2208,8 @@ fn find_conflicting_default(&self,
         // reporting for more then one conflict.
         for ty in &unbound_tyvars {
             if self.type_var_diverges(ty) {
-                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                                   self.tcx.mk_diverging_default());
             } else {
                 match self.type_is_unconstrained_numeric(ty) {
                     UnconstrainedInt => {
@@ -2271,7 +2284,7 @@ fn make_overloaded_lvalue_return_type(&self,
         // extract method return type, which will be &T;
         // all LB regions should have been instantiated during method lookup
         let ret_ty = method.ty.fn_ret();
-        let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
+        let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap();
 
         // method returns &T, but the type as visible to user is T, so deref
         ret_ty.builtin_deref(true, NoPreference).unwrap()
@@ -2400,7 +2413,7 @@ fn check_method_argument_types(&self,
                                    args_no_rcvr: &'gcx [P<hir::Expr>],
                                    tuple_arguments: TupleArgumentsFlag,
                                    expected: Expectation<'tcx>)
-                                   -> ty::FnOutput<'tcx> {
+                                   -> Ty<'tcx> {
         if method_fn_ty.references_error() {
             let err_inputs = self.err_args(args_no_rcvr.len());
 
@@ -2411,7 +2424,7 @@ fn check_method_argument_types(&self,
 
             self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
                                       false, tuple_arguments);
-            ty::FnConverging(self.tcx.types.err)
+            self.tcx.types.err
         } else {
             match method_fn_ty.sty {
                 ty::TyFnDef(_, _, ref fty) => {
@@ -2601,7 +2614,10 @@ fn parameter_count_error<'tcx>(sess: &Session, sp: Span, fn_inputs: &[Ty<'tcx>],
                 }
 
                 if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) {
-                    any_diverges = any_diverges || self.type_var_diverges(arg_ty);
+                    // FIXME(canndrew): This is_never should probably be an is_uninhabited
+                    any_diverges = any_diverges ||
+                                   self.type_var_diverges(arg_ty) ||
+                                   arg_ty.is_never();
                 }
             }
             if any_diverges && !warned {
@@ -2669,11 +2685,8 @@ fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
 
     fn write_call(&self,
                   call_expr: &hir::Expr,
-                  output: ty::FnOutput<'tcx>) {
-        self.write_ty(call_expr.id, match output {
-            ty::FnConverging(output_ty) => output_ty,
-            ty::FnDiverging => self.next_diverging_ty_var()
-        });
+                  output: Ty<'tcx>) {
+        self.write_ty(call_expr.id, output);
     }
 
     // AST fragment checking
@@ -2796,35 +2809,31 @@ pub fn impl_self_ty(&self,
     fn expected_types_for_fn_args(&self,
                                   call_span: Span,
                                   expected_ret: Expectation<'tcx>,
-                                  formal_ret: ty::FnOutput<'tcx>,
+                                  formal_ret: Ty<'tcx>,
                                   formal_args: &[Ty<'tcx>])
                                   -> Vec<Ty<'tcx>> {
         let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| {
-            if let ty::FnConverging(formal_ret_ty) = formal_ret {
-                self.commit_regions_if_ok(|| {
-                    // Attempt to apply a subtyping relationship between the formal
-                    // return type (likely containing type variables if the function
-                    // is polymorphic) and the expected return type.
-                    // No argument expectations are produced if unification fails.
-                    let origin = TypeOrigin::Misc(call_span);
-                    let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty);
-                    // FIXME(#15760) can't use try! here, FromError doesn't default
-                    // to identity so the resulting type is not constrained.
-                    match ures {
-                        // FIXME(#32730) propagate obligations
-                        Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
-                        Err(e) => return Err(e),
-                    }
+            self.commit_regions_if_ok(|| {
+                // Attempt to apply a subtyping relationship between the formal
+                // return type (likely containing type variables if the function
+                // is polymorphic) and the expected return type.
+                // No argument expectations are produced if unification fails.
+                let origin = TypeOrigin::Misc(call_span);
+                let ures = self.sub_types(false, origin, formal_ret, ret_ty);
+                // FIXME(#15760) can't use try! here, FromError doesn't default
+                // to identity so the resulting type is not constrained.
+                match ures {
+                    // FIXME(#32730) propagate obligations
+                    Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
+                    Err(e) => return Err(e),
+                }
 
-                    // Record all the argument types, with the substitutions
-                    // produced from the above subtyping unification.
-                    Ok(formal_args.iter().map(|ty| {
-                        self.resolve_type_vars_if_possible(ty)
-                    }).collect())
-                }).ok()
-            } else {
-                None
-            }
+                // Record all the argument types, with the substitutions
+                // produced from the above subtyping unification.
+                Ok(formal_args.iter().map(|ty| {
+                    self.resolve_type_vars_if_possible(ty)
+                }).collect())
+            }).ok()
         }).unwrap_or(vec![]);
         debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})",
                formal_args, formal_ret,
@@ -3481,39 +3490,26 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
               }
               self.write_nil(id);
           }
-          hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
-          hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
+          hir::ExprBreak(_) => { self.write_never(id); }
+          hir::ExprAgain(_) => { self.write_never(id); }
           hir::ExprRet(ref expr_opt) => {
-            match self.ret_ty {
-                ty::FnConverging(result_type) => {
-                    if let Some(ref e) = *expr_opt {
-                        self.check_expr_coercable_to_type(&e, result_type);
-                    } else {
-                        let eq_result = self.eq_types(false,
-                                                      TypeOrigin::Misc(expr.span),
-                                                      result_type,
-                                                      tcx.mk_nil())
-                            // FIXME(#32730) propagate obligations
-                            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
-                        if eq_result.is_err() {
-                            struct_span_err!(tcx.sess, expr.span, E0069,
-                                     "`return;` in a function whose return type is not `()`")
-                                .span_label(expr.span, &format!("return type is not ()"))
-                                .emit();
-                        }
-                    }
-                }
-                ty::FnDiverging => {
-                    if let Some(ref e) = *expr_opt {
-                        self.check_expr(&e);
-                    }
-                    struct_span_err!(tcx.sess, expr.span, E0166,
-                        "`return` in a function declared as diverging")
-                        .span_label(expr.span, &format!("diverging function cannot return"))
+            if let Some(ref e) = *expr_opt {
+                self.check_expr_coercable_to_type(&e, self.ret_ty);
+            } else {
+                let eq_result = self.eq_types(false,
+                                              TypeOrigin::Misc(expr.span),
+                                              self.ret_ty,
+                                              tcx.mk_nil())
+                    // FIXME(#32730) propagate obligations
+                    .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
+                if eq_result.is_err() {
+                    struct_span_err!(tcx.sess, expr.span, E0069,
+                             "`return;` in a function whose return type is not `()`")
+                        .span_label(expr.span, &format!("return type is not ()"))
                         .emit();
                 }
             }
-            self.write_ty(id, self.next_diverging_ty_var());
+            self.write_never(id);
           }
           hir::ExprAssign(ref lhs, ref rhs) => {
             self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
@@ -3560,7 +3556,7 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
           hir::ExprLoop(ref body, _) => {
             self.check_block_no_value(&body);
             if !may_break(tcx, expr.id, &body) {
-                self.write_ty(id, self.next_diverging_ty_var());
+                self.write_never(id);
             } else {
                 self.write_nil(id);
             }
@@ -4016,7 +4012,10 @@ fn check_block_with_expected(&self,
                               "unreachable statement".to_string());
                 warned = true;
             }
-            any_diverges = any_diverges || self.type_var_diverges(s_ty);
+            // FIXME(canndrew): This is_never should probably be an is_uninhabited
+            any_diverges = any_diverges ||
+                           self.type_var_diverges(s_ty) ||
+                           s_ty.is_never();
             any_err = any_err || s_ty.references_error();
         }
         match blk.expr {
index cdca988084cceb201332bcdae430a1da96850a7c..a8b1683f6d354e1dce9bd28185f0bd6e7e4224c8 100644 (file)
@@ -349,7 +349,7 @@ fn lookup_op_method(&self,
                 // extract return type for method; all late bound regions
                 // should have been instantiated by now
                 let ret_ty = method_ty.fn_ret();
-                Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap())
+                Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap())
             }
             None => {
                 Err(())
index f3a6442f35d1127721bf424710b864d8e4d26847..22ffcfbaae111df894576ee75b2fdce6675fb10e 100644 (file)
@@ -311,7 +311,7 @@ fn visit_fn_body(&mut self,
         let fn_sig_tys: Vec<_> =
             fn_sig.inputs.iter()
                          .cloned()
-                         .chain(Some(fn_sig.output.unwrap_or(self.tcx.types.bool)))
+                         .chain(Some(fn_sig.output))
                          .collect();
 
         let old_body_id = self.set_body_id(body.id);
@@ -708,7 +708,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                                             None::<hir::Expr>.iter(), true);
                         // late-bound regions in overloaded method calls are instantiated
                         let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret());
-                        fn_ret.unwrap().unwrap()
+                        fn_ret.unwrap()
                     }
                     None => self.resolve_node_type(base.id)
                 };
@@ -980,14 +980,9 @@ fn constrain_autoderefs(&mut self,
                     // Specialized version of constrain_call.
                     self.type_must_outlive(infer::CallRcvr(deref_expr.span),
                                            self_ty, r_deref_expr);
-                    match fn_sig.output {
-                        ty::FnConverging(return_type) => {
-                            self.type_must_outlive(infer::CallReturn(deref_expr.span),
-                                                   return_type, r_deref_expr);
-                            return_type
-                        }
-                        ty::FnDiverging => bug!()
-                    }
+                    self.type_must_outlive(infer::CallReturn(deref_expr.span),
+                                           fn_sig.output, r_deref_expr);
+                    fn_sig.output
                 }
                 None => derefd_ty
             };
index e2080906ca24294c9f029cdbcfbe7a6bf1e08c8a..4bb9f4fd332f2e3c183d75d79a5790622b8cfe13 100644 (file)
@@ -51,7 +51,7 @@ fn with_fcx<F>(&'tcx mut self, f: F) where
         let id = self.id;
         let span = self.span;
         self.inherited.enter(|inh| {
-            let fcx = FnCtxt::new(&inh, ty::FnDiverging, id);
+            let fcx = FnCtxt::new(&inh, inh.ccx.tcx.types.never, id);
             let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
                 ccx: fcx.ccx,
                 code: code
@@ -394,15 +394,10 @@ fn check_fn_or_method<'fcx, 'tcx>(&mut self,
         }
         implied_bounds.extend(sig.inputs);
 
-        match sig.output {
-            ty::FnConverging(output) => {
-                fcx.register_wf_obligation(output, span, self.code.clone());
+        fcx.register_wf_obligation(sig.output, span, self.code.clone());
 
-                // FIXME(#25759) return types should not be implied bounds
-                implied_bounds.push(output);
-            }
-            ty::FnDiverging => { }
-        }
+        // FIXME(#25759) return types should not be implied bounds
+        implied_bounds.push(sig.output);
 
         self.check_where_clauses(fcx, span, predicates);
     }
index 9026920e7f48abb0936f7e02165516c39bc5e72a..5f8861f309948d1dfdff5a65d1b18a2f931bc14c 100644 (file)
@@ -378,6 +378,10 @@ fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
 
             Some(adjustment) => {
                 let resolved_adjustment = match adjustment {
+                    adjustment::AdjustNeverToAny(ty) => {
+                        adjustment::AdjustNeverToAny(self.resolve(&ty, reason))
+                    }
+
                     adjustment::AdjustReifyFnPointer => {
                         adjustment::AdjustReifyFnPointer
                     }
index 13deac57330e3b28e5c44914b07b439d29d905cc..9b26e95f7fa55b3255c9514cfe6d21331827ced6 100644 (file)
@@ -24,7 +24,7 @@
 use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
 use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
 use rustc::ty::{TyParam, TyRawPtr};
-use rustc::ty::{TyRef, TyStruct, TyTrait, TyTuple};
+use rustc::ty::{TyRef, TyStruct, TyTrait, TyNever, TyTuple};
 use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
 use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
 use rustc::ty::{TyProjection, TyAnon};
@@ -84,7 +84,7 @@ fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
 
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
             TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
-            TyTuple(..) | TyParam(..) | TyError |
+            TyTuple(..) | TyParam(..) | TyError | TyNever |
             TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => {
                 None
             }
index 75bfad053a32855c9d6f079b67bcf3465429c019..d38065f4f1238912f3624ef2dbff74702f5c0c5e 100644 (file)
@@ -971,7 +971,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 abi: abi::Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
                     inputs: inputs,
-                    output: ty::FnConverging(scheme.ty),
+                    output: scheme.ty,
                     variadic: false
                 })
             }))
@@ -2155,11 +2155,9 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
 
     let output = match decl.output {
         hir::Return(ref ty) =>
-            ty::FnConverging(AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty)),
+            AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty),
         hir::DefaultReturn(..) =>
-            ty::FnConverging(ccx.tcx.mk_nil()),
-        hir::NoReturn(..) =>
-            ty::FnDiverging
+            ccx.tcx.mk_nil(),
     };
 
     // feature gate SIMD types in FFI, since I (huonw) am not sure the
@@ -2180,7 +2178,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
             check(&input.ty, ty)
         }
         if let hir::Return(ref ty) = decl.output {
-            check(&ty, output.unwrap())
+            check(&ty, output)
         }
     }
 
index ac40708e25cdea049bc316f63456b1290df6723a..337b87ce994ad93e50b21f740d0fe1eea2de75dc 100644 (file)
@@ -1866,20 +1866,6 @@ fn bar(foo: Foo) -> u32 {
 ```
 "##,
 
-E0166: r##"
-This error means that the compiler found a return expression in a function
-marked as diverging. A function diverges if it has `!` in the place of the
-return type in its signature. For example:
-
-```compile_fail,E0166
-fn foo() -> ! { return; } // error
-```
-
-For a function that diverges, every control path in the function must never
-return, for example with a `loop` that never breaks or a call to another
-diverging function (such as `panic!()`).
-"##,
-
 E0172: r##"
 This error means that an attempt was made to specify the type of a variable with
 a combination of a concrete type and a trait. Consider the following example:
index 0dd4bc4143927ce6dd0081a4e8767d3c727cb30d..11743ade2d469260008a5b01688be69e48a938d5 100644 (file)
@@ -238,7 +238,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
                     inputs: Vec::new(),
-                    output: ty::FnConverging(tcx.mk_nil()),
+                    output: tcx.mk_nil(),
                     variadic: false
                 })
             }));
@@ -294,7 +294,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                         tcx.types.isize,
                         tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
                     ),
-                    output: ty::FnConverging(tcx.types.isize),
+                    output: tcx.types.isize,
                     variadic: false,
                 }),
             }));
index b9e0b4a10ea45ec9396a186cd103800ac0b085c1..a4faee8f633ed71a423c5bce34392a1daae94365 100644 (file)
@@ -322,7 +322,7 @@ fn add_constraints_from_ty(&mut self,
         match ty.sty {
             ty::TyBool |
             ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
-            ty::TyFloat(_) | ty::TyStr => {
+            ty::TyFloat(_) | ty::TyStr | ty::TyNever => {
                 /* leaf type -- noop */
             }
 
@@ -490,9 +490,7 @@ fn add_constraints_from_sig(&mut self,
         for &input in &sig.0.inputs {
             self.add_constraints_from_ty(generics, input, contra);
         }
-        if let ty::FnConverging(result_type) = sig.0.output {
-            self.add_constraints_from_ty(generics, result_type, variance);
-        }
+        self.add_constraints_from_ty(generics, sig.0.output, variance);
     }
 
     /// Adds constraints appropriate for a region appearing in a
index 73bc647fa9ffbcf63d8129fb30d8f66e452a5502..99d2732c4bb06c300bad012c7589c08770d94626 100644 (file)
@@ -1176,15 +1176,6 @@ fn clean(&self, cx: &DocContext) -> FnDecl {
     }
 }
 
-impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
-    fn clean(&self, cx: &DocContext) -> Type {
-        match *self {
-            ty::FnConverging(ty) => ty.clean(cx),
-            ty::FnDiverging => Bottom
-        }
-    }
-}
-
 impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
     fn clean(&self, cx: &DocContext) -> FnDecl {
         let (did, sig) = *self;
@@ -1254,7 +1245,6 @@ fn clean(&self, cx: &DocContext) -> Argument {
 pub enum FunctionRetTy {
     Return(Type),
     DefaultReturn,
-    NoReturn
 }
 
 impl Clean<FunctionRetTy> for hir::FunctionRetTy {
@@ -1262,7 +1252,6 @@ fn clean(&self, cx: &DocContext) -> FunctionRetTy {
         match *self {
             hir::Return(ref typ) => Return(typ.clean(cx)),
             hir::DefaultReturn(..) => DefaultReturn,
-            hir::NoReturn(..) => NoReturn
         }
     }
 }
@@ -1470,8 +1459,7 @@ pub enum Type {
     Tuple(Vec<Type>),
     Vector(Box<Type>),
     FixedVector(Box<Type>, String),
-    /// aka TyBot
-    Bottom,
+    Never,
     Unique(Box<Type>),
     RawPointer(Mutability, Box<Type>),
     BorrowedRef {
@@ -1682,6 +1670,7 @@ impl Clean<Type> for hir::Ty {
     fn clean(&self, cx: &DocContext) -> Type {
         use rustc::hir::*;
         match self.node {
+            TyNever => Never,
             TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
             TyRptr(ref l, ref m) =>
                 BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
@@ -1790,6 +1779,7 @@ fn clean(&self, cx: &DocContext) -> Type {
 impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
     fn clean(&self, cx: &DocContext) -> Type {
         match self.sty {
+            ty::TyNever => Never,
             ty::TyBool => Primitive(Bool),
             ty::TyChar => Primitive(Char),
             ty::TyInt(ast::IntTy::Is) => Primitive(Isize),
index 854ca57e8556c72a606a0f4e49c2de298c3e9c22..2f03b235e9f672f397664bdbe874a4dc82734139 100644 (file)
@@ -492,7 +492,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 primitive_link(f, clean::PrimitiveType::Array,
                                &format!("; {}]", Escape(s)))
             }
-            clean::Bottom => f.write_str("!"),
+            clean::Never => f.write_str("!"),
             clean::RawPointer(m, ref t) => {
                 match **t {
                     clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
@@ -634,7 +634,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
             clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
             clean::DefaultReturn => Ok(()),
-            clean::NoReturn => write!(f, " -&gt; !")
         }
     }
 }
index 3f929e6d23aea0cedcd5eda3d8aa9256e7a3ae5e..f8a5cb0b04a8e8bcab9f759e780b0fd9dab19d80 100644 (file)
@@ -1348,6 +1348,7 @@ pub struct BareFnTy {
 /// The different kinds of types recognized by the compiler
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum TyKind {
+    /// A variable-length array (`[T]`)
     Vec(P<Ty>),
     /// A fixed length array (`[T; n]`)
     FixedLengthVec(P<Ty>, P<Expr>),
@@ -1357,6 +1358,8 @@ pub enum TyKind {
     Rptr(Option<Lifetime>, MutTy),
     /// A bare function (e.g. `fn(usize) -> bool`)
     BareFn(P<BareFnTy>),
+    /// The never type (`!`)
+    Never,
     /// A tuple (`(A, B, C, D,...)`)
     Tup(Vec<P<Ty>> ),
     /// A path (`module::module::...::Type`), optionally
@@ -1564,9 +1567,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum FunctionRetTy {
-    /// Functions with return type `!`that always
-    /// raise an error or exit (i.e. never return to the caller)
-    None(Span),
     /// Return type is not specified.
     ///
     /// Functions default to `()` and
@@ -1580,7 +1580,6 @@ pub enum FunctionRetTy {
 impl FunctionRetTy {
     pub fn span(&self) -> Span {
         match *self {
-            FunctionRetTy::None(span) => span,
             FunctionRetTy::Default(span) => span,
             FunctionRetTy::Ty(ref ty) => ty.span,
         }
index a6f0e0ca31e3e4fa94dec928990daab430ac29df..d94bfe7dcbdac2df758c55f87ec3256c1b9ee523 100644 (file)
@@ -284,7 +284,10 @@ pub fn new() -> Features {
 
     // Allows tuple structs and variants in more contexts,
     // Permits numeric fields in struct expressions and patterns.
-    (active, relaxed_adts, "1.12.0", Some(35626))
+    (active, relaxed_adts, "1.12.0", Some(35626)),
+
+    // The `!` type
+    (active, never_type, "1.13.0", Some(35121))
 );
 
 declare_features! (
@@ -963,11 +966,25 @@ fn visit_ty(&mut self, ty: &ast::Ty) {
                 gate_feature_post!(&self, conservative_impl_trait, ty.span,
                                    "`impl Trait` is experimental");
             }
+            ast::TyKind::Never => {
+                gate_feature_post!(&self, never_type, ty.span,
+                                   "The `!` type is experimental");
+            },
             _ => {}
         }
         visit::walk_ty(self, ty)
     }
 
+    fn visit_fn_ret_ty(&mut self, ret_ty: &ast::FunctionRetTy) {
+        if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
+            match output_ty.node {
+                ast::TyKind::Never => return,
+                _ => (),
+            };
+            self.visit_ty(output_ty)
+        }
+    }
+
     fn visit_expr(&mut self, e: &ast::Expr) {
         match e.node {
             ast::ExprKind::Box(_) => {
index afc990f498e6f824d5502292a77a80f1ec18f778..b257ab98987dc24701760d1ec76301380d39aa1e 100644 (file)
@@ -373,6 +373,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
                     decl: fld.fold_fn_decl(decl)
                 }))
             }
+            TyKind::Never => node,
             TyKind::Tup(tys) => TyKind::Tup(tys.move_map(|ty| fld.fold_ty(ty))),
             TyKind::Paren(ty) => TyKind::Paren(fld.fold_ty(ty)),
             TyKind::Path(qself, path) => {
@@ -637,7 +638,6 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
         output: match output {
             FunctionRetTy::Ty(ty) => FunctionRetTy::Ty(fld.fold_ty(ty)),
             FunctionRetTy::Default(span) => FunctionRetTy::Default(span),
-            FunctionRetTy::None(span) => FunctionRetTy::None(span),
         },
         variadic: variadic
     })
index e174f3ad08d6adb4ef916d5a9f85bdb1ac65a27b..126e8816d055924d3faf250ed32a4c840efdc68f 100644 (file)
@@ -1332,11 +1332,7 @@ pub fn parse_mt(&mut self) -> PResult<'a, MutTy> {
     /// Parse optional return type [ -> TY ] in function decl
     pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
         if self.eat(&token::RArrow) {
-            if self.eat(&token::Not) {
-                Ok(FunctionRetTy::None(self.last_span))
-            } else {
-                Ok(FunctionRetTy::Ty(self.parse_ty()?))
-            }
+            Ok(FunctionRetTy::Ty(self.parse_ty()?))
         } else {
             let pos = self.span.lo;
             Ok(FunctionRetTy::Default(mk_sp(pos, pos)))
@@ -1399,6 +1395,8 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
             } else {
                 TyKind::Tup(ts)
             }
+        } else if self.eat(&token::Not) {
+            TyKind::Never
         } else if self.check(&token::BinOp(token::Star)) {
             // STAR POINTER (bare pointer?)
             self.bump();
index 62e55eb78b72383eda8accaa5bbbec407af72564..a77c678248b565642a31fc5b60851c62ff1a9299 100644 (file)
@@ -976,6 +976,9 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
                 try!(self.print_opt_lifetime(lifetime));
                 try!(self.print_mt(mt));
             }
+            ast::TyKind::Never => {
+                try!(word(&mut self.s, "!"));
+            },
             ast::TyKind::Tup(ref elts) => {
                 try!(self.popen());
                 try!(self.commasep(Inconsistent, &elts[..],
@@ -2693,10 +2696,6 @@ pub fn print_fn_block_args(
                 self.maybe_print_comment(ty.span.lo)
             }
             ast::FunctionRetTy::Default(..) => unreachable!(),
-            ast::FunctionRetTy::None(span) => {
-                try!(self.word_nbsp("!"));
-                self.maybe_print_comment(span.lo)
-            }
         }
     }
 
@@ -2952,8 +2951,6 @@ pub fn print_fn_output(&mut self, decl: &ast::FnDecl) -> io::Result<()> {
         try!(self.ibox(INDENT_UNIT));
         try!(self.word_space("->"));
         match decl.output {
-            ast::FunctionRetTy::None(_) =>
-                try!(self.word_nbsp("!")),
             ast::FunctionRetTy::Default(..) => unreachable!(),
             ast::FunctionRetTy::Ty(ref ty) =>
                 try!(self.print_type(&ty))
index 6d3cdbdc6da7cc414e63de5ef5bcf4f0023ee849..582412119caa875923f6d41e6ad34c40829547e1 100644 (file)
@@ -128,6 +128,9 @@ fn visit_macro_def(&mut self, macro_def: &MacroDef) {
     fn visit_vis(&mut self, vis: &Visibility) {
         walk_vis(self, vis)
     }
+    fn visit_fn_ret_ty(&mut self, ret_ty: &FunctionRetTy) {
+        walk_fn_ret_ty(self, ret_ty)
+    }
 }
 
 #[macro_export]
@@ -319,6 +322,7 @@ pub fn walk_ty<V: Visitor>(visitor: &mut V, typ: &Ty) {
             walk_list!(visitor, visit_lifetime, opt_lifetime);
             visitor.visit_ty(&mutable_type.ty)
         }
+        TyKind::Never => {},
         TyKind::Tup(ref tuple_element_types) => {
             walk_list!(visitor, visit_ty, tuple_element_types);
         }
@@ -509,7 +513,7 @@ pub fn walk_fn_decl<V: Visitor>(visitor: &mut V, function_declaration: &FnDecl)
         visitor.visit_pat(&argument.pat);
         visitor.visit_ty(&argument.ty)
     }
-    walk_fn_ret_ty(visitor, &function_declaration.output)
+    visitor.visit_fn_ret_ty(&function_declaration.output)
 }
 
 pub fn walk_fn_kind<V: Visitor>(visitor: &mut V, function_kind: FnKind) {
diff --git a/src/test/compile-fail/E0166.rs b/src/test/compile-fail/E0166.rs
deleted file mode 100644 (file)
index f8585d7..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn foo() -> ! { return; }
-    //~^ ERROR E0166
-    //~| NOTE diverging function cannot return
-
-fn main() {
-}
diff --git a/src/test/compile-fail/bad-bang-ann-3.rs b/src/test/compile-fail/bad-bang-ann-3.rs
deleted file mode 100644 (file)
index 1a5496f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Tests that a function with a ! annotation always actually fails
-
-fn bad_bang(i: usize) -> ! {
-    return 7;
-    //~^ ERROR `return` in a function declared as diverging [E0166]
-    //~| NOTE diverging function cannot return
-}
-
-fn main() { bad_bang(5); }
diff --git a/src/test/compile-fail/bad-bang-ann.rs b/src/test/compile-fail/bad-bang-ann.rs
deleted file mode 100644 (file)
index f0ecf31..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Tests that a function with a ! annotation always actually fails
-
-fn bad_bang(i: usize) -> ! { //~ ERROR computation may converge in a function marked as diverging
-    if i < 0 { } else { panic!(); }
-}
-
-fn main() { bad_bang(5); }
diff --git a/src/test/compile-fail/bang-tailexpr.rs b/src/test/compile-fail/bang-tailexpr.rs
deleted file mode 100644 (file)
index 7d79ea0..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn f() -> ! { //~ ERROR computation may converge in a function marked as diverging
-    3
-}
-fn main() { }
diff --git a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs
new file mode 100644 (file)
index 0000000..583befe
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can't pass other types for !
+
+#![feature(never_type)]
+
+fn foo(x: !) -> ! {
+    x
+}
+
+fn main() {
+    foo("wow"); //~ ERROR mismatched types
+}
+
diff --git a/src/test/compile-fail/issue-20105.rs b/src/test/compile-fail/issue-20105.rs
deleted file mode 100644 (file)
index f133a59..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn f<F, R>(_: F) where F: Fn() -> R {
-}
-
-fn main() {
-    f(|| -> ! { () });
-//~^ ERROR: computation may converge in a function marked as diverging [E0270]
-}
diff --git a/src/test/compile-fail/issue-897-2.rs b/src/test/compile-fail/issue-897-2.rs
deleted file mode 100644 (file)
index 659b142..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![deny(unreachable_code)]
-
-fn g() -> ! { panic!(); }
-fn f() -> ! {
-    return g(); //~ ERROR `return` in a function declared as diverging
-    g();
-}
-fn h() -> ! {
-    loop {}
-    g();
-}
-
-fn main() { f() }
diff --git a/src/test/compile-fail/issue-897.rs b/src/test/compile-fail/issue-897.rs
deleted file mode 100644 (file)
index b9cfbd6..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![deny(unreachable_code)]
-
-fn f() -> ! {
-    return panic!(); //~ ERROR `return` in a function declared as diverging
-    panic!(); // the unreachable statement error is in <std macro>, at this line, there
-             // only is a note
-}
-
-fn main() { f() }
diff --git a/src/test/compile-fail/liveness-bad-bang-2.rs b/src/test/compile-fail/liveness-bad-bang-2.rs
deleted file mode 100644 (file)
index d0bc71e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Tests that a function with a ! annotation always actually fails
-
-fn bad_bang(i: usize) -> ! { //~ ERROR computation may converge in a function marked as diverging
-    println!("{}", 3);
-}
-
-fn main() { bad_bang(5); }
diff --git a/src/test/compile-fail/loop-does-not-diverge.rs b/src/test/compile-fail/loop-does-not-diverge.rs
deleted file mode 100644 (file)
index 451b306..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/* Make sure a loop{} with a break in it can't be
-   the tailexpr in the body of a diverging function */
-fn forever() -> ! {
-  loop {
-    break;
-  }
-  return 42; //~ ERROR `return` in a function declared as diverging
-}
-
-fn main() {
-}
diff --git a/src/test/compile-fail/loop-properly-diverging.rs b/src/test/compile-fail/loop-properly-diverging.rs
deleted file mode 100644 (file)
index 01dfbcc..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn forever2() -> ! { //~ ERROR computation may converge in a function marked as diverging
-  loop { break }
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs
new file mode 100644 (file)
index 0000000..57e0bca
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that an assignment of type ! makes the rest of the block dead code.
+
+#![feature(never_type)]
+#![deny(unused, unreachable_code)]
+
+fn main() {
+    let x: ! = panic!("aah"); //~ ERROR unused
+    drop(x); //~ ERROR unreachable
+}
+
diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs
new file mode 100644 (file)
index 0000000..53d96aa
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can't use another type in place of !
+
+#![feature(never_type)]
+
+fn main() {
+    let x: ! = "hello"; //~ ERROR mismatched types
+}
+
+
diff --git a/src/test/compile-fail/never-disabled.rs b/src/test/compile-fail/never-disabled.rs
new file mode 100644 (file)
index 0000000..11b9f41
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that ! 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 = &fn(!) -> !; //~ ERROR type is experimental
+type Skwoz = &mut !; //~ ERROR type is experimental
+
+impl Foo for Meeshka {
+    type Wub = !; //~ ERROR type is experimental
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/never-fallback.rs b/src/test/compile-fail/never-fallback.rs
new file mode 100644 (file)
index 0000000..a43b1a4
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that diverging types default to ! when feature(never_type) is enabled. This test is the
+// same as run-pass/unit-fallback.rs except that ! is enabled.
+
+#![feature(never_type)]
+
+trait Balls: Sized {
+    fn smeg() -> Result<Self, ()>;
+}
+
+impl Balls for () {
+    fn smeg() -> Result<(), ()> { Ok(()) }
+}
+
+struct Flah;
+
+impl Flah {
+    fn flah<T: Balls>(&self) -> Result<T, ()> {
+        T::smeg()
+    }
+}
+
+fn doit() -> Result<(), ()> {
+    // The type of _ is unconstrained here and should default to !
+    let _ = try!(Flah.flah()); //~ ERROR the trait bound
+    Ok(())
+}
+
+fn main() {
+    let _ = doit();
+}
+
diff --git a/src/test/compile-fail/return-from-diverging.rs b/src/test/compile-fail/return-from-diverging.rs
new file mode 100644 (file)
index 0000000..cec59fa
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that return another type in place of ! raises a type mismatch.
+
+fn fail() -> ! {
+    return "wow"; //~ ERROR mismatched types
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/return-unit-from-diverging.rs b/src/test/compile-fail/return-unit-from-diverging.rs
new file mode 100644 (file)
index 0000000..ae2a325
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we get the usual error that we'd get for any other return type and not something about
+// diverging functions not being able to return.
+
+fn fail() -> ! {
+    return; //~ ERROR in a function whose return type is not
+}
+
+fn main() {
+}
+
diff --git a/src/test/run-fail/adjust_never.rs b/src/test/run-fail/adjust_never.rs
new file mode 100644 (file)
index 0000000..ccdb1ca
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a variable of type ! can coerce to another type.
+
+#![feature(never_type)]
+
+// error-pattern:explicit
+fn main() {
+    let x: ! = panic!();
+    let y: u32 = x;
+}
diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/run-fail/call-fn-never-arg.rs
new file mode 100644 (file)
index 0000000..95101e7
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can use a ! for an argument of type !
+
+// error-pattern:wowzers!
+
+#![feature(never_type)]
+#![allow(unreachable_code)]
+
+fn foo(x: !) -> ! {
+    x
+}
+
+fn main() {
+    foo(panic!("wowzers!"))
+}
+
diff --git a/src/test/run-fail/cast-never.rs b/src/test/run-fail/cast-never.rs
new file mode 100644 (file)
index 0000000..acd0024
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can explicitly cast ! to another type
+
+#![feature(never_type)]
+
+// error-pattern:explicit
+fn main() {
+    let x: ! = panic!();
+    let y: u32 = x as u32;
+}
+
diff --git a/src/test/run-fail/never-associated-type.rs b/src/test/run-fail/never-associated-type.rs
new file mode 100644 (file)
index 0000000..345674f
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can use ! as an associated type.
+
+#![feature(never_type)]
+
+// error-pattern:kapow!
+
+trait Foo {
+    type Wow;
+
+    fn smeg(&self) -> Self::Wow;
+}
+
+struct Blah;
+impl Foo for Blah {
+    type Wow = !;
+    fn smeg(&self) -> ! {
+        panic!("kapow!");
+    }
+}
+
+fn main() {
+    Blah.smeg();
+}
+
diff --git a/src/test/run-fail/never-type-arg.rs b/src/test/run-fail/never-type-arg.rs
new file mode 100644 (file)
index 0000000..826ca3a
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can use ! as an argument to a trait impl.
+
+// error-pattern:oh no!
+
+#![feature(never_type)]
+
+struct Wub;
+
+impl PartialEq<!> for Wub {
+    fn eq(&self, other: &!) -> bool {
+        *other
+    }
+}
+
+fn main() {
+    let _ = Wub == panic!("oh no!");
+}
+
diff --git a/src/test/run-fail/return-never-coerce.rs b/src/test/run-fail/return-never-coerce.rs
new file mode 100644 (file)
index 0000000..4cd93ac
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that ! coerces to other types.
+
+// error-pattern:aah!
+
+fn call_another_fn<T, F: FnOnce() -> T>(f: F) -> T {
+    f()
+}
+
+fn wub() -> ! {
+    panic!("aah!");
+}
+
+fn main() {
+    let x: i32 = call_another_fn(wub);
+    let y: u32 = wub();
+}
+
+
diff --git a/src/test/run-pass/impl-for-never.rs b/src/test/run-pass/impl-for-never.rs
new file mode 100644 (file)
index 0000000..794f596
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can call static methods on ! both directly and when it appears in a generic
+
+#![feature(never_type)]
+
+trait StringifyType {
+    fn stringify_type() -> &'static str;
+}
+
+impl StringifyType for ! {
+    fn stringify_type() -> &'static str {
+        "!"
+    }
+}
+
+fn maybe_stringify<T: StringifyType>(opt: Option<T>) -> &'static str {
+    match opt {
+        Some(_) => T::stringify_type(),
+        None => "none",
+    }
+}
+
+fn main() {
+    println!("! is {}", <!>::stringify_type());
+    println!("None is {}", maybe_stringify(None::<!>));
+}
+
diff --git a/src/test/run-pass/issue-10714.rs b/src/test/run-pass/issue-10714.rs
deleted file mode 100644 (file)
index 795ad8f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// pretty-expanded FIXME #23616
-
-enum v {}
-pub fn main() {
-    let y: v = unsafe { ::std::mem::uninitialized() };
-}
diff --git a/src/test/run-pass/never-result.rs b/src/test/run-pass/never-result.rs
new file mode 100644 (file)
index 0000000..5c0af39
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can extract a ! through pattern matching then use it as several different types.
+
+#![feature(never_type)]
+
+fn main() {
+    let x: Result<u32, !> = Ok(123);
+    match x {
+        Ok(z) => (),
+        Err(y) => {
+            let q: u32 = y;
+            let w: i32 = y;
+            let e: String = y;
+            y
+        },
+    }
+}
+
diff --git a/src/test/run-pass/never_coercions.rs b/src/test/run-pass/never_coercions.rs
new file mode 100644 (file)
index 0000000..dfba5d2
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that having something of type ! doesn't screw up type-checking and that it coerces to the
+// LUB type of the other match arms.
+
+fn main() {
+    let v: Vec<u32> = Vec::new();
+    match 0u32 {
+        0 => &v,
+        1 => return,
+        _ => &v[..],
+    };
+}
+
diff --git a/src/test/run-pass/unit-fallback.rs b/src/test/run-pass/unit-fallback.rs
new file mode 100644 (file)
index 0000000..2babc63
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that diverging types default to () (with feature(never_type) disabled).
+
+trait Balls: Sized {
+    fn smeg() -> Result<Self, ()>;
+}
+
+impl Balls for () {
+    fn smeg() -> Result<(), ()> { Ok(()) }
+}
+
+struct Flah;
+
+impl Flah {
+    fn flah<T: Balls>(&self) -> Result<T, ()> {
+        T::smeg()
+    }
+}
+
+fn doit() -> Result<(), ()> {
+    // The type of _ is unconstrained here and should default to ()
+    let _ = try!(Flah.flah());
+    Ok(())
+}
+
+fn main() {
+    let _ = doit();
+}
+