diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 8992381135ea8..88757c6873c5f 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 7dab8c4c5fb2a..6d527f77800f6 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 0000000000000..b227be9c543b2 --- /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 or the MIT license +// , 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 0000000000000..4d5c59276d750 --- /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 or the MIT license +// , 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 ()) { }