Auto merge of #33303 - Aatch:mir-coercion-cast, r=arielb1

[MIR] Handle coercion casts properly when building the MIR

Coercion casts (`expr as T` where the type of `expr` can be coerced to
`T`) are essentially no-ops, as the actual work is done by a coercion.
Previously a check for type equality was used to avoid emitting the
redundant cast in the MIR, but this failed for coercion casts of
function items that had lifetime parameters. The MIR trans code doesn't
handle `FnPtr -> FnPtr` casts and produced an error.

Also fixes a bug with type ascription expressions not having any
adjustments applied.

Fixes #33295

/cc @eddyb
This commit is contained in:
bors 2016-05-02 06:58:11 -07:00
commit 0eb575c702
4 changed files with 448 additions and 394 deletions

View File

@ -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));

View File

@ -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,
}
}
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
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() },
};
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)

View File

@ -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];
}

View File

@ -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 ()) { }