@@ -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 > {
@@ -1055,25 +1056,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10551056
10561057 let lhs_ty = self . check_expr_with_needs ( & lhs, Needs :: MutPlace ) ;
10571058
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) {
10651074 err. span_suggestion_verbose (
10661075 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" ,
10691077 "*" . to_string ( ) ,
10701078 Applicability :: MachineApplicable ,
10711079 ) ;
10721080 }
10731081 }
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) ;
10741087 } ) ;
10751088
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+ }
10771098
10781099 self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
10791100
0 commit comments