]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/op.rs
Auto merge of #30641 - tsion:match-range, r=eddyb
[rust.git] / src / librustc_typeck / check / op.rs
index 35bbf10d06cad192205052c44b36c054c11cfb00..c5a36fb4ada256d96cfad9da7ef91282329d320c 100644 (file)
@@ -36,7 +36,7 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
 
     let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr));
     let (rhs_ty, return_ty) =
-        check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, true);
+        check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
     let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_ty);
 
     if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
@@ -83,7 +83,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             // overloaded. This is the way to be most flexible w/r/t
             // types that get inferred.
             let (rhs_ty, return_ty) =
-                check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, false);
+                check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::No);
 
             // Supply type inference hints if relevant. Probably these
             // hints should be enforced during select as part of the
@@ -156,15 +156,15 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                     lhs_ty: Ty<'tcx>,
                                     rhs_expr: &'tcx hir::Expr,
                                     op: hir::BinOp,
-                                    assign: bool)
+                                    is_assign: IsAssign)
                                     -> (Ty<'tcx>, Ty<'tcx>)
 {
-    debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, assign={})",
+    debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})",
            expr.id,
            lhs_ty,
-           assign);
+           is_assign);
 
-    let (name, trait_def_id) = name_and_trait_def_id(fcx, op, assign);
+    let (name, trait_def_id) = name_and_trait_def_id(fcx, op, is_assign);
 
     // NB: As we have not yet type-checked the RHS, we don't have the
     // type at hand. Make a variable to represent it. The whole reason
@@ -181,16 +181,38 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         Err(()) => {
             // error types are considered "builtin"
             if !lhs_ty.references_error() {
-                if assign {
+                if let IsAssign::Yes = is_assign {
                     span_err!(fcx.tcx().sess, lhs_expr.span, E0368,
                               "binary assignment operation `{}=` cannot be applied to type `{}`",
                               hir_util::binop_to_string(op.node),
                               lhs_ty);
                 } else {
-                    span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
-                              "binary operation `{}` cannot be applied to type `{}`",
-                              hir_util::binop_to_string(op.node),
-                              lhs_ty);
+                    let mut err = struct_span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
+                        "binary operation `{}` cannot be applied to type `{}`",
+                        hir_util::binop_to_string(op.node),
+                        lhs_ty);
+                    let missing_trait = match op.node {
+                        hir::BiAdd    => Some("std::ops::Add"),
+                        hir::BiSub    => Some("std::ops::Sub"),
+                        hir::BiMul    => Some("std::ops::Mul"),
+                        hir::BiDiv    => Some("std::ops::Div"),
+                        hir::BiRem    => Some("std::ops::Rem"),
+                        hir::BiBitAnd => Some("std::ops::BitAnd"),
+                        hir::BiBitOr  => Some("std::ops::BitOr"),
+                        hir::BiShl    => Some("std::ops::Shl"),
+                        hir::BiShr    => Some("std::ops::Shr"),
+                        hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
+                        hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
+                            Some("std::cmp::PartialOrd"),
+                        _             => None
+                    };
+
+                    if let Some(missing_trait) = missing_trait {
+                        span_note!(&mut err, lhs_expr.span,
+                                   "an implementation of `{}` might be missing for `{}`",
+                                    missing_trait, lhs_ty);
+                    }
+                    err.emit();
                 }
             }
             fcx.tcx().types.err
@@ -230,11 +252,11 @@ pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
 fn name_and_trait_def_id(fcx: &FnCtxt,
                          op: hir::BinOp,
-                         assign: bool)
+                         is_assign: IsAssign)
                          -> (&'static str, Option<DefId>) {
     let lang = &fcx.tcx().lang_items;
 
-    if assign {
+    if let IsAssign::Yes = is_assign {
         match op.node {
             hir::BiAdd => ("add_assign", lang.add_assign_trait()),
             hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
@@ -383,6 +405,13 @@ fn from(op: hir::BinOp) -> BinOpCategory {
     }
 }
 
+/// Whether the binary operation is an assignment (`a += b`), or not (`a + b`)
+#[derive(Clone, Copy, Debug)]
+enum IsAssign {
+    No,
+    Yes,
+}
+
 /// Returns true if this is a built-in arithmetic operation (e.g. u32
 /// + u32, i16x4 == i16x4) and false if these types would have to be
 /// overloaded to be legal. There are two reasons that we distinguish