Skip to content

Commit

Permalink
Detect double reference when applying binary op
Browse files Browse the repository at this point in the history
```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.

Bug rust-lang#33877
  • Loading branch information
estebank authored and pnkfelix committed Jan 3, 2017
1 parent 8f62c29 commit 0d39584
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
17 changes: 16 additions & 1 deletion src/librustc_typeck/check/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -204,6 +204,21 @@ 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.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var],
token::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"),
Expand Down
20 changes: 20 additions & 0 deletions src/test/compile-fail/binary-op-on-double-ref.rs
Original file line number Diff line number Diff line change
@@ -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 `&&_`
//~| NOTE this is a reference of type that `%` can be applied to
//~| NOTE an implementation of `std::ops::Rem` might be missing for `&&_`
});
println!("{:?}", vr);
}
19 changes: 19 additions & 0 deletions src/test/compile-fail/str-concat-on-double-ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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 this is a reference of type that `+` can be applied to
//~| NOTE an implementation of `std::ops::Add` might be missing for `&std::string::String`
println!("{:?}", c);
}

0 comments on commit 0d39584

Please sign in to comment.