@@ -51,6 +51,7 @@ use rustc_span::lev_distance::find_best_match_for_name;
5151use rustc_span:: source_map:: Span ;
5252use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
5353use rustc_span:: { BytePos , Pos } ;
54+ use rustc_trait_selection:: infer:: InferCtxtExt ;
5455use rustc_trait_selection:: traits:: { self , ObligationCauseCode } ;
5556
5657impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -836,6 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
836837 lhs : & ' tcx hir:: Expr < ' tcx > ,
837838 err_code : & ' static str ,
838839 op_span : Span ,
840+ adjust_err : impl FnOnce ( & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ) ,
839841 ) {
840842 if lhs. is_syntactic_place_expr ( ) {
841843 return ;
@@ -858,6 +860,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
858860 ) ;
859861 } ) ;
860862
863+ adjust_err ( & mut err) ;
864+
861865 err. emit ( ) ;
862866 }
863867
@@ -1050,10 +1054,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10501054 return self . tcx . ty_error ( ) ;
10511055 }
10521056
1053- self . check_lhs_assignable ( lhs, "E0070" , span) ;
1054-
10551057 let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
1056- let rhs_ty = self . check_expr_coercable_to_type ( & rhs, lhs_ty, Some ( lhs) ) ;
1058+
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) {
1074+ err. span_suggestion_verbose (
1075+ lhs. span . shrink_to_lo ( ) ,
1076+ "consider dereferencing here to assign to the mutably borrowed value" ,
1077+ "*" . to_string ( ) ,
1078+ Applicability :: MachineApplicable ,
1079+ ) ;
1080+ }
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) ;
1087+ } ) ;
1088+
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+ }
10571098
10581099 self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
10591100
0 commit comments