@@ -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 > {
@@ -836,6 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
836
837
lhs : & ' tcx hir:: Expr < ' tcx > ,
837
838
err_code : & ' static str ,
838
839
op_span : Span ,
840
+ adjust_err : impl FnOnce ( & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ) ,
839
841
) {
840
842
if lhs. is_syntactic_place_expr ( ) {
841
843
return ;
@@ -858,6 +860,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
858
860
) ;
859
861
} ) ;
860
862
863
+ adjust_err ( & mut err) ;
864
+
861
865
err. emit ( ) ;
862
866
}
863
867
@@ -1050,10 +1054,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1050
1054
return self . tcx . ty_error ( ) ;
1051
1055
}
1052
1056
1053
- self . check_lhs_assignable ( lhs, "E0070" , span) ;
1054
-
1055
1057
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
+ }
1057
1098
1058
1099
self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
1059
1100
0 commit comments