@@ -79,12 +79,6 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
7979 /// used for error reporting
8080 static_candidates : RefCell < Vec < CandidateSource > > ,
8181
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-
8882 scope_expr_id : HirId ,
8983
9084 /// Is this probe being done for a diagnostic? This will skip some error reporting
@@ -162,6 +156,21 @@ impl AutorefOrPtrAdjustment {
162156 }
163157}
164158
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+
165174#[ derive( Debug , Clone ) ]
166175pub ( crate ) struct Pick < ' tcx > {
167176 pub item : ty:: AssocItem ,
@@ -665,7 +674,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
665674 private_candidates : Vec :: new ( ) ,
666675 private_candidate : Cell :: new ( None ) ,
667676 static_candidates : RefCell :: new ( Vec :: new ( ) ) ,
668- unsatisfied_predicates : RefCell :: new ( Vec :: new ( ) ) ,
669677 scope_expr_id,
670678 is_suggestion,
671679 }
@@ -678,7 +686,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
678686 self . private_candidates . clear ( ) ;
679687 self . private_candidate . set ( None ) ;
680688 self . static_candidates . borrow_mut ( ) . clear ( ) ;
681- self . unsatisfied_predicates . borrow_mut ( ) . clear ( ) ;
682689 }
683690
684691 /// When we're looking up a method by path (UFCS), we relate the receiver
@@ -1054,7 +1061,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10541061 fn pick ( mut self ) -> PickResult < ' tcx > {
10551062 assert ! ( self . method_name. is_some( ) ) ;
10561063
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) {
10581067 return r;
10591068 }
10601069
@@ -1074,7 +1083,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10741083
10751084 let static_candidates = std:: mem:: take ( self . static_candidates . get_mut ( ) ) ;
10761085 let private_candidate = self . private_candidate . take ( ) ;
1077- let unsatisfied_predicates = std:: mem:: take ( self . unsatisfied_predicates . get_mut ( ) ) ;
10781086
10791087 // things failed, so lets look at all traits, for diagnostic purposes now:
10801088 self . reset ( ) ;
@@ -1084,7 +1092,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10841092
10851093 self . assemble_extension_candidates_for_all_traits ( ) ;
10861094
1087- let out_of_scope_traits = match self . pick_core ( ) {
1095+ let out_of_scope_traits = match self . pick_core ( & mut Vec :: new ( ) ) {
10881096 Some ( Ok ( p) ) => vec ! [ p. item. container_id( self . tcx) ] ,
10891097 Some ( Err ( MethodError :: Ambiguity ( v) ) ) => v
10901098 . into_iter ( )
@@ -1119,14 +1127,40 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11191127 } ) )
11201128 }
11211129
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 > > {
11231138 // 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+ } )
11251159 }
11261160
1127- fn pick_all_method (
1161+ fn pick_all_method < ' b > (
11281162 & self ,
1129- mut unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1163+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
11301164 ) -> Option < PickResult < ' tcx > > {
11311165 self . steps
11321166 . iter ( )
@@ -1151,37 +1185,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11511185 . unwrap_or_else ( |_| {
11521186 span_bug ! ( self . span, "{:?} was applicable but now isn't?" , step. self_ty)
11531187 } ) ;
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)
11621190 . or_else ( || {
11631191 self . pick_autorefd_method (
11641192 step,
11651193 self_ty,
11661194 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,
11821196 )
11831197 } )
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+ } )
11851201 } )
11861202 }
11871203
@@ -1191,17 +1207,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11911207 /// we will potentially *reborrow* it to a shorter lifetime. This allows us
11921208 /// to transparently pass `&mut` pointers, in particular, without consuming
11931209 /// them for their entire lifetime.
1194- fn pick_by_value_method (
1210+ fn pick_by_value_method < ' b > (
11951211 & self ,
11961212 step : & CandidateStep < ' tcx > ,
11971213 self_ty : Ty < ' tcx > ,
1198- unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1214+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
11991215 ) -> Option < PickResult < ' tcx > > {
12001216 if step. unsize {
12011217 return None ;
12021218 }
12031219
1204- self . pick_method ( self_ty, unstable_candidates ) . map ( |r| {
1220+ self . pick_method ( self_ty, pick_diag_hints ) . map ( |r| {
12051221 r. map ( |mut pick| {
12061222 pick. autoderefs = step. autoderefs ;
12071223
@@ -1234,20 +1250,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12341250 } )
12351251 }
12361252
1237- fn pick_autorefd_method (
1253+ fn pick_autorefd_method < ' b > (
12381254 & self ,
12391255 step : & CandidateStep < ' tcx > ,
12401256 self_ty : Ty < ' tcx > ,
12411257 mutbl : hir:: Mutability ,
1242- unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1258+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
12431259 ) -> Option < PickResult < ' tcx > > {
12441260 let tcx = self . tcx ;
12451261
12461262 // In general, during probing we erase regions.
12471263 let region = tcx. lifetimes . re_erased ;
12481264
12491265 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| {
12511267 r. map ( |mut pick| {
12521268 pick. autoderefs = step. autoderefs ;
12531269 pick. autoref_or_ptr_adjustment =
@@ -1258,12 +1274,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12581274 }
12591275
12601276 /// 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 > (
12631279 & self ,
12641280 step : & CandidateStep < ' tcx > ,
12651281 self_ty : Ty < ' tcx > ,
1266- unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1282+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
12671283 ) -> Option < PickResult < ' tcx > > {
12681284 if !self . tcx . features ( ) . pin_ergonomics ( ) {
12691285 return None ;
@@ -1284,7 +1300,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12841300
12851301 let region = self . tcx . lifetimes . re_erased ;
12861302 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| {
12881304 r. map ( |mut pick| {
12891305 pick. autoderefs = step. autoderefs ;
12901306 pick. autoref_or_ptr_adjustment =
@@ -1297,11 +1313,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12971313 /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
12981314 /// special case for this is because going from `*mut T` to `*const T` with autoderefs and
12991315 /// autorefs would require dereferencing the pointer, which is not safe.
1300- fn pick_const_ptr_method (
1316+ fn pick_const_ptr_method < ' b > (
13011317 & self ,
13021318 step : & CandidateStep < ' tcx > ,
13031319 self_ty : Ty < ' tcx > ,
1304- unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1320+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
13051321 ) -> Option < PickResult < ' tcx > > {
13061322 // Don't convert an unsized reference to ptr
13071323 if step. unsize {
@@ -1313,7 +1329,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13131329 } ;
13141330
13151331 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| {
13171333 r. map ( |mut pick| {
13181334 pick. autoderefs = step. autoderefs ;
13191335 pick. autoref_or_ptr_adjustment = Some ( AutorefOrPtrAdjustment :: ToConstPtr ) ;
@@ -1322,61 +1338,50 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13221338 } )
13231339 }
13241340
1325- fn pick_method (
1341+ fn pick_method < ' b > (
13261342 & self ,
13271343 self_ty : Ty < ' tcx > ,
1328- mut unstable_candidates : Option < & mut Vec < ( Candidate < ' tcx > , Symbol ) > > ,
1344+ pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
13291345 ) -> Option < PickResult < ' tcx > > {
13301346 debug ! ( "pick_method(self_ty={})" , self . ty_to_string( self_ty) ) ;
13311347
1332- let mut possibly_unsatisfied_predicates = Vec :: new ( ) ;
1333-
13341348 for ( kind, candidates) in
13351349 [ ( "inherent" , & self . inherent_candidates ) , ( "extension" , & self . extension_candidates ) ]
13361350 {
13371351 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) ;
13441353 if let Some ( pick) = res {
13451354 return Some ( pick) ;
13461355 }
13471356 }
13481357
13491358 if self . private_candidate . get ( ) . is_none ( ) {
13501359 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 )
13521361 {
13531362 self . private_candidate . set ( Some ( ( pick. item . kind . as_def_kind ( ) , pick. item . def_id ) ) ) ;
13541363 }
13551364 }
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- }
13621365 None
13631366 }
13641367
1365- fn consider_candidates (
1368+ fn consider_candidates < ' b > (
13661369 & self ,
13671370 self_ty : Ty < ' tcx > ,
13681371 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 > ,
13751373 ) -> Option < PickResult < ' tcx > > {
13761374 let mut applicable_candidates: Vec < _ > = candidates
13771375 . iter ( )
13781376 . 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+ )
13801385 } )
13811386 . filter ( |& ( _, status) | status != ProbeResult :: NoMatch )
13821387 . collect ( ) ;
@@ -1391,7 +1396,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13911396 }
13921397 }
13931398
1394- if let Some ( uc) = & mut unstable_candidates {
1399+ if let Some ( uc) = & mut pick_diag_hints . unstable_candidates {
13951400 applicable_candidates. retain ( |& ( candidate, _) | {
13961401 if let stability:: EvalResult :: Deny { feature, .. } =
13971402 self . tcx . eval_stability ( candidate. item . def_id , None , self . span , None )
@@ -1409,10 +1414,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14091414 }
14101415
14111416 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+ ) ) ,
14161421 ProbeResult :: NoMatch | ProbeResult :: BadReturnType => Err ( MethodError :: BadReturnType ) ,
14171422 } )
14181423 }
@@ -1854,7 +1859,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18541859 pcx. method_name = Some ( method_name) ;
18551860 pcx. assemble_inherent_candidates ( ) ;
18561861 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 )
18581863 } )
18591864 . collect ( ) ;
18601865
0 commit comments