@@ -47,6 +47,9 @@ use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
4747use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
4848use rustc_middle:: ty:: print:: { with_forced_trimmed_paths, with_no_trimmed_paths} ;
4949
50+ use itertools:: EitherOrBoth ;
51+ use itertools:: Itertools ;
52+
5053#[ derive( Debug ) ]
5154pub enum CoroutineInteriorOrUpvar {
5255 // span of interior type
@@ -838,78 +841,132 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
838841 }
839842 }
840843 }
841- } else if let ( ObligationCauseCode :: BinOp { lhs_hir_id, rhs_hir_id : Some ( _rhs_hir_id) , .. } , predicate) =
842- code. peel_derives_with_predicate ( )
844+ } else if let (
845+ ObligationCauseCode :: BinOp { lhs_hir_id, rhs_hir_id : Some ( rhs_hir_id) , .. } ,
846+ predicate,
847+ ) = code. peel_derives_with_predicate ( )
848+ && let Some ( typeck_results) = & self . typeck_results
843849 && let hir:: Node :: Expr ( lhs) = self . tcx . hir ( ) . get ( * lhs_hir_id)
850+ && let hir:: Node :: Expr ( rhs) = self . tcx . hir ( ) . get ( * rhs_hir_id)
851+ && let Some ( rhs_ty) = typeck_results. expr_ty_opt ( rhs)
844852 {
845853 let trait_pred = predicate. unwrap_or ( trait_pred) ;
846854 let lhs_ty = self . tcx . instantiate_bound_regions_with_erased ( trait_pred. self_ty ( ) ) ;
847855 let lhs_autoderef = ( self . autoderef_steps ) ( lhs_ty) ;
848- if let Some ( mut steps) =
849- lhs_autoderef. into_iter ( ) . enumerate ( ) . find_map ( |( steps, ( ty, obligations) ) | {
850- // Remapping bound vars here
851- let trait_pred_and_ty =
852- trait_pred. map_bound ( |inner_trait_pred| ( inner_trait_pred, ty) ) ;
856+ let rhs_autoderef = ( self . autoderef_steps ) ( rhs_ty) ;
857+ let first_lhs = lhs_autoderef. first ( ) . unwrap ( ) . clone ( ) ;
858+ let first_rhs = rhs_autoderef. first ( ) . unwrap ( ) . clone ( ) ;
859+ let mut autoderefs = lhs_autoderef
860+ . into_iter ( )
861+ . enumerate ( )
862+ . rev ( )
863+ . zip_longest ( rhs_autoderef. into_iter ( ) . enumerate ( ) . rev ( ) )
864+ . map ( |t| match t {
865+ EitherOrBoth :: Both ( a, b) => ( a, b) ,
866+ EitherOrBoth :: Left ( a) => ( a, ( 0 , first_rhs. clone ( ) ) ) ,
867+ EitherOrBoth :: Right ( b) => ( ( 0 , first_lhs. clone ( ) ) , b) ,
868+ } )
869+ . rev ( ) ;
870+ if let Some ( ( lsteps, rsteps) ) =
871+ autoderefs. find_map ( |( ( lsteps, ( l_ty, _) ) , ( rsteps, ( r_ty, _) ) ) | {
872+ let trait_pred_and_ty = trait_pred. map_bound ( |inner| {
873+ (
874+ ty:: TraitPredicate {
875+ trait_ref : ty:: TraitRef :: new (
876+ self . tcx ,
877+ inner. trait_ref . def_id ,
878+ self . tcx . mk_args ( & [ l_ty. into ( ) , r_ty. into ( ) ] ) ,
879+ ) ,
880+ polarity : inner. polarity ,
881+ } ,
882+ l_ty,
883+ )
884+ } ) ;
853885 let obligation = self . mk_trait_obligation_with_new_self_ty (
854886 obligation. param_env ,
855887 trait_pred_and_ty,
856888 ) ;
857-
858- let may_hold = obligations
859- . iter ( )
860- . chain ( [ & obligation] )
861- . all ( |obligation| self . predicate_may_hold ( obligation) )
862- . then_some ( steps) ;
863-
864- may_hold
889+ self . predicate_may_hold ( & obligation) . then_some ( match ( lsteps, rsteps) {
890+ ( _, 0 ) => ( Some ( lsteps) , None ) ,
891+ ( 0 , _) => ( None , Some ( rsteps) ) ,
892+ _ => ( Some ( lsteps) , Some ( rsteps) ) ,
893+ } )
865894 } )
866895 {
867- if steps > 0 {
868- // Suggest `&*` rather than `*&`
869- let span = lhs. peel_borrows ( ) . span ;
870-
871- let mut lhs = lhs;
872- let mut prefix_span = lhs. span . shrink_to_lo ( ) ;
896+ let make_sugg = |mut expr : & Expr < ' _ > , mut steps| {
897+ let mut prefix_span = expr. span . shrink_to_lo ( ) ;
873898 let mut msg = "consider dereferencing here" ;
874- if let hir:: ExprKind :: AddrOf ( _, _, inner) = lhs . kind {
899+ if let hir:: ExprKind :: AddrOf ( _, _, inner) = expr . kind {
875900 msg = "consider removing the borrow and dereferencing instead" ;
876901 if let hir:: ExprKind :: AddrOf ( ..) = inner. kind {
877902 msg = "consider removing the borrows and dereferencing instead" ;
878903 }
879904 }
880- while let hir:: ExprKind :: AddrOf ( _, _, inner) = lhs . kind
905+ while let hir:: ExprKind :: AddrOf ( _, _, inner) = expr . kind
881906 && steps > 0
882907 {
883908 prefix_span = prefix_span. with_hi ( inner. span . lo ( ) ) ;
884- lhs = inner;
909+ expr = inner;
885910 steps -= 1 ;
886911 }
887912 if steps == 0 {
888913 msg = msg. trim_end_matches ( " and dereferencing instead" ) ;
889914 }
890-
891915 let derefs = "*" . repeat ( steps) ;
892916 let needs_parens = steps > 0
893- && match lhs . kind {
917+ && match expr . kind {
894918 hir:: ExprKind :: Cast ( _, _) | hir:: ExprKind :: Binary ( _, _, _) => true ,
895- _ if is_range_literal ( lhs ) => true ,
919+ _ if is_range_literal ( expr ) => true ,
896920 _ => false ,
897921 } ;
898922 let mut suggestion = if needs_parens {
899923 vec ! [
900- ( span. shrink_to_lo( ) , format!( "{derefs}(" ) ) ,
901- ( span. shrink_to_hi( ) , ")" . to_string( ) ) ,
924+ (
925+ expr. span. with_lo( prefix_span. hi( ) ) . shrink_to_lo( ) ,
926+ format!( "{derefs}(" ) ,
927+ ) ,
928+ ( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
902929 ]
903930 } else {
904- vec ! [ ( span. shrink_to_lo( ) , format!( "{derefs}" ) ) ]
931+ vec ! [ (
932+ expr. span. with_lo( prefix_span. hi( ) ) . shrink_to_lo( ) ,
933+ format!( "{derefs}" ) ,
934+ ) ]
905935 } ;
906936 suggestion. push ( ( prefix_span, "" . to_string ( ) ) ) ;
937+ ( msg, suggestion)
938+ } ;
939+
940+ if let Some ( lsteps) = lsteps
941+ && let Some ( rsteps) = rsteps
942+ && lsteps > 0
943+ && rsteps > 0
944+ {
945+ let mut suggestion = make_sugg ( lhs, lsteps) . 1 ;
946+ suggestion. append ( & mut make_sugg ( rhs, rsteps) . 1 ) ;
947+ err. multipart_suggestion_verbose (
948+ "consider dereferencing both sides" ,
949+ suggestion,
950+ Applicability :: MachineApplicable ,
951+ ) ;
952+ } else if let Some ( lsteps) = lsteps
953+ && lsteps > 0
954+ {
955+ let ( msg, suggestion) = make_sugg ( lhs, lsteps) ;
956+ err. multipart_suggestion_verbose (
957+ msg,
958+ suggestion,
959+ Applicability :: MachineApplicable ,
960+ ) ;
961+ } else if let Some ( rsteps) = rsteps
962+ && rsteps > 0
963+ {
964+ let ( msg, suggestion) = make_sugg ( rhs, rsteps) ;
907965 err. multipart_suggestion_verbose (
908966 msg,
909967 suggestion,
910968 Applicability :: MachineApplicable ,
911969 ) ;
912- return true ;
913970 }
914971 }
915972 }
0 commit comments