]> git.lizzy.rs Git - rust.git/commitdiff
Remove ty_bot from the type system
authorJakub Bukaj <jakub@jakub.cc>
Fri, 24 Oct 2014 19:14:37 +0000 (21:14 +0200)
committerJakub Bukaj <jakub@jakub.cc>
Tue, 28 Oct 2014 16:54:16 +0000 (17:54 +0100)
We now instead use a fresh variable for expressions that diverge.

49 files changed:
src/libcore/intrinsics.rs
src/librustc/diagnostics.rs
src/librustc/lint/builtin.rs
src/librustc/metadata/tydecode.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/cfg/construct.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/middle/traits/coherence.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/closure.rs
src/librustc/middle/trans/common.rs
src/librustc/middle/trans/controlflow.rs
src/librustc/middle/trans/datum.rs
src/librustc/middle/trans/debuginfo.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/foreign.rs
src/librustc/middle/trans/glue.rs
src/librustc/middle/trans/intrinsic.rs
src/librustc/middle/trans/type_of.rs
src/librustc/middle/ty.rs
src/librustc/middle/ty_fold.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/_match.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionck.rs
src/librustc/middle/typeck/check/regionmanip.rs
src/librustc/middle/typeck/check/wf.rs
src/librustc/middle/typeck/coherence/mod.rs
src/librustc/middle/typeck/collect.rs
src/librustc/middle/typeck/infer/combine.rs
src/librustc/middle/typeck/infer/equate.rs
src/librustc/middle/typeck/infer/lattice.rs
src/librustc/middle/typeck/infer/mod.rs
src/librustc/middle/typeck/infer/resolve.rs
src/librustc/middle/typeck/infer/skolemize.rs
src/librustc/middle/typeck/infer/sub.rs
src/librustc/middle/typeck/infer/type_variable.rs
src/librustc/middle/typeck/mod.rs
src/librustc/middle/typeck/variance.rs
src/librustc/util/ppaux.rs
src/librustdoc/clean/mod.rs
src/test/compile-fail/issue-13847.rs

index 8486535d188762ec261a87066fb83667f05da4b0..68b3ca96de14715dbe14abee4b099d2078e103b3 100644 (file)
@@ -149,7 +149,7 @@ fn visit_enter_fn(&mut self, purity: uint, proto: uint,
     fn visit_fn_input(&mut self, i: uint, mode: uint,
                       inner: *const TyDesc) -> bool;
     fn visit_fn_output(&mut self, retstyle: uint, variadic: bool,
-                       inner: *const TyDesc) -> bool;
+                       converging: bool, inner: *const TyDesc) -> bool;
     fn visit_leave_fn(&mut self, purity: uint, proto: uint,
                       n_inputs: uint, retstyle: uint) -> bool;
 
index 9db79074d1fd12b0b0a62fb6901a7ba6541dd344..f405e9df51db0e132294ddf994ac1ec24b41eaef 100644 (file)
     E0162,
     E0163,
     E0164,
-    E0165
+    E0165,
+    E0166
 )
index 8c44adc55d288cd8f5c87e0a699c48885ea52c3a..99ca5770a8a2f690f2966cbd78c28fabf4b486ee 100644 (file)
@@ -683,7 +683,7 @@ fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
         let t = ty::expr_ty(cx.tcx, expr);
         let mut warned = false;
         match ty::get(t).sty {
-            ty::ty_nil | ty::ty_bot | ty::ty_bool => return,
+            ty::ty_nil | ty::ty_bool => return,
             ty::ty_struct(did, _) |
             ty::ty_enum(did, _) => {
                 if ast_util::is_local(did) {
index b5456e724d28b65660ab81e6b4eb882c0ccda160..60fb490e270b3c0193c6ba8205a4dc644675fb1d 100644 (file)
@@ -359,7 +359,6 @@ fn parse_trait_ref(st: &mut PState, conv: conv_did) -> ty::TraitRef {
 fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
     match next(st) {
       'n' => return ty::mk_nil(),
-      'z' => return ty::mk_bot(),
       'b' => return ty::mk_bool(),
       'i' => return ty::mk_int(),
       'u' => return ty::mk_uint(),
@@ -590,10 +589,16 @@ fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig {
         'N' => false,
         r => fail!(format!("bad variadic: {}", r)),
     };
-    let ret_ty = parse_ty(st, |x,y| conv(x,y));
+    let output = match peek(st) {
+        'z' => {
+          st.pos += 1u;
+          ty::FnDiverging
+        }
+        _ => ty::FnConverging(parse_ty(st, |x,y| conv(x,y)))
+    };
     ty::FnSig {binder_id: id,
                inputs: inputs,
-               output: ret_ty,
+               output: output,
                variadic: variadic}
 }
 
index 6c59537b377723c8b33bb3df5bdff53c5448880d..5fb1fec53400cfe2b47f3deae2e51dc92740f62e 100644 (file)
@@ -200,7 +200,6 @@ pub fn enc_trait_store(w: &mut SeekableMemWriter, cx: &ctxt, s: ty::TraitStore)
 fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
     match *st {
         ty::ty_nil => mywrite!(w, "n"),
-        ty::ty_bot => mywrite!(w, "z"),
         ty::ty_bool => mywrite!(w, "b"),
         ty::ty_char => mywrite!(w, "c"),
         ty::ty_int(t) => {
@@ -346,7 +345,14 @@ fn enc_fn_sig(w: &mut SeekableMemWriter, cx: &ctxt, fsig: &ty::FnSig) {
     } else {
         mywrite!(w, "N");
     }
-    enc_ty(w, cx, fsig.output);
+    match fsig.output {
+        ty::FnConverging(result_type) => {
+            enc_ty(w, cx, result_type);
+        }
+        ty::FnDiverging => {
+            mywrite!(w, "z");
+        }
+    }
 }
 
 pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::BuiltinBounds) {
index f63dafe861e10197ae5932783809e0bb744e29a8..146891825d6846a2b01dc2b7206efea5e4a9c9de 100644 (file)
@@ -511,12 +511,15 @@ fn call<'a, I: Iterator<&'a ast::Expr>>(&mut self,
             pred: CFGIndex,
             func_or_rcvr: &ast::Expr,
             args: I) -> CFGIndex {
+        let method_call = typeck::MethodCall::expr(call_expr.id);
+        let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().find(&method_call) {
+            Some(method) => method.ty,
+            None => ty::expr_ty(self.tcx, func_or_rcvr)
+        });
+
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
         let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
-
-        let return_ty = ty::node_id_to_type(self.tcx, call_expr.id);
-        let fails = ty::type_is_bot(return_ty);
-        if fails {
+        if return_ty == ty::FnDiverging {
             self.add_node(ast::DUMMY_NODE_ID, [])
         } else {
             ret
index ee9dc05c0e7612a5efb68e314344234ac2da567b..e8a85b89b58474d5d1373dd65cd761b858cd1f30 100644 (file)
@@ -396,13 +396,9 @@ pub fn walk_expr(&mut self, expr: &ast::Expr) {
                 // make sure that the thing we are pointing out stays valid
                 // for the lifetime `scope_r` of the resulting ptr:
                 let expr_ty = ty::expr_ty(self.tcx(), expr);
-                if !ty::type_is_bot(expr_ty) {
-                    let r = ty::ty_region(self.tcx(), expr.span, expr_ty);
-                    let bk = ty::BorrowKind::from_mutbl(m);
-                    self.borrow_expr(&**base, r, bk, AddrOf);
-                } else {
-                    self.walk_expr(&**base);
-                }
+                let r = ty::ty_region(self.tcx(), expr.span, expr_ty);
+                let bk = ty::BorrowKind::from_mutbl(m);
+                self.borrow_expr(&**base, r, bk, AddrOf);
             }
 
             ast::ExprInlineAsm(ref ia) => {
index d7707be58bb58b5aa93388f48a4d247f64f0608b..1dd823539b4c6216cf0b179085eb0ec3dd818398 100644 (file)
@@ -126,9 +126,10 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
                         match ty::get(typ).sty {
                             ty_bare_fn(ref bare_fn_ty)
                                     if bare_fn_ty.abi == RustIntrinsic => {
-                                let from = bare_fn_ty.sig.inputs[0];
-                                let to = bare_fn_ty.sig.output;
-                                self.check_transmute(expr.span, from, to, expr.id);
+                                if let ty::FnConverging(to) = bare_fn_ty.sig.output {
+                                    let from = bare_fn_ty.sig.inputs[0];
+                                    self.check_transmute(expr.span, from, to, expr.id);
+                                }
                             }
                             _ => {
                                 self.tcx
index 63e9a80adc61aa3aad273224ad662c84a01e8a65..3d031c966ae0a0a19bca5cb8fe97c0c21e82cc10 100644 (file)
  * - `no_ret_var`: a synthetic variable that is only 'read' from, the
  *   fallthrough node.  This allows us to detect functions where we fail
  *   to return explicitly.
+ * - `clean_exit_var`: a synthetic variable that is only 'read' from the
+ *   fallthrough node.  It is only live if the function could converge
+ *   via means other than an explicit `return` expression. That is, it is
+ *   only dead if the end of the function's block can never be reached.
  */
 
 use middle::def::*;
 use middle::mem_categorization::Typer;
 use middle::pat_util;
+use middle::typeck;
 use middle::ty;
 use lint;
 use util::nodemap::NodeMap;
@@ -250,7 +255,8 @@ struct LocalInfo {
 enum VarKind {
     Arg(NodeId, Ident),
     Local(LocalInfo),
-    ImplicitRet
+    ImplicitRet,
+    CleanExit
 }
 
 struct IrMaps<'a, 'tcx: 'a> {
@@ -306,7 +312,7 @@ fn add_variable(&mut self, vk: VarKind) -> Variable {
             Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => {
                 self.variable_map.insert(node_id, v);
             },
-            ImplicitRet => {}
+            ImplicitRet | CleanExit => {}
         }
 
         debug!("{} is {}", v.to_string(), vk);
@@ -331,7 +337,8 @@ fn variable_name(&self, var: Variable) -> String {
             Local(LocalInfo { ident: nm, .. }) | Arg(_, nm) => {
                 token::get_ident(nm).get().to_string()
             },
-            ImplicitRet => "<implicit-ret>".to_string()
+            ImplicitRet => "<implicit-ret>".to_string(),
+            CleanExit => "<clean-exit>".to_string()
         }
     }
 
@@ -397,7 +404,8 @@ fn visit_fn(ir: &mut IrMaps,
     let specials = Specials {
         exit_ln: fn_maps.add_live_node(ExitNode),
         fallthrough_ln: fn_maps.add_live_node(ExitNode),
-        no_ret_var: fn_maps.add_variable(ImplicitRet)
+        no_ret_var: fn_maps.add_variable(ImplicitRet),
+        clean_exit_var: fn_maps.add_variable(CleanExit)
     };
 
     // compute liveness
@@ -546,7 +554,8 @@ fn invalid_users() -> Users {
 struct Specials {
     exit_ln: LiveNode,
     fallthrough_ln: LiveNode,
-    no_ret_var: Variable
+    no_ret_var: Variable,
+    clean_exit_var: Variable
 }
 
 static ACC_READ: uint = 1u;
@@ -873,6 +882,7 @@ fn propagate_through_fn_block(&mut self, _: &FnDecl, blk: &Block)
         if blk.expr.is_none() {
             self.acc(s.fallthrough_ln, s.no_ret_var, ACC_READ)
         }
+        self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ);
 
         self.propagate_through_block(blk, s.fallthrough_ln)
     }
@@ -943,9 +953,7 @@ fn propagate_through_opt_expr(&mut self,
                                   opt_expr: Option<&Expr>,
                                   succ: LiveNode)
                                   -> LiveNode {
-        opt_expr.iter().fold(succ, |succ, expr| {
-            self.propagate_through_expr(&**expr, succ)
-        })
+        opt_expr.map_or(succ, |expr| self.propagate_through_expr(expr, succ))
     }
 
     fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
@@ -1146,13 +1154,11 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           }
 
           ExprCall(ref f, ref args) => {
-            // calling a fn with bot return type means that the fn
-            // will fail, and hence the successors can be ignored
-            let is_bot = !self.ir.tcx.is_method_call(expr.id) && {
+            let diverges = !self.ir.tcx.is_method_call(expr.id) && {
                 let t_ret = ty::ty_fn_ret(ty::expr_ty(self.ir.tcx, &**f));
-                ty::type_is_bot(t_ret)
+                t_ret == ty::FnDiverging
             };
-            let succ = if is_bot {
+            let succ = if diverges {
                 self.s.exit_ln
             } else {
                 succ
@@ -1162,11 +1168,14 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           }
 
           ExprMethodCall(_, _, ref args) => {
-            // calling a method with bot return type means that the method
-            // will fail, and hence the successors can be ignored
-            let t_ret = ty::node_id_to_type(self.ir.tcx, expr.id);
-            let succ = if ty::type_is_bot(t_ret) {self.s.exit_ln}
-                       else {succ};
+            let method_call = typeck::MethodCall::expr(expr.id);
+            let method_ty = self.ir.tcx.method_map.borrow().find(&method_call).unwrap().ty;
+            let diverges = ty::ty_fn_ret(method_ty) == ty::FnDiverging;
+            let succ = if diverges {
+                self.s.exit_ln
+            } else {
+                succ
+            };
             self.propagate_through_exprs(args.as_slice(), succ)
           }
 
@@ -1507,50 +1516,68 @@ fn check_fn(_v: &Liveness,
 }
 
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
+    fn fn_ret(&self, id: NodeId) -> ty::FnOutput {
+        let fn_ty = ty::node_id_to_type(self.ir.tcx, id);
+        match ty::get(fn_ty).sty {
+            ty::ty_unboxed_closure(closure_def_id, _, _) =>
+                self.ir.tcx.unboxed_closures()
+                    .borrow()
+                    .find(&closure_def_id)
+                    .unwrap()
+                    .closure_type
+                    .sig
+                    .output,
+            _ => ty::ty_fn_ret(fn_ty)
+        }
+    }
+
     fn check_ret(&self,
                  id: NodeId,
                  sp: Span,
                  _fk: FnKind,
                  entry_ln: LiveNode,
                  body: &Block) {
-        if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
-            // if no_ret_var is live, then we fall off the end of the
-            // function without any kind of return expression:
-
-            let t_ret = ty::ty_fn_ret(ty::node_id_to_type(self.ir.tcx, id));
-            if ty::type_is_nil(t_ret) {
-                // for nil return types, it is ok to not return a value expl.
-            } else if ty::type_is_bot(t_ret) {
-                // for bot return types, not ok.  Function should fail.
-                self.ir.tcx.sess.span_err(
-                    sp, "some control paths may return");
-            } else {
-                let ends_with_stmt = match body.expr {
-                    None if body.stmts.len() > 0 =>
-                        match body.stmts.last().unwrap().node {
-                            StmtSemi(ref e, _) => {
-                                let t_stmt = ty::expr_ty(self.ir.tcx, &**e);
-                                ty::get(t_stmt).sty == ty::get(t_ret).sty
+        match self.fn_ret(id) {
+            ty::FnConverging(t_ret)
+                if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() => {
+
+                if ty::type_is_nil(t_ret) {
+                    // for nil return types, it is ok to not return a value expl.
+                } else {
+                    let ends_with_stmt = match body.expr {
+                        None if body.stmts.len() > 0 =>
+                            match body.stmts.last().unwrap().node {
+                                StmtSemi(ref e, _) => {
+                                    let t_stmt = ty::expr_ty(self.ir.tcx, &**e);
+                                    ty::get(t_stmt).sty == ty::get(t_ret).sty
+                                },
+                                _ => false
                             },
-                            _ => false
-                        },
-                    _ => false
-                };
-                self.ir.tcx.sess.span_err(
-                    sp, "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
+                        _ => false
                     };
-                    self.ir.tcx.sess.span_note(
-                        span_semicolon, "consider removing this semicolon:");
+                    self.ir.tcx.sess.span_err(
+                        sp, "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
+                        };
+                        self.ir.tcx.sess.span_note(
+                            span_semicolon, "consider removing this semicolon:");
+                    }
                 }
-           }
+            }
+            ty::FnDiverging
+                if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() => {
+                    self.ir.tcx.sess.span_err(sp,
+                        "computation may converge in a function marked as diverging");
+                }
+
+            _ => {}
         }
     }
 
index abdbd80ebf2e35e5240c057d95d4cc3206e64b39..c0188cac259ced92a9509683844e371c9103305a 100644 (file)
@@ -485,7 +485,7 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt> {
                 Some(method_ty) => {
                     // If this is an index implemented by a method call, then it will
                     // include an implicit deref of the result.
-                    let ret_ty = ty::ty_fn_ret(method_ty);
+                    let ret_ty = ty::ty_fn_ret(method_ty).unwrap();
                     Ok(self.cat_deref(expr,
                                       self.cat_rvalue_node(expr.id(),
                                                            expr.span(),
@@ -878,7 +878,7 @@ fn cat_deref<N:ast_node>(&self,
 
         let base_cmt = match method_ty {
             Some(method_ty) => {
-                let ref_ty = ty::ty_fn_ret(method_ty);
+                let ref_ty = ty::ty_fn_ret(method_ty).unwrap();
                 self.cat_rvalue_node(node.id(), node.span(), ref_ty)
             }
             None => base_cmt
@@ -957,7 +957,7 @@ pub fn cat_index<N:ast_node>(&self,
 
         let element_ty = match method_ty {
             Some(method_ty) => {
-                let ref_ty = ty::ty_fn_ret(method_ty);
+                let ref_ty = ty::ty_fn_ret(method_ty).unwrap();
                 base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
                 ty::ty_fn_args(method_ty)[0]
             }
index e045b9fd4f4a3a58ca523fb0f5780f974b3eb7af..8b2ddca3131971acb997194d5911956947e05ced 100644 (file)
@@ -80,7 +80,6 @@ pub fn ty_is_local(tcx: &ty::ctxt,
 
     match ty::get(ty).sty {
         ty::ty_nil |
-        ty::ty_bot |
         ty::ty_bool |
         ty::ty_char |
         ty::ty_int(..) |
index 2f345e2e6196c8370b07540fe002e3243be0e18a..f8c1c37452b38c4e93b6ac35a75ee3cbc720b382 100644 (file)
@@ -1193,7 +1193,6 @@ fn builtin_bound(&mut self,
             ty::ty_uint(_) |
             ty::ty_int(_) |
             ty::ty_nil |
-            ty::ty_bot |
             ty::ty_bool |
             ty::ty_float(_) |
             ty::ty_bare_fn(_) |
@@ -1681,7 +1680,7 @@ fn confirm_unboxed_closure_candidate(&mut self,
             def_id: obligation.trait_ref.def_id,
             substs: Substs::new_trait(
                 vec![arguments_tuple.subst(self.tcx(), substs),
-                     new_signature.output.subst(self.tcx(), substs)],
+                     new_signature.output.unwrap().subst(self.tcx(), substs)],
                 vec![],
                 obligation.self_ty())
         });
index e4f34d8ab47be48ad1bdd53fabff54351aba337b..2379a5e7f53a2e6f8a04db11175a5c35cdf7394f 100644 (file)
@@ -1462,15 +1462,11 @@ fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
             // General path.
             let init_datum =
                 unpack_datum!(bcx, expr::trans_to_lvalue(bcx, &**init_expr, "let"));
-            if ty::type_is_bot(expr_ty(bcx, &**init_expr)) {
-                create_dummy_locals(bcx, pat)
-            } else {
-                if bcx.sess().asm_comments() {
-                    add_comment(bcx, "creating zeroable ref llval");
-                }
-                let var_scope = cleanup::var_scope(tcx, local.id);
-                bind_irrefutable_pat(bcx, pat, init_datum.val, var_scope)
+            if bcx.sess().asm_comments() {
+                add_comment(bcx, "creating zeroable ref llval");
             }
+            let var_scope = cleanup::var_scope(tcx, local.id);
+            bind_irrefutable_pat(bcx, pat, init_datum.val, var_scope)
         }
         None => {
             create_dummy_locals(bcx, pat)
index a739f6e3db279f066f0573a01df0193b469b219f..16ff2f901f6d59b73a3f74787a62068baf819aba 100644 (file)
@@ -180,7 +180,7 @@ fn drop(&mut self) {
 
 // only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
 pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
-           ty: Type, output: ty::t) -> ValueRef {
+           ty: Type, output: ty::FnOutput) -> ValueRef {
 
     let llfn: ValueRef = name.with_c_str(|buf| {
         unsafe {
@@ -188,12 +188,9 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
         }
     });
 
-    match ty::get(output).sty {
-        // functions returning bottom may unwind, but can never return normally
-        ty::ty_bot => {
-            llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute)
-        }
-        _ => {}
+    // diverging functions may unwind, but can never return normally
+    if output == ty::FnDiverging {
+        llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute);
     }
 
     if ccx.tcx().sess.opts.cg.no_redzone {
@@ -216,7 +213,7 @@ pub fn decl_cdecl_fn(ccx: &CrateContext,
                      name: &str,
                      ty: Type,
                      output: ty::t) -> ValueRef {
-    decl_fn(ccx, name, llvm::CCallConv, ty, output)
+    decl_fn(ccx, name, llvm::CCallConv, ty, ty::FnConverging(output))
 }
 
 // only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
@@ -231,7 +228,7 @@ pub fn get_extern_fn(ccx: &CrateContext,
         Some(n) => return *n,
         None => {}
     }
-    let f = decl_fn(ccx, name, cc, ty, output);
+    let f = decl_fn(ccx, name, cc, ty, ty::FnConverging(output));
     externs.insert(name.to_string(), f);
     f
 }
@@ -1417,7 +1414,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
                              llfndecl: ValueRef,
                              id: ast::NodeId,
                              has_env: bool,
-                             output_type: ty::t,
+                             output_type: ty::FnOutput,
                              param_substs: &'a param_substs,
                              sp: Option<Span>,
                              block_arena: &'a TypedArena<common::BlockS<'a, 'tcx>>)
@@ -1432,8 +1429,13 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
            },
            id, param_substs.repr(ccx.tcx()));
 
-    let substd_output_type = output_type.substp(ccx.tcx(), param_substs);
-    let uses_outptr = type_of::return_uses_outptr(ccx, substd_output_type);
+    let uses_outptr = match output_type {
+        ty::FnConverging(output_type) => {
+            let substd_output_type = output_type.substp(ccx.tcx(), param_substs);
+            type_of::return_uses_outptr(ccx, substd_output_type)
+        }
+        ty::FnDiverging => false
+    };
     let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
     let nested_returns = has_nested_returns(ccx.tcx(), id);
 
@@ -1468,7 +1470,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
 /// and allocating space for the return pointer.
 pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>,
                                skip_retptr: bool,
-                               output_type: ty::t) -> Block<'a, 'tcx> {
+                               output: ty::FnOutput) -> Block<'a, 'tcx> {
     let entry_bcx = fcx.new_temp_block("entry-block");
 
     // Use a dummy instruction as the insertion point for all allocas.
@@ -1478,18 +1480,19 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>,
         llvm::LLVMGetFirstInstruction(entry_bcx.llbb)
     }));
 
-    // This shouldn't need to recompute the return type,
-    // as new_fn_ctxt did it already.
-    let substd_output_type = output_type.substp(fcx.ccx.tcx(), fcx.param_substs);
-
-    if !return_type_is_void(fcx.ccx, substd_output_type) {
-        // If the function returns nil/bot, there is no real return
-        // value, so do not set `llretslotptr`.
-        if !skip_retptr || fcx.caller_expects_out_pointer {
-            // Otherwise, we normally allocate the llretslotptr, unless we
-            // have been instructed to skip it for immediate return
-            // values.
-            fcx.llretslotptr.set(Some(make_return_slot_pointer(fcx, substd_output_type)));
+    if let ty::FnConverging(output_type) = output {
+        // This shouldn't need to recompute the return type,
+        // as new_fn_ctxt did it already.
+        let substd_output_type = output_type.substp(fcx.ccx.tcx(), fcx.param_substs);
+        if !return_type_is_void(fcx.ccx, substd_output_type) {
+            // If the function returns nil/bot, there is no real return
+            // value, so do not set `llretslotptr`.
+            if !skip_retptr || fcx.caller_expects_out_pointer {
+                // Otherwise, we normally allocate the llretslotptr, unless we
+                // have been instructed to skip it for immediate return
+                // values.
+                fcx.llretslotptr.set(Some(make_return_slot_pointer(fcx, substd_output_type)));
+            }
         }
     }
 
@@ -1693,13 +1696,9 @@ fn copy_unboxed_closure_args_to_allocas<'blk, 'tcx>(
 // and builds the return block.
 pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>,
                              last_bcx: Block<'blk, 'tcx>,
-                             retty: ty::t) {
+                             retty: ty::FnOutput) {
     let _icx = push_ctxt("finish_fn");
 
-    // This shouldn't need to recompute the return type,
-    // as new_fn_ctxt did it already.
-    let substd_retty = retty.substp(fcx.ccx.tcx(), fcx.param_substs);
-
     let ret_cx = match fcx.llreturn.get() {
         Some(llreturn) => {
             if !last_bcx.terminated.get() {
@@ -1709,13 +1708,18 @@ pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>,
         }
         None => last_bcx
     };
+
+    // This shouldn't need to recompute the return type,
+    // as new_fn_ctxt did it already.
+    let substd_retty = retty.substp(fcx.ccx.tcx(), fcx.param_substs);
     build_return_block(fcx, ret_cx, substd_retty);
+
     debuginfo::clear_source_location(fcx);
     fcx.cleanup();
 }
 
 // Builds the return block for a function.
-pub fn build_return_block(fcx: &FunctionContext, ret_cx: Block, retty: ty::t) {
+pub fn build_return_block(fcx: &FunctionContext, ret_cx: Block, retty: ty::FnOutput) {
     if fcx.llretslotptr.get().is_none() ||
        (!fcx.needs_ret_allocas && fcx.caller_expects_out_pointer) {
         return RetVoid(ret_cx);
@@ -1738,26 +1742,37 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: Block, retty: ty::t) {
                 retptr.erase_from_parent();
             }
 
-            let retval = if ty::type_is_bool(retty) {
+            let retval = if retty == ty::FnConverging(ty::mk_bool()) {
                 Trunc(ret_cx, retval, Type::i1(fcx.ccx))
             } else {
                 retval
             };
 
             if fcx.caller_expects_out_pointer {
-                store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty);
-                return RetVoid(ret_cx);
+                if let ty::FnConverging(retty) = retty {
+                    store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty);
+                }
+                RetVoid(ret_cx)
             } else {
-                return Ret(ret_cx, retval);
+                Ret(ret_cx, retval)
             }
         }
         // Otherwise, copy the return value to the ret slot
-        None => {
-            if fcx.caller_expects_out_pointer {
-                memcpy_ty(ret_cx, get_param(fcx.llfn, 0), retslot, retty);
-                return RetVoid(ret_cx);
-            } else {
-                return Ret(ret_cx, load_ty(ret_cx, retslot, retty));
+        None => match retty {
+            ty::FnConverging(retty) => {
+                if fcx.caller_expects_out_pointer {
+                    memcpy_ty(ret_cx, get_param(fcx.llfn, 0), retslot, retty);
+                    RetVoid(ret_cx)
+                } else {
+                    Ret(ret_cx, load_ty(ret_cx, retslot, retty))
+                }
+            }
+            ty::FnDiverging => {
+                if fcx.caller_expects_out_pointer {
+                    RetVoid(ret_cx)
+                } else {
+                    Ret(ret_cx, C_undef(Type::nil(fcx.ccx)))
+                }
             }
         }
     }
@@ -1780,7 +1795,7 @@ pub fn trans_closure(ccx: &CrateContext,
                      fn_ast_id: ast::NodeId,
                      _attributes: &[ast::Attribute],
                      arg_types: Vec<ty::t>,
-                     output_type: ty::t,
+                     output_type: ty::FnOutput,
                      abi: Abi,
                      has_env: bool,
                      is_unboxed_closure: IsUnboxedClosureFlag,
@@ -1860,7 +1875,7 @@ pub fn trans_closure(ccx: &CrateContext,
     debuginfo::start_emitting_source_locations(&fcx);
 
     let dest = match fcx.llretslotptr.get() {
-        Some(_) => expr::SaveIn(fcx.get_ret_slot(bcx, block_ty, "iret_slot")),
+        Some(_) => expr::SaveIn(fcx.get_ret_slot(bcx, ty::FnConverging(block_ty), "iret_slot")),
         None => {
             assert!(type_is_zero_size(bcx.ccx(), block_ty));
             expr::Ignore
@@ -1965,7 +1980,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let tcx = ccx.tcx();
 
     let result_ty = match ty::get(ctor_ty).sty {
-        ty::ty_bare_fn(ref bft) => bft.sig.output,
+        ty::ty_bare_fn(ref bft) => bft.sig.output.unwrap(),
         _ => ccx.sess().bug(
             format!("trans_enum_variant_constructor: \
                      unexpected ctor return type {}",
@@ -2055,9 +2070,9 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
 
     let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
 
-    if !type_is_zero_size(fcx.ccx, result_ty) {
+    if !type_is_zero_size(fcx.ccx, result_ty.unwrap()) {
         let dest = fcx.get_ret_slot(bcx, result_ty, "eret_slot");
-        let repr = adt::represent_type(ccx, result_ty);
+        let repr = adt::represent_type(ccx, result_ty.unwrap());
         for (i, arg_datum) in arg_datums.into_iter().enumerate() {
             let lldestptr = adt::trans_field_ptr(bcx,
                                                  &*repr,
@@ -2393,53 +2408,55 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
         _ => fn_sig.inputs.clone()
     };
 
-    // A function pointer is called without the declaration
-    // available, so we have to apply any attributes with ABI
-    // implications directly to the call instruction. Right now,
-    // the only attribute we need to worry about is `sret`.
-    if type_of::return_uses_outptr(ccx, ret_ty) {
-        let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, ret_ty));
-
-        // The outptr can be noalias and nocapture because it's entirely
-        // invisible to the program. We also know it's nonnull as well
-        // as how many bytes we can dereference
-        attrs.arg(1, llvm::StructRetAttribute)
-             .arg(1, llvm::NoAliasAttribute)
-             .arg(1, llvm::NoCaptureAttribute)
-             .arg(1, llvm::DereferenceableAttribute(llret_sz));
-
-        // Add one more since there's an outptr
-        first_arg_offset += 1;
-    } else {
-        // The `noalias` attribute on the return value is useful to a
-        // function ptr caller.
-        match ty::get(ret_ty).sty {
-            // `~` pointer return values never alias because ownership
-            // is transferred
-            ty::ty_uniq(it) if !ty::type_is_sized(ccx.tcx(), it) => {}
-            ty::ty_uniq(_) => {
-                attrs.ret(llvm::NoAliasAttribute);
+    if let ty::FnConverging(ret_ty) = ret_ty {
+        // A function pointer is called without the declaration
+        // available, so we have to apply any attributes with ABI
+        // implications directly to the call instruction. Right now,
+        // the only attribute we need to worry about is `sret`.
+        if type_of::return_uses_outptr(ccx, ret_ty) {
+            let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, ret_ty));
+
+            // The outptr can be noalias and nocapture because it's entirely
+            // invisible to the program. We also know it's nonnull as well
+            // as how many bytes we can dereference
+            attrs.arg(1, llvm::StructRetAttribute)
+                 .arg(1, llvm::NoAliasAttribute)
+                 .arg(1, llvm::NoCaptureAttribute)
+                 .arg(1, llvm::DereferenceableAttribute(llret_sz));
+
+            // Add one more since there's an outptr
+            first_arg_offset += 1;
+        } else {
+            // The `noalias` attribute on the return value is useful to a
+            // function ptr caller.
+            match ty::get(ret_ty).sty {
+                // `~` pointer return values never alias because ownership
+                // is transferred
+                ty::ty_uniq(it) if !ty::type_is_sized(ccx.tcx(), it) => {}
+                ty::ty_uniq(_) => {
+                    attrs.ret(llvm::NoAliasAttribute);
+                }
+                _ => {}
             }
-            _ => {}
-        }
 
-        // We can also mark the return value as `dereferenceable` in certain cases
-        match ty::get(ret_ty).sty {
-            // These are not really pointers but pairs, (pointer, len)
-            ty::ty_uniq(it) |
-            ty::ty_rptr(_, ty::mt { ty: it, .. }) if !ty::type_is_sized(ccx.tcx(), it) => {}
-            ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => {
-                let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner));
-                attrs.ret(llvm::DereferenceableAttribute(llret_sz));
+            // We can also mark the return value as `dereferenceable` in certain cases
+            match ty::get(ret_ty).sty {
+                // These are not really pointers but pairs, (pointer, len)
+                ty::ty_uniq(it) |
+                ty::ty_rptr(_, ty::mt { ty: it, .. }) if !ty::type_is_sized(ccx.tcx(), it) => {}
+                ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => {
+                    let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner));
+                    attrs.ret(llvm::DereferenceableAttribute(llret_sz));
+                }
+                _ => {}
             }
-            _ => {}
-        }
 
-        match ty::get(ret_ty).sty {
-            ty::ty_bool => {
-                attrs.ret(llvm::ZExtAttribute);
+            match ty::get(ret_ty).sty {
+                ty::ty_bool => {
+                    attrs.ret(llvm::ZExtAttribute);
+                }
+                _ => {}
             }
-            _ => {}
         }
     }
 
@@ -2523,7 +2540,7 @@ pub fn register_fn_llvmty(ccx: &CrateContext,
                           llfty: Type) -> ValueRef {
     debug!("register_fn_llvmty id={} sym={}", node_id, sym);
 
-    let llfn = decl_fn(ccx, sym.as_slice(), cc, llfty, ty::mk_nil());
+    let llfn = decl_fn(ccx, sym.as_slice(), cc, llfty, ty::FnConverging(ty::mk_nil()));
     finish_register_fn(ccx, sp, sym, node_id, llfn);
     llfn
 }
index b8895e9486a05623b07c561cabf9e5620fd85541..045f50bf6b1e0013f8156d59f9bd6be125d78c8f 100644 (file)
@@ -375,10 +375,9 @@ pub fn trans_unboxing_shim(bcx: Block,
         llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
     }
     assert!(!fcx.needs_ret_allocas);
-    let dest = match fcx.llretslotptr.get() {
-        Some(_) => Some(expr::SaveIn(fcx.get_ret_slot(bcx, return_type, "ret_slot"))),
-        None => None
-    };
+    let dest = fcx.llretslotptr.get().map(|_|
+        expr::SaveIn(fcx.get_ret_slot(bcx, return_type, "ret_slot"))
+    );
     bcx = trans_call_inner(bcx,
                            None,
                            function_type,
@@ -757,24 +756,29 @@ pub fn trans_call_inner<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Generate a location to store the result. If the user does
     // not care about the result, just make a stack slot.
-    let opt_llretslot = match dest {
-        None => {
-            assert!(!type_of::return_uses_outptr(ccx, ret_ty));
-            None
-        }
-        Some(expr::SaveIn(dst)) => Some(dst),
-        Some(expr::Ignore) if !is_rust_fn ||
-                type_of::return_uses_outptr(ccx, ret_ty) ||
-                ty::type_needs_drop(bcx.tcx(), ret_ty) => {
-            if !type_is_zero_size(ccx, ret_ty) {
-                Some(alloc_ty(bcx, ret_ty, "__llret"))
+    let opt_llretslot = dest.and_then(|dest| match dest {
+        expr::SaveIn(dst) => Some(dst),
+        expr::Ignore => {
+            let ret_ty = match ret_ty {
+                ty::FnConverging(ret_ty) => ret_ty,
+                ty::FnDiverging => ty::mk_nil()
+            };
+            if !is_rust_fn ||
+              type_of::return_uses_outptr(ccx, ret_ty) ||
+              ty::type_needs_drop(bcx.tcx(), ret_ty) {
+                // Push the out-pointer if we use an out-pointer for this
+                // return type, otherwise push "undef".
+                if type_is_zero_size(ccx, ret_ty) {
+                    let llty = type_of::type_of(ccx, ret_ty);
+                    Some(C_undef(llty.ptr_to()))
+                } else {
+                    Some(alloc_ty(bcx, ret_ty, "__llret"))
+                }
             } else {
-                let llty = type_of::type_of(ccx, ret_ty);
-                Some(C_undef(llty.ptr_to()))
+                None
             }
         }
-        Some(expr::Ignore) => None
-    };
+    });
 
     let mut llresult = unsafe {
         llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref())
@@ -789,17 +793,15 @@ pub fn trans_call_inner<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     if is_rust_fn {
         let mut llargs = Vec::new();
 
-        // Push the out-pointer if we use an out-pointer for this
-        // return type, otherwise push "undef".
-        if type_of::return_uses_outptr(ccx, ret_ty) {
-            llargs.push(opt_llretslot.unwrap());
+        if let (ty::FnConverging(ret_ty), Some(llretslot)) = (ret_ty, opt_llretslot) {
+            if type_of::return_uses_outptr(ccx, ret_ty) {
+                llargs.push(llretslot);
+            }
         }
 
         // Push the environment (or a trait object's self).
         match (llenv, llself) {
-            (Some(llenv), None) => {
-                llargs.push(llenv)
-            },
+            (Some(llenv), None) => llargs.push(llenv),
             (None, Some(llself)) => llargs.push(llself),
             _ => {}
         }
@@ -827,15 +829,15 @@ pub fn trans_call_inner<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
         // If the Rust convention for this type is return via
         // the return value, copy it into llretslot.
-        match opt_llretslot {
-            Some(llretslot) => {
+        match (opt_llretslot, ret_ty) {
+            (Some(llretslot), ty::FnConverging(ret_ty)) => {
                 if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) &&
                     !type_is_zero_size(bcx.ccx(), ret_ty)
                 {
                     store_ty(bcx, llret, llretslot, ret_ty)
                 }
             }
-            None => {}
+            (_, _) => {}
         }
     } else {
         // Lang items are the only case where dest is None, and
@@ -865,8 +867,8 @@ pub fn trans_call_inner<'blk, 'tcx>(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) {
-        (Some(expr::Ignore), Some(llretslot)) => {
+    match (dest, opt_llretslot, ret_ty) {
+        (Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => {
             // drop the value if it is not being saved.
             bcx = glue::drop_ty(bcx, llretslot, ret_ty, call_info);
             call_lifetime_end(bcx, llretslot);
@@ -874,8 +876,11 @@ pub fn trans_call_inner<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         _ => {}
     }
 
-    if ty::type_is_bot(ret_ty) {
-        Unreachable(bcx);
+    match ret_ty {
+        ty::FnConverging(_) => {},
+        ty::FnDiverging => {
+            Unreachable(bcx);
+        }
     }
 
     Result::new(bcx, llresult)
@@ -1118,52 +1123,41 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     debug!("   arg datum: {}", arg_datum.to_string(bcx.ccx()));
 
     let mut val;
-    if ty::type_is_bot(arg_datum_ty) {
-        // For values of type _|_, we generate an
-        // "undef" value, as such a value should never
-        // be inspected. It's important for the value
-        // to have type lldestty (the callee's expected type).
-        let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
-        unsafe {
-            val = llvm::LLVMGetUndef(llformal_arg_ty.to_ref());
+    // FIXME(#3548) use the adjustments table
+    match autoref_arg {
+        DoAutorefArg(arg_id) => {
+            // We will pass argument by reference
+            // We want an lvalue, so that we can pass by reference and
+            let arg_datum = unpack_datum!(
+                bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
+            val = arg_datum.val;
         }
-    } else {
-        // FIXME(#3548) use the adjustments table
-        match autoref_arg {
-            DoAutorefArg(arg_id) => {
-                // We will pass argument by reference
-                // We want an lvalue, so that we can pass by reference and
-                let arg_datum = unpack_datum!(
-                    bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
-                val = arg_datum.val;
-            }
-            DontAutorefArg => {
-                // Make this an rvalue, since we are going to be
-                // passing ownership.
-                let arg_datum = unpack_datum!(
-                    bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
-
-                // Now that arg_datum is owned, get it into the appropriate
-                // mode (ref vs value).
-                let arg_datum = unpack_datum!(
-                    bcx, arg_datum.to_appropriate_datum(bcx));
-
-                // Technically, ownership of val passes to the callee.
-                // However, we must cleanup should we fail before the
-                // callee is actually invoked.
-                val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope);
-            }
+        DontAutorefArg => {
+            // Make this an rvalue, since we are going to be
+            // passing ownership.
+            let arg_datum = unpack_datum!(
+                bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
+
+            // Now that arg_datum is owned, get it into the appropriate
+            // mode (ref vs value).
+            let arg_datum = unpack_datum!(
+                bcx, arg_datum.to_appropriate_datum(bcx));
+
+            // Technically, ownership of val passes to the callee.
+            // However, we must cleanup should we fail before the
+            // callee is actually invoked.
+            val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope);
         }
+    }
 
-        if formal_arg_ty != arg_datum_ty {
-            // this could happen due to e.g. subtyping
-            let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
-            debug!("casting actual type ({}) to match formal ({})",
-                   bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty));
-            debug!("Rust types: {}; {}", ty_to_string(bcx.tcx(), arg_datum_ty),
-                                         ty_to_string(bcx.tcx(), formal_arg_ty));
-            val = PointerCast(bcx, val, llformal_arg_ty);
-        }
+    if formal_arg_ty != arg_datum_ty {
+        // this could happen due to e.g. subtyping
+        let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
+        debug!("casting actual type ({}) to match formal ({})",
+               bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty));
+        debug!("Rust types: {}; {}", ty_to_string(bcx.tcx(), arg_datum_ty),
+                                     ty_to_string(bcx.tcx(), formal_arg_ty));
+        val = PointerCast(bcx, val, llformal_arg_ty);
     }
 
     debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val));
index d4e1473f0e5c21036087e88a55816b0cd7496210..b6f45b2ccda774754abf154943a6acb36e089c5b 100644 (file)
@@ -623,10 +623,17 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
     llargs.extend(args.iter().map(|arg| arg.val));
 
     let retval = Call(bcx, fn_ptr, llargs.as_slice(), None);
-    if type_is_zero_size(ccx, f.sig.output) || fcx.llretslotptr.get().is_some() {
-        RetVoid(bcx);
-    } else {
-        Ret(bcx, retval);
+    match f.sig.output {
+        ty::FnConverging(output_type) => {
+            if type_is_zero_size(ccx, output_type) || fcx.llretslotptr.get().is_some() {
+                RetVoid(bcx);
+            } else {
+                Ret(bcx, retval);
+            }
+        }
+        ty::FnDiverging => {
+            RetVoid(bcx);
+        }
     }
 
     // HACK(eddyb) finish_fn cannot be used here, we returned directly.
index 496838c9e84f23ecbd1a253fd9173356fc3afa36..5d386b0a706b5b34bcdbc174804e80f757e27922 100644 (file)
@@ -74,7 +74,7 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
     let tcx = ccx.tcx();
     let simple = ty::type_is_scalar(ty) ||
         ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) ||
-        type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) ||
+        type_is_newtype_immediate(ccx, ty) ||
         ty::type_is_simd(tcx, ty);
     if simple && !ty::type_is_fat_ptr(tcx, ty) {
         return true;
@@ -83,7 +83,6 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
         return false;
     }
     match ty::get(ty).sty {
-        ty::ty_bot => true,
         ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) |
         ty::ty_unboxed_closure(..) => {
             let llty = sizing_type_of(ccx, ty);
@@ -113,7 +112,7 @@ pub fn return_type_is_void(ccx: &CrateContext, ty: ty::t) -> bool {
      * return type (in order to aid with C ABI compatibility).
      */
 
-    ty::type_is_nil(ty) || ty::type_is_bot(ty) || ty::type_is_empty(ccx.tcx(), ty)
+    ty::type_is_nil(ty) || ty::type_is_empty(ccx.tcx(), ty)
 }
 
 /// Generates a unique symbol based off the name given. This is used to create
@@ -217,7 +216,7 @@ fn substp(&self, tcx: &ty::ctxt, param_substs: &param_substs)
               -> Self;
 }
 
-impl<T:Subst+Clone> SubstP for T {
+impl<T: Subst + Clone> SubstP for T {
     fn substp(&self, tcx: &ty::ctxt, substs: &param_substs) -> T {
         self.subst(tcx, &substs.substs)
     }
@@ -343,9 +342,12 @@ pub fn get_llreturn(&self) -> BasicBlockRef {
         self.llreturn.get().unwrap()
     }
 
-    pub fn get_ret_slot(&self, bcx: Block, ty: ty::t, name: &str) -> ValueRef {
+    pub fn get_ret_slot(&self, bcx: Block, output: ty::FnOutput, name: &str) -> ValueRef {
         if self.needs_ret_allocas {
-            base::alloca_no_lifetime(bcx, type_of::type_of(bcx.ccx(), ty), name)
+            base::alloca_no_lifetime(bcx, match output {
+                ty::FnConverging(output_type) => type_of::type_of(bcx.ccx(), output_type),
+                ty::FnDiverging => Type::void(bcx.ccx())
+            }, name)
         } else {
             self.llretslotptr.get().unwrap()
         }
index 995943c301731fe27f1e7b5404d0df2f4283a03e..f7210bb4e08bba8f2a18726905bff3f2a26c9350 100644 (file)
@@ -296,7 +296,7 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                      .borrow())[method_call]
                                      .ty;
     let method_type = monomorphize_type(loopback_bcx_in, method_type);
-    let method_result_type = ty::ty_fn_ret(method_type);
+    let method_result_type = ty::ty_fn_ret(method_type).unwrap();
     let option_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope();
     let option_cleanup_scope_id = cleanup::CustomScope(option_cleanup_scope);
 
@@ -402,10 +402,6 @@ pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     fcx.pop_loop_cleanup_scope(loop_id);
 
-    if ty::type_is_bot(node_id_type(bcx, loop_id)) {
-        Unreachable(next_bcx_in);
-    }
-
     return next_bcx_in;
 }
 
@@ -465,7 +461,7 @@ pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let dest = match (fcx.llretslotptr.get(), e) {
         (Some(_), Some(e)) => {
             let ret_ty = expr_ty(bcx, &*e);
-            expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot"))
+            expr::SaveIn(fcx.get_ret_slot(bcx, ty::FnConverging(ret_ty), "ret_slot"))
         }
         _ => expr::Ignore,
     };
index ea6d9e1dd8c48a61a93ae7618934948e66aa5cd9..8ee258e77fa5d3493f0ee7d290c0eb1ac6b942c1 100644 (file)
@@ -650,7 +650,7 @@ pub fn to_llscalarish(self, bcx: Block) -> ValueRef {
     }
 
     pub fn to_llbool(self, bcx: Block) -> ValueRef {
-        assert!(ty::type_is_bool(self.ty) || ty::type_is_bot(self.ty))
+        assert!(ty::type_is_bool(self.ty))
         self.to_llscalarish(bcx)
     }
 }
index 3368b2b7765b88f336d059c167708701bd15344c..5e039a3c098c70ee7e1f4e4e9c8a60eef6ae1068 100644 (file)
@@ -352,7 +352,6 @@ fn get_unique_type_id_of_type(&mut self, cx: &CrateContext, type_: ty::t) -> Uni
 
         match ty::get(type_).sty {
             ty::ty_nil      |
-            ty::ty_bot      |
             ty::ty_bool     |
             ty::ty_char     |
             ty::ty_str      |
@@ -451,9 +450,16 @@ fn get_unique_type_id_of_type(&mut self, cx: &CrateContext, type_: ty::t) -> Uni
                 }
 
                 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.as_slice());
+                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.as_slice());
+                    }
+                    ty::FnDiverging => {
+                        unique_type_id.push_str("!");
+                    }
+                }
             },
             ty::ty_closure(box ref closure_ty) => {
                 self.get_unique_type_id_of_closure_type(cx,
@@ -578,9 +584,16 @@ fn get_unique_type_id_of_closure_type(&mut self,
 
         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.as_slice());
+        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.as_slice());
+            }
+            ty::FnDiverging => {
+                unique_type_id.push_str("!");
+            }
+        }
 
         unique_type_id.push(':');
 
@@ -1707,13 +1720,25 @@ fn scope_metadata(fcx: &FunctionContext,
     }
 }
 
+fn diverging_type_metadata(cx: &CrateContext) -> DIType {
+    "!".with_c_str(|name| {
+        unsafe {
+            llvm::LLVMDIBuilderCreateBasicType(
+                DIB(cx),
+                name,
+                bytes_to_bits(0),
+                bytes_to_bits(0),
+                DW_ATE_unsigned)
+        }
+    })
+}
+
 fn basic_type_metadata(cx: &CrateContext, t: ty::t) -> DIType {
 
     debug!("basic_type_metadata: {}", ty::get(t));
 
     let (name, encoding) = match ty::get(t).sty {
         ty::ty_nil => ("()".to_string(), DW_ATE_unsigned),
-        ty::ty_bot => ("!".to_string(), DW_ATE_unsigned),
         ty::ty_bool => ("bool".to_string(), DW_ATE_boolean),
         ty::ty_char => ("char".to_string(), DW_ATE_unsigned_char),
         ty::ty_int(int_ty) => match int_ty {
@@ -2748,9 +2773,12 @@ fn subroutine_type_metadata(cx: &CrateContext,
     let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
 
     // return type
-    signature_metadata.push(match ty::get(signature.output).sty {
-        ty::ty_nil => ptr::null_mut(),
-        _ => type_metadata(cx, signature.output, span)
+    signature_metadata.push(match signature.output {
+        ty::FnConverging(ret_ty) => match ty::get(ret_ty).sty {
+            ty::ty_nil => ptr::null_mut(),
+            _ => type_metadata(cx, ret_ty, span)
+        },
+        ty::FnDiverging => diverging_type_metadata(cx)
     });
 
     // regular arguments
@@ -2855,7 +2883,6 @@ fn type_metadata(cx: &CrateContext,
     let sty = &ty::get(t).sty;
     let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty {
         ty::ty_nil      |
-        ty::ty_bot      |
         ty::ty_bool     |
         ty::ty_char     |
         ty::ty_int(_)   |
@@ -3647,7 +3674,6 @@ fn push_debuginfo_type_name(cx: &CrateContext,
                             output:&mut String) {
     match ty::get(t).sty {
         ty::ty_nil               => output.push_str("()"),
-        ty::ty_bot               => output.push_str("!"),
         ty::ty_bool              => output.push_str("bool"),
         ty::ty_char              => output.push_str("char"),
         ty::ty_str               => output.push_str("str"),
@@ -3749,9 +3775,15 @@ fn push_debuginfo_type_name(cx: &CrateContext,
 
             output.push(')');
 
-            if !ty::type_is_nil(sig.output) {
-                output.push_str(" -> ");
-                push_debuginfo_type_name(cx, sig.output, true, output);
+            match sig.output {
+                ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {}
+                ty::FnConverging(result_type) => {
+                    output.push_str(" -> ");
+                    push_debuginfo_type_name(cx, result_type, true, output);
+                }
+                ty::FnDiverging => {
+                    output.push_str(" -> !");
+                }
             }
         },
         ty::ty_closure(box ty::ClosureTy { fn_style,
@@ -3803,9 +3835,15 @@ fn push_debuginfo_type_name(cx: &CrateContext,
 
             output.push(param_list_closing_char);
 
-            if !ty::type_is_nil(sig.output) {
-                output.push_str(" -> ");
-                push_debuginfo_type_name(cx, sig.output, true, output);
+            match sig.output {
+                ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {}
+                ty::FnConverging(result_type) => {
+                    output.push_str(" -> ");
+                    push_debuginfo_type_name(cx, result_type, true, output);
+                }
+                ty::FnDiverging => {
+                    output.push_str(" -> !");
+                }
             }
         },
         ty::ty_unboxed_closure(..) => {
index 622da4840b047bee4eccf44f8602b8d809a208a8..7d64c42a00030986ccd3baac5a35dd209c37995b 100644 (file)
@@ -609,7 +609,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             start.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id)));
             end.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id)));
 
-            let result_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty.unwrap()));
+            let result_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty.unwrap())).unwrap();
             let scratch = rvalue_scratch_datum(bcx, result_ty, "trans_slice");
 
             unpack_result!(bcx,
@@ -757,7 +757,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                                    base_datum,
                                                    vec![(ix_datum, idx.id)],
                                                    None));
-            let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
+            let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty)).unwrap();
             let elt_ty = match ty::deref(ref_ty, true) {
                 None => {
                     bcx.tcx().sess.span_bug(index_expr.span,
@@ -1614,8 +1614,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let tcx = bcx.tcx();
     let is_simd = ty::type_is_simd(tcx, lhs_t);
     let intype = {
-        if ty::type_is_bot(lhs_t) { rhs_t }
-        else if is_simd { ty::simd_type(tcx, lhs_t) }
+        if is_simd { ty::simd_type(tcx, lhs_t) }
         else { lhs_t }
     };
     let is_float = ty::type_is_fp(intype);
@@ -1675,9 +1674,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         } else { LShr(bcx, lhs, rhs) }
       }
       ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
-        if ty::type_is_bot(rhs_t) {
-            C_bool(bcx.ccx(), false)
-        } else if ty::type_is_scalar(rhs_t) {
+        if ty::type_is_scalar(rhs_t) {
             unpack_result!(bcx, base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op))
         } else if is_simd {
             base::compare_simd_types(bcx, lhs, rhs, intype, ty::simd_size(tcx, lhs_t), op)
@@ -2098,7 +2095,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 _ => datum
             };
 
-            let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty));
+            let ref_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty)).unwrap();
             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
 
             unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
index 406ccc56a62389c017d62b609db73812d299940a..aa195837b67d4a3a5178c07d95910a566d03fce6 100644 (file)
@@ -49,9 +49,6 @@ struct ForeignTypes {
 
     /// LLVM types that will appear on the foreign function
     llsig: LlvmSignature,
-
-    /// True if there is a return value (not bottom, not unit)
-    ret_def: bool,
 }
 
 struct LlvmSignature {
@@ -63,6 +60,9 @@ struct LlvmSignature {
     // function, because the foreign function may opt to return via an
     // out pointer.
     llret_ty: Type,
+
+    /// True if there is a return value (not bottom, not unit)
+    ret_def: bool,
 }
 
 
@@ -286,11 +286,10 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         _ => ccx.sess().bug("trans_native_call called on non-function type")
     };
     let llsig = foreign_signature(ccx, &fn_sig, passed_arg_tys.as_slice());
-    let ret_def = !return_type_is_void(bcx.ccx(), fn_sig.output);
     let fn_type = cabi::compute_abi_info(ccx,
                                          llsig.llarg_tys.as_slice(),
                                          llsig.llret_ty,
-                                         ret_def);
+                                         llsig.ret_def);
 
     let arg_tys: &[cabi::ArgType] = fn_type.arg_tys.as_slice();
 
@@ -437,7 +436,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // type to match because some ABIs will use a different type than
     // the Rust type. e.g., a {u32,u32} struct could be returned as
     // u64.
-    if ret_def && !fn_type.ret_ty.is_indirect() {
+    if llsig.ret_def && !fn_type.ret_ty.is_indirect() {
         let llrust_ret_ty = llsig.llret_ty;
         let llforeign_ret_ty = match fn_type.ret_ty.cast {
             Some(ty) => ty,
@@ -450,7 +449,12 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         debug!("llforeign_ret_ty={}", ccx.tn().type_to_string(llforeign_ret_ty));
 
         if llrust_ret_ty == llforeign_ret_ty {
-            base::store_ty(bcx, llforeign_retval, llretptr, fn_sig.output)
+            match fn_sig.output {
+                ty::FnConverging(result_ty) => {
+                    base::store_ty(bcx, llforeign_retval, llretptr, result_ty)
+                }
+                ty::FnDiverging => {}
+            }
         } else {
             // The actual return type is a struct, but the ABI
             // adaptation code has cast it into some scalar type.  The
@@ -549,7 +553,7 @@ pub fn decl_rust_fn_with_foreign_abi(ccx: &CrateContext,
         }
         _ => fail!("expected bare fn in decl_rust_fn_with_foreign_abi")
     };
-    let llfn = base::decl_fn(ccx, name, cconv, llfn_ty, ty::mk_nil());
+    let llfn = base::decl_fn(ccx, name, cconv, llfn_ty, ty::FnConverging(ty::mk_nil()));
     add_argument_attributes(&tys, llfn);
     debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})",
            ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
@@ -698,8 +702,10 @@ unsafe fn build_wrap_fn(ccx: &CrateContext,
         };
 
         // Push Rust return pointer, using null if it will be unused.
-        let rust_uses_outptr =
-            type_of::return_uses_outptr(ccx, tys.fn_sig.output);
+        let rust_uses_outptr = match tys.fn_sig.output {
+            ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty),
+            ty::FnDiverging => false
+        };
         let return_alloca: Option<ValueRef>;
         let llrust_ret_ty = tys.llsig.llret_ty;
         let llrust_retptr_ty = llrust_ret_ty.ptr_to();
@@ -714,7 +720,7 @@ unsafe fn build_wrap_fn(ccx: &CrateContext,
                     debug!("out pointer, foreign={}",
                            ccx.tn().val_to_string(llforeign_outptr));
                     let llrust_retptr =
-                        builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to());
+                        builder.bitcast(llforeign_outptr, llrust_retptr_ty);
                     debug!("out pointer, foreign={} (casted)",
                            ccx.tn().val_to_string(llrust_retptr));
                     llrust_args.push(llrust_retptr);
@@ -817,7 +823,7 @@ unsafe fn build_wrap_fn(ccx: &CrateContext,
             None => tys.fn_ty.ret_ty.ty
         };
         match foreign_outptr {
-            None if !tys.ret_def => {
+            None if !tys.llsig.ret_def => {
                 // Function returns `()` or `bot`, which in Rust is the LLVM
                 // type "{}" but in foreign ABIs is "Void".
                 builder.ret_void();
@@ -896,10 +902,16 @@ fn foreign_signature(ccx: &CrateContext, fn_sig: &ty::FnSig, arg_tys: &[ty::t])
      */
 
     let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect();
-    let llret_ty = type_of::arg_type_of(ccx, fn_sig.output);
+    let (llret_ty, ret_def) = match fn_sig.output {
+        ty::FnConverging(ret_ty) =>
+            (type_of::arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
+        ty::FnDiverging =>
+            (Type::nil(ccx), false)
+    };
     LlvmSignature {
         llarg_tys: llarg_tys,
-        llret_ty: llret_ty
+        llret_ty: llret_ty,
+        ret_def: ret_def
     }
 }
 
@@ -915,11 +927,10 @@ fn foreign_types_for_fn_ty(ccx: &CrateContext,
         _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
     };
     let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice());
-    let ret_def = !return_type_is_void(ccx, fn_sig.output);
     let fn_ty = cabi::compute_abi_info(ccx,
                                        llsig.llarg_tys.as_slice(),
                                        llsig.llret_ty,
-                                       ret_def);
+                                       llsig.ret_def);
     debug!("foreign_types_for_fn_ty(\
            ty={}, \
            llsig={} -> {}, \
@@ -930,12 +941,11 @@ fn foreign_types_for_fn_ty(ccx: &CrateContext,
            ccx.tn().type_to_string(llsig.llret_ty),
            ccx.tn().types_to_str(fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>().as_slice()),
            ccx.tn().type_to_string(fn_ty.ret_ty.ty),
-           ret_def);
+           llsig.ret_def);
 
     ForeignTypes {
         fn_sig: fn_sig,
         llsig: llsig,
-        ret_def: ret_def,
         fn_ty: fn_ty
     }
 }
index 8fc3426e372996d48105a81a171dd9a650ef2f02..e914dbcc082a672333cd82a8018f637ad7e11d07 100644 (file)
@@ -538,10 +538,10 @@ fn make_generic_glue(ccx: &CrateContext,
 
     let arena = TypedArena::new();
     let empty_param_substs = param_substs::empty();
-    let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false, ty::mk_nil(),
+    let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false, ty::FnConverging(ty::mk_nil()),
                           &empty_param_substs, None, &arena);
 
-    let bcx = init_function(&fcx, false, ty::mk_nil());
+    let bcx = init_function(&fcx, false, ty::FnConverging(ty::mk_nil()));
 
     update_linkage(ccx, llfn, None, OriginalTranslation);
 
@@ -556,7 +556,7 @@ fn make_generic_glue(ccx: &CrateContext,
 
     let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
     let bcx = helper(bcx, llrawptr0, t);
-    finish_fn(&fcx, bcx, ty::mk_nil());
+    finish_fn(&fcx, bcx, ty::FnConverging(ty::mk_nil()));
 
     llfn
 }
index 3e75b0772fb10d9616072cb52795c73e10e9bec6..61559e12a975e7049b9a2722c2df477cd8fccd4b 100644 (file)
@@ -149,12 +149,12 @@ pub fn trans_intrinsic_call<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, node: ast::N
         ty::ty_bare_fn(ref f) => f.sig.output,
         _ => fail!("expected bare_fn in trans_intrinsic_call")
     };
-    let llret_ty = type_of::type_of(ccx, ret_ty);
     let foreign_item = tcx.map.expect_foreign_item(node);
     let name = token::get_ident(foreign_item.ident);
 
     // For `transmute` we can just trans the input expr directly into dest
     if name.get() == "transmute" {
+        let llret_ty = type_of::type_of(ccx, ret_ty.unwrap());
         match args {
             callee::ArgExprs(arg_exprs) => {
                 assert_eq!(arg_exprs.len(), 1);
@@ -192,6 +192,36 @@ pub fn trans_intrinsic_call<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, node: ast::N
         }
     }
 
+    // Push the arguments.
+    let mut llargs = Vec::new();
+    bcx = callee::trans_args(bcx,
+                             args,
+                             callee_ty,
+                             &mut llargs,
+                             cleanup::CustomScope(cleanup_scope),
+                             false,
+                             RustIntrinsic);
+
+    fcx.pop_custom_cleanup_scope(cleanup_scope);
+
+    // The only intrinsic function that diverges.
+    if name.get() == "abort" {
+        let llfn = ccx.get_intrinsic(&("llvm.trap"));
+        Call(bcx, llfn, [], None);
+        Unreachable(bcx);
+        return Result::new(bcx, C_undef(Type::nil(ccx).ptr_to()));
+    } else if name.get() == "unreachable" {
+        Unreachable(bcx);
+        return Result::new(bcx, C_nil(ccx));
+    }
+
+    let ret_ty = match ret_ty {
+        ty::FnConverging(ret_ty) => ret_ty,
+        ty::FnDiverging => unreachable!()
+    };
+
+    let llret_ty = type_of::type_of(ccx, ret_ty);
+
     // Get location to store the result. If the user does
     // not care about the result, just make a stack slot
     let llresult = match dest {
@@ -205,34 +235,11 @@ pub fn trans_intrinsic_call<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, node: ast::N
         }
     };
 
-    // Push the arguments.
-    let mut llargs = Vec::new();
-    bcx = callee::trans_args(bcx,
-                             args,
-                             callee_ty,
-                             &mut llargs,
-                             cleanup::CustomScope(cleanup_scope),
-                             false,
-                             RustIntrinsic);
-
-    fcx.pop_custom_cleanup_scope(cleanup_scope);
-
     let simple = get_simple_intrinsic(ccx, &*foreign_item);
-
     let llval = match (simple, name.get()) {
         (Some(llfn), _) => {
             Call(bcx, llfn, llargs.as_slice(), None)
         }
-        (_, "abort") => {
-            let llfn = ccx.get_intrinsic(&("llvm.trap"));
-            let v = Call(bcx, llfn, [], None);
-            Unreachable(bcx);
-            v
-        }
-        (_, "unreachable") => {
-            Unreachable(bcx);
-            C_nil(ccx)
-        }
         (_, "breakpoint") => {
             let llfn = ccx.get_intrinsic(&("llvm.debugtrap"));
             Call(bcx, llfn, [], None)
index 6d7985767ab869fe3592b94e68728cfacb4b0d4f..64ab86721bcc7cec9eacd633022358e1a8280d24 100644 (file)
@@ -97,7 +97,7 @@ pub fn untuple_arguments_if_necessary(ccx: &CrateContext,
 pub fn type_of_rust_fn(cx: &CrateContext,
                        llenvironment_type: Option<Type>,
                        inputs: &[ty::t],
-                       output: ty::t,
+                       output: ty::FnOutput,
                        abi: abi::Abi)
                        -> Type {
     let mut atys: Vec<Type> = Vec::new();
@@ -107,11 +107,22 @@ pub fn type_of_rust_fn(cx: &CrateContext,
 
     // Arg 0: Output pointer.
     // (if the output type is non-immediate)
-    let use_out_pointer = return_uses_outptr(cx, output);
-    let lloutputtype = arg_type_of(cx, output);
-    if use_out_pointer {
-        atys.push(lloutputtype.ptr_to());
-    }
+    let lloutputtype = match output {
+        ty::FnConverging(output) => {
+            let use_out_pointer = return_uses_outptr(cx, output);
+            let lloutputtype = arg_type_of(cx, output);
+            // Use the output as the actual return value if it's immediate.
+            if use_out_pointer {
+                atys.push(lloutputtype.ptr_to());
+                Type::void(cx)
+            } else if return_type_is_void(cx, output) {
+                Type::void(cx)
+            } else {
+                lloutputtype
+            }
+        }
+        ty::FnDiverging => Type::void(cx)
+    };
 
     // Arg 1: Environment
     match llenvironment_type {
@@ -123,12 +134,7 @@ pub fn type_of_rust_fn(cx: &CrateContext,
     let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
     atys.extend(input_tys);
 
-    // Use the output as the actual return value if it's immediate.
-    if use_out_pointer || return_type_is_void(cx, output) {
-        Type::func(atys.as_slice(), &Type::void(cx))
-    } else {
-        Type::func(atys.as_slice(), &lloutputtype)
-    }
+    Type::func(atys.as_slice(), &lloutputtype)
 }
 
 // Given a function type and a count of ty params, construct an llvm type
@@ -181,7 +187,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
                                   ppaux::ty_to_string(cx.tcx(), t)).as_slice())
         }
 
-        ty::ty_nil | ty::ty_bot => Type::nil(cx),
+        ty::ty_nil => Type::nil(cx),
         ty::ty_bool => Type::bool(cx),
         ty::ty_char => Type::char(cx),
         ty::ty_int(t) => Type::int_from_ty(cx, t),
@@ -293,7 +299,7 @@ fn type_of_unsize_info(cx: &CrateContext, t: ty::t) -> Type {
     }
 
     let mut llty = match ty::get(t).sty {
-      ty::ty_nil | ty::ty_bot => Type::nil(cx),
+      ty::ty_nil => Type::nil(cx),
       ty::ty_bool => Type::bool(cx),
       ty::ty_char => Type::char(cx),
       ty::ty_int(t) => Type::int_from_ty(cx, t),
index 7fedea67f79af3facbf9d1aea6312b4a87e04c7e..6666b85879a89d330136b426f2c0d149cf118fdc 100644 (file)
@@ -598,7 +598,6 @@ pub struct ctxt<'tcx> {
         const HAS_RE_INFER  = 0b1000,
         const HAS_REGIONS   = 0b10000,
         const HAS_TY_ERR    = 0b100000,
-        const HAS_TY_BOT    = 0b1000000,
         const NEEDS_SUBST   = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits,
     }
 }
@@ -672,6 +671,21 @@ pub struct ClosureTy {
     pub abi: abi::Abi,
 }
 
+#[deriving(Clone, PartialEq, Eq, Hash)]
+pub enum FnOutput {
+    FnConverging(ty::t),
+    FnDiverging
+}
+
+impl FnOutput {
+    pub fn unwrap(&self) -> ty::t {
+        match *self {
+            ty::FnConverging(ref t) => *t,
+            ty::FnDiverging => unreachable!()
+        }
+    }
+}
+
 /**
  * Signature of a function type, which I have arbitrarily
  * decided to use to refer to the input/output types.
@@ -688,7 +702,7 @@ pub struct ClosureTy {
 pub struct FnSig {
     pub binder_id: ast::NodeId,
     pub inputs: Vec<t>,
-    pub output: t,
+    pub output: FnOutput,
     pub variadic: bool
 }
 
@@ -919,12 +933,6 @@ macro_rules! def_prim_ty(
     def_prim_ty!(TY_F32,    super::ty_float(ast::TyF32),    14)
     def_prim_ty!(TY_F64,    super::ty_float(ast::TyF64),    15)
 
-    pub static TY_BOT: t_box_ = t_box_ {
-        sty: super::ty_bot,
-        id: 16,
-        flags: super::HAS_TY_BOT,
-    };
-
     pub static TY_ERR: t_box_ = t_box_ {
         sty: super::ty_err,
         id: 17,
@@ -939,7 +947,6 @@ macro_rules! def_prim_ty(
 #[deriving(Clone, PartialEq, Eq, Hash, Show)]
 pub enum sty {
     ty_nil,
-    ty_bot,
     ty_bool,
     ty_char,
     ty_int(ast::IntTy),
@@ -1044,6 +1051,7 @@ pub enum type_err {
     terr_builtin_bounds(expected_found<BuiltinBounds>),
     terr_variadic_mismatch(expected_found<bool>),
     terr_cyclic_ty,
+    terr_convergence_mismatch(expected_found<bool>)
 }
 
 /// Bounds suitable for a named type parameter like `A` in `fn foo<A>`
@@ -1578,7 +1586,6 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
         ty_uint(u) => return mk_mach_uint(u),
         ty_float(f) => return mk_mach_float(f),
         ty_char => return mk_char(),
-        ty_bot => return mk_bot(),
         _ => {}
     };
 
@@ -1627,7 +1634,6 @@ fn flags_for_bounds(bounds: &ExistentialBounds) -> TypeFlags {
       // But doing so caused sporadic memory corruption, and
       // neither I (tjc) nor nmatsakis could figure out why,
       // so we're doing it this way.
-      &ty_bot => flags = flags | HAS_TY_BOT,
       &ty_err => flags = flags | HAS_TY_ERR,
       &ty_param(ref p) => {
           if p.space == subst::SelfSpace {
@@ -1661,9 +1667,9 @@ fn flags_for_bounds(bounds: &ExistentialBounds) -> TypeFlags {
       &ty_tup(ref ts) => for tt in ts.iter() { flags = flags | get(*tt).flags; },
       &ty_bare_fn(ref f) => {
         for a in f.sig.inputs.iter() { flags = flags | get(*a).flags; }
-        flags = flags | get(f.sig.output).flags;
-        // T -> _|_ is *not* _|_ !
-        flags = flags - HAS_TY_BOT;
+        if let ty::FnConverging(output) = f.sig.output {
+            flags = flags | get(output).flags;
+        }
       }
       &ty_closure(ref f) => {
         match f.store {
@@ -1673,9 +1679,9 @@ fn flags_for_bounds(bounds: &ExistentialBounds) -> TypeFlags {
             _ => {}
         }
         for a in f.sig.inputs.iter() { flags = flags | get(*a).flags; }
-        flags = flags | get(f.sig.output).flags;
-        // T -> _|_ is *not* _|_ !
-        flags = flags - HAS_TY_BOT;
+        if let ty::FnConverging(output) = f.sig.output {
+            flags = flags | get(output).flags;
+        }
         flags = flags | flags_for_bounds(&f.bounds);
       }
     }
@@ -1714,9 +1720,6 @@ pub fn mk_nil() -> t { mk_prim_t(&primitives::TY_NIL) }
 #[inline]
 pub fn mk_err() -> t { mk_prim_t(&primitives::TY_ERR) }
 
-#[inline]
-pub fn mk_bot() -> t { mk_prim_t(&primitives::TY_BOT) }
-
 #[inline]
 pub fn mk_bool() -> t { mk_prim_t(&primitives::TY_BOOL) }
 
@@ -1862,7 +1865,7 @@ pub fn mk_ctor_fn(cx: &ctxt,
                    sig: FnSig {
                     binder_id: binder_id,
                     inputs: input_args,
-                    output: output,
+                    output: ty::FnConverging(output),
                     variadic: false
                    }
                 })
@@ -1924,7 +1927,7 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
         return;
     }
     match get(ty).sty {
-        ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
+        ty_nil | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
         ty_str | ty_infer(_) | ty_param(_) | ty_err => {}
         ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f),
         ty_ptr(ref tm) | ty_rptr(_, ref tm) => {
@@ -1939,11 +1942,15 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
         ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } }
         ty_bare_fn(ref ft) => {
             for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
-            maybe_walk_ty(ft.sig.output, f);
+            if let ty::FnConverging(output) = ft.sig.output {
+                maybe_walk_ty(output, f);
+            }
         }
         ty_closure(ref ft) => {
             for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
-            maybe_walk_ty(ft.sig.output, f);
+            if let ty::FnConverging(output) = ft.sig.output {
+                maybe_walk_ty(output, f);
+            }
         }
     }
 }
@@ -1995,10 +2002,6 @@ pub fn type_is_nil(ty: t) -> bool {
     get(ty).sty == ty_nil
 }
 
-pub fn type_is_bot(ty: t) -> bool {
-    get(ty).flags.intersects(HAS_TY_BOT)
-}
-
 pub fn type_is_error(ty: t) -> bool {
     get(ty).flags.intersects(HAS_TY_ERR)
 }
@@ -2013,8 +2016,8 @@ pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
 
 pub fn type_is_ty_var(ty: t) -> bool {
     match get(ty).sty {
-      ty_infer(TyVar(_)) => true,
-      _ => false
+        ty_infer(TyVar(_)) => true,
+        _ => false
     }
 }
 
@@ -2170,7 +2173,7 @@ fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t, tycache: &mut HashSet<t>) -> boo
         let mut needs_unwind_cleanup = false;
         maybe_walk_ty(ty, |ty| {
             needs_unwind_cleanup |= match get(ty).sty {
-                ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) |
+                ty_nil | ty_bool | ty_int(_) | ty_uint(_) |
                 ty_float(_) | ty_tup(_) | ty_ptr(_) => false,
 
                 ty_enum(did, ref substs) =>
@@ -2430,7 +2433,7 @@ fn tc_ty(cx: &ctxt,
 
             // Scalar and unique types are sendable, and durable
             ty_infer(ty::SkolemizedIntTy(_)) |
-            ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
+            ty_nil | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
             ty_bare_fn(_) | ty::ty_char => {
                 TC::None
             }
@@ -2560,7 +2563,7 @@ fn tc_ty(cx: &ctxt,
                 // We only ever ask for the kind of types that are defined in
                 // the current crate; therefore, the only type parameters that
                 // could be in scope are those defined in the current crate.
-                // If this assertion failures, it is likely because of a
+                // If this assertion fails, it is likely because of a
                 // failure in the cross-crate inlining code to translate a
                 // def-id.
                 assert_eq!(p.def_id.krate, ast::LOCAL_CRATE);
@@ -2742,7 +2745,6 @@ fn subtypes_require(cx: &ctxt, seen: &mut Vec<DefId>,
             ty_vec(ty, Some(_)) => type_requires(cx, seen, r_ty, ty),
 
             ty_nil |
-            ty_bot |
             ty_bool |
             ty_char |
             ty_int(_) |
@@ -3276,7 +3278,7 @@ pub fn ty_closure_store(fty: t) -> TraitStore {
     }
 }
 
-pub fn ty_fn_ret(fty: t) -> t {
+pub fn ty_fn_ret(fty: t) -> FnOutput {
     match get(fty).sty {
         ty_bare_fn(ref f) => f.sig.output,
         ty_closure(ref f) => f.sig.output,
@@ -3451,7 +3453,9 @@ pub fn adjust_ty(cx: &ctxt,
                             let method_call = typeck::MethodCall::autoderef(expr_id, i);
                             match method_type(method_call) {
                                 Some(method_ty) => {
-                                    adjusted_ty = ty_fn_ret(method_ty);
+                                    if let ty::FnConverging(result_type) = ty_fn_ret(method_ty) {
+                                        adjusted_ty = result_type;
+                                    }
                                 }
                                 None => {}
                             }
@@ -3779,7 +3783,7 @@ pub fn impl_or_trait_item_idx(id: ast::Name, trait_items: &[ImplOrTraitItem])
 
 pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
     match get(t).sty {
-        ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) |
+        ty_nil | ty_bool | ty_char | ty_int(_) |
         ty_uint(_) | ty_float(_) | ty_str => {
             ::util::ppaux::ty_to_string(cx, t)
         }
@@ -3959,6 +3963,11 @@ fn tstore_to_closure(s: &TraitStore) -> String {
                     if values.expected { "variadic" } else { "non-variadic" },
                     if values.found { "variadic" } else { "non-variadic" })
         }
+        terr_convergence_mismatch(ref values) => {
+            format!("expected {} fn, found {} function",
+                    if values.expected { "converging" } else { "diverging" },
+                    if values.found { "converging" } else { "diverging" })
+        }
     }
 }
 
@@ -4667,7 +4676,6 @@ pub fn is_binopable(cx: &ctxt, ty: t, op: ast::BinOp) -> bool {
     static tycat_char: int = 2;
     static tycat_int: int = 3;
     static tycat_float: int = 4;
-    static tycat_bot: int = 5;
     static tycat_raw_ptr: int = 6;
 
     static opcat_add: int = 0;
@@ -4712,7 +4720,6 @@ fn tycat(cx: &ctxt, ty: t) -> int {
           ty_bool => tycat_bool,
           ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int,
           ty_float(_) | ty_infer(FloatVar(_)) => tycat_float,
-          ty_bot => tycat_bot,
           ty_ptr(_) => tycat_raw_ptr,
           _ => tycat_other
         }
@@ -5149,7 +5156,6 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
     ty::walk_ty(t, |t| {
         match ty::get(t).sty {
             ty_nil => byte!(0),
-            ty_bot => byte!(1),
             ty_bool => byte!(2),
             ty_char => byte!(3),
             ty_int(i) => {
@@ -5520,7 +5526,6 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
                 accum_substs(accumulator, substs);
             }
             ty_nil |
-            ty_bot |
             ty_bool |
             ty_char |
             ty_int(_) |
index c7fe8a19937c9f93ce4d3de5b7bdce6586326442..a96e81ce20bb418a47393dbce3be4f5e99b534fa 100644 (file)
@@ -91,6 +91,12 @@ fn fold_sig(&mut self,
         super_fold_sig(self, sig)
     }
 
+    fn fold_output(&mut self,
+                      output: &ty::FnOutput)
+                      -> ty::FnOutput {
+        super_fold_output(self, output)
+    }
+
     fn fold_bare_fn_ty(&mut self,
                        fty: &ty::BareFnTy)
                        -> ty::BareFnTy
@@ -207,6 +213,12 @@ fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::mt {
     }
 }
 
+impl TypeFoldable for ty::FnOutput {
+    fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnOutput {
+        folder.fold_output(self)
+    }
+}
+
 impl TypeFoldable for ty::FnSig {
     fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig {
         folder.fold_sig(self)
@@ -453,6 +465,15 @@ pub fn super_fold_sig<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
                 variadic: sig.variadic }
 }
 
+pub fn super_fold_output<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
+                                                    output: &ty::FnOutput)
+                                                    -> ty::FnOutput {
+    match *output {
+        ty::FnConverging(ref ty) => ty::FnConverging(ty.fold_with(this)),
+        ty::FnDiverging => ty::FnDiverging
+    }
+}
+
 pub fn super_fold_bare_fn_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
                                                         fty: &ty::BareFnTy)
                                                         -> ty::BareFnTy
@@ -537,7 +558,7 @@ pub fn super_fold_sty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
         ty::ty_unboxed_closure(did, ref region, ref substs) => {
             ty::ty_unboxed_closure(did, region.fold_with(this), substs.fold_with(this))
         }
-        ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str |
+        ty::ty_nil | ty::ty_bool | ty::ty_char | ty::ty_str |
         ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
         ty::ty_err | ty::ty_infer(_) |
         ty::ty_param(..) => {
index 15e3ee4c8fad3b754b6141f2822577217ba7f2f2..42990ac79c005e52cee389ba6bb681fbca2383a0 100644 (file)
@@ -793,7 +793,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
     let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| {
         match ast_ty.node {
             ast::TyNil => ty::mk_nil(),
-            ast::TyBot => ty::mk_bot(),
+            ast::TyBot => unreachable!(),
             ast::TyUniq(ref ty) => {
                 mk_pointer(this, rscope, ast::MutImmutable, &**ty, Uniq,
                            |ty| ty::mk_uniq(tcx, ty))
@@ -1171,22 +1171,21 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
                                                                    .collect();
 
     let output_ty = match decl.output.node {
-        ast::TyInfer => this.ty_infer(decl.output.span),
-        _ => {
-            match implied_output_region {
-                Some(implied_output_region) => {
-                    let rb = SpecificRscope::new(implied_output_region);
-                    ast_ty_to_ty(this, &rb, &*decl.output)
-                }
-                None => {
-                    // All regions must be explicitly specified in the output
-                    // if the lifetime elision rules do not apply. This saves
-                    // the user from potentially-confusing errors.
-                    let rb = UnelidableRscope::new(param_lifetimes);
-                    ast_ty_to_ty(this, &rb, &*decl.output)
-                }
+        ast::TyBot => ty::FnDiverging,
+        ast::TyInfer => ty::FnConverging(this.ty_infer(decl.output.span)),
+        _ => ty::FnConverging(match implied_output_region {
+            Some(implied_output_region) => {
+                let rb = SpecificRscope::new(implied_output_region);
+                ast_ty_to_ty(this, &rb, &*decl.output)
             }
-        }
+            None => {
+                // All regions must be explicitly specified in the output
+                // if the lifetime elision rules do not apply. This saves
+                // the user from potentially-confusing errors.
+                let rb = UnelidableRscope::new(param_lifetimes);
+                ast_ty_to_ty(this, &rb, &*decl.output)
+            }
+        })
     };
 
     (ty::BareFnTy {
@@ -1308,10 +1307,12 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
     }).collect();
 
     let expected_ret_ty = expected_sig.map(|e| e.output);
+
     let output_ty = match decl.output.node {
+        ast::TyBot => ty::FnDiverging,
         ast::TyInfer if expected_ret_ty.is_some() => expected_ret_ty.unwrap(),
-        ast::TyInfer => this.ty_infer(decl.output.span),
-        _ => ast_ty_to_ty(this, &rb, &*decl.output)
+        ast::TyInfer => ty::FnConverging(this.ty_infer(decl.output.span)),
+        _ => ty::FnConverging(ast_ty_to_ty(this, &rb, &*decl.output))
     };
 
     ty::ClosureTy {
index 1dcd8c76f4b84b573d68b8f91404f9b93cd26303..d9f8625504daf518683d238ed426dc5b6114d1dd 100644 (file)
@@ -261,7 +261,7 @@ pub fn check_match(fcx: &FnCtxt,
     // on any empty type and is therefore unreachable; should the flow
     // of execution reach it, we will fail, so bottom is an appropriate
     // type in that case)
-    let result_ty = arms.iter().fold(ty::mk_bot(), |result_ty, arm| {
+    let result_ty = arms.iter().fold(fcx.infcx().next_diverging_ty_var(), |result_ty, arm| {
         check_expr(fcx, &*arm.body);
         let bty = fcx.node_ty(arm.body.id);
 
@@ -347,7 +347,10 @@ pub fn check_pat_enum(pcx: &pat_ctxt, pat: &ast::Pat,
 
     let ctor_pty = ty::lookup_item_type(tcx, enum_def);
     let path_ty = if ty::is_fn_ty(ctor_pty.ty) {
-        ty::Polytype { ty: ty::ty_fn_ret(ctor_pty.ty), ..ctor_pty }
+        ty::Polytype {
+            ty: ty::ty_fn_ret(ctor_pty.ty).unwrap(),
+            ..ctor_pty
+        }
     } else {
         ctor_pty
     };
index 82a3d1a523d3979ab6cc878ba46364900d5caf7c..6ace73931bfe86886d920700babc0270a07115e6 100644 (file)
@@ -1082,7 +1082,7 @@ fn search_for_autoptrd_method(&self, self_ty: ty::t, autoderefs: uint)
             ty_bare_fn(..) | ty_uniq(..) | ty_rptr(..) |
             ty_infer(IntVar(_)) |
             ty_infer(FloatVar(_)) |
-            ty_param(..) | ty_nil | ty_bot | ty_bool |
+            ty_param(..) | ty_nil | ty_bool |
             ty_char | ty_int(..) | ty_uint(..) |
             ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) |
             ty_unboxed_closure(..) | ty_tup(..) | ty_open(..) |
@@ -1603,8 +1603,10 @@ fn enforce_object_limitations(&self, candidate: &Candidate) -> bool {
                 return false;
             }
         }
-        if !check_for_self_ty(sig.output) {
-            return false;
+        if let ty::FnConverging(result_type) = sig.output {
+            if !check_for_self_ty(result_type) {
+                return false;
+            }
         }
 
         if candidate.method_ty.generics.has_type_params(subst::FnSpace) {
index 53a4a8141e65c489e25d33de4aedd29a01c37328..8843be3cf816f387c0745d0df42d5c45da4a4343 100644 (file)
@@ -280,7 +280,7 @@ pub struct FnCtxt<'a, 'tcx: 'a> {
     // expects the types within the function to be consistent.
     err_count_on_creation: uint,
 
-    ret_ty: ty::t,
+    ret_ty: ty::FnOutput,
 
     ps: RefCell<FnStyleState>,
 
@@ -346,7 +346,7 @@ fn new(tcx: &'a ty::ctxt<'tcx>,
 // Used by check_const and check_enum_variants
 pub fn blank_fn_ctxt<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
                                inh: &'a Inherited<'a, 'tcx>,
-                               rty: ty::t,
+                               rty: ty::FnOutput,
                                body_id: ast::NodeId)
                                -> FnCtxt<'a, 'tcx> {
     FnCtxt {
@@ -410,6 +410,7 @@ fn check_bare_fn(ccx: &CrateCtxt,
 
             vtable::select_all_fcx_obligations_or_error(&fcx);
             regionck::regionck_fn(&fcx, id, body);
+            fcx.default_diverging_type_variables_to_nil();
             writeback::resolve_type_vars_in_fn(&fcx, decl, body);
         }
         _ => ccx.tcx.sess.impossible_case(body.span,
@@ -426,8 +427,7 @@ fn assign(&mut self, _span: Span, nid: ast::NodeId, ty_opt: Option<ty::t>) -> ty
         match ty_opt {
             None => {
                 // infer the variable's type
-                let var_id = self.fcx.infcx().next_ty_var_id();
-                let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
+                let var_ty = self.fcx.infcx().next_ty_var();
                 self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
                 var_ty
             }
@@ -551,8 +551,16 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
     };
 
     // Remember return type so that regionck can access it later.
-    let fn_sig_tys: Vec<ty::t> =
-        arg_tys.iter().chain([ret_ty].iter()).map(|&ty| ty).collect();
+    let mut fn_sig_tys: Vec<ty::t> =
+        arg_tys.iter()
+        .map(|&ty| ty)
+        .collect();
+
+    if let ty::FnConverging(ret_ty) = ret_ty {
+        fcx.require_type_is_sized(ret_ty, decl.output.span, traits::ReturnType);
+        fn_sig_tys.push(ret_ty);
+    }
+
     debug!("fn-sig-map: fn_id={} fn_sig_tys={}",
            fn_id,
            fn_sig_tys.repr(tcx));
@@ -584,9 +592,11 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
 
         visit.visit_block(body);
     }
-    fcx.require_type_is_sized(ret_ty, decl.output.span, traits::ReturnType);
 
-    check_block_with_expected(&fcx, body, ExpectHasType(ret_ty));
+    check_block_with_expected(&fcx, body, match ret_ty {
+        ty::FnConverging(result_type) => ExpectHasType(result_type),
+        ty::FnDiverging => NoExpectation
+    });
 
     for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
         fcx.write_ty(input.id, *arg);
@@ -1333,11 +1343,6 @@ fn check_cast(fcx: &FnCtxt,
         return
     }
 
-    if ty::type_is_bot(t_e) {
-        fcx.write_bot(id);
-        return
-    }
-
     if !ty::type_is_sized(fcx.tcx(), t_1) {
         let tstr = fcx.infcx().ty_to_string(t_1);
         fcx.type_error_message(span, |actual| {
@@ -1562,6 +1567,14 @@ pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
         }
     }
 
+    pub fn default_diverging_type_variables_to_nil(&self) {
+        for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() {
+            if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) {
+                demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil());
+            }
+        }
+    }
+
     #[inline]
     pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
         debug!("write_ty({}, {}) in fcx {}",
@@ -1726,9 +1739,6 @@ pub fn instantiate_item_type(&self,
     pub fn write_nil(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, ty::mk_nil());
     }
-    pub fn write_bot(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, ty::mk_bot());
-    }
     pub fn write_error(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, ty::mk_err());
     }
@@ -2051,10 +2061,6 @@ pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
     for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
         let resolved_t = structurally_resolved_type(fcx, sp, t);
 
-        if ty::type_is_bot(resolved_t) {
-            return (resolved_t, autoderefs, None);
-        }
-
         match should_stop(resolved_t, autoderefs) {
             Some(x) => return (resolved_t, autoderefs, Some(x)),
             None => {}
@@ -2197,7 +2203,12 @@ fn make_return_type(fcx: &FnCtxt,
                 }
                 None => {}
             }
-            ty::deref(ref_ty, true)
+            match ref_ty {
+                ty::FnConverging(ref_ty) =>
+                    ty::deref(ref_ty, true),
+                ty::FnDiverging =>
+                    None
+            }
         }
         None => None,
     }
@@ -2285,7 +2296,12 @@ fn try_overloaded_slice(fcx: &FnCtxt,
                 }
                 None => {}
             }
-            Some(ty::mt { ty: result_ty, mutbl: ast::MutImmutable })
+            match result_ty {
+                ty::FnConverging(result_ty) =>
+                    Some(ty::mt { ty: result_ty, mutbl: ast::MutImmutable }),
+                ty::FnDiverging =>
+                    None
+            }
         }
         None => None,
     }
@@ -2400,9 +2416,11 @@ fn lookup_method_for_for_loop(fcx: &FnCtxt,
 
             // We expect the return type to be `Option` or something like it.
             // Grab the first parameter of its type substitution.
-            let return_type = structurally_resolved_type(fcx,
-                                                         iterator_expr.span,
-                                                         return_type);
+            let return_type = match return_type {
+                ty::FnConverging(return_type) =>
+                    structurally_resolved_type(fcx, iterator_expr.span, return_type),
+                ty::FnDiverging => ty::mk_err()
+            };
             match ty::get(return_type).sty {
                 ty::ty_enum(_, ref substs)
                         if !substs.types.is_empty_in(subst::TypeSpace) => {
@@ -2427,7 +2445,7 @@ fn check_method_argument_types<'a>(fcx: &FnCtxt,
                                    args_no_rcvr: &[&'a P<ast::Expr>],
                                    deref_args: DerefArgs,
                                    tuple_arguments: TupleArgumentsFlag)
-                                   -> ty::t {
+                                   -> ty::FnOutput {
     if ty::type_is_error(method_fn_ty) {
        let err_inputs = err_args(args_no_rcvr.len());
         check_argument_types(fcx,
@@ -2438,7 +2456,7 @@ fn check_method_argument_types<'a>(fcx: &FnCtxt,
                              deref_args,
                              false,
                              tuple_arguments);
-        method_fn_ty
+        ty::FnConverging(method_fn_ty)
     } else {
         match ty::get(method_fn_ty).sty {
             ty::ty_bare_fn(ref fty) => {
@@ -2654,8 +2672,11 @@ fn err_args(len: uint) -> Vec<ty::t> {
     Vec::from_fn(len, |_| ty::mk_err())
 }
 
-fn write_call(fcx: &FnCtxt, call_expr: &ast::Expr, output: ty::t) {
-    fcx.write_ty(call_expr.id, output);
+fn write_call(fcx: &FnCtxt, call_expr: &ast::Expr, output: ty::FnOutput) {
+    fcx.write_ty(call_expr.id, match output {
+        ty::FnConverging(output_ty) => output_ty,
+        ty::FnDiverging => fcx.infcx().next_diverging_ty_var()
+    });
 }
 
 // AST fragment checking
@@ -2845,8 +2866,8 @@ enum TupleArgumentsFlag {
 /// strict, _|_ can appear in the type of an expression that does not,
 /// itself, diverge: for example, fn() -> _|_.)
 /// Note that inspecting a type's structure *directly* may expose the fact
-/// that there are actually multiple representations for both `ty_err` and
-/// `ty_bot`, so avoid that when err and bot need to be handled differently.
+/// that there are actually multiple representations for `ty_err`, so avoid
+/// that when err needs to be handled differently.
 fn check_expr_with_unifier(fcx: &FnCtxt,
                            expr: &ast::Expr,
                            expected: Expectation,
@@ -2873,7 +2894,7 @@ fn check_call<'a>(fcx: &FnCtxt,
         let error_fn_sig = FnSig {
             binder_id: ast::CRATE_NODE_ID,
             inputs: err_args(args.len()),
-            output: ty::mk_err(),
+            output: ty::FnConverging(ty::mk_err()),
             variadic: false
         };
 
@@ -3021,8 +3042,6 @@ fn check_then_else(fcx: &FnCtxt,
         let cond_ty = fcx.expr_ty(cond_expr);
         let if_ty = if ty::type_is_error(cond_ty) {
             ty::mk_err()
-        } else if ty::type_is_bot(cond_ty) {
-            ty::mk_bot()
         } else {
             branches_ty
         };
@@ -3055,13 +3074,16 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
                 // HACK(eddyb) Fully qualified path to work around a resolve bug.
                 let method_call = ::middle::typeck::MethodCall::expr(op_ex.id);
                 fcx.inh.method_map.borrow_mut().insert(method_call, method);
-                check_method_argument_types(fcx,
+                match check_method_argument_types(fcx,
                                             op_ex.span,
                                             method_ty,
                                             op_ex,
                                             args.as_slice(),
                                             DoDerefArgs,
-                                            DontTupleArguments)
+                                            DontTupleArguments) {
+                    ty::FnConverging(result_type) => result_type,
+                    ty::FnDiverging => ty::mk_err()
+                }
             }
             None => {
                 unbound_method();
@@ -3663,9 +3685,6 @@ fn check_struct_constructor(fcx: &FnCtxt,
             None => {}
             Some(base_expr) => {
                 check_expr_has_type(fcx, &*base_expr, struct_type);
-                if ty::type_is_bot(fcx.node_ty(base_expr.id)) {
-                    struct_type = ty::mk_bot();
-                }
             }
         }
 
@@ -3763,10 +3782,6 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
             ty::type_is_error(rhs_ty) {
             fcx.write_error(id);
         }
-        else if ty::type_is_bot(lhs_ty) ||
-          (ty::type_is_bot(rhs_ty) && !ast_util::lazy_binop(op)) {
-            fcx.write_bot(id);
-        }
       }
       ast::ExprAssignOp(op, ref lhs, ref rhs) => {
         check_binop(fcx, expr, op, &**lhs, rhs, BinopAssignment);
@@ -3785,8 +3800,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
         // Overwrite result of check_binop...this preserves existing behavior
         // but seems quite dubious with regard to user-defined methods
         // and so forth. - Niko
-        if !ty::type_is_error(result_t)
-            && !ty::type_is_bot(result_t) {
+        if !ty::type_is_error(result_t) {
             fcx.write_nil(expr.id);
         }
       }
@@ -3820,9 +3834,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
         if !ty::type_is_error(oprnd_t) {
             match unop {
                 ast::UnUniq => {
-                    if !ty::type_is_bot(oprnd_t) {
-                        oprnd_t = ty::mk_uniq(tcx, oprnd_t);
-                    }
+                    oprnd_t = ty::mk_uniq(tcx, oprnd_t);
                 }
                 ast::UnDeref => {
                     oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
@@ -3859,27 +3871,23 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
                     };
                 }
                 ast::UnNot => {
-                    if !ty::type_is_bot(oprnd_t) {
-                        oprnd_t = structurally_resolved_type(fcx, oprnd.span,
-                                                             oprnd_t);
-                        if !(ty::type_is_integral(oprnd_t) ||
-                             ty::get(oprnd_t).sty == ty::ty_bool) {
-                            oprnd_t = check_user_unop(fcx, "!", "not",
-                                                      tcx.lang_items.not_trait(),
-                                                      expr, &**oprnd, oprnd_t);
-                        }
+                    oprnd_t = structurally_resolved_type(fcx, oprnd.span,
+                                                         oprnd_t);
+                    if !(ty::type_is_integral(oprnd_t) ||
+                         ty::get(oprnd_t).sty == ty::ty_bool) {
+                        oprnd_t = check_user_unop(fcx, "!", "not",
+                                                  tcx.lang_items.not_trait(),
+                                                  expr, &**oprnd, oprnd_t);
                     }
                 }
                 ast::UnNeg => {
-                    if !ty::type_is_bot(oprnd_t) {
-                        oprnd_t = structurally_resolved_type(fcx, oprnd.span,
-                                                             oprnd_t);
-                        if !(ty::type_is_integral(oprnd_t) ||
-                             ty::type_is_fp(oprnd_t)) {
-                            oprnd_t = check_user_unop(fcx, "-", "neg",
-                                                      tcx.lang_items.neg_trait(),
-                                                      expr, &**oprnd, oprnd_t);
-                        }
+                    oprnd_t = structurally_resolved_type(fcx, oprnd.span,
+                                                         oprnd_t);
+                    if !(ty::type_is_integral(oprnd_t) ||
+                         ty::type_is_fp(oprnd_t)) {
+                        oprnd_t = check_user_unop(fcx, "-", "neg",
+                                                  tcx.lang_items.neg_trait(),
+                                                  expr, &**oprnd, oprnd_t);
                     }
                 }
             }
@@ -3904,10 +3912,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
         let tm = ty::mt { ty: fcx.expr_ty(&**oprnd), mutbl: mutbl };
         let oprnd_t = if ty::type_is_error(tm.ty) {
             ty::mk_err()
-        } else if ty::type_is_bot(tm.ty) {
-            ty::mk_bot()
-        }
-        else {
+        } else {
             // Note: at this point, we cannot say what the best lifetime
             // is to use for resulting pointer.  We want to use the
             // shortest lifetime possible so as to avoid spurious borrowck
@@ -3961,24 +3966,32 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
           fcx.write_nil(id);
       }
       ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"),
-      ast::ExprBreak(_) => { fcx.write_bot(id); }
-      ast::ExprAgain(_) => { fcx.write_bot(id); }
+      ast::ExprBreak(_) => { fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); }
+      ast::ExprAgain(_) => { fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); }
       ast::ExprRet(ref expr_opt) => {
-        let ret_ty = fcx.ret_ty;
-        match *expr_opt {
-          None => match fcx.mk_eqty(false, infer::Misc(expr.span),
-                                    ret_ty, ty::mk_nil()) {
-            Ok(_) => { /* fall through */ }
-            Err(_) => {
-                span_err!(tcx.sess, expr.span, E0069,
-                    "`return;` in function returning non-nil");
+        match fcx.ret_ty {
+            ty::FnConverging(result_type) => {
+                match *expr_opt {
+                    None =>
+                        if let Err(_) = fcx.mk_eqty(false, infer::Misc(expr.span),
+                                                    result_type, ty::mk_nil()) {
+                            span_err!(tcx.sess, expr.span, E0069,
+                                "`return;` in function returning non-nil");
+                        },
+                    Some(ref e) => {
+                        check_expr_coercable_to_type(fcx, &**e, result_type);
+                    }
+                }
+            }
+            ty::FnDiverging => {
+                if let Some(ref e) = *expr_opt {
+                    check_expr(fcx, &**e);
+                }
+                span_err!(tcx.sess, expr.span, E0166,
+                    "`return` in a function declared as diverging");
             }
-          },
-          Some(ref e) => {
-              check_expr_coercable_to_type(fcx, &**e, ret_ty);
-          }
         }
-        fcx.write_bot(id);
+        fcx.write_ty(id, fcx.infcx().next_diverging_ty_var());
       }
       ast::ExprParen(ref a) => {
         check_expr_with_expectation_and_lvalue_pref(fcx,
@@ -4004,8 +4017,6 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
 
         if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
             fcx.write_error(id);
-        } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
-            fcx.write_bot(id);
         } else {
             fcx.write_nil(id);
         }
@@ -4025,9 +4036,6 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
         if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) {
             fcx.write_error(id);
         }
-        else if ty::type_is_bot(cond_ty) {
-            fcx.write_bot(id);
-        }
         else {
             fcx.write_nil(id);
         }
@@ -4052,7 +4060,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
       ast::ExprLoop(ref body, _) => {
         check_block_no_value(fcx, &**body);
         if !may_break(tcx, expr.id, &**body) {
-            fcx.write_bot(id);
+            fcx.write_ty(id, fcx.infcx().next_diverging_ty_var());
         } else {
             fcx.write_nil(id);
         }
@@ -4100,31 +4108,24 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
           let args: Vec<_> = args.iter().map(|x| x).collect();
           if !try_overloaded_call(fcx, expr, &**f, f_ty, args.as_slice()) {
               check_call(fcx, expr, &**f, args.as_slice());
-              let (args_bot, args_err) = args.iter().fold((false, false),
-                 |(rest_bot, rest_err), a| {
+              let args_err = args.iter().fold(false,
+                 |rest_err, a| {
                      // is this not working?
                      let a_ty = fcx.expr_ty(&***a);
-                     (rest_bot || ty::type_is_bot(a_ty),
-                      rest_err || ty::type_is_error(a_ty))});
+                     rest_err || ty::type_is_error(a_ty)});
               if ty::type_is_error(f_ty) || args_err {
                   fcx.write_error(id);
               }
-              else if ty::type_is_bot(f_ty) || args_bot {
-                  fcx.write_bot(id);
-              }
           }
       }
       ast::ExprMethodCall(ident, ref tps, ref args) => {
         check_method_call(fcx, expr, ident, args.as_slice(), tps.as_slice(), lvalue_pref);
         let mut arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
-        let (args_bot, args_err) = arg_tys.fold((false, false),
-             |(rest_bot, rest_err), a| {
-              (rest_bot || ty::type_is_bot(a),
-               rest_err || ty::type_is_error(a))});
+        let  args_err = arg_tys.fold(false,
+             |rest_err, a| {
+              rest_err || ty::type_is_error(a)});
         if args_err {
             fcx.write_error(id);
-        } else if args_bot {
-            fcx.write_bot(id);
         }
       }
       ast::ExprCast(ref e, ref t) => {
@@ -4203,8 +4204,6 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
 
         if ty::type_is_error(element_ty) {
             fcx.write_error(id);
-        } else if ty::type_is_bot(element_ty) {
-            fcx.write_bot(id);
         } else {
             let t = ty::mk_vec(tcx, t, Some(count));
             fcx.write_ty(id, t);
@@ -4218,7 +4217,6 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
                 _ => None
             }
         });
-        let mut bot_field = false;
         let mut err_field = false;
 
         let elt_ts = elts.iter().enumerate().map(|(i, e)| {
@@ -4234,12 +4232,9 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
                 }
             };
             err_field = err_field || ty::type_is_error(t);
-            bot_field = bot_field || ty::type_is_bot(t);
             t
         }).collect();
-        if bot_field {
-            fcx.write_bot(id);
-        } else if err_field {
+        if err_field {
             fcx.write_error(id);
         } else {
             let typ = ty::mk_tup(tcx, elt_ts);
@@ -4352,7 +4347,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
                 autoderef(fcx, expr.span, raw_base_t, Some(base.id),
                           lvalue_pref, |base_t, _| ty::index(base_t));
               match field_ty {
-                  Some(ty) if !ty::type_is_bot(ty) => {
+                  Some(ty) => {
                       check_expr_has_type(fcx, &**idx, ty::mk_uint());
                       fcx.write_ty(id, ty);
                       fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
@@ -4394,7 +4389,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
           let raw_base_t = fcx.expr_ty(&**base);
 
           let mut some_err = false;
-          if ty::type_is_error(raw_base_t) || ty::type_is_bot(raw_base_t) {
+          if ty::type_is_error(raw_base_t) {
               fcx.write_ty(id, raw_base_t);
               some_err = true;
           }
@@ -4403,7 +4398,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
               let check_slice_idx = |e: &ast::Expr| {
                   check_expr(fcx, e);
                   let e_t = fcx.expr_ty(e);
-                  if ty::type_is_error(e_t) || ty::type_is_bot(e_t) {
+                  if ty::type_is_error(e_t) {
                     fcx.write_ty(id, e_t);
                     some_err = true;
                   }
@@ -4543,7 +4538,7 @@ pub fn check_decl_local(fcx: &FnCtxt, local: &ast::Local)  {
         Some(ref init) => {
             check_decl_initializer(fcx, local.id, &**init);
             let init_ty = fcx.expr_ty(&**init);
-            if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
+            if ty::type_is_error(init_ty) {
                 fcx.write_ty(local.id, init_ty);
             }
         }
@@ -4556,7 +4551,7 @@ pub fn check_decl_local(fcx: &FnCtxt, local: &ast::Local)  {
     };
     _match::check_pat(&pcx, &*local.pat, t);
     let pat_ty = fcx.node_ty(local.pat.id);
-    if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
+    if ty::type_is_error(pat_ty) {
         fcx.write_ty(local.id, pat_ty);
     }
 }
@@ -4572,7 +4567,7 @@ pub fn check_stmt(fcx: &FnCtxt, stmt: &ast::Stmt)  {
           ast::DeclLocal(ref l) => {
               check_decl_local(fcx, &**l);
               let l_t = fcx.node_ty(l.id);
-              saw_bot = saw_bot || ty::type_is_bot(l_t);
+              saw_bot = saw_bot || fcx.infcx().type_var_diverges(l_t);
               saw_err = saw_err || ty::type_is_error(l_t);
           }
           ast::DeclItem(_) => {/* ignore for now */ }
@@ -4583,20 +4578,20 @@ pub fn check_stmt(fcx: &FnCtxt, stmt: &ast::Stmt)  {
         // Check with expected type of ()
         check_expr_has_type(fcx, &**expr, ty::mk_nil());
         let expr_ty = fcx.expr_ty(&**expr);
-        saw_bot = saw_bot || ty::type_is_bot(expr_ty);
+        saw_bot = saw_bot || fcx.infcx().type_var_diverges(expr_ty);
         saw_err = saw_err || ty::type_is_error(expr_ty);
       }
       ast::StmtSemi(ref expr, id) => {
         node_id = id;
         check_expr(fcx, &**expr);
         let expr_ty = fcx.expr_ty(&**expr);
-        saw_bot |= ty::type_is_bot(expr_ty);
+        saw_bot |= fcx.infcx().type_var_diverges(expr_ty);
         saw_err |= ty::type_is_error(expr_ty);
       }
       ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro")
     }
     if saw_bot {
-        fcx.write_bot(node_id);
+        fcx.write_ty(node_id, fcx.infcx().next_diverging_ty_var());
     }
     else if saw_err {
         fcx.write_error(node_id);
@@ -4611,11 +4606,7 @@ pub fn check_block_no_value(fcx: &FnCtxt, blk: &ast::Block)  {
     let blkty = fcx.node_ty(blk.id);
     if ty::type_is_error(blkty) {
         fcx.write_error(blk.id);
-    }
-    else if ty::type_is_bot(blkty) {
-        fcx.write_bot(blk.id);
-    }
-    else {
+    } else {
         let nilty = ty::mk_nil();
         demand::suptype(fcx, blk.span, nilty, blkty);
     }
@@ -4631,14 +4622,13 @@ fn check_block_with_expected(fcx: &FnCtxt,
     };
 
     let mut warned = false;
-    let mut last_was_bot = false;
-    let mut any_bot = false;
+    let mut any_diverges = false;
     let mut any_err = false;
     for s in blk.stmts.iter() {
         check_stmt(fcx, &**s);
         let s_id = ast_util::stmt_id(&**s);
         let s_ty = fcx.node_ty(s_id);
-        if last_was_bot && !warned && match s.node {
+        if any_diverges && !warned && match s.node {
             ast::StmtDecl(ref decl, _) => {
                 match decl.node {
                     ast::DeclLocal(_) => true,
@@ -4657,22 +4647,19 @@ fn check_block_with_expected(fcx: &FnCtxt,
                           "unreachable statement".to_string());
             warned = true;
         }
-        if ty::type_is_bot(s_ty) {
-            last_was_bot = true;
-        }
-        any_bot = any_bot || ty::type_is_bot(s_ty);
+        any_diverges = any_diverges || fcx.infcx().type_var_diverges(s_ty);
         any_err = any_err || ty::type_is_error(s_ty);
     }
     match blk.expr {
         None => if any_err {
             fcx.write_error(blk.id);
-        } else if any_bot {
-            fcx.write_bot(blk.id);
+        } else if any_diverges {
+            fcx.write_ty(blk.id, fcx.infcx().next_diverging_ty_var());
         } else {
             fcx.write_nil(blk.id);
         },
         Some(ref e) => {
-            if any_bot && !warned {
+            if any_diverges && !warned {
                 fcx.ccx
                     .tcx
                     .sess
@@ -4692,11 +4679,12 @@ fn check_block_with_expected(fcx: &FnCtxt,
                 }
             };
 
-            fcx.write_ty(blk.id, ety);
             if any_err {
                 fcx.write_error(blk.id);
-            } else if any_bot {
-                fcx.write_bot(blk.id);
+            } else if any_diverges {
+                fcx.write_ty(blk.id, fcx.infcx().next_diverging_ty_var());
+            } else {
+                fcx.write_ty(blk.id, ety);
             }
         }
     };
@@ -4718,7 +4706,7 @@ pub fn check_const_in_type(tcx: &ty::ctxt,
         tcx: tcx,
     };
     let inh = static_inherited_fields(&ccx);
-    let fcx = blank_fn_ctxt(&ccx, &inh, expected_type, expr.id);
+    let fcx = blank_fn_ctxt(&ccx, &inh, ty::FnConverging(expected_type), expr.id);
     check_const_with_ty(&fcx, expr.span, expr, expected_type);
 }
 
@@ -4728,7 +4716,7 @@ pub fn check_const(ccx: &CrateCtxt,
                    id: ast::NodeId) {
     let inh = static_inherited_fields(ccx);
     let rty = ty::node_id_to_type(ccx.tcx, id);
-    let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
+    let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
     let declty = (*fcx.ccx.tcx.tcache.borrow())[local_def(id)].ty;
     check_const_with_ty(&fcx, sp, e, declty);
 }
@@ -4892,7 +4880,7 @@ fn do_check(ccx: &CrateCtxt,
                     debug!("disr expr, checking {}", pprust::expr_to_string(&**e));
 
                     let inh = static_inherited_fields(ccx);
-                    let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
+                    let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
                     let declty = match hint {
                         attr::ReprAny | attr::ReprPacked | attr::ReprExtern => ty::mk_int(),
                         attr::ReprInt(_, attr::SignedInt(ity)) => {
@@ -5494,7 +5482,7 @@ fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
         assert!(split.len() >= 2, "Atomic intrinsic not correct format");
 
         //We only care about the operation here
-        match split[1] {
+        let (n_tps, inputs, output) = match split[1] {
             "cxchg" => (1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)),
                                 param(ccx, 0),
                                 param(ccx, 0)),
@@ -5517,12 +5505,12 @@ fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
                     "unrecognized atomic operation function: `{}`", op);
                 return;
             }
-        }
-
+        };
+        (n_tps, inputs, ty::FnConverging(output))
+    } else if name.get() == "abort" || name.get() == "unreachable" {
+        (0, Vec::new(), ty::FnDiverging)
     } else {
-        match name.get() {
-            "abort" => (0, Vec::new(), ty::mk_bot()),
-            "unreachable" => (0, Vec::new(), ty::mk_bot()),
+        let (n_tps, inputs, output) = match name.get() {
             "breakpoint" => (0, Vec::new(), ty::mk_nil()),
             "size_of" |
             "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),
@@ -5730,7 +5718,8 @@ fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
                     "unrecognized intrinsic function: `{}`", *other);
                 return;
             }
-        }
+        };
+        (n_tps, inputs, ty::FnConverging(output))
     };
     let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
         fn_style: ast::UnsafeFn,
index 8585cacdbc43472975cfc48f288c2b33007f6829..bcade1e74ca65d8b910b1c6cfce1ab21d28e76f8 100644 (file)
@@ -334,7 +334,7 @@ fn resolve_method_type(&self, method_call: MethodCall) -> Option<ty::t> {
     /// Try to resolve the type for the given node.
     pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
         let ty_unadjusted = self.resolve_node_type(expr.id);
-        if ty::type_is_error(ty_unadjusted) || ty::type_is_bot(ty_unadjusted) {
+        if ty::type_is_error(ty_unadjusted) {
             ty_unadjusted
         } else {
             let tcx = self.fcx.tcx();
@@ -690,7 +690,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
                 Some(method) => {
                     constrain_call(rcx, expr, Some(&**base),
                                    None::<ast::Expr>.iter(), true);
-                    ty::ty_fn_ret(method.ty)
+                    ty::ty_fn_ret(method.ty).unwrap()
                 }
                 None => rcx.resolve_node_type(base.id)
             };
@@ -1217,9 +1217,14 @@ fn constrain_autoderefs(rcx: &mut Rcx,
                 // Specialized version of constrain_call.
                 type_must_outlive(rcx, infer::CallRcvr(deref_expr.span),
                                   self_ty, r_deref_expr);
-                type_must_outlive(rcx, infer::CallReturn(deref_expr.span),
-                                  fn_sig.output, r_deref_expr);
-                fn_sig.output
+                match fn_sig.output {
+                    ty::FnConverging(return_type) => {
+                        type_must_outlive(rcx, infer::CallReturn(deref_expr.span),
+                                          return_type, r_deref_expr);
+                        return_type
+                    }
+                    ty::FnDiverging => unreachable!()
+                }
             }
             None => derefd_ty
         };
@@ -1445,7 +1450,7 @@ fn link_region_from_node_type(rcx: &Rcx,
      */
 
     let rptr_ty = rcx.resolve_node_type(id);
-    if !ty::type_is_bot(rptr_ty) && !ty::type_is_error(rptr_ty) {
+    if !ty::type_is_error(rptr_ty) {
         let tcx = rcx.fcx.ccx.tcx;
         debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty));
         let r = ty::ty_region(tcx, span, rptr_ty);
index 06b633ba15b57a1ee4bfc1f000b8a3d066987ef4..225a3162af90470c62d7d5d617961817e4b55389 100644 (file)
@@ -92,7 +92,6 @@ fn accumulate_from_ty(&mut self, ty: ty::t) {
 
         match ty::get(ty).sty {
             ty::ty_nil |
-            ty::ty_bot |
             ty::ty_bool |
             ty::ty_char |
             ty::ty_int(..) |
index 3c594fbf2d3661ea4277cdfe79dd34d41092b48e..b3449d658f6d6e556da15cb8914a003960f97e7f 100644 (file)
@@ -98,7 +98,7 @@ fn with_fcx(&mut self,
                                                 &polytype.generics,
                                                 item.id);
         let inh = Inherited::new(ccx.tcx, param_env);
-        let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id);
+        let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(polytype.ty), item.id);
         f(self, &fcx);
         vtable::select_all_fcx_obligations_or_error(&fcx);
         regionck::regionck_item(&fcx, item);
index 38ac317b7a3d4f281af1f666bdd7c33b65296ed0..92fc61cf4c034e2c5b16ae681e9ac4bb029cddf0 100644 (file)
@@ -23,7 +23,7 @@
 use middle::ty::get;
 use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
 use middle::ty::{TypeTraitItemId, lookup_item_type};
-use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_enum, ty_err};
+use middle::ty::{t, ty_bool, ty_char, ty_enum, ty_err};
 use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open};
 use middle::ty::{ty_param, Polytype, ty_ptr};
 use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
@@ -82,7 +82,7 @@ fn get_base_type(inference_context: &InferCtxt,
             Some(resolved_type)
         }
 
-        ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
+        ty_nil | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
         ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
         ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
         ty_ptr(_) | ty_rptr(_, _) => {
index 1f4b80b360bd266a2f6fa4634d1807e37172d764..4c85418669fbb789175a7d3ebd11fec15a245c87 100644 (file)
@@ -2236,7 +2236,10 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
                         .map(|a| ty_of_arg(ccx, &rb, a, None))
                         .collect();
 
-    let output_ty = ast_ty_to_ty(ccx, &rb, &*decl.output);
+    let output = match decl.output.node {
+        ast::TyBot => ty::FnDiverging,
+        _ => ty::FnConverging(ast_ty_to_ty(ccx, &rb, &*decl.output))
+    };
 
     let t_fn = ty::mk_bare_fn(
         ccx.tcx,
@@ -2245,7 +2248,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
             fn_style: ast::UnsafeFn,
             sig: ty::FnSig {binder_id: def_id.node,
                             inputs: input_tys,
-                            output: output_ty,
+                            output: output,
                             variadic: decl.variadic}
         });
     let pty = Polytype {
index de59fb80ad515c46a37b8943a03f1e1b247e0da4..de9379a3aa763e79442d94105340877a9d1f7495 100644 (file)
@@ -359,7 +359,18 @@ fn argvecs<'tcx, C: Combine<'tcx>>(this: &C,
     let inputs = try!(argvecs(this,
                                 a.inputs.as_slice(),
                                 b.inputs.as_slice()));
-    let output = try!(this.tys(a.output, b.output));
+
+    let output = try!(match (a.output, b.output) {
+        (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
+            Ok(ty::FnConverging(try!(this.tys(a_ty, b_ty)))),
+        (ty::FnDiverging, ty::FnDiverging) =>
+            Ok(ty::FnDiverging),
+        (a, b) =>
+            Err(ty::terr_convergence_mismatch(
+                expected_found(this, a != ty::FnDiverging, b != ty::FnDiverging)
+            )),
+    });
+
     Ok(FnSig {binder_id: a.binder_id,
               inputs: inputs,
               output: output,
@@ -373,9 +384,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
     let b_sty = &ty::get(b).sty;
     debug!("super_tys: a_sty={} b_sty={}", a_sty, b_sty);
     return match (a_sty, b_sty) {
-      // The "subtype" ought to be handling cases involving bot or var:
-      (&ty::ty_bot, _) |
-      (_, &ty::ty_bot) |
+      // The "subtype" ought to be handling cases involving var:
       (&ty::ty_infer(TyVar(_)), _) |
       (_, &ty::ty_infer(TyVar(_))) => {
         tcx.sess.bug(
index fd4a5927362188d066f61e5626e03f0225409695..97453dc86efd442ed6fe769fedf33fd721212d07 100644 (file)
@@ -112,15 +112,6 @@ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
         let a = infcx.type_variables.borrow().replace_if_possible(a);
         let b = infcx.type_variables.borrow().replace_if_possible(b);
         match (&ty::get(a).sty, &ty::get(b).sty) {
-            (&ty::ty_bot, &ty::ty_bot) => {
-                Ok(a)
-            }
-
-            (&ty::ty_bot, _) |
-            (_, &ty::ty_bot) => {
-                Err(ty::terr_sorts(expected_found(self, a, b)))
-            }
-
             (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
                 infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id);
                 Ok(a)
index 24642d5213892ddb1a563f383d7278d1bf9fc18d..4fb7bebc58f6d7e29c695f5af6afb7d14694566c 100644 (file)
 use std::collections::HashMap;
 
 pub trait LatticeDir {
-    // Relates the bottom type to `t` and returns LUB(t, _|_) or
-    // GLB(t, _|_) as appropriate.
-    fn ty_bot(&self, t: ty::t) -> cres<ty::t>;
-
     // Relates the type `v` to `a` and `b` such that `v` represents
     // the LUB/GLB of `a` and `b` as appropriate.
     fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()>;
 }
 
 impl<'a, 'tcx> LatticeDir for Lub<'a, 'tcx> {
-    fn ty_bot(&self, t: ty::t) -> cres<ty::t> {
-        Ok(t)
-    }
-
     fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()> {
         let sub = self.sub();
         try!(sub.tys(a, v));
@@ -65,10 +57,6 @@ fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()> {
 }
 
 impl<'a, 'tcx> LatticeDir for Glb<'a, 'tcx> {
-    fn ty_bot(&self, _: ty::t) -> cres<ty::t> {
-        Ok(ty::mk_bot())
-    }
-
     fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()> {
         let sub = self.sub();
         try!(sub.tys(v, a));
@@ -95,8 +83,12 @@ pub fn super_lattice_tys<'tcx, L:LatticeDir+Combine<'tcx>>(this: &L,
     let a = infcx.type_variables.borrow().replace_if_possible(a);
     let b = infcx.type_variables.borrow().replace_if_possible(b);
     match (&ty::get(a).sty, &ty::get(b).sty) {
-        (&ty::ty_bot, _) => { this.ty_bot(b) }
-        (_, &ty::ty_bot) => { this.ty_bot(a) }
+        (&ty::ty_infer(TyVar(..)), &ty::ty_infer(TyVar(..)))
+            if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => {
+            let v = infcx.next_diverging_ty_var();
+            try!(this.relate_bound(v, a, b));
+            Ok(v)
+        }
 
         (&ty::ty_infer(TyVar(..)), _) |
         (_, &ty::ty_infer(TyVar(..))) => {
index a466581ef394a0ea570a589e326f7dd654b7223b..fc508db3b2ebd967d4602fc0b6cd9ea49fc70e17 100644 (file)
@@ -510,6 +510,13 @@ pub fn skolemize<T:TypeFoldable>(&self, t: T) -> T {
         t.fold_with(&mut self.skolemizer())
     }
 
+    pub fn type_var_diverges(&'a self, ty: ty::t) -> bool {
+        match ty::get(ty).sty {
+            ty::ty_infer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid),
+            _ => false
+        }
+    }
+
     pub fn skolemizer<'a>(&'a self) -> TypeSkolemizer<'a, 'tcx> {
         skolemize::TypeSkolemizer::new(self)
     }
@@ -684,14 +691,18 @@ pub fn sub_trait_refs(&self,
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    pub fn next_ty_var_id(&self) -> TyVid {
+    pub fn next_ty_var_id(&self, diverging: bool) -> TyVid {
         self.type_variables
             .borrow_mut()
-            .new_var()
+            .new_var(diverging)
     }
 
     pub fn next_ty_var(&self) -> ty::t {
-        ty::mk_var(self.tcx, self.next_ty_var_id())
+        ty::mk_var(self.tcx, self.next_ty_var_id(false))
+    }
+
+    pub fn next_diverging_ty_var(&self) -> ty::t {
+        ty::mk_var(self.tcx, self.next_ty_var_id(true))
     }
 
     pub fn next_ty_vars(&self, n: uint) -> Vec<ty::t> {
index 87f3fd987871cdea8336a33a84896dcd4b364941..db26376fc69db2144f60271a286639c842ed1ee6 100644 (file)
@@ -205,7 +205,8 @@ pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region {
 
     pub fn resolve_ty_var(&mut self, vid: TyVid) -> ty::t {
         let tcx = self.infcx.tcx;
-        let t1 = match self.infcx.type_variables.borrow().probe(vid) {
+        let tv = self.infcx.type_variables.borrow();
+        match tv.probe(vid) {
             Some(t) => {
                 self.resolve_type(t)
             }
@@ -215,8 +216,7 @@ pub fn resolve_ty_var(&mut self, vid: TyVid) -> ty::t {
                 }
                 ty::mk_var(tcx, vid)
             }
-        };
-        return t1;
+        }
     }
 
     pub fn resolve_int_var(&mut self, vid: IntVid) -> ty::t {
index 1b3290c8b5af8f5c3172cfdfe4e63aee4256d6cd..0fe1e2b565befa4a12ce0588ba00778b9613de5e 100644 (file)
@@ -149,7 +149,6 @@ fn fold_ty(&mut self, t: ty::t) -> ty::t {
             }
 
             ty::ty_nil |
-            ty::ty_bot |
             ty::ty_bool |
             ty::ty_char |
             ty::ty_int(..) |
index 4c04bcc5236f4af88ab9949cbe0f0e5a2a817007..f44fa1ac1c69689272482f0e9b8472428a071823 100644 (file)
@@ -129,10 +129,6 @@ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
         let a = infcx.type_variables.borrow().replace_if_possible(a);
         let b = infcx.type_variables.borrow().replace_if_possible(b);
         match (&ty::get(a).sty, &ty::get(b).sty) {
-            (&ty::ty_bot, _) => {
-                Ok(a)
-            }
-
             (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
                 infcx.type_variables
                     .borrow_mut()
@@ -154,10 +150,6 @@ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
                 Ok(ty::mk_err())
             }
 
-            (_, &ty::ty_bot) => {
-                Err(ty::terr_sorts(expected_found(self, a, b)))
-            }
-
             _ => {
                 super_tys(self, a, b)
             }
index 5f67f8a048aa4e48148975db250b758319ab6304..deeb90503df2157d9cc9d5eec971548374396ba7 100644 (file)
@@ -17,7 +17,8 @@ pub struct TypeVariableTable {
 }
 
 struct TypeVariableData {
-    value: TypeVariableValue
+    value: TypeVariableValue,
+    diverging: bool
 }
 
 enum TypeVariableValue {
@@ -63,6 +64,10 @@ fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec<Relation> {
         relations(self.values.get_mut(a.index))
     }
 
+    pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
+        self.values.get(vid.index).diverging
+    }
+
     pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) {
         /*!
          * Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`.
@@ -108,10 +113,11 @@ pub fn instantiate_and_push(
         self.values.record(SpecifyVar(vid, relations));
     }
 
-    pub fn new_var(&mut self) -> ty::TyVid {
-        let index =
-            self.values.push(
-                TypeVariableData { value: Bounded(Vec::new()) });
+    pub fn new_var(&mut self, diverging: bool) -> ty::TyVid {
+        let index = self.values.push(TypeVariableData {
+            value: Bounded(vec![]),
+            diverging: diverging
+        });
         ty::TyVid { index: index }
     }
 
index 5a23d54c9720b60766dbe0e6d00c4bec7b258097..22898221d9b53468a5839592dbafd2e7e9b6b748 100644 (file)
@@ -381,7 +381,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 sig: ty::FnSig {
                     binder_id: main_id,
                     inputs: Vec::new(),
-                    output: ty::mk_nil(),
+                    output: ty::FnConverging(ty::mk_nil()),
                     variadic: false
                 }
             });
@@ -433,7 +433,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                         ty::mk_int(),
                         ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8()))
                     ),
-                    output: ty::mk_int(),
+                    output: ty::FnConverging(ty::mk_int()),
                     variadic: false
                 }
             });
index d8541a54bd9866153c67b4624c6ed7a4e069f832..8e4aea4463ee37633ab7abe1be3453236b01f078 100644 (file)
@@ -728,7 +728,7 @@ fn add_constraints_from_ty(&mut self,
         debug!("add_constraints_from_ty(ty={})", ty.repr(self.tcx()));
 
         match ty::get(ty).sty {
-            ty::ty_nil | ty::ty_bot | ty::ty_bool |
+            ty::ty_nil | ty::ty_bool |
             ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) |
             ty::ty_float(_) | ty::ty_str => {
                 /* leaf type -- noop */
@@ -882,7 +882,9 @@ fn add_constraints_from_sig(&mut self,
         for &input in sig.inputs.iter() {
             self.add_constraints_from_ty(input, contra);
         }
-        self.add_constraints_from_ty(sig.output, variance);
+        if let ty::FnConverging(result_type) = sig.output {
+            self.add_constraints_from_ty(result_type, variance);
+        }
     }
 
     /// Adds constraints appropriate for a region appearing in a
index 943570743e83f21a133315bc3cee556210470332..b1f8b2de417fb464e17e3e222b8c5f63b633fc31 100644 (file)
@@ -17,7 +17,7 @@
 use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty};
 use middle::ty::{ReSkolemized, ReVar, BrEnv};
 use middle::ty::{mt, t, ParamTy};
-use middle::ty::{ty_bool, ty_char, ty_bot, ty_struct, ty_enum};
+use middle::ty::{ty_bool, ty_char, ty_struct, ty_enum};
 use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
 use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
 use middle::ty::{ty_unboxed_closure};
@@ -352,12 +352,15 @@ fn push_sig_to_string(cx: &ctxt,
             s.push_str(bounds);
         }
 
-        if ty::get(sig.output).sty != ty_nil {
-            s.push_str(" -> ");
-            if ty::type_is_bot(sig.output) {
-                s.push('!');
-            } else {
-                s.push_str(ty_to_string(cx, sig.output).as_slice());
+        match sig.output {
+            ty::FnConverging(t) => {
+                if !ty::type_is_nil(t) {
+                    s.push_str(" -> ");
+                   s.push_str(ty_to_string(cx, t).as_slice());
+                }
+            }
+            ty::FnDiverging => {
+                s.push_str(" -> !");
             }
         }
     }
@@ -371,7 +374,6 @@ fn push_sig_to_string(cx: &ctxt,
     // pretty print the structural type representation:
     return match ty::get(typ).sty {
       ty_nil => "()".to_string(),
-      ty_bot => "!".to_string(),
       ty_bool => "bool".to_string(),
       ty_char => "char".to_string(),
       ty_int(t) => ast_util::int_ty_to_string(t, None).to_string(),
@@ -952,6 +954,19 @@ fn repr(&self, tcx: &ctxt) -> String {
     }
 }
 
+impl Repr for ty::FnOutput {
+    fn repr(&self, tcx: &ctxt) -> String {
+        match *self {
+          ty::FnConverging(ty) => {
+            format!("FnConverging({0})", ty.repr(tcx))
+          }
+          ty::FnDiverging => {
+            "FnDiverging".to_string()
+          }
+        }
+    }
+}
+
 impl Repr for typeck::MethodCallee {
     fn repr(&self, tcx: &ctxt) -> String {
         format!("MethodCallee {{origin: {}, ty: {}, {}}}",
index bdafe192705ce3a8c51119f2274ca06e6c51715f..c4d7e85904cb31e745dd0d30e1ff801c74eff622 100644 (file)
@@ -880,6 +880,15 @@ fn clean(&self, cx: &DocContext) -> FnDecl {
     }
 }
 
+impl<'a> Clean<Type> for ty::FnOutput {
+    fn clean(&self, cx: &DocContext) -> Type {
+        match *self {
+            ty::FnConverging(ty) => ty.clean(cx),
+            ty::FnDiverging => Bottom
+        }
+    }
+}
+
 impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) {
     fn clean(&self, cx: &DocContext) -> FnDecl {
         let (did, sig) = *self;
@@ -1258,7 +1267,6 @@ fn clean(&self, cx: &DocContext) -> Type {
 impl Clean<Type> for ty::t {
     fn clean(&self, cx: &DocContext) -> Type {
         match ty::get(*self).sty {
-            ty::ty_bot => Bottom,
             ty::ty_nil => Primitive(Unit),
             ty::ty_bool => Primitive(Bool),
             ty::ty_char => Primitive(Char),
index fb6d1d4fc6efe9ecfe06259debfde2bc79197e72..c2972d4c5a8e0657463b9e318ed07710c82fccff 100644 (file)
@@ -9,6 +9,5 @@
 // except according to those terms.
 
 fn main() {
-    return.is_failure
-//~^ ERROR attempted access of field `is_failure` on type `!`, but no field with that name was found
+    return.is_failure //~ ERROR unconstrained type variable
 }