@@ -47,6 +47,9 @@ use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
47
47
use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
48
48
use rustc_middle:: ty:: print:: { with_forced_trimmed_paths, with_no_trimmed_paths} ;
49
49
50
+ use itertools:: EitherOrBoth ;
51
+ use itertools:: Itertools ;
52
+
50
53
#[ derive( Debug ) ]
51
54
pub enum CoroutineInteriorOrUpvar {
52
55
// span of interior type
@@ -838,78 +841,132 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
838
841
}
839
842
}
840
843
}
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
843
849
&& 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)
844
852
{
845
853
let trait_pred = predicate. unwrap_or ( trait_pred) ;
846
854
let lhs_ty = self . tcx . instantiate_bound_regions_with_erased ( trait_pred. self_ty ( ) ) ;
847
855
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
+ } ) ;
853
885
let obligation = self . mk_trait_obligation_with_new_self_ty (
854
886
obligation. param_env ,
855
887
trait_pred_and_ty,
856
888
) ;
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
+ } )
865
894
} )
866
895
{
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 ( ) ;
873
898
let mut msg = "consider dereferencing here" ;
874
- if let hir:: ExprKind :: AddrOf ( _, _, inner) = lhs . kind {
899
+ if let hir:: ExprKind :: AddrOf ( _, _, inner) = expr . kind {
875
900
msg = "consider removing the borrow and dereferencing instead" ;
876
901
if let hir:: ExprKind :: AddrOf ( ..) = inner. kind {
877
902
msg = "consider removing the borrows and dereferencing instead" ;
878
903
}
879
904
}
880
- while let hir:: ExprKind :: AddrOf ( _, _, inner) = lhs . kind
905
+ while let hir:: ExprKind :: AddrOf ( _, _, inner) = expr . kind
881
906
&& steps > 0
882
907
{
883
908
prefix_span = prefix_span. with_hi ( inner. span . lo ( ) ) ;
884
- lhs = inner;
909
+ expr = inner;
885
910
steps -= 1 ;
886
911
}
887
912
if steps == 0 {
888
913
msg = msg. trim_end_matches ( " and dereferencing instead" ) ;
889
914
}
890
-
891
915
let derefs = "*" . repeat ( steps) ;
892
916
let needs_parens = steps > 0
893
- && match lhs . kind {
917
+ && match expr . kind {
894
918
hir:: ExprKind :: Cast ( _, _) | hir:: ExprKind :: Binary ( _, _, _) => true ,
895
- _ if is_range_literal ( lhs ) => true ,
919
+ _ if is_range_literal ( expr ) => true ,
896
920
_ => false ,
897
921
} ;
898
922
let mut suggestion = if needs_parens {
899
923
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( ) ) ,
902
929
]
903
930
} 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
+ ) ]
905
935
} ;
906
936
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) ;
907
965
err. multipart_suggestion_verbose (
908
966
msg,
909
967
suggestion,
910
968
Applicability :: MachineApplicable ,
911
969
) ;
912
- return true ;
913
970
}
914
971
}
915
972
}
0 commit comments