about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs9
-rw-r--r--src/librustc_mir/hair/cx/expr.rs791
-rw-r--r--src/test/run-pass/mir_ascription_coercion.rs20
-rw-r--r--src/test/run-pass/mir_coercion_casts.rs22
4 files changed, 448 insertions, 394 deletions
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 8992381135e..88757c6873c 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -87,12 +87,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
             }
             ExprKind::Cast { source } => {
                 let source = this.hir.mirror(source);
-                if source.ty == expr.ty {
-                    this.expr_as_rvalue(block, source)
-                } else {
-                    let source = unpack!(block = this.as_operand(block, source));
-                    block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
-                }
+
+                let source = unpack!(block = this.as_operand(block, source));
+                block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
             }
             ExprKind::ReifyFnPointer { source } => {
                 let source = unpack!(block = this.as_operand(block, source));
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 7dab8c4c5fb..6d527f77800 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -21,6 +21,7 @@ use rustc_const_eval as const_eval;
 use rustc::middle::region::CodeExtent;
 use rustc::hir::pat_util;
 use rustc::ty::{self, VariantDef, Ty};
+use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::mir::repr::*;
 use rustc::hir;
 use syntax::ptr::P;
@@ -29,398 +30,12 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     type Output = Expr<'tcx>;
 
     fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
-        debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
-
-        let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)!
         let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id);
         let expr_extent = cx.tcx.region_maps.node_extent(self.id);
 
-        let kind = match self.node {
-            // Here comes the interesting stuff:
-            hir::ExprMethodCall(_, _, ref args) => {
-                // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
-                let expr = method_callee(cx, self, ty::MethodCall::expr(self.id));
-                let args = args.iter()
-                               .map(|e| e.to_ref())
-                               .collect();
-                ExprKind::Call {
-                    ty: expr.ty,
-                    fun: expr.to_ref(),
-                    args: args,
-                }
-            }
-
-            hir::ExprCall(ref fun, ref args) => {
-                if cx.tcx.is_method_call(self.id) {
-                    // The callee is something implementing Fn, FnMut, or FnOnce.
-                    // Find the actual method implementation being called and
-                    // build the appropriate UFCS call expression with the
-                    // callee-object as self parameter.
-
-                    // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
-
-                    let method = method_callee(cx, self, ty::MethodCall::expr(self.id));
-
-                    let sig = match method.ty.sty {
-                        ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig,
-                        _ => span_bug!(self.span, "type of method is not an fn")
-                    };
-
-                    let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| {
-                        span_bug!(self.span, "method call has late-bound regions")
-                    });
-
-                    assert_eq!(sig.inputs.len(), 2);
-
-                    let tupled_args = Expr {
-                        ty: sig.inputs[1],
-                        temp_lifetime: temp_lifetime,
-                        span: self.span,
-                        kind: ExprKind::Tuple {
-                            fields: args.iter().map(ToRef::to_ref).collect()
-                        }
-                    };
-
-                    ExprKind::Call {
-                        ty: method.ty,
-                        fun: method.to_ref(),
-                        args: vec![fun.to_ref(), tupled_args.to_ref()]
-                    }
-                } else {
-                    let adt_data = if let hir::ExprPath(..) = fun.node {
-                        // Tuple-like ADTs are represented as ExprCall. We convert them here.
-                        expr_ty.ty_adt_def().and_then(|adt_def|{
-                            match cx.tcx.def_map.borrow()[&fun.id].full_def() {
-                                Def::Variant(_, variant_id) => {
-                                    Some((adt_def, adt_def.variant_index_with_id(variant_id)))
-                                },
-                                Def::Struct(..) => {
-                                    Some((adt_def, 0))
-                                },
-                                _ => None
-                            }
-                        })
-                    } else { None };
-                    if let Some((adt_def, index)) = adt_data {
-                        let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(fun.id).substs);
-                        let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef {
-                            name: Field::new(idx),
-                            expr: e.to_ref()
-                        }).collect();
-                        ExprKind::Adt {
-                            adt_def: adt_def,
-                            substs: substs,
-                            variant_index: index,
-                            fields: field_refs,
-                            base: None
-                        }
-                    } else {
-                        ExprKind::Call {
-                            ty: cx.tcx.node_id_to_type(fun.id),
-                            fun: fun.to_ref(),
-                            args: args.to_ref(),
-                        }
-                    }
-                }
-            }
-
-            hir::ExprAddrOf(mutbl, ref expr) => {
-                let region = match expr_ty.sty {
-                    ty::TyRef(r, _) => r,
-                    _ => span_bug!(expr.span, "type of & not region"),
-                };
-                ExprKind::Borrow {
-                    region: *region,
-                    borrow_kind: to_borrow_kind(mutbl),
-                    arg: expr.to_ref(),
-                }
-            }
-
-            hir::ExprBlock(ref blk) => {
-                ExprKind::Block { body: &blk }
-            }
-
-            hir::ExprAssign(ref lhs, ref rhs) => {
-                ExprKind::Assign {
-                    lhs: lhs.to_ref(),
-                    rhs: rhs.to_ref(),
-                }
-            }
-
-            hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-                if cx.tcx.is_method_call(self.id) {
-                    let pass_args = if op.node.is_by_value() {
-                        PassArgs::ByValue
-                    } else {
-                        PassArgs::ByRef
-                    };
-                    overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
-                                        pass_args, lhs.to_ref(), vec![rhs])
-                } else {
-                    ExprKind::AssignOp {
-                        op: bin_op(op.node),
-                        lhs: lhs.to_ref(),
-                        rhs: rhs.to_ref(),
-                    }
-                }
-            }
-
-            hir::ExprLit(..) => ExprKind::Literal {
-                literal: cx.const_eval_literal(self)
-            },
-
-            hir::ExprBinary(op, ref lhs, ref rhs) => {
-                if cx.tcx.is_method_call(self.id) {
-                    let pass_args = if op.node.is_by_value() {
-                        PassArgs::ByValue
-                    } else {
-                        PassArgs::ByRef
-                    };
-                    overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
-                                        pass_args, lhs.to_ref(), vec![rhs])
-                } else {
-                    // FIXME overflow
-                    match op.node {
-                        hir::BinOp_::BiAnd => {
-                            ExprKind::LogicalOp {
-                                op: LogicalOp::And,
-                                lhs: lhs.to_ref(),
-                                rhs: rhs.to_ref(),
-                            }
-                        }
-                        hir::BinOp_::BiOr => {
-                            ExprKind::LogicalOp {
-                                op: LogicalOp::Or,
-                                lhs: lhs.to_ref(),
-                                rhs: rhs.to_ref(),
-                            }
-                        }
-                        _ => {
-                            let op = bin_op(op.node);
-                            ExprKind::Binary {
-                                op: op,
-                                lhs: lhs.to_ref(),
-                                rhs: rhs.to_ref(),
-                            }
-                        }
-                    }
-                }
-            }
-
-            hir::ExprIndex(ref lhs, ref index) => {
-                if cx.tcx.is_method_call(self.id) {
-                    overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id),
-                                      PassArgs::ByValue, lhs.to_ref(), vec![index])
-                } else {
-                    ExprKind::Index {
-                        lhs: lhs.to_ref(),
-                        index: index.to_ref(),
-                    }
-                }
-            }
-
-            hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
-                if cx.tcx.is_method_call(self.id) {
-                    overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id),
-                                      PassArgs::ByValue, arg.to_ref(), vec![])
-                } else {
-                    ExprKind::Deref { arg: arg.to_ref() }
-                }
-            }
-
-            hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
-                if cx.tcx.is_method_call(self.id) {
-                    overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
-                                        PassArgs::ByValue, arg.to_ref(), vec![])
-                } else {
-                    ExprKind::Unary {
-                        op: UnOp::Not,
-                        arg: arg.to_ref(),
-                    }
-                }
-            }
-
-            hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
-                if cx.tcx.is_method_call(self.id) {
-                    overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
-                                        PassArgs::ByValue, arg.to_ref(), vec![])
-                } else {
-                    // FIXME runtime-overflow
-                    if let hir::ExprLit(_) = arg.node {
-                        ExprKind::Literal {
-                            literal: cx.const_eval_literal(self),
-                        }
-                    } else {
-                        ExprKind::Unary {
-                            op: UnOp::Neg,
-                            arg: arg.to_ref(),
-                        }
-                    }
-                }
-            }
-
-            hir::ExprStruct(_, ref fields, ref base) => {
-                match expr_ty.sty {
-                    ty::TyStruct(adt, substs) => {
-                        let field_refs = field_refs(&adt.variants[0], fields);
-                        ExprKind::Adt {
-                            adt_def: adt,
-                            variant_index: 0,
-                            substs: substs,
-                            fields: field_refs,
-                            base: base.as_ref().map(|base| {
-                                FruInfo {
-                                    base: base.to_ref(),
-                                    field_types: cx.tcx.tables
-                                        .borrow()
-                                        .fru_field_types[&self.id]
-                                        .clone()
-                                }
-                            })
-                        }
-                    }
-                    ty::TyEnum(adt, substs) => {
-                        match cx.tcx.def_map.borrow()[&self.id].full_def() {
-                            Def::Variant(enum_id, variant_id) => {
-                                debug_assert!(adt.did == enum_id);
-                                assert!(base.is_none());
-
-                                let index = adt.variant_index_with_id(variant_id);
-                                let field_refs = field_refs(&adt.variants[index], fields);
-                                ExprKind::Adt {
-                                    adt_def: adt,
-                                    variant_index: index,
-                                    substs: substs,
-                                    fields: field_refs,
-                                    base: None
-                                }
-                            }
-                            ref def => {
-                                span_bug!(
-                                    self.span,
-                                    "unexpected def: {:?}",
-                                    def);
-                            }
-                        }
-                    }
-                    _ => {
-                        span_bug!(
-                            self.span,
-                            "unexpected type for struct literal: {:?}",
-                            expr_ty);
-                    }
-                }
-            }
-
-            hir::ExprClosure(..) => {
-                let closure_ty = cx.tcx.expr_ty(self);
-                let (def_id, substs) = match closure_ty.sty {
-                    ty::TyClosure(def_id, ref substs) => (def_id, substs),
-                    _ => {
-                        span_bug!(self.span,
-                                  "closure expr w/o closure type: {:?}",
-                                  closure_ty);
-                    }
-                };
-                let upvars = cx.tcx.with_freevars(self.id, |freevars| {
-                    freevars.iter()
-                            .enumerate()
-                            .map(|(i, fv)| capture_freevar(cx, self, fv, substs.upvar_tys[i]))
-                            .collect()
-                });
-                ExprKind::Closure {
-                    closure_id: def_id,
-                    substs: &substs,
-                    upvars: upvars,
-                }
-            }
-
-            hir::ExprPath(..) => {
-                convert_path_expr(cx, self)
-            }
-
-            hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => {
-                ExprKind::InlineAsm {
-                    asm: asm,
-                    outputs: outputs.to_ref(),
-                    inputs: inputs.to_ref()
-                }
-            }
-
-            // Now comes the rote stuff:
-
-            hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat {
-                value: v.to_ref(),
-                count: TypedConstVal {
-                    ty: cx.tcx.expr_ty(c),
-                    span: c.span,
-                    value: match const_eval::eval_const_expr(cx.tcx, c) {
-                        ConstVal::Integral(ConstInt::Usize(u)) => u,
-                        other => bug!("constant evaluation of repeat count yielded {:?}", other),
-                    },
-                }
-            },
-            hir::ExprRet(ref v) =>
-                ExprKind::Return { value: v.to_ref() },
-            hir::ExprBreak(label) =>
-                ExprKind::Break { label: label.map(|_| loop_label(cx, self)) },
-            hir::ExprAgain(label) =>
-                ExprKind::Continue { label: label.map(|_| loop_label(cx, self)) },
-            hir::ExprMatch(ref discr, ref arms, _) =>
-                ExprKind::Match { discriminant: discr.to_ref(),
-                                  arms: arms.iter().map(|a| convert_arm(cx, a)).collect() },
-            hir::ExprIf(ref cond, ref then, ref otherwise) =>
-                ExprKind::If { condition: cond.to_ref(),
-                               then: block::to_expr_ref(cx, then),
-                               otherwise: otherwise.to_ref() },
-            hir::ExprWhile(ref cond, ref body, _) =>
-                ExprKind::Loop { condition: Some(cond.to_ref()),
-                                 body: block::to_expr_ref(cx, body) },
-            hir::ExprLoop(ref body, _) =>
-                ExprKind::Loop { condition: None,
-                                 body: block::to_expr_ref(cx, body) },
-            hir::ExprField(ref source, name) => {
-                let index = match cx.tcx.expr_ty_adjusted(source).sty {
-                    ty::TyStruct(adt_def, _) =>
-                        adt_def.variants[0].index_of_field_named(name.node),
-                    ref ty =>
-                        span_bug!(
-                            self.span,
-                            "field of non-struct: {:?}",
-                            ty),
-                };
-                let index = index.unwrap_or_else(|| {
-                    span_bug!(
-                        self.span,
-                        "no index found for field `{}`",
-                        name.node)
-                });
-                ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) }
-            }
-            hir::ExprTupField(ref source, index) =>
-                ExprKind::Field { lhs: source.to_ref(),
-                                  name: Field::new(index.node as usize) },
-            hir::ExprCast(ref source, _) =>
-                ExprKind::Cast { source: source.to_ref() },
-            hir::ExprType(ref source, _) =>
-                return source.make_mirror(cx),
-            hir::ExprBox(ref value) =>
-                ExprKind::Box {
-                    value: value.to_ref(),
-                    value_extents: cx.tcx.region_maps.node_extent(value.id)
-                },
-            hir::ExprVec(ref fields) =>
-                ExprKind::Vec { fields: fields.to_ref() },
-            hir::ExprTup(ref fields) =>
-                ExprKind::Tuple { fields: fields.to_ref() },
-        };
+        debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
 
-        let mut expr = Expr {
-            temp_lifetime: temp_lifetime,
-            ty: expr_ty,
-            span: self.span,
-            kind: kind,
-        };
+        let mut expr = make_mirror_unadjusted(cx, self);
 
         debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
                expr, cx.tcx.tables.borrow().adjustments.get(&self.id));
@@ -587,6 +202,406 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     }
 }
 
+fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> {
+    let expr_ty = cx.tcx.expr_ty(expr);
+    let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
+
+    let kind = match expr.node {
+        // Here comes the interesting stuff:
+        hir::ExprMethodCall(_, _, ref args) => {
+            // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
+            let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
+            let args = args.iter()
+                .map(|e| e.to_ref())
+                .collect();
+            ExprKind::Call {
+                ty: expr.ty,
+                fun: expr.to_ref(),
+                args: args,
+            }
+        }
+
+        hir::ExprCall(ref fun, ref args) => {
+            if cx.tcx.is_method_call(expr.id) {
+                // The callee is something implementing Fn, FnMut, or FnOnce.
+                // Find the actual method implementation being called and
+                // build the appropriate UFCS call expression with the
+                // callee-object as expr parameter.
+
+                // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
+
+                let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
+
+                let sig = match method.ty.sty {
+                    ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig,
+                    _ => span_bug!(expr.span, "type of method is not an fn")
+                };
+
+                let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| {
+                    span_bug!(expr.span, "method call has late-bound regions")
+                });
+
+                assert_eq!(sig.inputs.len(), 2);
+
+                let tupled_args = Expr {
+                    ty: sig.inputs[1],
+                    temp_lifetime: temp_lifetime,
+                    span: expr.span,
+                    kind: ExprKind::Tuple {
+                        fields: args.iter().map(ToRef::to_ref).collect()
+                    }
+                };
+
+                ExprKind::Call {
+                    ty: method.ty,
+                    fun: method.to_ref(),
+                    args: vec![fun.to_ref(), tupled_args.to_ref()]
+                }
+            } else {
+                let adt_data = if let hir::ExprPath(..) = fun.node {
+                    // Tuple-like ADTs are represented as ExprCall. We convert them here.
+                    expr_ty.ty_adt_def().and_then(|adt_def|{
+                        match cx.tcx.def_map.borrow()[&fun.id].full_def() {
+                            Def::Variant(_, variant_id) => {
+                                Some((adt_def, adt_def.variant_index_with_id(variant_id)))
+                            },
+                            Def::Struct(..) => {
+                                Some((adt_def, 0))
+                            },
+                            _ => None
+                        }
+                    })
+                } else { None };
+                if let Some((adt_def, index)) = adt_data {
+                    let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(fun.id).substs);
+                    let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef {
+                        name: Field::new(idx),
+                        expr: e.to_ref()
+                    }).collect();
+                    ExprKind::Adt {
+                        adt_def: adt_def,
+                        substs: substs,
+                        variant_index: index,
+                        fields: field_refs,
+                        base: None
+                    }
+                } else {
+                    ExprKind::Call {
+                        ty: cx.tcx.node_id_to_type(fun.id),
+                        fun: fun.to_ref(),
+                        args: args.to_ref(),
+                    }
+                }
+            }
+        }
+
+        hir::ExprAddrOf(mutbl, ref expr) => {
+            let region = match expr_ty.sty {
+                ty::TyRef(r, _) => r,
+                _ => span_bug!(expr.span, "type of & not region"),
+            };
+            ExprKind::Borrow {
+                region: *region,
+                borrow_kind: to_borrow_kind(mutbl),
+                arg: expr.to_ref(),
+            }
+        }
+
+        hir::ExprBlock(ref blk) => {
+            ExprKind::Block { body: &blk }
+        }
+
+        hir::ExprAssign(ref lhs, ref rhs) => {
+            ExprKind::Assign {
+                lhs: lhs.to_ref(),
+                rhs: rhs.to_ref(),
+            }
+        }
+
+        hir::ExprAssignOp(op, ref lhs, ref rhs) => {
+            if cx.tcx.is_method_call(expr.id) {
+                let pass_args = if op.node.is_by_value() {
+                    PassArgs::ByValue
+                } else {
+                    PassArgs::ByRef
+                };
+                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
+                                    pass_args, lhs.to_ref(), vec![rhs])
+            } else {
+                ExprKind::AssignOp {
+                    op: bin_op(op.node),
+                    lhs: lhs.to_ref(),
+                    rhs: rhs.to_ref(),
+                }
+            }
+        }
+
+        hir::ExprLit(..) => ExprKind::Literal {
+            literal: cx.const_eval_literal(expr)
+        },
+
+        hir::ExprBinary(op, ref lhs, ref rhs) => {
+            if cx.tcx.is_method_call(expr.id) {
+                let pass_args = if op.node.is_by_value() {
+                    PassArgs::ByValue
+                } else {
+                    PassArgs::ByRef
+                };
+                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
+                                    pass_args, lhs.to_ref(), vec![rhs])
+            } else {
+                // FIXME overflow
+                match op.node {
+                    hir::BinOp_::BiAnd => {
+                        ExprKind::LogicalOp {
+                            op: LogicalOp::And,
+                            lhs: lhs.to_ref(),
+                            rhs: rhs.to_ref(),
+                        }
+                    }
+                    hir::BinOp_::BiOr => {
+                        ExprKind::LogicalOp {
+                            op: LogicalOp::Or,
+                            lhs: lhs.to_ref(),
+                            rhs: rhs.to_ref(),
+                        }
+                    }
+                    _ => {
+                        let op = bin_op(op.node);
+                        ExprKind::Binary {
+                            op: op,
+                            lhs: lhs.to_ref(),
+                            rhs: rhs.to_ref(),
+                        }
+                    }
+                }
+            }
+        }
+
+        hir::ExprIndex(ref lhs, ref index) => {
+            if cx.tcx.is_method_call(expr.id) {
+                overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id),
+                                  PassArgs::ByValue, lhs.to_ref(), vec![index])
+            } else {
+                ExprKind::Index {
+                    lhs: lhs.to_ref(),
+                    index: index.to_ref(),
+                }
+            }
+        }
+
+        hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
+            if cx.tcx.is_method_call(expr.id) {
+                overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id),
+                                  PassArgs::ByValue, arg.to_ref(), vec![])
+            } else {
+                ExprKind::Deref { arg: arg.to_ref() }
+            }
+        }
+
+        hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
+            if cx.tcx.is_method_call(expr.id) {
+                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
+                                    PassArgs::ByValue, arg.to_ref(), vec![])
+            } else {
+                ExprKind::Unary {
+                    op: UnOp::Not,
+                    arg: arg.to_ref(),
+                }
+            }
+        }
+
+        hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
+            if cx.tcx.is_method_call(expr.id) {
+                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
+                                    PassArgs::ByValue, arg.to_ref(), vec![])
+            } else {
+                // FIXME runtime-overflow
+                if let hir::ExprLit(_) = arg.node {
+                    ExprKind::Literal {
+                        literal: cx.const_eval_literal(expr),
+                    }
+                } else {
+                    ExprKind::Unary {
+                        op: UnOp::Neg,
+                        arg: arg.to_ref(),
+                    }
+                }
+            }
+        }
+
+        hir::ExprStruct(_, ref fields, ref base) => {
+            match expr_ty.sty {
+                ty::TyStruct(adt, substs) => {
+                    let field_refs = field_refs(&adt.variants[0], fields);
+                    ExprKind::Adt {
+                        adt_def: adt,
+                        variant_index: 0,
+                        substs: substs,
+                        fields: field_refs,
+                        base: base.as_ref().map(|base| {
+                            FruInfo {
+                                base: base.to_ref(),
+                                field_types: cx.tcx.tables
+                                    .borrow()
+                                    .fru_field_types[&expr.id]
+                                    .clone()
+                            }
+                        })
+                    }
+                }
+                ty::TyEnum(adt, substs) => {
+                    match cx.tcx.def_map.borrow()[&expr.id].full_def() {
+                        Def::Variant(enum_id, variant_id) => {
+                            debug_assert!(adt.did == enum_id);
+                            assert!(base.is_none());
+
+                            let index = adt.variant_index_with_id(variant_id);
+                            let field_refs = field_refs(&adt.variants[index], fields);
+                            ExprKind::Adt {
+                                adt_def: adt,
+                                variant_index: index,
+                                substs: substs,
+                                fields: field_refs,
+                                base: None
+                            }
+                        }
+                        ref def => {
+                            span_bug!(
+                                expr.span,
+                                "unexpected def: {:?}",
+                                def);
+                        }
+                    }
+                }
+                _ => {
+                    span_bug!(
+                        expr.span,
+                        "unexpected type for struct literal: {:?}",
+                        expr_ty);
+                }
+            }
+        }
+
+        hir::ExprClosure(..) => {
+            let closure_ty = cx.tcx.expr_ty(expr);
+            let (def_id, substs) = match closure_ty.sty {
+                ty::TyClosure(def_id, ref substs) => (def_id, substs),
+                _ => {
+                    span_bug!(expr.span,
+                              "closure expr w/o closure type: {:?}",
+                              closure_ty);
+                }
+            };
+            let upvars = cx.tcx.with_freevars(expr.id, |freevars| {
+                freevars.iter()
+                    .enumerate()
+                    .map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i]))
+                    .collect()
+            });
+            ExprKind::Closure {
+                closure_id: def_id,
+                substs: &substs,
+                upvars: upvars,
+            }
+        }
+
+        hir::ExprPath(..) => {
+            convert_path_expr(cx, expr)
+        }
+
+        hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => {
+            ExprKind::InlineAsm {
+                asm: asm,
+                outputs: outputs.to_ref(),
+                inputs: inputs.to_ref()
+            }
+        }
+
+        // Now comes the rote stuff:
+
+        hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat {
+            value: v.to_ref(),
+            count: TypedConstVal {
+                ty: cx.tcx.expr_ty(c),
+                span: c.span,
+                value: match const_eval::eval_const_expr(cx.tcx, c) {
+                    ConstVal::Integral(ConstInt::Usize(u)) => u,
+                    other => bug!("constant evaluation of repeat count yielded {:?}", other),
+                },
+            }
+        },
+        hir::ExprRet(ref v) =>
+            ExprKind::Return { value: v.to_ref() },
+        hir::ExprBreak(label) =>
+            ExprKind::Break { label: label.map(|_| loop_label(cx, expr)) },
+        hir::ExprAgain(label) =>
+            ExprKind::Continue { label: label.map(|_| loop_label(cx, expr)) },
+        hir::ExprMatch(ref discr, ref arms, _) =>
+            ExprKind::Match { discriminant: discr.to_ref(),
+                              arms: arms.iter().map(|a| convert_arm(cx, a)).collect() },
+        hir::ExprIf(ref cond, ref then, ref otherwise) =>
+            ExprKind::If { condition: cond.to_ref(),
+                           then: block::to_expr_ref(cx, then),
+                           otherwise: otherwise.to_ref() },
+        hir::ExprWhile(ref cond, ref body, _) =>
+            ExprKind::Loop { condition: Some(cond.to_ref()),
+                             body: block::to_expr_ref(cx, body) },
+        hir::ExprLoop(ref body, _) =>
+            ExprKind::Loop { condition: None,
+                             body: block::to_expr_ref(cx, body) },
+        hir::ExprField(ref source, name) => {
+            let index = match cx.tcx.expr_ty_adjusted(source).sty {
+                ty::TyStruct(adt_def, _) =>
+                    adt_def.variants[0].index_of_field_named(name.node),
+                ref ty =>
+                    span_bug!(
+                        expr.span,
+                        "field of non-struct: {:?}",
+                        ty),
+            };
+            let index = index.unwrap_or_else(|| {
+                span_bug!(
+                    expr.span,
+                    "no index found for field `{}`",
+                    name.node)
+            });
+            ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) }
+        }
+        hir::ExprTupField(ref source, index) =>
+            ExprKind::Field { lhs: source.to_ref(),
+                              name: Field::new(index.node as usize) },
+        hir::ExprCast(ref source, _) => {
+            // Check to see if this cast is a "coercion cast", where the cast is actually done
+            // using a coercion (or is a no-op).
+            if let Some(&TyCastKind::CoercionCast) = cx.tcx.cast_kinds.borrow().get(&source.id) {
+                // Skip the actual cast itexpr, as it's now a no-op.
+                return source.make_mirror(cx);
+            } else {
+                ExprKind::Cast { source: source.to_ref() }
+            }
+        }
+        hir::ExprType(ref source, _) =>
+            return source.make_mirror(cx),
+        hir::ExprBox(ref value) =>
+            ExprKind::Box {
+                value: value.to_ref(),
+                value_extents: cx.tcx.region_maps.node_extent(value.id)
+            },
+        hir::ExprVec(ref fields) =>
+            ExprKind::Vec { fields: fields.to_ref() },
+        hir::ExprTup(ref fields) =>
+            ExprKind::Tuple { fields: fields.to_ref() },
+    };
+
+    Expr {
+        temp_lifetime: temp_lifetime,
+        ty: expr_ty,
+        span: expr.span,
+        kind: kind,
+    }
+}
+
 fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
                                expr: &hir::Expr,
                                method_call: ty::MethodCall)
diff --git a/src/test/run-pass/mir_ascription_coercion.rs b/src/test/run-pass/mir_ascription_coercion.rs
new file mode 100644
index 00000000000..b227be9c543
--- /dev/null
+++ b/src/test/run-pass/mir_ascription_coercion.rs
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that the result of type ascription has adjustments applied
+
+#![feature(rustc_attrs, type_ascription)]
+
+#[rustc_mir]
+fn main() {
+    let x = [1, 2, 3];
+    // The RHS should coerce to &[i32]
+    let _y : &[i32] = &x : &[i32; 3];
+}
diff --git a/src/test/run-pass/mir_coercion_casts.rs b/src/test/run-pass/mir_coercion_casts.rs
new file mode 100644
index 00000000000..4d5c59276d7
--- /dev/null
+++ b/src/test/run-pass/mir_coercion_casts.rs
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests the coercion casts are handled properly
+
+#![feature(rustc_attrs)]
+
+#[rustc_mir]
+fn main() {
+    // This should produce only a reification of f,
+    // not a fn -> fn cast as well
+    let _ = f as fn(&());
+}
+
+fn f<'a>(_: &'a ()) { }