11use  std:: mem; 
2+ use  std:: ops:: ControlFlow ; 
23
34use  rustc_infer:: infer:: InferCtxt ; 
4- use  rustc_infer:: traits:: solve:: MaybeCause ; 
5+ use  rustc_infer:: traits:: query:: NoSolution ; 
6+ use  rustc_infer:: traits:: solve:: inspect:: ProbeKind ; 
7+ use  rustc_infer:: traits:: solve:: { CandidateSource ,  GoalSource ,  MaybeCause } ; 
58use  rustc_infer:: traits:: { 
6-     query :: NoSolution ,  FulfillmentError ,  FulfillmentErrorCode ,  MismatchedProjectionTypes , 
9+     self ,  FulfillmentError ,  FulfillmentErrorCode ,  MismatchedProjectionTypes ,   Obligation , 
710    PredicateObligation ,  SelectionError ,  TraitEngine , 
811} ; 
912use  rustc_middle:: ty; 
1013use  rustc_middle:: ty:: error:: { ExpectedFound ,  TypeError } ; 
1114
1215use  super :: eval_ctxt:: GenerateProofTree ; 
16+ use  super :: inspect:: { ProofTreeInferCtxtExt ,  ProofTreeVisitor } ; 
1317use  super :: { Certainty ,  InferCtxtEvalExt } ; 
1418
1519/// A trait engine using the new trait solver. 
@@ -133,9 +137,9 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
133137            . collect ( ) ; 
134138
135139        errors. extend ( self . obligations . overflowed . drain ( ..) . map ( |obligation| FulfillmentError  { 
136-             root_obligation :  obligation . clone ( ) , 
140+             obligation :   find_best_leaf_obligation ( infcx ,   & obligation ) , 
137141            code :  FulfillmentErrorCode :: Ambiguity  {  overflow :  Some ( true )  } , 
138-             obligation, 
142+             root_obligation :   obligation, 
139143        } ) ) ; 
140144
141145        errors
@@ -192,8 +196,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
192196
193197fn  fulfillment_error_for_no_solution < ' tcx > ( 
194198    infcx :  & InferCtxt < ' tcx > , 
195-     obligation :  PredicateObligation < ' tcx > , 
199+     root_obligation :  PredicateObligation < ' tcx > , 
196200)  -> FulfillmentError < ' tcx >  { 
201+     let  obligation = find_best_leaf_obligation ( infcx,  & root_obligation) ; 
202+ 
197203    let  code = match  obligation. predicate . kind ( ) . skip_binder ( )  { 
198204        ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( _) )  => { 
199205            FulfillmentErrorCode :: ProjectionError ( 
@@ -213,14 +219,14 @@ fn fulfillment_error_for_no_solution<'tcx>(
213219        } 
214220        ty:: PredicateKind :: Subtype ( pred)  => { 
215221            let  ( a,  b)  = infcx. enter_forall_and_leak_universe ( 
216-                 obligation . predicate . kind ( ) . rebind ( ( pred. a ,  pred. b ) ) , 
222+                 root_obligation . predicate . kind ( ) . rebind ( ( pred. a ,  pred. b ) ) , 
217223            ) ; 
218224            let  expected_found = ExpectedFound :: new ( true ,  a,  b) ; 
219225            FulfillmentErrorCode :: SubtypeError ( expected_found,  TypeError :: Sorts ( expected_found) ) 
220226        } 
221227        ty:: PredicateKind :: Coerce ( pred)  => { 
222228            let  ( a,  b)  = infcx. enter_forall_and_leak_universe ( 
223-                 obligation . predicate . kind ( ) . rebind ( ( pred. a ,  pred. b ) ) , 
229+                 root_obligation . predicate . kind ( ) . rebind ( ( pred. a ,  pred. b ) ) , 
224230            ) ; 
225231            let  expected_found = ExpectedFound :: new ( false ,  a,  b) ; 
226232            FulfillmentErrorCode :: SubtypeError ( expected_found,  TypeError :: Sorts ( expected_found) ) 
@@ -234,7 +240,8 @@ fn fulfillment_error_for_no_solution<'tcx>(
234240            bug ! ( "unexpected goal: {obligation:?}" ) 
235241        } 
236242    } ; 
237-     FulfillmentError  {  root_obligation :  obligation. clone ( ) ,  code,  obligation } 
243+ 
244+     FulfillmentError  {  obligation,  code,  root_obligation } 
238245} 
239246
240247fn  fulfillment_error_for_stalled < ' tcx > ( 
@@ -258,5 +265,135 @@ fn fulfillment_error_for_stalled<'tcx>(
258265        } 
259266    } ) ; 
260267
261-     FulfillmentError  {  obligation :  obligation. clone ( ) ,  code,  root_obligation :  obligation } 
268+     FulfillmentError  { 
269+         obligation :  find_best_leaf_obligation ( infcx,  & obligation) , 
270+         code, 
271+         root_obligation :  obligation, 
272+     } 
273+ } 
274+ 
275+ struct  BestObligation < ' tcx >  { 
276+     obligation :  PredicateObligation < ' tcx > , 
277+ } 
278+ 
279+ impl < ' tcx >  BestObligation < ' tcx >  { 
280+     fn  with_derived_obligation ( 
281+         & mut  self , 
282+         derive_obligation :  impl  FnOnce ( & mut  Self )  -> PredicateObligation < ' tcx > , 
283+         and_then :  impl  FnOnce ( & mut  Self )  -> <Self  as  ProofTreeVisitor < ' tcx > >:: Result , 
284+     )  -> <Self  as  ProofTreeVisitor < ' tcx > >:: Result  { 
285+         let  derived_obligation = derive_obligation ( self ) ; 
286+         let  old_obligation = std:: mem:: replace ( & mut  self . obligation ,  derived_obligation) ; 
287+         let  res = and_then ( self ) ; 
288+         self . obligation  = old_obligation; 
289+         res
290+     } 
291+ } 
292+ 
293+ impl < ' tcx >  ProofTreeVisitor < ' tcx >  for  BestObligation < ' tcx >  { 
294+     type  Result  = ControlFlow < PredicateObligation < ' tcx > > ; 
295+ 
296+     fn  span ( & self )  -> rustc_span:: Span  { 
297+         self . obligation . cause . span 
298+     } 
299+ 
300+     fn  visit_goal ( & mut  self ,  goal :  & super :: inspect:: InspectGoal < ' _ ,  ' tcx > )  -> Self :: Result  { 
301+         let  candidates = goal. candidates ( ) ; 
302+         // FIXME: Throw out candidates that have no failing WC and >1 failing misc goal. 
303+ 
304+         // HACK: 
305+         if  self . obligation . recursion_depth  > 3  { 
306+             return  ControlFlow :: Break ( self . obligation . clone ( ) ) ; 
307+         } 
308+ 
309+         let  [ candidate]  = candidates. as_slice ( )  else  { 
310+             return  ControlFlow :: Break ( self . obligation . clone ( ) ) ; 
311+         } ; 
312+ 
313+         // FIXME: Could we extract a trait ref from a projection here too? 
314+         // FIXME: Also, what about considering >1 layer up the stack? May be necessary 
315+         // for normalizes-to. 
316+         let  Some ( parent_trait_pred)  = goal. goal ( ) . predicate . to_opt_poly_trait_pred ( )  else  { 
317+             return  ControlFlow :: Break ( self . obligation . clone ( ) ) ; 
318+         } ; 
319+ 
320+         let  tcx = goal. infcx ( ) . tcx ; 
321+         let  mut  impl_where_bound_count = 0 ; 
322+         for  nested_goal in  candidate. instantiate_nested_goals ( self . span ( ) )  { 
323+             if  matches ! ( nested_goal. source( ) ,  GoalSource :: ImplWhereBound )  { 
324+                 impl_where_bound_count += 1 ; 
325+             }  else  { 
326+                 continue ; 
327+             } 
328+ 
329+             // Skip nested goals that hold. 
330+             if  matches ! ( nested_goal. result( ) ,  Ok ( Certainty :: Yes ) )  { 
331+                 continue ; 
332+             } 
333+ 
334+             self . with_derived_obligation ( 
335+                 |self_| { 
336+                     let  mut  cause = self_. obligation . cause . clone ( ) ; 
337+                     cause = match  candidate. kind ( )  { 
338+                         ProbeKind :: TraitCandidate  { 
339+                             source :  CandidateSource :: Impl ( impl_def_id) , 
340+                             result :  _, 
341+                         }  => { 
342+                             let  idx = impl_where_bound_count - 1 ; 
343+                             if  let  Some ( ( _,  span) )  = tcx
344+                                 . predicates_of ( impl_def_id) 
345+                                 . instantiate_identity ( tcx) 
346+                                 . iter ( ) 
347+                                 . nth ( idx) 
348+                             { 
349+                                 cause. derived_cause ( parent_trait_pred,  |derived| { 
350+                                     traits:: ImplDerivedObligation ( Box :: new ( 
351+                                         traits:: ImplDerivedObligationCause  { 
352+                                             derived, 
353+                                             impl_or_alias_def_id :  impl_def_id, 
354+                                             impl_def_predicate_index :  Some ( idx) , 
355+                                             span, 
356+                                         } , 
357+                                     ) ) 
358+                                 } ) 
359+                             }  else  { 
360+                                 cause
361+                             } 
362+                         } 
363+                         ProbeKind :: TraitCandidate  { 
364+                             source :  CandidateSource :: BuiltinImpl ( ..) , 
365+                             result :  _, 
366+                         }  => { 
367+                             cause. derived_cause ( parent_trait_pred,  traits:: BuiltinDerivedObligation ) 
368+                         } 
369+                         _ => cause, 
370+                     } ; 
371+ 
372+                     Obligation  { 
373+                         cause, 
374+                         param_env :  nested_goal. goal ( ) . param_env , 
375+                         predicate :  nested_goal. goal ( ) . predicate , 
376+                         recursion_depth :  self_. obligation . recursion_depth  + 1 , 
377+                     } 
378+                 } , 
379+                 |self_| self_. visit_goal ( & nested_goal) , 
380+             ) ?; 
381+         } 
382+ 
383+         ControlFlow :: Break ( self . obligation . clone ( ) ) 
384+     } 
385+ } 
386+ 
387+ fn  find_best_leaf_obligation < ' tcx > ( 
388+     infcx :  & InferCtxt < ' tcx > , 
389+     obligation :  & PredicateObligation < ' tcx > , 
390+ )  -> PredicateObligation < ' tcx >  { 
391+     let  obligation = infcx. resolve_vars_if_possible ( obligation. clone ( ) ) ; 
392+     infcx
393+         . visit_proof_tree ( 
394+             obligation. clone ( ) . into ( ) , 
395+             & mut  BestObligation  {  obligation :  obligation. clone ( )  } , 
396+         ) 
397+         . break_value ( ) 
398+         . unwrap_or ( obligation) 
262399} 
0 commit comments