diff options
| author | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-05-28 15:04:13 +0300 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-06-01 08:59:47 +0300 |
| commit | 3ce443828be823cac2791d2b8392c33db9320677 (patch) | |
| tree | 2d77afc66e961aacbebd03d429d1456a39469840 | |
| parent | 194fe695e3af6f03953cbb4ca66f159993f6214d (diff) | |
| download | rust-3ce443828be823cac2791d2b8392c33db9320677.tar.gz rust-3ce443828be823cac2791d2b8392c33db9320677.zip | |
rustc: adjust the RHS of comparison operators instead of assuming autorefs.
| -rw-r--r-- | src/librustc/middle/expr_use_visitor.rs | 100 | ||||
| -rw-r--r-- | src/librustc_mir/hair/cx/expr.rs | 129 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 11 | ||||
| -rw-r--r-- | src/librustc_typeck/check/op.rs | 102 | ||||
| -rw-r--r-- | src/librustc_typeck/check/regionck.rs | 83 | ||||
| -rw-r--r-- | src/librustc_typeck/check/writeback.rs | 9 |
6 files changed, 114 insertions, 320 deletions
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 55c3049155f..bb56439a157 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -263,12 +263,6 @@ macro_rules! return_if_err { ) } -/// Whether the elements of an overloaded operation are passed by value or by reference -enum PassArgs { - ByValue, - ByRef, -} - impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), region_maps: &'a RegionMaps, @@ -382,9 +376,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprUnary(hir::UnDeref, ref base) => { // *base - if !self.walk_overloaded_operator(expr, &base, Vec::new(), PassArgs::ByRef) { - self.select_from_expr(&base); - } + self.select_from_expr(&base); } hir::ExprField(ref base, _) => { // base.f @@ -396,13 +388,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] - if !self.walk_overloaded_operator(expr, - &lhs, - vec![&rhs], - PassArgs::ByValue) { - self.select_from_expr(&lhs); - self.consume_expr(&rhs); - } + self.select_from_expr(&lhs); + self.consume_expr(&rhs); } hir::ExprCall(ref callee, ref args) => { // callee(args) @@ -485,29 +472,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.walk_block(&blk); } - hir::ExprUnary(op, ref lhs) => { - let pass_args = if op.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - - if !self.walk_overloaded_operator(expr, &lhs, Vec::new(), pass_args) { - self.consume_expr(&lhs); - } + hir::ExprUnary(_, ref lhs) => { + self.consume_expr(&lhs); } - hir::ExprBinary(op, ref lhs, ref rhs) => { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - - if !self.walk_overloaded_operator(expr, &lhs, vec![&rhs], pass_args) { - self.consume_expr(&lhs); - self.consume_expr(&rhs); - } + hir::ExprBinary(_, ref lhs, ref rhs) => { + self.consume_expr(&lhs); + self.consume_expr(&rhs); } hir::ExprBlock(ref blk) => { @@ -529,14 +500,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&base); } - hir::ExprAssignOp(op, ref lhs, ref rhs) => { - // NB All our assignment operations take the RHS by value - assert!(op.node.is_by_value()); - - if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) { + hir::ExprAssignOp(_, ref lhs, ref rhs) => { + if self.mc.infcx.tables.borrow().is_method_call(expr) { + self.consume_expr(lhs); + } else { self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead); - self.consume_expr(&rhs); } + self.consume_expr(&rhs); } hir::ExprRepeat(ref base, _) => { @@ -784,50 +754,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } - - // When this returns true, it means that the expression *is* a - // method-call (i.e. via the operator-overload). This true result - // also implies that walk_overloaded_operator already took care of - // recursively processing the input arguments, and thus the caller - // should not do so. - fn walk_overloaded_operator(&mut self, - expr: &hir::Expr, - receiver: &hir::Expr, - rhs: Vec<&hir::Expr>, - pass_args: PassArgs) - -> bool - { - if !self.mc.infcx.tables.borrow().is_method_call(expr) { - return false; - } - - match pass_args { - PassArgs::ByValue => { - self.consume_expr(receiver); - for &arg in &rhs { - self.consume_expr(arg); - } - - return true; - }, - PassArgs::ByRef => {}, - } - - self.walk_expr(receiver); - - // Arguments (but not receivers) to overloaded operator - // methods are implicitly autoref'd which sadly does not use - // adjustments, so we must hardcode the borrow here. - - let r = self.tcx().node_scope_region(expr.id); - let bk = ty::ImmBorrow; - - for &arg in &rhs { - self.borrow_expr(arg, r, bk, OverloadedOperator); - } - return true; - } - fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode { let mut mode = Unknown; for pat in &arm.pats { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 6d1509e7e24..2c3f5196926 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -21,7 +21,6 @@ use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::ty::subst::Subst; use rustc::hir; -use syntax::ptr::P; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { type Output = Expr<'tcx>; @@ -117,13 +116,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }, }; - overloaded_lvalue(cx, - hir_expr, - adjustment.target, - Some(call), - PassArgs::ByValue, - expr.to_ref(), - vec![]) + overloaded_lvalue(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) } Adjust::Borrow(AutoBorrow::Ref(r, m)) => { ExprKind::Borrow { @@ -281,17 +274,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprAssignOp(op, ref lhs, ref rhs) => { if cx.tables().is_method_call(expr) { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - overloaded_operator(cx, - expr, - None, - pass_args, - lhs.to_ref(), - vec![rhs]) + overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) } else { ExprKind::AssignOp { op: bin_op(op.node), @@ -305,17 +288,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprBinary(op, ref lhs, ref rhs) => { if cx.tables().is_method_call(expr) { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - overloaded_operator(cx, - expr, - None, - pass_args, - lhs.to_ref(), - vec![rhs]) + overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) } else { // FIXME overflow match (op.node, cx.constness) { @@ -365,13 +338,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprIndex(ref lhs, ref index) => { if cx.tables().is_method_call(expr) { - overloaded_lvalue(cx, - expr, - expr_ty, - None, - PassArgs::ByValue, - lhs.to_ref(), - vec![index]) + overloaded_lvalue(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) } else { ExprKind::Index { lhs: lhs.to_ref(), @@ -382,13 +349,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { if cx.tables().is_method_call(expr) { - overloaded_lvalue(cx, - expr, - expr_ty, - None, - PassArgs::ByValue, - arg.to_ref(), - vec![]) + overloaded_lvalue(cx, expr, expr_ty, None, vec![arg.to_ref()]) } else { ExprKind::Deref { arg: arg.to_ref() } } @@ -396,12 +357,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { if cx.tables().is_method_call(expr) { - overloaded_operator(cx, - expr, - None, - PassArgs::ByValue, - arg.to_ref(), - vec![]) + overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { ExprKind::Unary { op: UnOp::Not, @@ -412,12 +368,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { if cx.tables().is_method_call(expr) { - overloaded_operator(cx, - expr, - None, - PassArgs::ByValue, - arg.to_ref(), - vec![]) + overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { // FIXME runtime-overflow if let hir::ExprLit(_) = arg.node { @@ -873,61 +824,15 @@ fn bin_op(op: hir::BinOp_) -> BinOp { } } -enum PassArgs { - ByValue, - ByRef, -} - fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, - custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, - pass_args: PassArgs, - receiver: ExprRef<'tcx>, - args: Vec<&'tcx P<hir::Expr>>) + args: Vec<ExprRef<'tcx>>) -> ExprKind<'tcx> { - // the receiver has all the adjustments that are needed, so we can - // just push a reference to it - let mut argrefs = vec![receiver]; - - // the arguments, unfortunately, do not, so if this is a ByRef - // operator, we have to gin up the autorefs (but by value is easy) - match pass_args { - PassArgs::ByValue => argrefs.extend(args.iter().map(|arg| arg.to_ref())), - - PassArgs::ByRef => { - let region = cx.tcx.node_scope_region(expr.id); - let (temp_lifetime, was_shrunk) = - cx.region_maps.temporary_scope2(expr.id); - argrefs.extend(args.iter() - .map(|arg| { - let arg_ty = cx.tables().expr_ty_adjusted(arg); - let adjusted_ty = cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: arg_ty, - mutbl: hir::MutImmutable, - }); - Expr { - temp_lifetime: temp_lifetime, - temp_lifetime_was_shrunk: was_shrunk, - ty: adjusted_ty, - span: expr.span, - kind: ExprKind::Borrow { - region: region, - borrow_kind: BorrowKind::Shared, - arg: arg.to_ref(), - }, - } - .to_ref() - })) - } - } - - // now create the call itself - let fun = method_callee(cx, expr, custom_callee); + let fun = method_callee(cx, expr, None); ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), - args: argrefs, + args, } } @@ -935,15 +840,13 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, lvalue_ty: Ty<'tcx>, custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, - pass_args: PassArgs, - receiver: ExprRef<'tcx>, - args: Vec<&'tcx P<hir::Expr>>) + args: Vec<ExprRef<'tcx>>) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // 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): - let recv_ty = match receiver { + let recv_ty = match args[0] { ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e), ExprRef::Mirror(ref e) => e.ty }; @@ -963,13 +866,17 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // 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, custom_callee, pass_args, receiver, args); + let fun = method_callee(cx, expr, custom_callee); let ref_expr = Expr { temp_lifetime: temp_lifetime, temp_lifetime_was_shrunk: was_shrunk, ty: ref_ty, span: expr.span, - kind: ref_kind, + kind: ExprKind::Call { + ty: fun.ty, + fun: fun.to_ref(), + args, + }, }; // construct and return a deref wrapper `*foo()` diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 813e199f85a..32c3f5c8a5e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3424,10 +3424,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref); if !oprnd_t.references_error() { + oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); match unop { hir::UnDeref => { - oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); - if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { oprnd_t = mt.ty; } else if let Some(ok) = self.try_overloaded_deref( @@ -3450,18 +3449,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } hir::UnNot => { - oprnd_t = self.structurally_resolved_type(oprnd.span, - oprnd_t); - let result = self.check_user_unop(expr, &oprnd, oprnd_t, unop); + let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) { oprnd_t = result; } } hir::UnNeg => { - oprnd_t = self.structurally_resolved_type(oprnd.span, - oprnd_t); - let result = self.check_user_unop(expr, &oprnd, oprnd_t, unop); + let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { oprnd_t = result; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index cbb89355bf9..8e5b7a65469 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -11,11 +11,13 @@ //! Code related to processing overloaded binary and unary operators. use super::FnCtxt; +use super::method::MethodCallee; use rustc::ty::{self, Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; use rustc::ty::TypeVariants::{TyStr, TyRef}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::infer::type_variable::TypeVariableOrigin; use errors; +use syntax_pos::Span; use syntax::symbol::Symbol; use rustc::hir; @@ -181,14 +183,41 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // particularly for things like `String + &String`. let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); - let return_ty = self.lookup_op_method(expr, lhs_ty, &[rhs_ty_var], - Op::Binary(op, is_assign), lhs_expr); + let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); - let return_ty = match return_ty { - Ok(return_ty) => return_ty, + let return_ty = match result { + Ok(method) => { + let by_ref_binop = !op.node.is_by_value(); + if is_assign == IsAssign::Yes || by_ref_binop { + if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { + let autoref = Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[0] + }; + self.apply_adjustments(lhs_expr, vec![autoref]); + } + } + if by_ref_binop { + if let ty::TyRef(region, mt) = method.sig.inputs()[1].sty { + let autoref = Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), + target: method.sig.inputs()[1] + }; + // HACK(eddyb) Bypass checks due to reborrows being in + // some cases applied on the RHS, on top of which we need + // to autoref, which is not allowed by apply_adjustments. + // self.apply_adjustments(rhs_expr, vec![autoref]); + self.tables.borrow_mut().adjustments.entry(rhs_expr.id) + .or_insert(vec![]).push(autoref); + } + } + self.write_method_call(expr.id, method); + + method.sig.output() + } Err(()) => { // error types are considered "builtin" if !lhs_ty.references_error() { @@ -210,8 +239,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && - self.lookup_op_method(expr, ty_mut.ty, &[rhs_ty], - Op::Binary(op, is_assign), lhs_expr).is_ok() { + self.lookup_op_method(ty_mut.ty, &[rhs_ty], + Op::Binary(op, is_assign)).is_ok() { err.note( &format!( "this is a reference to a type that `{}` can be applied \ @@ -298,14 +327,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_user_unop(&self, ex: &'gcx hir::Expr, - operand_expr: &'gcx hir::Expr, operand_ty: Ty<'tcx>, op: hir::UnOp) -> Ty<'tcx> { assert!(op.is_by_value()); - match self.lookup_op_method(ex, operand_ty, &[], Op::Unary(op), operand_expr) { - Ok(t) => t, + match self.lookup_op_method(operand_ty, &[], Op::Unary(op, ex.span)) { + Ok(method) => { + self.write_method_call(ex.id, method); + method.sig.output() + } Err(()) => { let actual = self.resolve_type_vars_if_possible(&operand_ty); if !actual.references_error() { @@ -318,16 +349,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn lookup_op_method(&self, - expr: &'gcx hir::Expr, - lhs_ty: Ty<'tcx>, - other_tys: &[Ty<'tcx>], - op: Op, - lhs_expr: &'a hir::Expr) - -> Result<Ty<'tcx>,()> + fn lookup_op_method(&self, lhs_ty: Ty<'tcx>, other_tys: &[Ty<'tcx>], op: Op) + -> Result<MethodCallee<'tcx>, ()> { let lang = &self.tcx.lang_items; + let span = match op { + Op::Binary(op, _) => op.span, + Op::Unary(_, span) => span + }; let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op { match op.node { hir::BiAdd => ("add_assign", lang.add_assign_trait()), @@ -344,7 +374,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiGe | hir::BiGt | hir::BiEq | hir::BiNe | hir::BiAnd | hir::BiOr => { - span_bug!(op.span, + span_bug!(span, "impossible assignment operation: {}=", op.node.as_str()) } @@ -368,28 +398,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiEq => ("eq", lang.eq_trait()), hir::BiNe => ("ne", lang.eq_trait()), hir::BiAnd | hir::BiOr => { - span_bug!(op.span, "&& and || are not overloadable") + span_bug!(span, "&& and || are not overloadable") } } - } else if let Op::Unary(hir::UnNot) = op { + } else if let Op::Unary(hir::UnNot, _) = op { ("not", lang.not_trait()) - } else if let Op::Unary(hir::UnNeg) = op { + } else if let Op::Unary(hir::UnNeg, _) = op { ("neg", lang.neg_trait()) } else { bug!("lookup_op_method: op not supported: {:?}", op) }; - debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, \ - trait_did={:?}, lhs_expr={:?})", - expr, + debug!("lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})", lhs_ty, + op, opname, - trait_did, - lhs_expr); + trait_did); let method = trait_did.and_then(|trait_did| { let opname = Symbol::intern(opname); - self.lookup_method_in_trait(expr.span, opname, trait_did, lhs_ty, Some(other_tys)) + self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) }); match method { @@ -397,23 +425,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = self.register_infer_ok_obligations(ok); self.select_obligations_where_possible(); - let (lhs_by_ref, _rhs_by_ref) = match op { - Op::Binary(_, IsAssign::Yes) => (true, false), - Op::Binary(op, _) if !op.node.is_by_value() => (true, true), - Op::Binary(..) | Op::Unary(_) => (false, false), - }; - if lhs_by_ref { - if let ty::TyRef(region, mt) = method.sig.inputs()[0].sty { - let autoref = Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mt.mutbl)), - target: method.sig.inputs()[0] - }; - self.apply_adjustments(lhs_expr, vec![autoref]); - } - } - self.write_method_call(expr.id, method); - - Ok(method.sig.output()) + Ok(method) } None => { Err(()) @@ -479,7 +491,7 @@ impl BinOpCategory { } /// Whether the binary operation is an assignment (`a += b`), or not (`a + b`) -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] enum IsAssign { No, Yes, @@ -488,7 +500,7 @@ enum IsAssign { #[derive(Clone, Copy, Debug)] enum Op { Binary(hir::BinOp, IsAssign), - Unary(hir::UnOp), + Unary(hir::UnOp, Span), } /// Returns true if this is a built-in arithmetic operation (e.g. u32 diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index e1905c93106..33fbc006e4e 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -566,49 +566,38 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { hir::ExprCall(ref callee, ref args) => { if is_method_call { - self.constrain_call(expr, Some(&callee), - args.iter().map(|e| &*e), false); + self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e)); } else { self.constrain_callee(callee.id, expr, &callee); - self.constrain_call(expr, None, - args.iter().map(|e| &*e), false); + self.constrain_call(expr, None, args.iter().map(|e| &*e)); } intravisit::walk_expr(self, expr); } hir::ExprMethodCall(.., ref args) => { - self.constrain_call(expr, Some(&args[0]), - args[1..].iter().map(|e| &*e), false); + self.constrain_call(expr, Some(&args[0]), args[1..].iter().map(|e| &*e)); intravisit::walk_expr(self, expr); } hir::ExprAssignOp(_, ref lhs, ref rhs) => { if is_method_call { - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), false); + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); } intravisit::walk_expr(self, expr); } hir::ExprIndex(ref lhs, ref rhs) if is_method_call => { - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), true); + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); intravisit::walk_expr(self, expr); }, - hir::ExprBinary(op, ref lhs, ref rhs) if is_method_call => { - let implicitly_ref_args = !op.node.is_by_value(); - - // As `expr_method_call`, but the call is via an - // overloaded op. Note that we (sadly) currently use an - // implicit "by ref" sort of passing style here. This - // should be converted to an adjustment! - self.constrain_call(expr, Some(&lhs), - Some(&**rhs).into_iter(), implicitly_ref_args); + hir::ExprBinary(_, ref lhs, ref rhs) if is_method_call => { + // As `ExprMethodCall`, but the call is via an overloaded op. + self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); intravisit::walk_expr(self, expr); } @@ -625,21 +614,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } - hir::ExprUnary(op, ref lhs) if is_method_call => { - let implicitly_ref_args = !op.is_by_value(); - - // As above. - self.constrain_call(expr, Some(&lhs), - None::<hir::Expr>.iter(), implicitly_ref_args); - - intravisit::walk_expr(self, expr); - } - hir::ExprUnary(hir::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref - if self.tables.borrow().is_method_call(expr) { - self.constrain_call(expr, Some(base), - None::<hir::Expr>.iter(), true); + if is_method_call { + self.constrain_call(expr, Some(base), None::<hir::Expr>.iter()); } // For overloaded derefs, base_ty is the input to `Deref::deref`, // but it's a reference type uing the same region as the output. @@ -651,6 +629,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } + hir::ExprUnary(_, ref lhs) if is_method_call => { + // As above. + self.constrain_call(expr, Some(&lhs), None::<hir::Expr>.iter()); + + intravisit::walk_expr(self, expr); + } + hir::ExprIndex(ref vec_expr, _) => { // For a[b], the lifetime of a must enclose the deref let vec_type = self.resolve_expr_type_adjusted(&vec_expr); @@ -802,19 +787,15 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self, call_expr: &hir::Expr, receiver: Option<&hir::Expr>, - arg_exprs: I, - implicitly_ref_args: bool) { + arg_exprs: I) { //! Invoked on every call site (i.e., normal calls, method calls, //! and overloaded operators). Constrains the regions which appear //! in the type of the function. Also constrains the regions that //! appear in the arguments appropriately. - debug!("constrain_call(call_expr={:?}, \ - receiver={:?}, \ - implicitly_ref_args={})", + debug!("constrain_call(call_expr={:?}, receiver={:?})", call_expr, - receiver, - implicitly_ref_args); + receiver); // `callee_region` is the scope representing the time in which the // call occurs. @@ -832,14 +813,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // valid for at least the lifetime of the function: self.type_of_node_must_outlive(infer::CallArg(arg_expr.span), arg_expr.id, callee_region); - - // unfortunately, there are two means of taking implicit - // references, and we need to propagate constraints as a - // result. modes are going away and the "DerefArgs" code - // should be ported to use adjustments - if implicitly_ref_args { - self.link_by_ref(arg_expr, callee_scope); - } } // as loop above, but for receiver @@ -847,9 +820,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("receiver: {:?}", r); self.type_of_node_must_outlive(infer::CallRcvr(r.span), r.id, callee_region); - if implicitly_ref_args { - self.link_by_ref(&r, callee_scope); - } } } @@ -1111,19 +1081,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - /// Computes the guarantor for cases where the `expr` is being passed by implicit reference and - /// must outlive `callee_scope`. - fn link_by_ref(&self, - expr: &hir::Expr, - callee_scope: CodeExtent) { - debug!("link_by_ref(expr={:?}, callee_scope={:?})", - expr, callee_scope); - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - let expr_cmt = ignore_err!(mc.cat_expr(expr)); - let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope)); - self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt); - } - /// Like `link_region()`, except that the region is extracted from the type of `id`, /// which must be some reference (`&T`, `&str`, etc). fn link_region_from_node_type(&self, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 0b93db54980..012fde16d87 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -123,18 +123,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { tables.type_dependent_defs.remove(&e.id); tables.node_substs.remove(&e.id); - // weird but true: the by-ref binops put an - // adjustment on the lhs but not the rhs; the - // adjustment for rhs is kind of baked into the - // system. match e.node { hir::ExprBinary(..) => { if !op.node.is_by_value() { - tables.adjustments.remove(&lhs.id); + tables.adjustments.get_mut(&lhs.id).map(|a| a.pop()); + tables.adjustments.get_mut(&rhs.id).map(|a| a.pop()); } }, hir::ExprAssignOp(..) => { - tables.adjustments.remove(&lhs.id); + tables.adjustments.get_mut(&lhs.id).map(|a| a.pop()); }, _ => {}, } |
