use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
-use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{
+ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
+};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
+use rustc_type_ir::sty::TyKind::*;
use std::ops::ControlFlow;
return_ty
};
- self.check_lhs_assignable(lhs, "E0067", op.span);
+ self.check_lhs_assignable(lhs, "E0067", op.span, |err| {
+ if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+ if self
+ .lookup_op_method(
+ lhs_deref_ty,
+ Some(rhs_ty),
+ Some(rhs),
+ Op::Binary(op, IsAssign::Yes),
+ )
+ .is_ok()
+ {
+ // Suppress this error, since we already emitted
+ // a deref suggestion in check_overloaded_binop
+ err.delay_as_bug();
+ }
+ }
+ });
ty
}
(err, missing_trait, use_output)
}
};
- if let Ref(_, rty, _) = lhs_ty.kind() {
- if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span)
- && self
- .lookup_op_method(
- *rty,
- Some(rhs_ty),
- Some(rhs_expr),
- Op::Binary(op, is_assign),
- )
- .is_ok()
+
+ let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| {
+ if self
+ .lookup_op_method(
+ lhs_deref_ty,
+ Some(rhs_ty),
+ Some(rhs_expr),
+ Op::Binary(op, is_assign),
+ )
+ .is_ok()
{
if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
let msg = &format!(
IsAssign::Yes => "=",
IsAssign::No => "",
},
- rty.peel_refs(),
+ lhs_deref_ty.peel_refs(),
lstring,
);
err.span_suggestion_verbose(
lhs_expr.span.shrink_to_lo(),
msg,
- "*".to_string(),
+ "*",
rustc_errors::Applicability::MachineApplicable,
);
}
}
+ };
+
+ // We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
+ // `a += b` => `*a += b` if a is a mut ref.
+ if is_assign == IsAssign::Yes
+ && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+ suggest_deref_binop(lhs_deref_ty);
+ } else if is_assign == IsAssign::No
+ && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
+ if self.infcx.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
+ suggest_deref_binop(*lhs_deref_ty);
+ }
}
if let Some(missing_trait) = missing_trait {
let mut visitor = TypeParamVisitor(vec![]);
err.span_suggestion_verbose(
lhs_expr.span.until(lhs_inner_expr.span),
rm_borrow_msg,
- "".to_owned(),
+ "",
Applicability::MachineApplicable
);
} else {
err.span_suggestion_verbose(
lhs_expr.span.shrink_to_hi(),
to_owned_msg,
- ".to_owned()".to_owned(),
+ ".to_owned()",
Applicability::MachineApplicable
);
}
let predicates = errors
.iter()
.filter_map(|error| {
- error.obligation.predicate.clone().to_opt_poly_trait_pred()
+ error.obligation.predicate.to_opt_poly_trait_pred()
});
for pred in predicates {
self.infcx.suggest_restricting_param_bound(