1
+ use crate :: rustc_middle:: ty:: TypeVisitableExt ;
1
2
use crate :: FnCtxt ;
2
3
use rustc_infer:: traits:: solve:: Goal ;
3
4
use rustc_infer:: traits:: { self , ObligationCause } ;
@@ -31,10 +32,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
31
32
) -> bool {
32
33
match predicate. kind ( ) . skip_binder ( ) {
33
34
ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( data) ) => {
34
- self . self_type_matches_expected_vid ( data. self_ty ( ) , expected_vid )
35
+ self . type_matches_expected_vid ( expected_vid , data. self_ty ( ) )
35
36
}
36
37
ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( data) ) => {
37
- self . self_type_matches_expected_vid ( data. projection_ty . self_ty ( ) , expected_vid )
38
+ self . type_matches_expected_vid ( expected_vid , data. projection_ty . self_ty ( ) )
38
39
}
39
40
ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType ( ..) )
40
41
| ty:: PredicateKind :: Subtype ( ..)
@@ -52,11 +53,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
52
53
}
53
54
54
55
#[ instrument( level = "debug" , skip( self ) , ret) ]
55
- fn self_type_matches_expected_vid ( & self , self_ty : Ty < ' tcx > , expected_vid : ty:: TyVid ) -> bool {
56
- let self_ty = self . shallow_resolve ( self_ty ) ;
57
- debug ! ( ?self_ty ) ;
56
+ fn type_matches_expected_vid ( & self , expected_vid : ty:: TyVid , ty : Ty < ' tcx > ) -> bool {
57
+ let ty = self . shallow_resolve ( ty ) ;
58
+ debug ! ( ?ty ) ;
58
59
59
- match * self_ty . kind ( ) {
60
+ match * ty . kind ( ) {
60
61
ty:: Infer ( ty:: TyVar ( found_vid) ) => expected_vid == self . root_var ( found_vid) ,
61
62
_ => false ,
62
63
}
@@ -67,6 +68,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
67
68
self_ty : ty:: TyVid ,
68
69
) -> Vec < traits:: PredicateObligation < ' tcx > > {
69
70
let obligations = self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ;
71
+ debug ! ( ?obligations) ;
70
72
let mut obligations_for_self_ty = vec ! [ ] ;
71
73
for obligation in obligations {
72
74
let mut visitor = NestedObligationsForSelfTy {
@@ -79,6 +81,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
79
81
let goal = Goal :: new ( self . tcx , obligation. param_env , obligation. predicate ) ;
80
82
self . visit_proof_tree ( goal, & mut visitor) ;
81
83
}
84
+
85
+ obligations_for_self_ty. retain_mut ( |obligation| {
86
+ obligation. predicate = self . resolve_vars_if_possible ( obligation. predicate ) ;
87
+ !obligation. predicate . has_placeholders ( )
88
+ } ) ;
82
89
obligations_for_self_ty
83
90
}
84
91
}
@@ -90,26 +97,65 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
90
97
obligations_for_self_ty : & ' a mut Vec < traits:: PredicateObligation < ' tcx > > ,
91
98
}
92
99
100
+ impl < ' a , ' tcx > NestedObligationsForSelfTy < ' a , ' tcx > {
101
+ fn consider_goal ( & mut self , goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ) {
102
+ if self . fcx . predicate_has_self_ty ( goal. predicate , self . ty_var_root ) {
103
+ self . obligations_for_self_ty . push ( traits:: Obligation :: new (
104
+ self . fcx . tcx ,
105
+ self . root_cause . clone ( ) ,
106
+ goal. param_env ,
107
+ goal. predicate ,
108
+ ) ) ;
109
+ }
110
+ }
111
+ }
112
+
93
113
impl < ' a , ' tcx > ProofTreeVisitor < ' tcx > for NestedObligationsForSelfTy < ' a , ' tcx > {
94
114
type Result = ( ) ;
95
115
96
116
fn config ( & self ) -> InspectConfig {
97
117
// Using an intentionally low depth to minimize the chance of future
98
118
// breaking changes in case we adapt the approach later on. This also
99
119
// avoids any hangs for exponentially growing proof trees.
100
- InspectConfig { max_depth : 3 }
120
+ InspectConfig { max_depth : 5 }
101
121
}
102
122
103
123
fn visit_goal ( & mut self , inspect_goal : & InspectGoal < ' _ , ' tcx > ) {
104
124
let tcx = self . fcx . tcx ;
105
125
let goal = inspect_goal. goal ( ) ;
106
- if self . fcx . predicate_has_self_ty ( goal. predicate , self . ty_var_root ) {
107
- self . obligations_for_self_ty . push ( traits:: Obligation :: new (
108
- tcx,
109
- self . root_cause . clone ( ) ,
110
- goal. param_env ,
111
- goal. predicate ,
112
- ) ) ;
126
+ self . consider_goal ( goal) ;
127
+
128
+ // HACK: When proving `NormalizesTo(oapque; ?infer)` we don't emit the
129
+ // item bounds of the opaque as nested goals, so they never get picked up here.
130
+ // Manually add these as obligations instead.
131
+ //
132
+ // Alternatively, we could change the solver to always emit the item bounds
133
+ // as nested goals, even if the hidden type is an infer var. However, given that
134
+ // these nested goals would always just fail with ambiguity, that would be
135
+ // useless for everything apart from this exact `ProofTreeVisitor`, so we
136
+ // do it here.
137
+ match goal. predicate . kind ( ) . no_bound_vars ( ) {
138
+ Some ( ty:: PredicateKind :: NormalizesTo ( ty:: NormalizesTo { alias, term } ) ) => {
139
+ if alias. is_opaque ( tcx) {
140
+ let hidden_ty = term. ty ( ) . unwrap ( ) ;
141
+ if self . fcx . type_matches_expected_vid ( self . ty_var_root , hidden_ty) {
142
+ let mut obligations = vec ! [ ] ;
143
+ self . fcx . add_item_bounds_for_hidden_type (
144
+ alias. def_id ,
145
+ alias. args ,
146
+ self . root_cause . clone ( ) ,
147
+ goal. param_env ,
148
+ hidden_ty,
149
+ & mut obligations,
150
+ ) ;
151
+ debug ! ( ?obligations) ;
152
+ for obl in obligations {
153
+ self . consider_goal ( obl. into ( ) ) ;
154
+ }
155
+ }
156
+ }
157
+ }
158
+ Some ( _) | None => { }
113
159
}
114
160
115
161
if let Some ( candidate) = inspect_goal. unique_applicable_candidate ( ) {
0 commit comments