about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2017-01-27 14:41:09 -0800
committerAlex Crichton <alex@alexcrichton.com>2017-01-27 16:41:49 -0800
commita2a3074fb3ae6c1e7f0ccb6b111f3e16f9312f8f (patch)
tree50ee89fae80b4f34af743050c29a128f978be283
parent154c202afb256c379b7d454ec0244da69eaa2ced (diff)
parentb8669dff556a03ca37b39cbb81be65c94d24defe (diff)
downloadrust-a2a3074fb3ae6c1e7f0ccb6b111f3e16f9312f8f.tar.gz
rust-a2a3074fb3ae6c1e7f0ccb6b111f3e16f9312f8f.zip
Rollup merge of #38617 - pnkfelix:double-reference, r=pnkfelix
Detect double reference when applying binary op

``` rust
let vr = v.iter().filter(|x| {
    x % 2 == 0
});
```

will now yield the following compiler output:

``` bash
ERROR binary operation `%` cannot be applied to type `&&_`
NOTE this is a reference of a reference to a type that `%` can be applied to,
you need to dereference this variable once for this operation to work
NOTE an implementation of `std::ops::Rem` might be missing for `&&_`
```

The first NOTE is new.

Fix #33877

----

Thanks to @estebank for providing the original PR #34420 (of which this is a tweaked rebase).
-rw-r--r--src/librustc_typeck/check/op.rs18
-rw-r--r--src/test/compile-fail/binary-op-on-double-ref.rs20
-rw-r--r--src/test/compile-fail/str-concat-on-double-ref.rs18
3 files changed, 55 insertions, 1 deletions
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index d1a9b8ef85a..925d28247b6 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -12,7 +12,7 @@
 
 use super::FnCtxt;
 use hir::def_id::DefId;
-use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue};
+use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use syntax::ast;
 use syntax::symbol::Symbol;
@@ -204,6 +204,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             "binary operation `{}` cannot be applied to type `{}`",
                             op.node.as_str(),
                             lhs_ty);
+
+                        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, vec![rhs_ty_var],
+                                    Symbol::intern(name), trait_def_id,
+                                    lhs_expr).is_ok() {
+                                err.span_note(
+                                    lhs_expr.span,
+                                    &format!(
+                                        "this is a reference of type that `{}` can be applied to, \
+                                        you need to dereference this variable once for this \
+                                        operation to work",
+                                    op.node.as_str()));
+                            }
+                        }
+
                         let missing_trait = match op.node {
                             hir::BiAdd    => Some("std::ops::Add"),
                             hir::BiSub    => Some("std::ops::Sub"),
diff --git a/src/test/compile-fail/binary-op-on-double-ref.rs b/src/test/compile-fail/binary-op-on-double-ref.rs
new file mode 100644
index 00000000000..a49cfaa1760
--- /dev/null
+++ b/src/test/compile-fail/binary-op-on-double-ref.rs
@@ -0,0 +1,20 @@
+// Copyright 2012-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.
+
+fn main() {
+    let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
+    let vr = v.iter().filter(|x| {
+        x % 2 == 0
+        //~^ ERROR binary operation `%` cannot be applied to type `&&{integer}`
+        //~| NOTE this is a reference of type that `%` can be applied to
+        //~| NOTE an implementation of `std::ops::Rem` might be missing for `&&{integer}`
+    });
+    println!("{:?}", vr);
+}
diff --git a/src/test/compile-fail/str-concat-on-double-ref.rs b/src/test/compile-fail/str-concat-on-double-ref.rs
new file mode 100644
index 00000000000..f85422f76d4
--- /dev/null
+++ b/src/test/compile-fail/str-concat-on-double-ref.rs
@@ -0,0 +1,18 @@
+// Copyright 2012-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.
+
+fn main() {
+    let a: &String = &"1".to_owned();
+    let b: &str = &"2";
+    let c = a + b;
+    //~^ ERROR binary operation `+` cannot be applied to type `&std::string::String`
+    //~| NOTE an implementation of `std::ops::Add` might be missing for `&std::string::String`
+    println!("{:?}", c);
+}