@@ -6,15 +6,89 @@ use rustc_data_structures::{
6
6
stable_set:: FxHashSet ,
7
7
} ;
8
8
use rustc_middle:: traits;
9
- use rustc_middle:: ty:: { self , ToPredicate , Ty , WithConstness } ;
9
+ use rustc_middle:: ty:: { self , ToPredicate , Ty } ;
10
10
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
11
11
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
+ }
12
24
impl < ' tcx > FnCtxt < ' _ , ' tcx > {
13
25
/// Performs type inference fallback, returning true if any fallback
14
26
/// occurs.
15
27
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
+
16
84
// All type checking constraints were added, try to fallback unsolved variables.
17
85
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
+
18
92
let mut fallback_has_occurred = false ;
19
93
20
94
// Check if we have any unsolved varibales. If not, no need for fallback.
@@ -23,7 +97,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
23
97
return ;
24
98
}
25
99
26
- let diverging_fallback = self . calculate_diverging_fallback ( & unsolved_variables) ;
100
+ let diverging_fallback =
101
+ self . calculate_diverging_fallback ( & unsolved_variables, & relationships) ;
27
102
28
103
// We do fallback in two passes, to try to generate
29
104
// better error messages.
@@ -249,6 +324,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
249
324
fn calculate_diverging_fallback (
250
325
& self ,
251
326
unsolved_variables : & [ Ty < ' tcx > ] ,
327
+ relationships : & FxHashMap < ty:: TyVid , FoundRelationships > ,
252
328
) -> FxHashMap < Ty < ' tcx > , Ty < ' tcx > > {
253
329
debug ! ( "calculate_diverging_fallback({:?})" , unsolved_variables) ;
254
330
@@ -335,68 +411,27 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
335
411
roots_reachable_from_non_diverging,
336
412
) ;
337
413
414
+ debug ! ( "inherited: {:#?}" , self . inh. fulfillment_cx. borrow_mut( ) . pending_obligations( ) ) ;
415
+ debug ! ( "obligations: {:#?}" , self . fulfillment_cx. borrow_mut( ) . pending_obligations( ) ) ;
416
+
338
417
// For each diverging variable, figure out whether it can
339
418
// reach a member of N. If so, it falls back to `()`. Else
340
419
// `!`.
341
420
let mut diverging_fallback = FxHashMap :: default ( ) ;
342
421
diverging_fallback. reserve ( diverging_vids. len ( ) ) ;
343
- ' outer : for & diverging_vid in & diverging_vids {
422
+ for & diverging_vid in & diverging_vids {
344
423
let diverging_ty = self . tcx . mk_ty_var ( diverging_vid) ;
345
424
let root_vid = self . infcx . root_var ( diverging_vid) ;
346
425
let can_reach_non_diverging = coercion_graph
347
426
. depth_first_search ( root_vid)
348
427
. any ( |n| roots_reachable_from_non_diverging. visited ( n) ) ;
349
428
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 ( ) ;
398
430
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 {
400
435
debug ! ( "fallback to () - reached non-diverging: {:?}" , diverging_vid) ;
401
436
diverging_fallback. insert ( diverging_ty, self . tcx . types . unit ) ;
402
437
} else {
@@ -425,6 +460,15 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
425
460
let a_vid = self . root_vid ( a) ?;
426
461
let b_vid = self . root_vid ( b) ?;
427
462
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) )
428
472
} else {
429
473
None
430
474
}
@@ -436,7 +480,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
436
480
}
437
481
438
482
/// 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 > {
440
484
Some ( self . infcx . root_var ( self . infcx . shallow_resolve ( ty) . ty_vid ( ) ?) )
441
485
}
442
486
}
0 commit comments