@@ -51,6 +51,7 @@ use rustc_span::lev_distance::find_best_match_for_name;
51
51
use rustc_span:: source_map:: Span ;
52
52
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
53
53
use rustc_span:: { BytePos , Pos } ;
54
+ use rustc_trait_selection:: infer:: InferCtxtExt ;
54
55
use rustc_trait_selection:: traits:: { self , ObligationCauseCode } ;
55
56
56
57
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -1055,25 +1056,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1055
1056
1056
1057
let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
1057
1058
1058
- self . check_lhs_assignable ( lhs, "E0070" , span, |err| {
1059
- let rhs_ty = self . check_expr ( & rhs) ;
1060
-
1061
- // FIXME: This could be done any time lhs_ty is DerefMut into something that
1062
- // is compatible with rhs_ty, and not _just_ `&mut`
1063
- if let ty:: Ref ( _, lhs_inner_ty, hir:: Mutability :: Mut ) = lhs_ty. kind ( ) {
1064
- if self . can_coerce ( rhs_ty, * lhs_inner_ty) {
1059
+ let suggest_deref_binop = |err : & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ,
1060
+ rhs_ty : Ty < ' tcx > | {
1061
+ if let Some ( lhs_deref_ty) = self . deref_once_mutably_for_diagnostic ( lhs_ty) {
1062
+ // Can only assign if the type is sized, so if `DerefMut` yields a type that is
1063
+ // unsized, do not suggest dereferencing it.
1064
+ let lhs_deref_ty_is_sized = self
1065
+ . infcx
1066
+ . type_implements_trait (
1067
+ self . tcx . lang_items ( ) . sized_trait ( ) . unwrap ( ) ,
1068
+ lhs_deref_ty,
1069
+ ty:: List :: empty ( ) ,
1070
+ self . param_env ,
1071
+ )
1072
+ . may_apply ( ) ;
1073
+ if lhs_deref_ty_is_sized && self . can_coerce ( rhs_ty, lhs_deref_ty) {
1065
1074
err. span_suggestion_verbose (
1066
1075
lhs. span . shrink_to_lo ( ) ,
1067
- "consider dereferencing here to assign to the mutable \
1068
- borrowed piece of memory",
1076
+ "consider dereferencing here to assign to the mutably borrowed value" ,
1069
1077
"*" . to_string ( ) ,
1070
1078
Applicability :: MachineApplicable ,
1071
1079
) ;
1072
1080
}
1073
1081
}
1082
+ } ;
1083
+
1084
+ self . check_lhs_assignable ( lhs, "E0070" , span, |err| {
1085
+ let rhs_ty = self . check_expr ( & rhs) ;
1086
+ suggest_deref_binop ( err, rhs_ty) ;
1074
1087
} ) ;
1075
1088
1076
- let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty, Some ( lhs) ) ;
1089
+ // This is (basically) inlined `check_expr_coercable_to_type`, but we want
1090
+ // to suggest an additional fixup here in `suggest_deref_binop`.
1091
+ let rhs_ty = self . check_expr_with_hint ( & rhs, lhs_ty) ;
1092
+ if let ( _, Some ( mut diag) ) =
1093
+ self . demand_coerce_diag ( rhs, rhs_ty, lhs_ty, Some ( lhs) , AllowTwoPhase :: No )
1094
+ {
1095
+ suggest_deref_binop ( & mut diag, rhs_ty) ;
1096
+ diag. emit ( ) ;
1097
+ }
1077
1098
1078
1099
self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
1079
1100
0 commit comments