@@ -6,15 +6,89 @@ use rustc_data_structures::{
66 stable_set:: FxHashSet ,
77} ;
88use rustc_middle:: traits;
9- use rustc_middle:: ty:: { self , ToPredicate , Ty , WithConstness } ;
9+ use rustc_middle:: ty:: { self , ToPredicate , Ty } ;
1010use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
1111
12+ #[ derive( Default , Copy , Clone ) ]
13+ struct FoundRelationships {
14+ /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo`
15+ /// obligation, where:
16+ ///
17+ /// * `Foo` is not `Sized`
18+ /// * `(): Foo` may be satisfied
19+ self_in_trait : bool ,
20+ /// This is true if we identified that this Ty (`?T`) is found in a `<_ as
21+ /// _>::AssocType = ?T`
22+ output : bool ,
23+ }
1224impl < ' tcx > FnCtxt < ' _ , ' tcx > {
1325 /// Performs type inference fallback, returning true if any fallback
1426 /// occurs.
1527 pub ( super ) fn type_inference_fallback ( & self ) -> bool {
28+ debug ! (
29+ "type-inference-fallback start obligations: {:#?}" ,
30+ self . fulfillment_cx. borrow_mut( ) . pending_obligations( )
31+ ) ;
32+
33+ let mut relationships: FxHashMap < ty:: TyVid , FoundRelationships > = FxHashMap :: default ( ) ;
34+ for obligation in self . fulfillment_cx . borrow_mut ( ) . pending_obligations ( ) {
35+ if let ty:: PredicateKind :: Trait ( predicate, constness) =
36+ obligation. predicate . kind ( ) . skip_binder ( )
37+ {
38+ if predicate. trait_ref . def_id
39+ != self . infcx . tcx . require_lang_item ( rustc_hir:: LangItem :: Sized , None )
40+ {
41+ // fixme: copy of mk_trait_obligation_with_new_self_ty
42+ let new_self_ty = self . infcx . tcx . types . unit ;
43+
44+ let trait_ref = ty:: TraitRef {
45+ substs : self
46+ . infcx
47+ . tcx
48+ . mk_substs_trait ( new_self_ty, & predicate. trait_ref . substs [ 1 ..] ) ,
49+ ..predicate. trait_ref
50+ } ;
51+
52+ // Then contstruct a new obligation with Self = () added
53+ // to the ParamEnv, and see if it holds.
54+ let o = rustc_infer:: traits:: Obligation :: new (
55+ traits:: ObligationCause :: dummy ( ) ,
56+ obligation. param_env ,
57+ obligation
58+ . predicate
59+ . kind ( )
60+ . map_bound ( |_| {
61+ ty:: PredicateKind :: Trait (
62+ ty:: TraitPredicate { trait_ref } ,
63+ constness,
64+ )
65+ } )
66+ . to_predicate ( self . infcx . tcx ) ,
67+ ) ;
68+ if self . infcx . predicate_may_hold ( & o) {
69+ if let Some ( ty) = self . root_vid ( predicate. self_ty ( ) ) {
70+ relationships. entry ( ty) . or_default ( ) . self_in_trait = true ;
71+ }
72+ }
73+ }
74+ }
75+ if let ty:: PredicateKind :: Projection ( predicate) =
76+ obligation. predicate . kind ( ) . skip_binder ( )
77+ {
78+ if let Some ( ty) = self . root_vid ( predicate. ty ) {
79+ relationships. entry ( ty) . or_default ( ) . output = true ;
80+ }
81+ }
82+ }
83+
1684 // All type checking constraints were added, try to fallback unsolved variables.
1785 self . select_obligations_where_possible ( false , |_| { } ) ;
86+
87+ debug ! (
88+ "type-inference-fallback post selection obligations: {:#?}" ,
89+ self . fulfillment_cx. borrow_mut( ) . pending_obligations( )
90+ ) ;
91+
1892 let mut fallback_has_occurred = false ;
1993
2094 // Check if we have any unsolved varibales. If not, no need for fallback.
@@ -23,7 +97,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
2397 return ;
2498 }
2599
26- let diverging_fallback = self . calculate_diverging_fallback ( & unsolved_variables) ;
100+ let diverging_fallback =
101+ self . calculate_diverging_fallback ( & unsolved_variables, & relationships) ;
27102
28103 // We do fallback in two passes, to try to generate
29104 // better error messages.
@@ -249,6 +324,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
249324 fn calculate_diverging_fallback (
250325 & self ,
251326 unsolved_variables : & [ Ty < ' tcx > ] ,
327+ relationships : & FxHashMap < ty:: TyVid , FoundRelationships > ,
252328 ) -> FxHashMap < Ty < ' tcx > , Ty < ' tcx > > {
253329 debug ! ( "calculate_diverging_fallback({:?})" , unsolved_variables) ;
254330
@@ -335,68 +411,27 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
335411 roots_reachable_from_non_diverging,
336412 ) ;
337413
414+ debug ! ( "inherited: {:#?}" , self . inh. fulfillment_cx. borrow_mut( ) . pending_obligations( ) ) ;
415+ debug ! ( "obligations: {:#?}" , self . fulfillment_cx. borrow_mut( ) . pending_obligations( ) ) ;
416+
338417 // For each diverging variable, figure out whether it can
339418 // reach a member of N. If so, it falls back to `()`. Else
340419 // `!`.
341420 let mut diverging_fallback = FxHashMap :: default ( ) ;
342421 diverging_fallback. reserve ( diverging_vids. len ( ) ) ;
343- ' outer : for & diverging_vid in & diverging_vids {
422+ for & diverging_vid in & diverging_vids {
344423 let diverging_ty = self . tcx . mk_ty_var ( diverging_vid) ;
345424 let root_vid = self . infcx . root_var ( diverging_vid) ;
346425 let can_reach_non_diverging = coercion_graph
347426 . depth_first_search ( root_vid)
348427 . any ( |n| roots_reachable_from_non_diverging. visited ( n) ) ;
349428
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- }
429+ let relationship = relationships. get ( & root_vid) . copied ( ) . unwrap_or_default ( ) ;
398430
399- if can_reach_non_diverging {
431+ if relationship. self_in_trait && relationship. output {
432+ debug ! ( "fallback to () - found trait and projection: {:?}" , diverging_vid) ;
433+ diverging_fallback. insert ( diverging_ty, self . tcx . types . unit ) ;
434+ } else if can_reach_non_diverging {
400435 debug ! ( "fallback to () - reached non-diverging: {:?}" , diverging_vid) ;
401436 diverging_fallback. insert ( diverging_ty, self . tcx . types . unit ) ;
402437 } else {
@@ -425,6 +460,15 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
425460 let a_vid = self . root_vid ( a) ?;
426461 let b_vid = self . root_vid ( b) ?;
427462 Some ( ( a_vid, b_vid) )
463+ } else if let ty:: PredicateKind :: Subtype ( ty:: SubtypePredicate {
464+ a_is_expected : _,
465+ a,
466+ b,
467+ } ) = atom
468+ {
469+ let a_vid = self . root_vid ( a) ?;
470+ let b_vid = self . root_vid ( b) ?;
471+ Some ( ( a_vid, b_vid) )
428472 } else {
429473 None
430474 }
@@ -436,7 +480,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
436480 }
437481
438482 /// If `ty` is an unresolved type variable, returns its root vid.
439- fn root_vid ( & self , ty : Ty < ' tcx > ) -> Option < ty:: TyVid > {
483+ pub fn root_vid ( & self , ty : Ty < ' tcx > ) -> Option < ty:: TyVid > {
440484 Some ( self . infcx . root_var ( self . infcx . shallow_resolve ( ty) . ty_vid ( ) ?) )
441485 }
442486}
0 commit comments