@@ -79,12 +79,6 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
79
79
/// used for error reporting
80
80
static_candidates : RefCell < Vec < CandidateSource > > ,
81
81
82
- /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
83
- /// for error reporting
84
- unsatisfied_predicates : RefCell <
85
- Vec < ( ty:: Predicate < ' tcx > , Option < ty:: Predicate < ' tcx > > , Option < ObligationCause < ' tcx > > ) > ,
86
- > ,
87
-
88
82
scope_expr_id : HirId ,
89
83
90
84
/// Is this probe being done for a diagnostic? This will skip some error reporting
@@ -162,6 +156,20 @@ impl AutorefOrPtrAdjustment {
162
156
}
163
157
}
164
158
159
+ /// Extra information required only for error reporting.
160
+ struct PickDiagHints < ' a , ' tcx > {
161
+ /// Unstable candidates alongside the stable ones.
162
+ unstable_candidates : Option < Vec < ( Candidate < ' tcx > , Symbol ) > > ,
163
+
164
+ /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
165
+ /// for error reporting
166
+ unsatisfied_predicates : & ' a mut Vec < (
167
+ ty:: Predicate < ' tcx > ,
168
+ Option < ty:: Predicate < ' tcx > > ,
169
+ Option < ObligationCause < ' tcx > > ,
170
+ ) > ,
171
+ }
172
+
165
173
#[ derive( Debug , Clone ) ]
166
174
pub ( crate ) struct Pick < ' tcx > {
167
175
pub item : ty:: AssocItem ,
@@ -665,7 +673,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
665
673
private_candidates : Vec :: new ( ) ,
666
674
private_candidate : Cell :: new ( None ) ,
667
675
static_candidates : RefCell :: new ( Vec :: new ( ) ) ,
668
- unsatisfied_predicates : RefCell :: new ( Vec :: new ( ) ) ,
669
676
scope_expr_id,
670
677
is_suggestion,
671
678
}
@@ -678,7 +685,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
678
685
self . private_candidates . clear ( ) ;
679
686
self . private_candidate . set ( None ) ;
680
687
self . static_candidates . borrow_mut ( ) . clear ( ) ;
681
- self . unsatisfied_predicates . borrow_mut ( ) . clear ( ) ;
682
688
}
683
689
684
690
/// When we're looking up a method by path (UFCS), we relate the receiver
@@ -1054,7 +1060,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1054
1060
fn pick ( mut self ) -> PickResult < ' tcx > {
1055
1061
assert ! ( self . method_name. is_some( ) ) ;
1056
1062
1057
- if let Some ( r) = self . pick_core ( ) {
1063
+ let mut unsatisfied_predicates = Vec :: new ( ) ;
1064
+
1065
+ if let Some ( r) = self . pick_core ( & mut unsatisfied_predicates) {
1058
1066
return r;
1059
1067
}
1060
1068
@@ -1074,7 +1082,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1074
1082
1075
1083
let static_candidates = std:: mem:: take ( self . static_candidates . get_mut ( ) ) ;
1076
1084
let private_candidate = self . private_candidate . take ( ) ;
1077
- let unsatisfied_predicates = std:: mem:: take ( self . unsatisfied_predicates . get_mut ( ) ) ;
1078
1085
1079
1086
// things failed, so lets look at all traits, for diagnostic purposes now:
1080
1087
self . reset ( ) ;
@@ -1084,7 +1091,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1084
1091
1085
1092
self . assemble_extension_candidates_for_all_traits ( ) ;
1086
1093
1087
- let out_of_scope_traits = match self . pick_core ( ) {
1094
+ let out_of_scope_traits = match self . pick_core ( & mut Vec :: new ( ) ) {
1088
1095
Some ( Ok ( p) ) => vec ! [ p. item. container_id( self . tcx) ] ,
1089
1096
Some ( Err ( MethodError :: Ambiguity ( v) ) ) => v
1090
1097
. into_iter ( )
@@ -1119,14 +1126,40 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1119
1126
} ) )
1120
1127
}
1121
1128
1122
- fn pick_core ( & self ) -> Option < PickResult < ' tcx > > {
1129
+ fn pick_core (
1130
+ & self ,
1131
+ unsatisfied_predicates : & mut Vec < (
1132
+ ty:: Predicate < ' tcx > ,
1133
+ Option < ty:: Predicate < ' tcx > > ,
1134
+ Option < ObligationCause < ' tcx > > ,
1135
+ ) > ,
1136
+ ) -> Option < PickResult < ' tcx > > {
1123
1137
// Pick stable methods only first, and consider unstable candidates if not found.
1124
- self . pick_all_method ( Some ( & mut vec ! [ ] ) ) . or_else ( || self . pick_all_method ( None ) )
1138
+ self . pick_all_method ( & mut PickDiagHints {
1139
+ // This first cycle, maintain a list of unstable candidates which
1140
+ // we encounter. This will end up in the Pick for diagnostics.
1141
+ unstable_candidates : Some ( Vec :: new ( ) ) ,
1142
+ // Contribute to the list of unsatisfied predicates which may
1143
+ // also be used for diagnostics.
1144
+ unsatisfied_predicates,
1145
+ } )
1146
+ . or_else ( || {
1147
+ self . pick_all_method ( & mut PickDiagHints {
1148
+ // On the second search, don't provide a special list of unstable
1149
+ // candidates. This indicates to the picking code that it should
1150
+ // in fact include such unstable candidates in the actual
1151
+ // search.
1152
+ unstable_candidates : None ,
1153
+ // And there's no need to duplicate ourselves in the
1154
+ // unsatisifed predicates list. Provide a throwaway list.
1155
+ unsatisfied_predicates : & mut Vec :: new ( ) ,
1156
+ } )
1157
+ } )
1125
1158
}
1126
1159
1127
- fn pick_all_method (
1160
+ fn pick_all_method < ' b > (
1128
1161
& self ,
1129
- mut unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1162
+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1130
1163
) -> Option < PickResult < ' tcx > > {
1131
1164
self . steps
1132
1165
. iter ( )
@@ -1151,37 +1184,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1151
1184
. unwrap_or_else ( |_| {
1152
1185
span_bug ! ( self . span, "{:?} was applicable but now isn't?" , step. self_ty)
1153
1186
} ) ;
1154
- self . pick_by_value_method ( step, self_ty, unstable_candidates. as_deref_mut ( ) )
1155
- . or_else ( || {
1156
- self . pick_autorefd_method (
1157
- step,
1158
- self_ty,
1159
- hir:: Mutability :: Not ,
1160
- unstable_candidates. as_deref_mut ( ) ,
1161
- )
1187
+ self . pick_by_value_method ( step, self_ty, pick_diag_hints) . or_else ( || {
1188
+ self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Not , pick_diag_hints)
1162
1189
. or_else ( || {
1163
1190
self . pick_autorefd_method (
1164
1191
step,
1165
1192
self_ty,
1166
1193
hir:: Mutability :: Mut ,
1167
- unstable_candidates. as_deref_mut ( ) ,
1168
- )
1169
- } )
1170
- . or_else ( || {
1171
- self . pick_const_ptr_method (
1172
- step,
1173
- self_ty,
1174
- unstable_candidates. as_deref_mut ( ) ,
1175
- )
1176
- } )
1177
- . or_else ( || {
1178
- self . pick_reborrow_pin_method (
1179
- step,
1180
- self_ty,
1181
- unstable_candidates. as_deref_mut ( ) ,
1194
+ pick_diag_hints,
1182
1195
)
1183
1196
} )
1184
- } )
1197
+ . or_else ( || self . pick_const_ptr_method ( step, self_ty, pick_diag_hints) )
1198
+ . or_else ( || self . pick_reborrow_pin_method ( step, self_ty, pick_diag_hints) )
1199
+ } )
1185
1200
} )
1186
1201
}
1187
1202
@@ -1191,17 +1206,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1191
1206
/// we will potentially *reborrow* it to a shorter lifetime. This allows us
1192
1207
/// to transparently pass `&mut` pointers, in particular, without consuming
1193
1208
/// them for their entire lifetime.
1194
- fn pick_by_value_method (
1209
+ fn pick_by_value_method < ' b > (
1195
1210
& self ,
1196
1211
step : & CandidateStep < ' tcx > ,
1197
1212
self_ty : Ty < ' tcx > ,
1198
- unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1213
+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1199
1214
) -> Option < PickResult < ' tcx > > {
1200
1215
if step. unsize {
1201
1216
return None ;
1202
1217
}
1203
1218
1204
- self . pick_method ( self_ty, unstable_candidates ) . map ( |r| {
1219
+ self . pick_method ( self_ty, pick_diag_hints ) . map ( |r| {
1205
1220
r. map ( |mut pick| {
1206
1221
pick. autoderefs = step. autoderefs ;
1207
1222
@@ -1234,20 +1249,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1234
1249
} )
1235
1250
}
1236
1251
1237
- fn pick_autorefd_method (
1252
+ fn pick_autorefd_method < ' b > (
1238
1253
& self ,
1239
1254
step : & CandidateStep < ' tcx > ,
1240
1255
self_ty : Ty < ' tcx > ,
1241
1256
mutbl : hir:: Mutability ,
1242
- unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1257
+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1243
1258
) -> Option < PickResult < ' tcx > > {
1244
1259
let tcx = self . tcx ;
1245
1260
1246
1261
// In general, during probing we erase regions.
1247
1262
let region = tcx. lifetimes . re_erased ;
1248
1263
1249
1264
let autoref_ty = Ty :: new_ref ( tcx, region, self_ty, mutbl) ;
1250
- self . pick_method ( autoref_ty, unstable_candidates ) . map ( |r| {
1265
+ self . pick_method ( autoref_ty, pick_diag_hints ) . map ( |r| {
1251
1266
r. map ( |mut pick| {
1252
1267
pick. autoderefs = step. autoderefs ;
1253
1268
pick. autoref_or_ptr_adjustment =
@@ -1258,12 +1273,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1258
1273
}
1259
1274
1260
1275
/// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
1261
- #[ instrument( level = "debug" , skip( self , step, unstable_candidates ) ) ]
1262
- fn pick_reborrow_pin_method (
1276
+ #[ instrument( level = "debug" , skip( self , step, pick_diag_hints ) ) ]
1277
+ fn pick_reborrow_pin_method < ' b > (
1263
1278
& self ,
1264
1279
step : & CandidateStep < ' tcx > ,
1265
1280
self_ty : Ty < ' tcx > ,
1266
- unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1281
+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1267
1282
) -> Option < PickResult < ' tcx > > {
1268
1283
if !self . tcx . features ( ) . pin_ergonomics ( ) {
1269
1284
return None ;
@@ -1284,7 +1299,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1284
1299
1285
1300
let region = self . tcx . lifetimes . re_erased ;
1286
1301
let autopin_ty = Ty :: new_pinned_ref ( self . tcx , region, inner_ty, hir:: Mutability :: Not ) ;
1287
- self . pick_method ( autopin_ty, unstable_candidates ) . map ( |r| {
1302
+ self . pick_method ( autopin_ty, pick_diag_hints ) . map ( |r| {
1288
1303
r. map ( |mut pick| {
1289
1304
pick. autoderefs = step. autoderefs ;
1290
1305
pick. autoref_or_ptr_adjustment =
@@ -1297,11 +1312,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1297
1312
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
1298
1313
/// special case for this is because going from `*mut T` to `*const T` with autoderefs and
1299
1314
/// autorefs would require dereferencing the pointer, which is not safe.
1300
- fn pick_const_ptr_method (
1315
+ fn pick_const_ptr_method < ' b > (
1301
1316
& self ,
1302
1317
step : & CandidateStep < ' tcx > ,
1303
1318
self_ty : Ty < ' tcx > ,
1304
- unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1319
+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1305
1320
) -> Option < PickResult < ' tcx > > {
1306
1321
// Don't convert an unsized reference to ptr
1307
1322
if step. unsize {
@@ -1313,7 +1328,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1313
1328
} ;
1314
1329
1315
1330
let const_ptr_ty = Ty :: new_imm_ptr ( self . tcx , ty) ;
1316
- self . pick_method ( const_ptr_ty, unstable_candidates ) . map ( |r| {
1331
+ self . pick_method ( const_ptr_ty, pick_diag_hints ) . map ( |r| {
1317
1332
r. map ( |mut pick| {
1318
1333
pick. autoderefs = step. autoderefs ;
1319
1334
pick. autoref_or_ptr_adjustment = Some ( AutorefOrPtrAdjustment :: ToConstPtr ) ;
@@ -1322,61 +1337,50 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1322
1337
} )
1323
1338
}
1324
1339
1325
- fn pick_method (
1340
+ fn pick_method < ' b > (
1326
1341
& self ,
1327
1342
self_ty : Ty < ' tcx > ,
1328
- mut unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1343
+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1329
1344
) -> Option < PickResult < ' tcx > > {
1330
1345
debug ! ( "pick_method(self_ty={})" , self . ty_to_string( self_ty) ) ;
1331
1346
1332
- let mut possibly_unsatisfied_predicates = Vec :: new ( ) ;
1333
-
1334
1347
for ( kind, candidates) in
1335
1348
[ ( "inherent" , & self . inherent_candidates ) , ( "extension" , & self . extension_candidates ) ]
1336
1349
{
1337
1350
debug ! ( "searching {} candidates" , kind) ;
1338
- let res = self . consider_candidates (
1339
- self_ty,
1340
- candidates,
1341
- & mut possibly_unsatisfied_predicates,
1342
- unstable_candidates. as_deref_mut ( ) ,
1343
- ) ;
1351
+ let res = self . consider_candidates ( self_ty, candidates, pick_diag_hints) ;
1344
1352
if let Some ( pick) = res {
1345
1353
return Some ( pick) ;
1346
1354
}
1347
1355
}
1348
1356
1349
1357
if self . private_candidate . get ( ) . is_none ( ) {
1350
1358
if let Some ( Ok ( pick) ) =
1351
- self . consider_candidates ( self_ty, & self . private_candidates , & mut vec ! [ ] , None )
1359
+ self . consider_candidates ( self_ty, & self . private_candidates , pick_diag_hints )
1352
1360
{
1353
1361
self . private_candidate . set ( Some ( ( pick. item . kind . as_def_kind ( ) , pick. item . def_id ) ) ) ;
1354
1362
}
1355
1363
}
1356
-
1357
- // `pick_method` may be called twice for the same self_ty if no stable methods
1358
- // match. Only extend once.
1359
- if unstable_candidates. is_some ( ) {
1360
- self . unsatisfied_predicates . borrow_mut ( ) . extend ( possibly_unsatisfied_predicates) ;
1361
- }
1362
1364
None
1363
1365
}
1364
1366
1365
- fn consider_candidates (
1367
+ fn consider_candidates < ' b > (
1366
1368
& self ,
1367
1369
self_ty : Ty < ' tcx > ,
1368
1370
candidates : & [ Candidate < ' tcx > ] ,
1369
- possibly_unsatisfied_predicates : & mut Vec < (
1370
- ty:: Predicate < ' tcx > ,
1371
- Option < ty:: Predicate < ' tcx > > ,
1372
- Option < ObligationCause < ' tcx > > ,
1373
- ) > ,
1374
- mut unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1371
+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1375
1372
) -> Option < PickResult < ' tcx > > {
1376
1373
let mut applicable_candidates: Vec < _ > = candidates
1377
1374
. iter ( )
1378
1375
. map ( |probe| {
1379
- ( probe, self . consider_probe ( self_ty, probe, possibly_unsatisfied_predicates) )
1376
+ (
1377
+ probe,
1378
+ self . consider_probe (
1379
+ self_ty,
1380
+ probe,
1381
+ & mut pick_diag_hints. unsatisfied_predicates ,
1382
+ ) ,
1383
+ )
1380
1384
} )
1381
1385
. filter ( |& ( _, status) | status != ProbeResult :: NoMatch )
1382
1386
. collect ( ) ;
@@ -1391,7 +1395,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1391
1395
}
1392
1396
}
1393
1397
1394
- if let Some ( uc) = & mut unstable_candidates {
1398
+ if let Some ( uc) = & mut pick_diag_hints . unstable_candidates {
1395
1399
applicable_candidates. retain ( |& ( candidate, _) | {
1396
1400
if let stability:: EvalResult :: Deny { feature, .. } =
1397
1401
self . tcx . eval_stability ( candidate. item . def_id , None , self . span , None )
@@ -1409,10 +1413,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1409
1413
}
1410
1414
1411
1415
applicable_candidates. pop ( ) . map ( |( probe, status) | match status {
1412
- ProbeResult :: Match => {
1413
- Ok ( probe
1414
- . to_unadjusted_pick ( self_ty , unstable_candidates. cloned ( ) . unwrap_or_default ( ) ) )
1415
- }
1416
+ ProbeResult :: Match => Ok ( probe . to_unadjusted_pick (
1417
+ self_ty ,
1418
+ pick_diag_hints . unstable_candidates . clone ( ) . unwrap_or_default ( ) ,
1419
+ ) ) ,
1416
1420
ProbeResult :: NoMatch | ProbeResult :: BadReturnType => Err ( MethodError :: BadReturnType ) ,
1417
1421
} )
1418
1422
}
@@ -1854,7 +1858,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1854
1858
pcx. method_name = Some ( method_name) ;
1855
1859
pcx. assemble_inherent_candidates ( ) ;
1856
1860
pcx. assemble_extension_candidates_for_all_traits ( ) ;
1857
- pcx. pick_core ( ) . and_then ( |pick| pick. ok ( ) ) . map ( |pick| pick. item )
1861
+ pcx. pick_core ( & mut Vec :: new ( ) ) . and_then ( |pick| pick. ok ( ) ) . map ( |pick| pick. item )
1858
1862
} )
1859
1863
. collect ( ) ;
1860
1864
0 commit comments