@@ -15,11 +15,13 @@ use rustc_hir as hir;
15
15
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
16
16
use rustc_infer:: traits:: FulfillmentError ;
17
17
use 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
+ } ;
19
21
use rustc_session:: parse:: feature_err;
20
22
use rustc_span:: edit_distance:: find_best_match_for_name;
21
23
use rustc_span:: symbol:: { sym, Ident } ;
22
- use rustc_span:: { Span , Symbol , DUMMY_SP } ;
24
+ use rustc_span:: { BytePos , Span , Symbol , DUMMY_SP } ;
23
25
use rustc_trait_selection:: traits:: object_safety_violations_for_assoc_item;
24
26
25
27
impl < ' tcx > dyn HirTyLowerer < ' tcx > + ' _ {
@@ -1029,12 +1031,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
1029
1031
/// Emits an error regarding forbidden type binding associations
1030
1032
pub fn prohibit_assoc_item_binding (
1031
1033
tcx : TyCtxt < ' _ > ,
1032
- span : Span ,
1033
- segment : Option < ( & hir:: PathSegment < ' _ > , Span ) > ,
1034
+ binding : & hir :: TypeBinding < ' _ > ,
1035
+ segment : Option < ( DefId , & hir:: PathSegment < ' _ > , Span ) > ,
1034
1036
) {
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
1038
1040
&& segment. args ( ) . parenthesized == hir:: GenericArgsParentheses :: ParenSugar
1039
1041
{
1040
1042
Some ( ParenthesizedFnTraitExpansion {
@@ -1045,6 +1047,78 @@ pub fn prohibit_assoc_item_binding(
1045
1047
None
1046
1048
} ,
1047
1049
} ) ;
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 ( ) ;
1048
1122
}
1049
1123
1050
1124
pub ( crate ) fn fn_trait_to_string (
0 commit comments