@@ -247,16 +247,24 @@ fn fulfillment_error_for_no_solution<'tcx>(
247
247
248
248
fn fulfillment_error_for_stalled < ' tcx > (
249
249
infcx : & InferCtxt < ' tcx > ,
250
- obligation : PredicateObligation < ' tcx > ,
250
+ root_obligation : PredicateObligation < ' tcx > ,
251
251
) -> FulfillmentError < ' tcx > {
252
- let code = infcx. probe ( |_| {
253
- match infcx. evaluate_root_goal ( obligation. clone ( ) . into ( ) , GenerateProofTree :: Never ) . 0 {
254
- Ok ( ( _, Certainty :: Maybe ( MaybeCause :: Ambiguity ) ) ) => {
255
- FulfillmentErrorCode :: Ambiguity { overflow : None }
256
- }
257
- Ok ( ( _, Certainty :: Maybe ( MaybeCause :: Overflow { suggest_increasing_limit } ) ) ) => {
258
- FulfillmentErrorCode :: Ambiguity { overflow : Some ( suggest_increasing_limit) }
259
- }
252
+ let ( code, obligation) = infcx. probe ( |_| {
253
+ match infcx. evaluate_root_goal ( root_obligation. clone ( ) . into ( ) , GenerateProofTree :: Never ) . 0 {
254
+ Ok ( ( _, Certainty :: Maybe ( MaybeCause :: Ambiguity ) ) ) => (
255
+ FulfillmentErrorCode :: Ambiguity { overflow : None } ,
256
+ find_best_leaf_obligation ( infcx, & root_obligation, true ) ,
257
+ ) ,
258
+ Ok ( ( _, Certainty :: Maybe ( MaybeCause :: Overflow { suggest_increasing_limit } ) ) ) => (
259
+ FulfillmentErrorCode :: Ambiguity { overflow : Some ( suggest_increasing_limit) } ,
260
+ // Don't look into overflows because we treat overflows weirdly anyways.
261
+ // In `instantiate_response_discarding_overflow` we set `has_changed = false`,
262
+ // recomputing the goal again during `find_best_leaf_obligation` may apply
263
+ // inference guidance that makes other goals go from ambig -> pass, for example.
264
+ //
265
+ // FIXME: We should probably just look into overflows here.
266
+ root_obligation. clone ( ) ,
267
+ ) ,
260
268
Ok ( ( _, Certainty :: Yes ) ) => {
261
269
bug ! ( "did not expect successful goal when collecting ambiguity errors" )
262
270
}
@@ -266,11 +274,7 @@ fn fulfillment_error_for_stalled<'tcx>(
266
274
}
267
275
} ) ;
268
276
269
- FulfillmentError {
270
- obligation : find_best_leaf_obligation ( infcx, & obligation, true ) ,
271
- code,
272
- root_obligation : obligation,
273
- }
277
+ FulfillmentError { obligation, code, root_obligation }
274
278
}
275
279
276
280
fn find_best_leaf_obligation < ' tcx > (
@@ -305,41 +309,51 @@ impl<'tcx> BestObligation<'tcx> {
305
309
res
306
310
}
307
311
308
- /// Filter out the candidates that aren't either error or ambiguous (depending
309
- /// on what we are looking for), and also throw out candidates that have no
310
- /// failing WC (or higher-ranked obligations, for which there should only be
311
- /// one candidate anyways -- but I digress). This most likely means that the
312
- /// goal just didn't unify at all, e.g. a param candidate with an alias in it.
312
+ /// Filter out the candidates that aren't interesting to visit for the
313
+ /// purposes of reporting errors. For ambiguities, we only consider
314
+ /// candidates that may hold. For errors, we only consider candidates that
315
+ /// *don't* hold and which have impl-where clauses that also don't hold.
313
316
fn non_trivial_candidates < ' a > (
314
317
& self ,
315
318
goal : & ' a InspectGoal < ' a , ' tcx > ,
316
319
) -> Vec < InspectCandidate < ' a , ' tcx > > {
317
- let mut candidates = goal
318
- . candidates ( )
319
- . into_iter ( )
320
- . filter ( |candidate| match self . consider_ambiguities {
321
- true => matches ! ( candidate. result( ) , Ok ( Certainty :: Maybe ( _) ) ) ,
322
- false => matches ! ( candidate. result( ) , Err ( _) ) ,
323
- } )
324
- . collect :: < Vec < _ > > ( ) ;
325
-
326
- // If we have >1 candidate, one may still be due to "boring" reasons, like
327
- // an alias-relate that failed to hold when deeply evaluated. We really
328
- // don't care about reasons like this.
329
- if candidates. len ( ) > 1 {
330
- candidates. retain ( |candidate| {
331
- goal. infcx ( ) . probe ( |_| {
332
- candidate. instantiate_nested_goals ( self . span ( ) ) . iter ( ) . any ( |nested_goal| {
333
- matches ! (
334
- nested_goal. source( ) ,
335
- GoalSource :: ImplWhereBound | GoalSource :: InstantiateHigherRanked
336
- ) && match self . consider_ambiguities {
337
- true => matches ! ( nested_goal. result( ) , Ok ( Certainty :: Maybe ( _) ) ) ,
338
- false => matches ! ( nested_goal. result( ) , Err ( _) ) ,
339
- }
340
- } )
341
- } )
342
- } ) ;
320
+ let mut candidates = goal. candidates ( ) ;
321
+ match self . consider_ambiguities {
322
+ true => {
323
+ // If we have an ambiguous obligation, we must consider *all* candidates
324
+ // that hold, or else we may guide inference causing other goals to go
325
+ // from ambig -> pass/fail.
326
+ candidates. retain ( |candidate| candidate. result ( ) . is_ok ( ) ) ;
327
+ }
328
+ false => {
329
+ candidates. retain ( |candidate| candidate. result ( ) . is_err ( ) ) ;
330
+ // If we have >1 candidate, one may still be due to "boring" reasons, like
331
+ // an alias-relate that failed to hold when deeply evaluated. We really
332
+ // don't care about reasons like this.
333
+ if candidates. len ( ) > 1 {
334
+ candidates. retain ( |candidate| {
335
+ goal. infcx ( ) . probe ( |_| {
336
+ candidate. instantiate_nested_goals ( self . span ( ) ) . iter ( ) . any (
337
+ |nested_goal| {
338
+ matches ! (
339
+ nested_goal. source( ) ,
340
+ GoalSource :: ImplWhereBound
341
+ | GoalSource :: InstantiateHigherRanked
342
+ ) && match self . consider_ambiguities {
343
+ true => {
344
+ matches ! (
345
+ nested_goal. result( ) ,
346
+ Ok ( Certainty :: Maybe ( MaybeCause :: Ambiguity ) )
347
+ )
348
+ }
349
+ false => matches ! ( nested_goal. result( ) , Err ( _) ) ,
350
+ }
351
+ } ,
352
+ )
353
+ } )
354
+ } ) ;
355
+ }
356
+ }
343
357
}
344
358
345
359
candidates
@@ -404,7 +418,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
404
418
405
419
// Skip nested goals that aren't the *reason* for our goal's failure.
406
420
match self . consider_ambiguities {
407
- true if matches ! ( nested_goal. result( ) , Ok ( Certainty :: Maybe ( _) ) ) => { }
421
+ true if matches ! (
422
+ nested_goal. result( ) ,
423
+ Ok ( Certainty :: Maybe ( MaybeCause :: Ambiguity ) )
424
+ ) => { }
408
425
false if matches ! ( nested_goal. result( ) , Err ( _) ) => { }
409
426
_ => continue ,
410
427
}
0 commit comments