@@ -15,11 +15,13 @@ use rustc_hir as hir;
1515use rustc_hir:: def_id:: { DefId , LocalDefId } ;
1616use rustc_infer:: traits:: FulfillmentError ;
1717use rustc_middle:: query:: Key ;
18- use rustc_middle:: ty:: { self , suggest_constraining_type_param, Ty , TyCtxt , TypeVisitableExt } ;
18+ use rustc_middle:: ty:: {
19+ self , suggest_constraining_type_param, GenericParamCount , Ty , TyCtxt , TypeVisitableExt ,
20+ } ;
1921use rustc_session:: parse:: feature_err;
2022use rustc_span:: edit_distance:: find_best_match_for_name;
2123use rustc_span:: symbol:: { sym, Ident } ;
22- use rustc_span:: { Span , Symbol , DUMMY_SP } ;
24+ use rustc_span:: { BytePos , Span , Symbol , DUMMY_SP } ;
2325use rustc_trait_selection:: traits:: object_safety_violations_for_assoc_item;
2426
2527impl < ' tcx > dyn HirTyLowerer < ' tcx > + ' _ {
@@ -1029,12 +1031,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10291031/// Emits an error regarding forbidden type binding associations
10301032pub fn prohibit_assoc_item_binding (
10311033 tcx : TyCtxt < ' _ > ,
1032- span : Span ,
1033- segment : Option < ( & hir:: PathSegment < ' _ > , Span ) > ,
1034+ binding : & hir :: TypeBinding < ' _ > ,
1035+ segment : Option < ( DefId , & hir:: PathSegment < ' _ > , Span ) > ,
10341036) {
1035- tcx. dcx ( ) . emit_err ( AssocTypeBindingNotAllowed {
1036- span,
1037- fn_trait_expansion : if let Some ( ( segment, span) ) = segment
1037+ let mut err = tcx. dcx ( ) . create_err ( AssocTypeBindingNotAllowed {
1038+ span : binding . span ,
1039+ fn_trait_expansion : if let Some ( ( _ , segment, span) ) = segment
10381040 && segment. args ( ) . parenthesized == hir:: GenericArgsParentheses :: ParenSugar
10391041 {
10401042 Some ( ParenthesizedFnTraitExpansion {
@@ -1045,6 +1047,78 @@ pub fn prohibit_assoc_item_binding(
10451047 None
10461048 } ,
10471049 } ) ;
1050+
1051+ // Emit a suggestion if possible
1052+ if let Some ( ( def_id, segment, _) ) = segment
1053+ && segment. args ( ) . parenthesized == hir:: GenericArgsParentheses :: No
1054+ && let hir:: TypeBindingKind :: Equality { term : binding_arg_ty } = binding. kind
1055+ {
1056+ // Suggests removal of the offending equality constraint
1057+ let suggest_removal = |e : & mut Diag < ' _ > | {
1058+ let mut suggestion_span = binding. span . with_hi ( binding. span . hi ( ) + BytePos ( 1 ) ) ; // Include the comma or the angle bracket at the end
1059+ if segment. args ( ) . bindings . len ( ) == 1 {
1060+ // If it is the only binding specified
1061+ // include the starting angle bracket as well
1062+ suggestion_span = suggestion_span. with_lo ( suggestion_span. lo ( ) - BytePos ( 1 ) )
1063+ }
1064+ if let Ok ( suggestion) = tcx. sess . source_map ( ) . span_to_snippet ( suggestion_span) {
1065+ e. span_suggestion_verbose (
1066+ suggestion_span,
1067+ "try removing this type binding" ,
1068+ suggestion,
1069+ Applicability :: MaybeIncorrect ,
1070+ ) ;
1071+ }
1072+ } ;
1073+
1074+ // Suggests replacing the quality constraint with
1075+ // normal type argument
1076+ let suggest_direct_use = |e : & mut Diag < ' _ > , sp : Span , is_ty : bool | {
1077+ if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( sp) {
1078+ let ty_or_const = if is_ty { "generic" } else { "const" } ;
1079+ e. span_suggestion_verbose (
1080+ binding. span ,
1081+ format ! ( "to use `{snippet}` as a {ty_or_const} argument specify it directly" ) ,
1082+ snippet,
1083+ Applicability :: MaybeIncorrect ,
1084+ ) ;
1085+ }
1086+ } ;
1087+
1088+ // Get a sense of what generic args the type expects
1089+ let generics = tcx. generics_of ( def_id) ;
1090+ let GenericParamCount { mut types, consts, .. } = generics. own_counts ( ) ;
1091+ if generics. has_self && types > 0 {
1092+ types -= 1 // Ignore the `Self` type
1093+ }
1094+
1095+ // Now emit suggestion
1096+ if types == 0 && consts == 0 {
1097+ err. note ( format ! ( "`{0}` is not a generic type" , segment. ident) ) ;
1098+ suggest_removal ( & mut err) ;
1099+ } else {
1100+ match binding_arg_ty {
1101+ hir:: Term :: Ty ( ty) => {
1102+ if types > 0 {
1103+ suggest_direct_use ( & mut err, ty. span , true ) ;
1104+ } else {
1105+ suggest_removal ( & mut err) ;
1106+ }
1107+ }
1108+ hir:: Term :: Const ( c) if consts > 0 => {
1109+ if consts > 0 {
1110+ let span = tcx. hir ( ) . span ( c. hir_id ) ;
1111+ suggest_direct_use ( & mut err, span, false ) ;
1112+ } else {
1113+ suggest_removal ( & mut err) ;
1114+ }
1115+ }
1116+ _ => { }
1117+ }
1118+ }
1119+ }
1120+
1121+ err. emit ( ) ;
10481122}
10491123
10501124pub ( crate ) fn fn_trait_to_string (
0 commit comments