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