@@ -5,7 +5,9 @@ use rustc_data_structures::{
55 graph:: { iterate:: DepthFirstSearch , vec_graph:: VecGraph } ,
66 stable_set:: FxHashSet ,
77} ;
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 ;
911
1012impl < ' tcx > FnCtxt < ' _ , ' tcx > {
1113 /// Performs type inference fallback, returning true if any fallback
@@ -337,17 +339,68 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
337339 // reach a member of N. If so, it falls back to `()`. Else
338340 // `!`.
339341 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 {
341344 let diverging_ty = self . tcx . mk_ty_var ( diverging_vid) ;
342345 let root_vid = self . infcx . root_var ( diverging_vid) ;
343346 let can_reach_non_diverging = coercion_graph
344347 . depth_first_search ( root_vid)
345348 . 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+
346399 if can_reach_non_diverging {
347- debug ! ( "fallback to (): {:?}" , diverging_vid) ;
400+ debug ! ( "fallback to () - reached non-diverging : {:?}" , diverging_vid) ;
348401 diverging_fallback. insert ( diverging_ty, self . tcx . types . unit ) ;
349402 } else {
350- debug ! ( "fallback to !: {:?}" , diverging_vid) ;
403+ debug ! ( "fallback to ! - all diverging : {:?}" , diverging_vid) ;
351404 diverging_fallback. insert ( diverging_ty, self . tcx . mk_diverging_default ( ) ) ;
352405 }
353406 }
0 commit comments