about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndrew Cann <shum@canndrew.org>2016-07-22 13:50:04 +0800
committerAndrew Cann <shum@canndrew.org>2016-08-13 21:37:09 +0800
commit104963c539e538a89fff21c133692fc21dac3e64 (patch)
tree47f0eb74a863f329732f74914c7951fecd0d1260
parent9f9f8567eb4effe1052b7458c7451f62d1dcc0b1 (diff)
downloadrust-104963c539e538a89fff21c133692fc21dac3e64.tar.gz
rust-104963c539e538a89fff21c133692fc21dac3e64.zip
Switch on TyEmpty
Parse -> ! as FnConverging(!)
Add AdjustEmptyToAny coercion to all ! expressions
Some fixes
-rw-r--r--src/librustc/cfg/construct.rs2
-rw-r--r--src/librustc/middle/liveness.rs4
-rw-r--r--src/librustc/ty/sty.rs19
-rw-r--r--src/librustc_mir/build/expr/into.rs2
-rw-r--r--src/librustc_mir/transform/type_check.rs8
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs3
-rw-r--r--src/librustc_typeck/check/_match.rs6
-rw-r--r--src/librustc_typeck/check/intrinsic.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs84
-rw-r--r--src/librustc_typeck/check/op.rs6
-rw-r--r--src/libsyntax/parse/parser.rs6
11 files changed, 88 insertions, 54 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 601d3866b02..89964043819 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -379,7 +379,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
         let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
-        if fn_ty.fn_ret().diverges() {
+        if fn_ty.fn_ret().diverges(self.tcx) {
             self.add_unreachable_node()
         } else {
             ret
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index f62c9a5d882..3a293c304ee 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1112,7 +1112,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprCall(ref f, ref args) => {
             let diverges = !self.ir.tcx.is_method_call(expr.id) &&
-                self.ir.tcx.expr_ty_adjusted(&f).fn_ret().diverges();
+                self.ir.tcx.expr_ty_adjusted(&f).fn_ret().diverges(self.ir.tcx);
             let succ = if diverges {
                 self.s.exit_ln
             } else {
@@ -1125,7 +1125,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           hir::ExprMethodCall(_, _, ref args) => {
             let method_call = ty::MethodCall::expr(expr.id);
             let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
-            let succ = if method_ty.fn_ret().diverges() {
+            let succ = if method_ty.fn_ret().diverges(self.ir.tcx) {
                 self.s.exit_ln
             } else {
                 succ
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index d693f7f0b83..6cc7eef1c6f 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -484,8 +484,11 @@ pub enum FnOutput<'tcx> {
 }
 
 impl<'tcx> FnOutput<'tcx> {
-    pub fn diverges(&self) -> bool {
-        *self == FnDiverging
+    pub fn diverges(&self, tcx: TyCtxt) -> bool {
+        match *self {
+            FnConverging(ref ty) => ty.is_empty(tcx),
+            FnDiverging => true,
+        }
     }
 
     pub fn unwrap(self) -> Ty<'tcx> {
@@ -513,8 +516,8 @@ impl<'tcx> FnOutput<'tcx> {
 pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
 
 impl<'tcx> PolyFnOutput<'tcx> {
-    pub fn diverges(&self) -> bool {
-        self.0.diverges()
+    pub fn diverges(&self, tcx: TyCtxt) -> bool {
+        self.0.diverges(tcx)
     }
 }
 
@@ -936,11 +939,15 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 
-    pub fn is_empty(&self, _cx: TyCtxt) -> bool {
+    pub fn is_empty(&self, cx: TyCtxt) -> bool {
         // FIXME(#24885): be smarter here
         match self.sty {
             TyEnum(def, _) | TyStruct(def, _) => def.is_empty(),
-            _ => false
+            TyEmpty => true,
+            TyTuple(ref tys) => tys.iter().any(|ty| ty.is_empty(cx)),
+            // FIXME (canndrew): this line breaks core::fmt
+            //TyRef(_, ref tm) => tm.ty.is_empty(cx),
+            _ => false,
         }
     }
 
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 5705798dab0..692f0d3e5ac 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Call { ty, fun, args } => {
                 let diverges = match ty.sty {
                     ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
-                        f.sig.0.output.diverges()
+                        f.sig.0.output.diverges(this.hir.tcx())
                     }
                     _ => false
                 };
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 934357c9e1d..53329a85036 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -504,9 +504,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 }
             }
             (&None, ty::FnDiverging) => {}
-            (&None, ty::FnConverging(..)) => {
-                span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
-             }
+            (&None, ty::FnConverging(ref ty)) => {
+                if !ty.is_empty(tcx) {
+                    span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
+                }
+            }
         }
     }
 
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index ee13af80b2b..4c58ce6b78c 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -171,6 +171,7 @@ impl<'tcx> TypeMap<'tcx> {
         unique_type_id.push('{');
 
         match type_.sty {
+            ty::TyEmpty    |
             ty::TyBool     |
             ty::TyChar     |
             ty::TyStr      |
@@ -704,6 +705,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     let sty = &t.sty;
     let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty {
+        ty::TyEmpty    |
         ty::TyBool     |
         ty::TyChar     |
         ty::TyInt(_)   |
@@ -931,6 +933,7 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     debug!("basic_type_metadata: {:?}", t);
 
     let (name, encoding) = match t.sty {
+        ty::TyEmpty => ("!", DW_ATE_unsigned),
         ty::TyTuple(ref elements) if elements.is_empty() =>
             ("()", DW_ATE_unsigned),
         ty::TyBool => ("bool", DW_ATE_boolean),
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5f255cc1fb7..6b9917afdfb 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -473,7 +473,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
         }
 
-        self.write_ty(expr.id, result_ty);
+        self.write_ty_expr(expr.id, result_ty);
     }
 }
 
@@ -550,7 +550,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let scheme = tcx.lookup_item_type(def.def_id());
         let predicates = tcx.lookup_predicates(def.def_id());
         let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
-                                                 opt_ty, def, pat.span, pat.id);
+                                                 opt_ty, def, pat.span, pat.id, false);
         self.demand_suptype(pat.span, expected, pat_ty);
     }
 
@@ -618,7 +618,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         };
         let predicates = tcx.lookup_predicates(def.def_id());
         let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
-                                                 opt_ty, def, pat.span, pat.id);
+                                                 opt_ty, def, pat.span, pat.id, false);
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 9051b1c8069..4788911662d 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -106,7 +106,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
         };
         (n_tps, inputs, ty::FnConverging(output))
     } else if &name[..] == "abort" || &name[..] == "unreachable" {
-        (0, Vec::new(), ty::FnDiverging)
+        (0, Vec::new(), ty::FnConverging(tcx.mk_empty()))
     } else {
         let (n_tps, inputs, output) = match &name[..] {
             "breakpoint" => (0, Vec::new(), tcx.mk_nil()),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0c8e6d990a6..89a4bc4cac6 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -93,7 +93,7 @@ use rustc::traits::{self, Reveal};
 use rustc::ty::{GenericPredicates, TypeScheme};
 use rustc::ty::{ParamTy, ParameterEnvironment};
 use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
-use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
+use rustc::ty::{self, ToPolyTraitRef, Ty, TypeVariants, TyCtxt, Visibility};
 use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
@@ -1561,6 +1561,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.tables.borrow_mut().node_types.insert(node_id, ty);
     }
 
+    #[inline]
+    pub fn write_ty_expr(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
+        self.write_ty(node_id, ty);
+        if let TypeVariants::TyEmpty = ty.sty {
+            self.write_adjustment(node_id, adjustment::AdjustEmptyToAny(self.next_diverging_ty_var()));
+        }
+    }
+
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
         if !substs.substs.is_noop() {
             debug!("write_substs({}, {:?}) in fcx {}",
@@ -1731,6 +1739,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn write_nil(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.mk_nil());
     }
+
+    pub fn write_empty(&self, node_id: ast::NodeId) {
+        self.write_ty_expr(node_id, self.tcx.mk_empty());
+    }
+
     pub fn write_error(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.types.err);
     }
@@ -1788,6 +1801,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
+        if let Some(&adjustment::AdjustEmptyToAny(ref t))
+                = self.tables.borrow().adjustments.get(&ex.id) {
+            return t;
+        }
         match self.tables.borrow().node_types.get(&ex.id) {
             Some(&t) => t,
             None => {
@@ -1966,9 +1983,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         for ty in &self.unsolved_variables() {
             let resolved = self.resolve_type_vars_if_possible(ty);
             if self.type_var_diverges(resolved) {
-                debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges",
+                debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges",
                        resolved);
-                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_empty());
             } else {
                 match self.type_is_unconstrained_numeric(resolved) {
                     UnconstrainedInt => {
@@ -2042,7 +2059,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             for ty in &unsolved_variables {
                 let resolved = self.resolve_type_vars_if_possible(ty);
                 if self.type_var_diverges(resolved) {
-                    self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                    self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_empty());
                 } else {
                     match self.type_is_unconstrained_numeric(resolved) {
                         UnconstrainedInt | UnconstrainedFloat => {
@@ -2100,7 +2117,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| {
                 for ty in &unbound_tyvars {
                     if self.type_var_diverges(ty) {
-                        self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                        self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_empty());
                     } else {
                         match self.type_is_unconstrained_numeric(ty) {
                             UnconstrainedInt => {
@@ -2196,7 +2213,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // reporting for more then one conflict.
         for ty in &unbound_tyvars {
             if self.type_var_diverges(ty) {
-                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_empty());
             } else {
                 match self.type_is_unconstrained_numeric(ty) {
                     UnconstrainedInt => {
@@ -2601,7 +2618,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) {
-                    any_diverges = any_diverges || self.type_var_diverges(arg_ty);
+                    any_diverges = any_diverges ||
+                                   self.type_var_diverges(arg_ty) ||
+                                   arg_ty.is_empty(self.tcx);
                 }
             }
             if any_diverges && !warned {
@@ -2670,7 +2689,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn write_call(&self,
                   call_expr: &hir::Expr,
                   output: ty::FnOutput<'tcx>) {
-        self.write_ty(call_expr.id, match output {
+        self.write_ty_expr(call_expr.id, match output {
             ty::FnConverging(output_ty) => output_ty,
             ty::FnDiverging => self.next_diverging_ty_var()
         });
@@ -2910,7 +2929,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // the type of the block, because old trans still uses it.
                 let adj = self.tables.borrow().adjustments.get(&then.id).cloned();
                 if res.is_ok() && adj.is_some() {
-                    self.write_ty(then_blk.id, self.adjust_expr_ty(then, adj.as_ref()));
+                    self.write_ty_expr(then_blk.id, self.adjust_expr_ty(then, adj.as_ref()));
                 }
 
                 res
@@ -2951,7 +2970,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         };
 
-        self.write_ty(id, if_ty);
+        self.write_ty_expr(id, if_ty);
     }
 
     // Check field access expressions
@@ -2972,7 +2991,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     let field_ty = self.field_ty(expr.span, field, substs);
                     if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                         autoderef.finalize(lvalue_pref, Some(base));
-                        self.write_ty(expr.id, field_ty);
+                        self.write_ty_expr(expr.id, field_ty);
                         self.write_autoderef_adjustment(base.id, autoderefs);
                         return;
                     }
@@ -2984,7 +3003,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
-            self.write_ty(expr.id, field_ty);
+            self.write_ty_expr(expr.id, field_ty);
             let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
             let mut err = self.tcx().sess.struct_span_err(expr.span, &msg);
             // Also check if an accessible method exists, which is often what is meant.
@@ -3079,7 +3098,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             if let Some(field_ty) = field {
                 autoderef.finalize(lvalue_pref, Some(base));
-                self.write_ty(expr.id, field_ty);
+                self.write_ty_expr(expr.id, field_ty);
                 self.write_autoderef_adjustment(base.id, autoderefs);
                 return;
             }
@@ -3090,7 +3109,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let struct_path = self.tcx().item_path_str(did);
             let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
             self.tcx().sess.span_err(expr.span, &msg);
-            self.write_ty(expr.id, field_ty);
+            self.write_ty_expr(expr.id, field_ty);
             return;
         }
 
@@ -3343,7 +3362,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
           hir::ExprLit(ref lit) => {
             let typ = self.check_lit(&lit, expected);
-            self.write_ty(id, typ);
+            self.write_ty_expr(id, typ);
           }
           hir::ExprBinary(op, ref lhs, ref rhs) => {
             self.check_binop(expr, op, lhs, rhs);
@@ -3409,7 +3428,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, oprnd_t);
+            self.write_ty_expr(id, oprnd_t);
           }
           hir::ExprAddrOf(mutbl, ref oprnd) => {
             let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
@@ -3460,7 +3479,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
                                                                                      def);
                   self.instantiate_value_path(segments, scheme, &predicates,
-                                              opt_ty, def, expr.span, id);
+                                              opt_ty, def, expr.span, id, true);
               } else {
                   self.set_tainted_by_errors();
                   self.write_error(id);
@@ -3481,8 +3500,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               }
               self.write_nil(id);
           }
-          hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
-          hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
+          hir::ExprBreak(_) => { self.write_empty(id); }
+          hir::ExprAgain(_) => { self.write_empty(id); }
           hir::ExprRet(ref expr_opt) => {
             match self.ret_ty {
                 ty::FnConverging(result_type) => {
@@ -3513,7 +3532,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .emit();
                 }
             }
-            self.write_ty(id, self.next_diverging_ty_var());
+            self.write_empty(id);
           }
           hir::ExprAssign(ref lhs, ref rhs) => {
             self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
@@ -3555,7 +3574,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprLoop(ref body, _) => {
             self.check_block_no_value(&body);
             if !may_break(tcx, expr.id, &body) {
-                self.write_ty(id, self.next_diverging_ty_var());
+                self.write_empty(id);
             } else {
                 self.write_nil(id);
             }
@@ -3568,7 +3587,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           }
           hir::ExprBlock(ref b) => {
             self.check_block_with_expected(&b, expected);
-            self.write_ty(id, self.node_ty(b.id));
+            self.write_ty_expr(id, self.node_ty(b.id));
           }
           hir::ExprCall(ref callee, ref args) => {
               self.check_call(expr, &callee, &args[..], expected);
@@ -3604,7 +3623,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             } else {
                 // Write a type for the whole expression, assuming everything is going
                 // to work out Ok.
-                self.write_ty(id, t_cast);
+                self.write_ty_expr(id, t_cast);
 
                 // Defer other checks until we're done type checking.
                 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
@@ -3621,7 +3640,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprType(ref e, ref t) => {
             let typ = self.to_ty(&t);
             self.check_expr_eq_type(&e, typ);
-            self.write_ty(id, typ);
+            self.write_ty_expr(id, typ);
           }
           hir::ExprVec(ref args) => {
             let uty = expected.to_option(self).and_then(|uty| {
@@ -3755,7 +3774,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                       Some((index_ty, element_ty)) => {
                           let idx_expr_ty = self.expr_ty(idx);
                           self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
-                          self.write_ty(id, element_ty);
+                          self.write_ty_expr(id, element_ty);
                       }
                       None => {
                           self.check_expr_has_type(&idx, self.tcx.types.err);
@@ -4011,7 +4030,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               "unreachable statement".to_string());
                 warned = true;
             }
-            any_diverges = any_diverges || self.type_var_diverges(s_ty);
+            any_diverges = any_diverges ||
+                           self.type_var_diverges(s_ty) ||
+                           s_ty.is_empty(self.tcx);
             any_err = any_err || s_ty.references_error();
         }
         match blk.expr {
@@ -4047,7 +4068,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 } else if any_diverges {
                     self.write_ty(blk.id, self.next_diverging_ty_var());
                 } else {
-                    self.write_ty(blk.id, ety);
+                    self.write_ty_expr(blk.id, ety);
                 }
             }
         };
@@ -4096,7 +4117,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   opt_self_ty: Option<Ty<'tcx>>,
                                   def: Def,
                                   span: Span,
-                                  node_id: ast::NodeId)
+                                  node_id: ast::NodeId,
+                                  node_is_expr: bool) {
                                   -> Ty<'tcx> {
         debug!("instantiate_value_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
                segments,
@@ -4360,7 +4382,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
-        self.write_ty(node_id, ty_substituted);
+        if node_is_expr {
+            self.write_ty_expr(node_id, ty_substituted);
+        } else {
+            self.write_ty(node_id, ty_substituted);
+        }
         self.write_substs(node_id, ty::ItemSubsts {
             substs: substs
         });
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 63487683ec3..17da3cd3490 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -36,7 +36,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
             self.write_nil(expr.id);
         } else {
-            self.write_ty(expr.id, return_ty);
+            self.write_ty_expr(expr.id, return_ty);
         }
 
         let tcx = self.tcx;
@@ -69,7 +69,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // && and || are a simple case.
                 self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
                 self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool());
-                self.write_ty(expr.id, tcx.mk_bool());
+                self.write_ty_expr(expr.id, tcx.mk_bool());
             }
             _ => {
                 // Otherwise, we always treat operators as if they are
@@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     self.demand_suptype(expr.span, builtin_return_ty, return_ty);
                 }
 
-                self.write_ty(expr.id, return_ty);
+                self.write_ty_expr(expr.id, return_ty);
             }
         }
     }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index e3803591295..4f54f529322 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1332,11 +1332,7 @@ impl<'a> Parser<'a> {
     /// Parse optional return type [ -> TY ] in function decl
     pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
         if self.eat(&token::RArrow) {
-            if self.eat(&token::Not) {
-                Ok(FunctionRetTy::None(self.last_span))
-            } else {
-                Ok(FunctionRetTy::Ty(self.parse_ty()?))
-            }
+            Ok(FunctionRetTy::Ty(self.parse_ty()?))
         } else {
             let pos = self.span.lo;
             Ok(FunctionRetTy::Default(mk_sp(pos, pos)))