@@ -12,6 +12,7 @@ use rustc_hir::lang_items::LangItem;
12
12
use rustc_hir:: { ExprKind , Node , QPath } ;
13
13
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
14
14
use rustc_middle:: hir:: map as hir_map;
15
+ use rustc_middle:: ty:: fast_reject:: simplify_type;
15
16
use rustc_middle:: ty:: print:: with_crate_prefix;
16
17
use rustc_middle:: ty:: {
17
18
self , ToPolyTraitRef , ToPredicate , Ty , TyCtxt , TypeFoldable , WithConstness ,
@@ -1074,19 +1075,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1074
1075
} else {
1075
1076
"items from traits can only be used if the trait is implemented and in scope"
1076
1077
} ) ;
1078
+ let candidates_len = candidates. len ( ) ;
1077
1079
let message = |action| {
1078
1080
format ! (
1079
1081
"the following {traits_define} an item `{name}`, perhaps you need to {action} \
1080
1082
{one_of_them}:",
1081
1083
traits_define =
1082
- if candidates . len ( ) == 1 { "trait defines" } else { "traits define" } ,
1084
+ if candidates_len == 1 { "trait defines" } else { "traits define" } ,
1083
1085
action = action,
1084
- one_of_them = if candidates . len ( ) == 1 { "it" } else { "one of them" } ,
1086
+ one_of_them = if candidates_len == 1 { "it" } else { "one of them" } ,
1085
1087
name = item_name,
1086
1088
)
1087
1089
} ;
1088
1090
// Obtain the span for `param` and use it for a structured suggestion.
1089
- let mut suggested = false ;
1090
1091
if let ( Some ( ref param) , Some ( ref table) ) =
1091
1092
( param_type, self . in_progress_typeck_results )
1092
1093
{
@@ -1147,7 +1148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1147
1148
Applicability :: MaybeIncorrect ,
1148
1149
) ;
1149
1150
}
1150
- suggested = true ;
1151
+ return ;
1151
1152
}
1152
1153
Node :: Item ( hir:: Item {
1153
1154
kind : hir:: ItemKind :: Trait ( .., bounds, _) ,
@@ -1167,45 +1168,96 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1167
1168
} ) ,
1168
1169
Applicability :: MaybeIncorrect ,
1169
1170
) ;
1170
- suggested = true ;
1171
+ return ;
1171
1172
}
1172
1173
_ => { }
1173
1174
}
1174
1175
}
1175
1176
}
1176
1177
1177
- if !suggested {
1178
- let action = if let Some ( param) = param_type {
1179
- format ! ( "restrict type parameter `{}` with" , param)
1180
- } else {
1181
- // FIXME: it might only need to be imported into scope, not implemented.
1182
- "implement" . to_string ( )
1183
- } ;
1184
- let mut use_note = true ;
1185
- if let [ trait_info] = & candidates[ ..] {
1186
- if let Some ( span) = self . tcx . hir ( ) . span_if_local ( trait_info. def_id ) {
1187
- err. span_note (
1188
- self . tcx . sess . source_map ( ) . guess_head_span ( span) ,
1189
- & format ! (
1190
- "`{}` defines an item `{}`, perhaps you need to {} it" ,
1191
- self . tcx. def_path_str( trait_info. def_id) ,
1192
- item_name,
1193
- action
1194
- ) ,
1195
- ) ;
1196
- use_note = false
1178
+ let ( potential_candidates, explicitly_negative) = if param_type. is_some ( ) {
1179
+ // FIXME: Even though negative bounds are not implemented, we could maybe handle
1180
+ // cases where a positive bound implies a negative impl.
1181
+ ( candidates, Vec :: new ( ) )
1182
+ } else if let Some ( simp_rcvr_ty) = simplify_type ( self . tcx , rcvr_ty, true ) {
1183
+ let mut potential_candidates = Vec :: new ( ) ;
1184
+ let mut explicitly_negative = Vec :: new ( ) ;
1185
+ for candidate in candidates {
1186
+ // Check if there's a negative impl of `candidate` for `rcvr_ty`
1187
+ if self
1188
+ . tcx
1189
+ . all_impls ( candidate. def_id )
1190
+ . filter ( |imp_did| {
1191
+ self . tcx . impl_polarity ( * imp_did) == ty:: ImplPolarity :: Negative
1192
+ } )
1193
+ . any ( |imp_did| {
1194
+ let imp = self . tcx . impl_trait_ref ( imp_did) . unwrap ( ) ;
1195
+ let imp_simp = simplify_type ( self . tcx , imp. self_ty ( ) , true ) ;
1196
+ imp_simp. map ( |s| s == simp_rcvr_ty) . unwrap_or ( false )
1197
+ } )
1198
+ {
1199
+ explicitly_negative. push ( candidate) ;
1200
+ } else {
1201
+ potential_candidates. push ( candidate) ;
1197
1202
}
1198
1203
}
1199
- if use_note {
1204
+ ( potential_candidates, explicitly_negative)
1205
+ } else {
1206
+ // We don't know enough about `recv_ty` to make proper suggestions.
1207
+ ( candidates, Vec :: new ( ) )
1208
+ } ;
1209
+
1210
+ let action = if let Some ( param) = param_type {
1211
+ format ! ( "restrict type parameter `{}` with" , param)
1212
+ } else {
1213
+ // FIXME: it might only need to be imported into scope, not implemented.
1214
+ "implement" . to_string ( )
1215
+ } ;
1216
+ match & potential_candidates[ ..] {
1217
+ [ ] => { }
1218
+ [ trait_info] if trait_info. def_id . is_local ( ) => {
1219
+ let span = self . tcx . hir ( ) . span_if_local ( trait_info. def_id ) . unwrap ( ) ;
1220
+ err. span_note (
1221
+ self . tcx . sess . source_map ( ) . guess_head_span ( span) ,
1222
+ & format ! (
1223
+ "`{}` defines an item `{}`, perhaps you need to {} it" ,
1224
+ self . tcx. def_path_str( trait_info. def_id) ,
1225
+ item_name,
1226
+ action
1227
+ ) ,
1228
+ ) ;
1229
+ }
1230
+ trait_infos => {
1200
1231
let mut msg = message ( action) ;
1201
- for ( i, trait_info) in candidates . iter ( ) . enumerate ( ) {
1232
+ for ( i, trait_info) in trait_infos . iter ( ) . enumerate ( ) {
1202
1233
msg. push_str ( & format ! (
1203
1234
"\n candidate #{}: `{}`" ,
1204
1235
i + 1 ,
1205
1236
self . tcx. def_path_str( trait_info. def_id) ,
1206
1237
) ) ;
1207
1238
}
1208
- err. note ( & msg[ ..] ) ;
1239
+ err. note ( & msg) ;
1240
+ }
1241
+ }
1242
+ match & explicitly_negative[ ..] {
1243
+ [ ] => { }
1244
+ [ trait_info] => {
1245
+ let msg = format ! (
1246
+ "the trait `{}` defines an item `{}`, but is explicitely unimplemented" ,
1247
+ self . tcx. def_path_str( trait_info. def_id) ,
1248
+ item_name
1249
+ ) ;
1250
+ err. note ( & msg) ;
1251
+ }
1252
+ trait_infos => {
1253
+ let mut msg = format ! (
1254
+ "the following traits define an item `{}`, but are explicitely unimplemented:" ,
1255
+ item_name
1256
+ ) ;
1257
+ for trait_info in trait_infos {
1258
+ msg. push_str ( & format ! ( "\n {}" , self . tcx. def_path_str( trait_info. def_id) ) ) ;
1259
+ }
1260
+ err. note ( & msg) ;
1209
1261
}
1210
1262
}
1211
1263
}
0 commit comments