use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, AdtKind, VariantDef, Ty};
use rustc::ty::cast::CastKind as TyCastKind;
+use rustc::ty::subst::Subst;
use rustc::hir;
use syntax::ptr::P;
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
let mut expr = make_mirror_unadjusted(cx, self);
- let adj = cx.tables().adjustments.get(&self.id).cloned();
+ let adj = cx.tables().adjustments.get(&self.id);
debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
expr,
adj);
// Now apply adjustments, if any.
- match adj.map(|adj| (adj.kind, adj.target)) {
+ match adj.map(|adj| (&adj.kind, adj.target)) {
None => {}
- Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
+ Some((&ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
expr = Expr {
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,
kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
};
}
- Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
+ Some((&ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
expr = Expr {
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,
kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
};
}
- Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
+ Some((&ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
expr = Expr {
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,
kind: ExprKind::ClosureFnPointer { source: expr.to_ref() },
};
}
- Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
+ Some((&ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
expr = Expr {
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,
kind: ExprKind::NeverToAny { source: expr.to_ref() },
};
}
- Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
+ Some((&ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
expr = Expr {
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,
kind: ExprKind::Cast { source: expr.to_ref() },
};
}
- Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize },
+ Some((&ty::adjustment::Adjust::DerefRef { ref autoderefs, autoref, unsize },
adjusted_ty)) => {
- for i in 0..autoderefs {
- let i = i as u32;
- let adjusted_ty =
- expr.ty.adjust_for_autoderef(cx.tcx, self.id, self.span, i, |mc| {
- cx.tables().method_map.get(&mc).map(|m| m.ty)
- });
- debug!("make_mirror: autoderef #{}, adjusted_ty={:?}",
- i,
- adjusted_ty);
- let method_key = ty::MethodCall::autoderef(self.id, i);
- let meth_ty = cx.tables().method_map.get(&method_key).map(|m| m.ty);
- let kind = if let Some(meth_ty) = meth_ty {
- debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
-
- let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
- let (region, mutbl) = match ref_ty {
- Some(&ty::TyS { sty: ty::TyRef(region, mt), .. }) => (region, mt.mutbl),
+ for &overloaded in autoderefs {
+ let mut ref_ty = expr.ty;
+ let kind = if let Some(method) = overloaded {
+ debug!("make_mirror: overloaded autoderef (method={:?})", method);
+
+ ref_ty = method.sig.output();
+ let (region, mt) = match ref_ty.sty {
+ ty::TyRef(region, mt) => (region, mt),
_ => span_bug!(expr.span, "autoderef returned bad type"),
};
ty: cx.tcx.mk_ref(region,
ty::TypeAndMut {
ty: expr.ty,
- mutbl: mutbl,
+ mutbl: mt.mutbl,
}),
span: expr.span,
kind: ExprKind::Borrow {
region: region,
- borrow_kind: to_borrow_kind(mutbl),
+ borrow_kind: to_borrow_kind(mt.mutbl),
arg: expr.to_ref(),
},
};
overloaded_lvalue(cx,
self,
- method_key,
+ mt.ty,
+ method,
PassArgs::ByRef,
expr.to_ref(),
vec![])
debug!("make_mirror: built-in autoderef");
ExprKind::Deref { arg: expr.to_ref() }
};
+ let adjusted_ty = match ref_ty.builtin_deref(true,
+ ty::LvaluePreference::NoPreference) {
+ Some(mt) => mt.ty,
+ None => {
+ span_bug!(self.span, "autoderef for {} failed: {}", self.id, ref_ty);
+ }
+ };
+ debug!("make_mirror: autoderef adjusted_ty={:?}", adjusted_ty);
expr = Expr {
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,
// 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 method = cx.tables().method_map[&expr.id];
+ let expr = method_callee(cx, expr, method);
let args = args.iter()
.map(|e| e.to_ref())
.collect();
}
hir::ExprCall(ref fun, ref args) => {
- if cx.tables().is_method_call(expr.id) {
+ if let Some(&method) = cx.tables().method_map.get(&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
// rewrite f(u, v) into FnOnce::call_once(f, (u, v))
- let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
-
- let sig = method.ty.fn_sig();
-
- 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 method = method_callee(cx, expr, method);
+ let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
let tupled_args = Expr {
- ty: sig.inputs()[1],
+ ty: cx.tcx.mk_tup(arg_tys, false),
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,
span: expr.span,
None
};
if let Some((adt_def, index)) = adt_data {
- let substs = cx.tables().node_id_item_substs(fun.id)
- .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
+ let substs = cx.tables().node_substs(fun.id);
let field_refs = args.iter()
.enumerate()
.map(|(idx, e)| {
}
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
- if cx.tables().is_method_call(expr.id) {
+ if let Some(&method) = cx.tables().method_map.get(&expr.id) {
let pass_args = if op.node.is_by_value() {
PassArgs::ByValue
} else {
};
overloaded_operator(cx,
expr,
- ty::MethodCall::expr(expr.id),
+ method,
pass_args,
lhs.to_ref(),
vec![rhs])
hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
hir::ExprBinary(op, ref lhs, ref rhs) => {
- if cx.tables().is_method_call(expr.id) {
+ if let Some(&method) = cx.tables().method_map.get(&expr.id) {
let pass_args = if op.node.is_by_value() {
PassArgs::ByValue
} else {
};
overloaded_operator(cx,
expr,
- ty::MethodCall::expr(expr.id),
+ method,
pass_args,
lhs.to_ref(),
vec![rhs])
}
hir::ExprIndex(ref lhs, ref index) => {
- if cx.tables().is_method_call(expr.id) {
+ if let Some(&method) = cx.tables().method_map.get(&expr.id) {
overloaded_lvalue(cx,
expr,
- ty::MethodCall::expr(expr.id),
+ expr_ty,
+ method,
PassArgs::ByValue,
lhs.to_ref(),
vec![index])
}
hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
- if cx.tables().is_method_call(expr.id) {
+ if let Some(&method) = cx.tables().method_map.get(&expr.id) {
overloaded_lvalue(cx,
expr,
- ty::MethodCall::expr(expr.id),
+ expr_ty,
+ method,
PassArgs::ByValue,
arg.to_ref(),
vec![])
}
hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
- if cx.tables().is_method_call(expr.id) {
+ if let Some(&method) = cx.tables().method_map.get(&expr.id) {
overloaded_operator(cx,
expr,
- ty::MethodCall::expr(expr.id),
+ method,
PassArgs::ByValue,
arg.to_ref(),
vec![])
}
hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
- if cx.tables().is_method_call(expr.id) {
+ if let Some(&method) = cx.tables().method_map.get(&expr.id) {
overloaded_operator(cx,
expr,
- ty::MethodCall::expr(expr.id),
+ method,
PassArgs::ByValue,
arg.to_ref(),
vec![])
fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &hir::Expr,
- method_call: ty::MethodCall)
+ callee: ty::MethodCallee<'tcx>)
-> Expr<'tcx> {
- let callee = cx.tables().method_map[&method_call];
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
Expr {
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,
- ty: callee.ty,
+ ty: cx.tcx.type_of(callee.def_id).subst(cx.tcx, callee.substs),
span: expr.span,
kind: ExprKind::Literal {
literal: Literal::Value {
expr: &'tcx hir::Expr,
def: Def)
-> ExprKind<'tcx> {
- let substs = cx.tables().node_id_item_substs(expr.id)
- .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
+ let substs = cx.tables().node_substs(expr.id);
match def {
// A regular function, constructor function or a constant.
Def::Fn(def_id) |
fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &'tcx hir::Expr,
- method_call: ty::MethodCall,
+ method: ty::MethodCallee<'tcx>,
pass_args: PassArgs,
receiver: ExprRef<'tcx>,
args: Vec<&'tcx P<hir::Expr>>)
}
// now create the call itself
- let fun = method_callee(cx, expr, method_call);
+ let fun = method_callee(cx, expr, method);
ExprKind::Call {
ty: fun.ty,
fun: fun.to_ref(),
fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &'tcx hir::Expr,
- method_call: ty::MethodCall,
+ lvalue_ty: Ty<'tcx>,
+ method: ty::MethodCallee<'tcx>,
pass_args: PassArgs,
receiver: ExprRef<'tcx>,
args: Vec<&'tcx P<hir::Expr>>)
// call returns an &T and we must add the deref so that the types
// line up (this is because `*x` and `x[y]` represent lvalues):
- // to find the type &T of the content returned by the method;
- let ref_ty = cx.tables().method_map[&method_call].ty.fn_ret();
- let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
- // callees always have all late-bound regions fully instantiated,
+ let recv_ty = match receiver {
+ ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e),
+ ExprRef::Mirror(ref e) => e.ty
+ };
+
+ // Reconstruct the output assuming it's a reference with the
+ // same region and mutability as the receiver. This holds for
+ // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
+ let (region, mutbl) = match recv_ty.sty {
+ ty::TyRef(region, mt) => (region, mt.mutbl),
+ _ => span_bug!(expr.span, "overloaded_lvalue: receiver is not a reference"),
+ };
+ let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut {
+ ty: lvalue_ty,
+ mutbl,
+ });
// construct the complete expression `foo()` for the overloaded call,
// which will yield the &T type
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
- let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
+ let ref_kind = overloaded_operator(cx, expr, method, pass_args, receiver, args);
let ref_expr = Expr {
temp_lifetime: temp_lifetime,
temp_lifetime_was_shrunk: was_shrunk,