1
+ //! A utility module to inspect currently ambiguous obligations in the current context.
2
+ use crate :: rustc_middle:: ty:: TypeVisitableExt ;
1
3
use crate :: FnCtxt ;
4
+ use rustc_infer:: traits:: solve:: Goal ;
5
+ use rustc_infer:: traits:: { self , ObligationCause } ;
2
6
use rustc_middle:: ty:: { self , Ty } ;
3
- use rustc_infer:: traits;
4
- use rustc_data_structures:: captures:: Captures ;
7
+ use rustc_span:: Span ;
8
+ use rustc_trait_selection:: solve:: inspect:: ProofTreeInferCtxtExt ;
9
+ use rustc_trait_selection:: solve:: inspect:: { InspectConfig , InspectGoal , ProofTreeVisitor } ;
5
10
6
11
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
12
+ /// Returns a list of all obligations whose self type has been unified
13
+ /// with the unconstrained type `self_ty`.
7
14
#[ instrument( skip( self ) , level = "debug" ) ]
8
- pub ( crate ) fn obligations_for_self_ty < ' b > (
9
- & ' b self ,
15
+ pub ( crate ) fn obligations_for_self_ty (
16
+ & self ,
10
17
self_ty : ty:: TyVid ,
11
- ) -> impl DoubleEndedIterator < Item = traits:: PredicateObligation < ' tcx > > + Captures < ' tcx > + ' b
12
- {
13
- let ty_var_root = self . root_var ( self_ty) ;
14
- trace ! ( "pending_obligations = {:#?}" , self . fulfillment_cx. borrow( ) . pending_obligations( ) ) ;
15
-
16
- self . fulfillment_cx . borrow ( ) . pending_obligations ( ) . into_iter ( ) . filter_map (
17
- move |obligation| match & obligation. predicate . kind ( ) . skip_binder ( ) {
18
- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( data) )
19
- if self . self_type_matches_expected_vid (
20
- data. projection_ty . self_ty ( ) ,
21
- ty_var_root,
22
- ) =>
23
- {
24
- Some ( obligation)
25
- }
26
- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( data) )
27
- if self . self_type_matches_expected_vid ( data. self_ty ( ) , ty_var_root) =>
28
- {
29
- Some ( obligation)
30
- }
18
+ ) -> Vec < traits:: PredicateObligation < ' tcx > > {
19
+ if self . next_trait_solver ( ) {
20
+ self . obligations_for_self_ty_next ( self_ty)
21
+ } else {
22
+ let ty_var_root = self . root_var ( self_ty) ;
23
+ let mut obligations = self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ;
24
+ trace ! ( "pending_obligations = {:#?}" , obligations) ;
25
+ obligations
26
+ . retain ( |obligation| self . predicate_has_self_ty ( obligation. predicate , ty_var_root) ) ;
27
+ obligations
28
+ }
29
+ }
31
30
32
- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( ..) )
33
- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( ..) )
34
- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType ( ..) )
35
- | ty:: PredicateKind :: Subtype ( ..)
36
- | ty:: PredicateKind :: Coerce ( ..)
37
- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: RegionOutlives ( ..) )
38
- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: TypeOutlives ( ..) )
39
- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: WellFormed ( ..) )
40
- | ty:: PredicateKind :: ObjectSafe ( ..)
41
- | ty:: PredicateKind :: NormalizesTo ( ..)
42
- | ty:: PredicateKind :: AliasRelate ( ..)
43
- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstEvaluatable ( ..) )
44
- | ty:: PredicateKind :: ConstEquate ( ..)
45
- | ty:: PredicateKind :: Ambiguous => None ,
46
- } ,
47
- )
31
+ #[ instrument( level = "debug" , skip( self ) , ret) ]
32
+ fn predicate_has_self_ty (
33
+ & self ,
34
+ predicate : ty:: Predicate < ' tcx > ,
35
+ expected_vid : ty:: TyVid ,
36
+ ) -> bool {
37
+ match predicate. kind ( ) . skip_binder ( ) {
38
+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( data) ) => {
39
+ self . type_matches_expected_vid ( expected_vid, data. self_ty ( ) )
40
+ }
41
+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( data) ) => {
42
+ self . type_matches_expected_vid ( expected_vid, data. projection_ty . self_ty ( ) )
43
+ }
44
+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType ( ..) )
45
+ | ty:: PredicateKind :: Subtype ( ..)
46
+ | ty:: PredicateKind :: Coerce ( ..)
47
+ | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: RegionOutlives ( ..) )
48
+ | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: TypeOutlives ( ..) )
49
+ | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: WellFormed ( ..) )
50
+ | ty:: PredicateKind :: ObjectSafe ( ..)
51
+ | ty:: PredicateKind :: NormalizesTo ( ..)
52
+ | ty:: PredicateKind :: AliasRelate ( ..)
53
+ | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstEvaluatable ( ..) )
54
+ | ty:: PredicateKind :: ConstEquate ( ..)
55
+ | ty:: PredicateKind :: Ambiguous => false ,
56
+ }
48
57
}
49
58
50
59
#[ instrument( level = "debug" , skip( self ) , ret) ]
51
- fn self_type_matches_expected_vid ( & self , self_ty : Ty < ' tcx > , expected_vid : ty:: TyVid ) -> bool {
52
- let self_ty = self . shallow_resolve ( self_ty ) ;
53
- debug ! ( ?self_ty ) ;
60
+ fn type_matches_expected_vid ( & self , expected_vid : ty:: TyVid , ty : Ty < ' tcx > ) -> bool {
61
+ let ty = self . shallow_resolve ( ty ) ;
62
+ debug ! ( ?ty ) ;
54
63
55
- match * self_ty . kind ( ) {
64
+ match * ty . kind ( ) {
56
65
ty:: Infer ( ty:: TyVar ( found_vid) ) => {
57
- let found_vid = self . root_var ( found_vid) ;
58
- debug ! ( "self_type_matches_expected_vid - found_vid={:?}" , found_vid) ;
59
- expected_vid == found_vid
66
+ self . root_var ( expected_vid) == self . root_var ( found_vid)
60
67
}
61
68
_ => false ,
62
69
}
63
70
}
64
- }
71
+
72
+ pub ( crate ) fn obligations_for_self_ty_next (
73
+ & self ,
74
+ self_ty : ty:: TyVid ,
75
+ ) -> Vec < traits:: PredicateObligation < ' tcx > > {
76
+ let obligations = self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ;
77
+ debug ! ( ?obligations) ;
78
+ let mut obligations_for_self_ty = vec ! [ ] ;
79
+ for obligation in obligations {
80
+ let mut visitor = NestedObligationsForSelfTy {
81
+ fcx : self ,
82
+ self_ty,
83
+ obligations_for_self_ty : & mut obligations_for_self_ty,
84
+ root_cause : & obligation. cause ,
85
+ } ;
86
+
87
+ let goal = Goal :: new ( self . tcx , obligation. param_env , obligation. predicate ) ;
88
+ self . visit_proof_tree ( goal, & mut visitor) ;
89
+ }
90
+
91
+ obligations_for_self_ty. retain_mut ( |obligation| {
92
+ obligation. predicate = self . resolve_vars_if_possible ( obligation. predicate ) ;
93
+ !obligation. predicate . has_placeholders ( )
94
+ } ) ;
95
+ obligations_for_self_ty
96
+ }
97
+ }
98
+
99
+ struct NestedObligationsForSelfTy < ' a , ' tcx > {
100
+ fcx : & ' a FnCtxt < ' a , ' tcx > ,
101
+ self_ty : ty:: TyVid ,
102
+ root_cause : & ' a ObligationCause < ' tcx > ,
103
+ obligations_for_self_ty : & ' a mut Vec < traits:: PredicateObligation < ' tcx > > ,
104
+ }
105
+
106
+ impl < ' a , ' tcx > ProofTreeVisitor < ' tcx > for NestedObligationsForSelfTy < ' a , ' tcx > {
107
+ type Result = ( ) ;
108
+
109
+ fn span ( & self ) -> Span {
110
+ self . root_cause . span
111
+ }
112
+
113
+ fn config ( & self ) -> InspectConfig {
114
+ // Using an intentionally low depth to minimize the chance of future
115
+ // breaking changes in case we adapt the approach later on. This also
116
+ // avoids any hangs for exponentially growing proof trees.
117
+ InspectConfig { max_depth : 5 }
118
+ }
119
+
120
+ fn visit_goal ( & mut self , inspect_goal : & InspectGoal < ' _ , ' tcx > ) {
121
+ let tcx = self . fcx . tcx ;
122
+ let goal = inspect_goal. goal ( ) ;
123
+ if self . fcx . predicate_has_self_ty ( goal. predicate , self . self_ty ) {
124
+ self . obligations_for_self_ty . push ( traits:: Obligation :: new (
125
+ tcx,
126
+ self . root_cause . clone ( ) ,
127
+ goal. param_env ,
128
+ goal. predicate ,
129
+ ) ) ;
130
+ }
131
+
132
+ // If there's a unique way to prove a given goal, recurse into
133
+ // that candidate. This means that for `impl<F: FnOnce(u32)> Trait<F> for () {}`
134
+ // and a `(): Trait<?0>` goal we recurse into the impl and look at
135
+ // the nested `?0: FnOnce(u32)` goal.
136
+ if let Some ( candidate) = inspect_goal. unique_applicable_candidate ( ) {
137
+ candidate. visit_nested_no_probe ( self )
138
+ }
139
+ }
140
+ }
0 commit comments