diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 59872c694620..59344258833a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -329,6 +329,12 @@ macro_rules! return_if_err( ) ) +/// Whether the elements of an overloaded operation are passed by value or by reference +enum PassArgs { + ByValue, + ByRef, +} + impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { pub fn new(delegate: &'d mut Delegate<'tcx>, typer: &'t TYPER, @@ -438,7 +444,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { ast::ExprPath(..) => { } ast::ExprUnary(ast::UnDeref, ref base) => { // *base - if !self.walk_overloaded_operator(expr, &**base, Vec::new(), None) { + if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) { self.select_from_expr(&**base); } } @@ -452,7 +458,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] - if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], None) { + if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], PassArgs::ByRef) { self.select_from_expr(&**lhs); self.consume_expr(&**rhs); } @@ -465,7 +471,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { (&None, &Some(ref e)) => vec![&**e], (&None, &None) => Vec::new() }; - let overloaded = self.walk_overloaded_operator(expr, &**base, args, None); + let overloaded = + self.walk_overloaded_operator(expr, &**base, args, PassArgs::ByRef); assert!(overloaded); } @@ -570,14 +577,19 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprUnary(_, ref lhs) => { - if !self.walk_overloaded_operator(expr, &**lhs, Vec::new(), None) { + if !self.walk_overloaded_operator(expr, &**lhs, Vec::new(), PassArgs::ByRef) { self.consume_expr(&**lhs); } } ast::ExprBinary(op, ref lhs, ref rhs) => { - if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], Some(op)) - { + let pass_args = if ast_util::is_by_value_binop(op) { + PassArgs::ByValue + } else { + PassArgs::ByRef + }; + + if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], pass_args) { self.consume_expr(&**lhs); self.consume_expr(&**rhs); } @@ -913,21 +925,21 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { expr: &ast::Expr, receiver: &ast::Expr, rhs: Vec<&ast::Expr>, - binop: Option) + pass_args: PassArgs) -> bool { if !self.typer.is_method_call(expr.id) { return false; } - match binop { - Some(binop) if ast_util::is_by_value_binop(binop) => { + match pass_args { + PassArgs::ByValue => { self.consume_expr(receiver); self.consume_expr(rhs[0]); return true; }, - _ => {}, + PassArgs::ByRef => {}, } self.walk_expr(receiver); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2dcb07e0fb50..5f8991278b08 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -77,7 +77,6 @@ type parameter). */ pub use self::LvaluePreference::*; -pub use self::DerefArgs::*; pub use self::Expectation::*; use self::IsBinopAssignment::*; use self::TupleArgumentsFlag::*; @@ -2117,7 +2116,7 @@ fn try_overloaded_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_callee.ty, call_expression, args, - DontDerefArgs, + AutorefArgs::No, TupleArguments); fcx.inh.method_map.borrow_mut().insert(method_call, method_callee); write_call(fcx, call_expression, output_type); @@ -2274,7 +2273,7 @@ fn try_overloaded_slice<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_ty_or_err, expr, args.as_slice(), - DoDerefArgs, + AutorefArgs::Yes, DontTupleArguments); opt_method_ty.map(|method_ty| { @@ -2480,7 +2479,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_type, iterator_expr, &[], - DontDerefArgs, + AutorefArgs::No, DontTupleArguments); match method { @@ -2522,7 +2521,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_fn_ty: Ty<'tcx>, callee_expr: &ast::Expr, args_no_rcvr: &[&P], - deref_args: DerefArgs, + autoref_args: AutorefArgs, tuple_arguments: TupleArgumentsFlag) -> ty::FnOutput<'tcx> { if ty::type_is_error(method_fn_ty) { @@ -2538,7 +2537,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, err_inputs.as_slice(), callee_expr, args_no_rcvr, - deref_args, + autoref_args, false, tuple_arguments); ty::FnConverging(ty::mk_err()) @@ -2551,7 +2550,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fty.sig.inputs.slice_from(1), callee_expr, args_no_rcvr, - deref_args, + autoref_args, fty.sig.variadic, tuple_arguments); fty.sig.output @@ -2571,7 +2570,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn_inputs: &[Ty<'tcx>], _callee_expr: &ast::Expr, args: &[&P], - deref_args: DerefArgs, + autoref_args: AutorefArgs, variadic: bool, tuple_arguments: TupleArgumentsFlag) { let tcx = fcx.ccx.tcx; @@ -2674,8 +2673,8 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("checking the argument"); let mut formal_ty = formal_tys[i]; - match deref_args { - DoDerefArgs => { + match autoref_args { + AutorefArgs::Yes => { match formal_ty.sty { ty::ty_rptr(_, mt) => formal_ty = mt.ty, ty::ty_err => (), @@ -2690,7 +2689,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } } - DontDerefArgs => {} + AutorefArgs::No => {} } check_expr_coercable_to_type(fcx, &***arg, formal_ty); @@ -2905,12 +2904,12 @@ pub fn lookup_tup_field_ty<'tcx>(tcx: &ty::ctxt<'tcx>, // Controls whether the arguments are automatically referenced. This is useful // for overloaded binary and unary operators. #[deriving(PartialEq)] -pub enum DerefArgs { - DontDerefArgs, - DoDerefArgs +pub enum AutorefArgs { + Yes, + No, } -impl Copy for DerefArgs {} +impl Copy for AutorefArgs {} /// Controls whether the arguments are tupled. This is used for the call /// operator. @@ -2998,7 +2997,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fn_sig.inputs.as_slice(), f, args, - DontDerefArgs, + AutorefArgs::No, fn_sig.variadic, DontTupleArguments); @@ -3048,7 +3047,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fn_ty, expr, args.as_slice(), - DontDerefArgs, + AutorefArgs::No, DontTupleArguments); write_call(fcx, expr, ret_ty); @@ -3132,7 +3131,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lhs: &'a ast::Expr, rhs: Option<&P>, unbound_method: F, - deref_args: DerefArgs) -> Ty<'tcx> where + autoref_args: AutorefArgs) -> Ty<'tcx> where F: FnOnce(), { let method = match trait_did { @@ -3148,7 +3147,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // traits that don't force left and right to have same // type. let (adj_ty, adjustment) = match lhs_ty.sty { - ty::ty_rptr(r_in, mt) if deref_args == DoDerefArgs => { + ty::ty_rptr(r_in, mt) => { let r_adj = fcx.infcx().next_region_var(infer::Autoref(lhs.span)); fcx.mk_subr(infer::Reborrow(lhs.span), r_adj, r_in); let adjusted_ty = ty::mk_rptr(fcx.tcx(), r_adj, mt); @@ -3185,7 +3184,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, method_ty, op_ex, args.as_slice(), - deref_args, + autoref_args, DontTupleArguments) { ty::FnConverging(result_type) => result_type, ty::FnDiverging => ty::mk_err() @@ -3201,7 +3200,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, expected_ty, op_ex, args.as_slice(), - deref_args, + autoref_args, DontTupleArguments); ty::mk_err() } @@ -3320,23 +3319,23 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, rhs: &P) -> Ty<'tcx> { let tcx = fcx.ccx.tcx; let lang = &tcx.lang_items; - let (name, trait_did, deref_args) = match op { - ast::BiAdd => ("add", lang.add_trait(), DontDerefArgs), - ast::BiSub => ("sub", lang.sub_trait(), DontDerefArgs), - ast::BiMul => ("mul", lang.mul_trait(), DontDerefArgs), - ast::BiDiv => ("div", lang.div_trait(), DontDerefArgs), - ast::BiRem => ("rem", lang.rem_trait(), DontDerefArgs), - ast::BiBitXor => ("bitxor", lang.bitxor_trait(), DontDerefArgs), - ast::BiBitAnd => ("bitand", lang.bitand_trait(), DontDerefArgs), - ast::BiBitOr => ("bitor", lang.bitor_trait(), DontDerefArgs), - ast::BiShl => ("shl", lang.shl_trait(), DontDerefArgs), - ast::BiShr => ("shr", lang.shr_trait(), DontDerefArgs), - ast::BiLt => ("lt", lang.ord_trait(), DoDerefArgs), - ast::BiLe => ("le", lang.ord_trait(), DoDerefArgs), - ast::BiGe => ("ge", lang.ord_trait(), DoDerefArgs), - ast::BiGt => ("gt", lang.ord_trait(), DoDerefArgs), - ast::BiEq => ("eq", lang.eq_trait(), DoDerefArgs), - ast::BiNe => ("ne", lang.eq_trait(), DoDerefArgs), + let (name, trait_did) = match op { + ast::BiAdd => ("add", lang.add_trait()), + ast::BiSub => ("sub", lang.sub_trait()), + ast::BiMul => ("mul", lang.mul_trait()), + ast::BiDiv => ("div", lang.div_trait()), + ast::BiRem => ("rem", lang.rem_trait()), + ast::BiBitXor => ("bitxor", lang.bitxor_trait()), + ast::BiBitAnd => ("bitand", lang.bitand_trait()), + ast::BiBitOr => ("bitor", lang.bitor_trait()), + ast::BiShl => ("shl", lang.shl_trait()), + ast::BiShr => ("shr", lang.shr_trait()), + ast::BiLt => ("lt", lang.ord_trait()), + ast::BiLe => ("le", lang.ord_trait()), + ast::BiGe => ("ge", lang.ord_trait()), + ast::BiGt => ("gt", lang.ord_trait()), + ast::BiEq => ("eq", lang.eq_trait()), + ast::BiNe => ("ne", lang.eq_trait()), ast::BiAnd | ast::BiOr => { check_expr(fcx, &**rhs); return ty::mk_err(); @@ -3349,7 +3348,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast_util::binop_to_string(op), actual) }, lhs_resolved_t, None) - }, deref_args) + }, if ast_util::is_by_value_binop(op) { AutorefArgs::No } else { AutorefArgs::Yes }) } fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -3365,7 +3364,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, format!("cannot apply unary operator `{}` to type `{}`", op_str, actual) }, rhs_t, None); - }, DontDerefArgs) + }, AutorefArgs::Yes) } // Check field access expressions