Skip to content

Commit 30df598

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#33877 ---- Thanks to @estebank for providing the original PR rust-lang#34420 (of which this is a tweaked rebase).
2 parents e3a6bdb + 98218b3 commit 30df598

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

Diff for: src/librustc_typeck/check/op.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
1313
use super::FnCtxt;
1414
use hir::def_id::DefId;
15-
use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue};
15+
use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants};
1616
use rustc::infer::type_variable::TypeVariableOrigin;
1717
use syntax::ast;
1818
use syntax::symbol::Symbol;
@@ -204,6 +204,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
204204
"binary operation `{}` cannot be applied to type `{}`",
205205
op.node.as_str(),
206206
lhs_ty);
207+
208+
if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
209+
if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) &&
210+
self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var],
211+
token::intern(name), trait_def_id,
212+
lhs_expr).is_ok() {
213+
err.span_note(
214+
lhs_expr.span,
215+
&format!(
216+
"this is a reference of type that `{}` can be applied to, \
217+
you need to dereference this variable once for this \
218+
operation to work",
219+
op.node.as_str()));
220+
}
221+
}
222+
207223
let missing_trait = match op.node {
208224
hir::BiAdd => Some("std::ops::Add"),
209225
hir::BiSub => Some("std::ops::Sub"),

Diff for: src/test/compile-fail/binary-op-on-double-ref.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
13+
let vr = v.iter().filter(|x| {
14+
x % 2 == 0
15+
//~^ ERROR binary operation `%` cannot be applied to type `&&_`
16+
//~| NOTE this is a reference of type that `%` can be applied to
17+
//~| NOTE an implementation of `std::ops::Rem` might be missing for `&&_`
18+
});
19+
println!("{:?}", vr);
20+
}

Diff for: src/test/compile-fail/str-concat-on-double-ref.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let a: &String = &"1".to_owned();
13+
let b: &str = &"2";
14+
let c = a + b;
15+
//~^ ERROR binary operation `+` cannot be applied to type `&std::string::String`
16+
//~| NOTE an implementation of `std::ops::Add` might be missing for `&std::string::String`
17+
println!("{:?}", c);
18+
}

0 commit comments

Comments
 (0)