@@ -5,7 +5,9 @@ use rustc_data_structures::{
5
5
graph:: { iterate:: DepthFirstSearch , vec_graph:: VecGraph } ,
6
6
stable_set:: FxHashSet ,
7
7
} ;
8
- use rustc_middle:: ty:: { self , Ty } ;
8
+ use rustc_middle:: traits;
9
+ use rustc_middle:: ty:: { self , ToPredicate , Ty , WithConstness } ;
10
+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
9
11
10
12
impl < ' tcx > FnCtxt < ' _ , ' tcx > {
11
13
/// Performs type inference fallback, returning true if any fallback
@@ -337,17 +339,68 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
337
339
// reach a member of N. If so, it falls back to `()`. Else
338
340
// `!`.
339
341
let mut diverging_fallback = FxHashMap :: default ( ) ;
340
- for & diverging_vid in & diverging_vids {
342
+ diverging_fallback. reserve ( diverging_vids. len ( ) ) ;
343
+ ' outer: for & diverging_vid in & diverging_vids {
341
344
let diverging_ty = self . tcx . mk_ty_var ( diverging_vid) ;
342
345
let root_vid = self . infcx . root_var ( diverging_vid) ;
343
346
let can_reach_non_diverging = coercion_graph
344
347
. depth_first_search ( root_vid)
345
348
. any ( |n| roots_reachable_from_non_diverging. visited ( n) ) ;
349
+
350
+ for obligation in self . fulfillment_cx . borrow_mut ( ) . pending_obligations ( ) {
351
+ // We need to check if this obligation is a trait bound like
352
+ // `root_vid: Foo`, and then we check:
353
+ //
354
+ // If `(): Foo` may hold, then fallback to (),
355
+ // otherwise continue on.
356
+ if let ty:: PredicateKind :: Trait ( predicate, constness) =
357
+ obligation. predicate . kind ( ) . skip_binder ( )
358
+ {
359
+ if predicate. trait_ref . def_id
360
+ == self . infcx . tcx . require_lang_item ( rustc_hir:: LangItem :: Sized , None )
361
+ {
362
+ // Skip sized obligations, those are not usually
363
+ // 'intentional', satisfied by both ! and () though.
364
+ continue ;
365
+ }
366
+
367
+ // If this trait bound is on the current root_vid...
368
+ if self . root_vid ( predicate. self_ty ( ) ) == Some ( root_vid) {
369
+ // fixme: copy of mk_trait_obligation_with_new_self_ty
370
+ let new_self_ty = self . infcx . tcx . types . unit ;
371
+
372
+ let trait_ref = ty:: TraitRef {
373
+ substs : self
374
+ . infcx
375
+ . tcx
376
+ . mk_substs_trait ( new_self_ty, & predicate. trait_ref . substs [ 1 ..] ) ,
377
+ ..predicate. trait_ref
378
+ } ;
379
+
380
+ // Then contstruct a new obligation with Self = () added
381
+ // to the ParamEnv, and see if it holds.
382
+ let o = rustc_infer:: traits:: Obligation :: new (
383
+ traits:: ObligationCause :: dummy ( ) ,
384
+ obligation. param_env ,
385
+ // FIXME: this drops the binder on the floor that
386
+ // previously existed?
387
+ trait_ref. with_constness ( constness) . to_predicate ( self . infcx . tcx ) ,
388
+ ) ;
389
+ if self . infcx . predicate_may_hold ( & o) {
390
+ // If we might hold for (), then fallback to ().
391
+ debug ! ( "fallback to () as {:?} may hold: {:?}" , o, diverging_vid) ;
392
+ diverging_fallback. insert ( diverging_ty, self . tcx . types . unit ) ;
393
+ continue ' outer;
394
+ }
395
+ }
396
+ }
397
+ }
398
+
346
399
if can_reach_non_diverging {
347
- debug ! ( "fallback to (): {:?}" , diverging_vid) ;
400
+ debug ! ( "fallback to () - reached non-diverging : {:?}" , diverging_vid) ;
348
401
diverging_fallback. insert ( diverging_ty, self . tcx . types . unit ) ;
349
402
} else {
350
- debug ! ( "fallback to !: {:?}" , diverging_vid) ;
403
+ debug ! ( "fallback to ! - all diverging : {:?}" , diverging_vid) ;
351
404
diverging_fallback. insert ( diverging_ty, self . tcx . mk_diverging_default ( ) ) ;
352
405
}
353
406
}
0 commit comments