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).
This commit is contained in:
Alex Crichton 2017-01-27 14:41:09 -08:00
commit a2a3074fb3
3 changed files with 55 additions and 1 deletions

View File

@ -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"),

View File

@ -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);
}

View File

@ -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);
}