Skip to content

Commit

Permalink
Rollup merge of rust-lang#38617 - pnkfelix:double-reference, r=pnkfelix
Browse files Browse the repository at this point in the history
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 rust-lang#33877

----

Thanks to @estebank for providing the original PR rust-lang#34420 (of which this is a tweaked rebase).
  • Loading branch information
steveklabnik committed Jan 4, 2017
2 parents e3a6bdb + 98218b3 commit 30df598
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
18 changes: 17 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,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],
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);
}
18 changes: 18 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,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);
}

0 comments on commit 30df598

Please sign in to comment.