1
1
use rustc_hir as hir;
2
- use rustc_infer:: infer:: { BoundRegionConversionTime , DefineOpaqueTypes , InferCtxt } ;
2
+ use rustc_infer:: infer:: { BoundRegionConversionTime , DefineOpaqueTypes } ;
3
3
use rustc_infer:: traits:: { ImplSource , Obligation , PredicateObligation } ;
4
4
use rustc_middle:: span_bug;
5
5
use rustc_middle:: ty:: fast_reject:: DeepRejectCtxt ;
6
6
use rustc_middle:: ty:: { self , TypingMode } ;
7
+ use rustc_type_ir:: elaborate:: elaborate;
7
8
use rustc_type_ir:: solve:: NoSolution ;
8
- use thin_vec:: ThinVec ;
9
+ use thin_vec:: { ThinVec , thin_vec } ;
9
10
10
11
use super :: SelectionContext ;
12
+ use super :: normalize:: normalize_with_depth_to;
11
13
12
14
pub type HostEffectObligation < ' tcx > = Obligation < ' tcx , ty:: HostEffectPredicate < ' tcx > > ;
13
15
@@ -38,6 +40,12 @@ pub fn evaluate_host_effect_obligation<'tcx>(
38
40
Err ( EvaluationFailure :: NoSolution ) => { }
39
41
}
40
42
43
+ match evaluate_host_effect_from_item_bounds ( selcx, obligation) {
44
+ Ok ( result) => return Ok ( result) ,
45
+ Err ( EvaluationFailure :: Ambiguous ) => return Err ( EvaluationFailure :: Ambiguous ) ,
46
+ Err ( EvaluationFailure :: NoSolution ) => { }
47
+ }
48
+
41
49
match evaluate_host_effect_from_selection_candiate ( selcx, obligation) {
42
50
Ok ( result) => return Ok ( result) ,
43
51
Err ( EvaluationFailure :: Ambiguous ) => return Err ( EvaluationFailure :: Ambiguous ) ,
@@ -48,24 +56,45 @@ pub fn evaluate_host_effect_obligation<'tcx>(
48
56
}
49
57
50
58
fn match_candidate < ' tcx > (
51
- infcx : & InferCtxt < ' tcx > ,
59
+ selcx : & mut SelectionContext < ' _ , ' tcx > ,
52
60
obligation : & HostEffectObligation < ' tcx > ,
53
61
candidate : ty:: Binder < ' tcx , ty:: HostEffectPredicate < ' tcx > > ,
62
+ candidate_is_unnormalized : bool ,
63
+ more_nested : impl FnOnce ( & mut SelectionContext < ' _ , ' tcx > , & mut ThinVec < PredicateObligation < ' tcx > > ) ,
54
64
) -> Result < ThinVec < PredicateObligation < ' tcx > > , NoSolution > {
55
65
if !candidate. skip_binder ( ) . constness . satisfies ( obligation. predicate . constness ) {
56
66
return Err ( NoSolution ) ;
57
67
}
58
68
59
- let candidate = infcx. instantiate_binder_with_fresh_vars (
69
+ let mut candidate = selcx . infcx . instantiate_binder_with_fresh_vars (
60
70
obligation. cause . span ,
61
71
BoundRegionConversionTime :: HigherRankedType ,
62
72
candidate,
63
73
) ;
64
74
65
- let mut nested = infcx
66
- . at ( & obligation. cause , obligation. param_env )
67
- . eq ( DefineOpaqueTypes :: Yes , obligation. predicate . trait_ref , candidate. trait_ref ) ?
68
- . into_obligations ( ) ;
75
+ let mut nested = thin_vec ! [ ] ;
76
+
77
+ // Unlike param-env bounds, item bounds may not be normalized.
78
+ if candidate_is_unnormalized {
79
+ candidate = normalize_with_depth_to (
80
+ selcx,
81
+ obligation. param_env ,
82
+ obligation. cause . clone ( ) ,
83
+ obligation. recursion_depth ,
84
+ candidate,
85
+ & mut nested,
86
+ ) ;
87
+ }
88
+
89
+ nested. extend (
90
+ selcx
91
+ . infcx
92
+ . at ( & obligation. cause , obligation. param_env )
93
+ . eq ( DefineOpaqueTypes :: Yes , obligation. predicate . trait_ref , candidate. trait_ref ) ?
94
+ . into_obligations ( ) ,
95
+ ) ;
96
+
97
+ more_nested ( selcx, & mut nested) ;
69
98
70
99
for nested in & mut nested {
71
100
nested. set_depth_from_parent ( obligation. recursion_depth ) ;
@@ -82,10 +111,70 @@ fn evaluate_host_effect_from_bounds<'tcx>(
82
111
let drcx = DeepRejectCtxt :: relate_rigid_rigid ( selcx. tcx ( ) ) ;
83
112
let mut candidate = None ;
84
113
85
- for predicate in obligation. param_env . caller_bounds ( ) {
86
- let bound_predicate = predicate. kind ( ) ;
87
- if let ty:: ClauseKind :: HostEffect ( data) = predicate. kind ( ) . skip_binder ( ) {
88
- let data = bound_predicate. rebind ( data) ;
114
+ for clause in obligation. param_env . caller_bounds ( ) {
115
+ let bound_clause = clause. kind ( ) ;
116
+ let ty:: ClauseKind :: HostEffect ( data) = bound_clause. skip_binder ( ) else {
117
+ continue ;
118
+ } ;
119
+ let data = bound_clause. rebind ( data) ;
120
+ if data. skip_binder ( ) . trait_ref . def_id != obligation. predicate . trait_ref . def_id {
121
+ continue ;
122
+ }
123
+
124
+ if !drcx
125
+ . args_may_unify ( obligation. predicate . trait_ref . args , data. skip_binder ( ) . trait_ref . args )
126
+ {
127
+ continue ;
128
+ }
129
+
130
+ let is_match =
131
+ infcx. probe ( |_| match_candidate ( selcx, obligation, data, false , |_, _| { } ) . is_ok ( ) ) ;
132
+
133
+ if is_match {
134
+ if candidate. is_some ( ) {
135
+ return Err ( EvaluationFailure :: Ambiguous ) ;
136
+ } else {
137
+ candidate = Some ( data) ;
138
+ }
139
+ }
140
+ }
141
+
142
+ if let Some ( data) = candidate {
143
+ Ok ( match_candidate ( selcx, obligation, data, false , |_, _| { } )
144
+ . expect ( "candidate matched before, so it should match again" ) )
145
+ } else {
146
+ Err ( EvaluationFailure :: NoSolution )
147
+ }
148
+ }
149
+
150
+ fn evaluate_host_effect_from_item_bounds < ' tcx > (
151
+ selcx : & mut SelectionContext < ' _ , ' tcx > ,
152
+ obligation : & HostEffectObligation < ' tcx > ,
153
+ ) -> Result < ThinVec < PredicateObligation < ' tcx > > , EvaluationFailure > {
154
+ let infcx = selcx. infcx ;
155
+ let tcx = infcx. tcx ;
156
+ let drcx = DeepRejectCtxt :: relate_rigid_rigid ( selcx. tcx ( ) ) ;
157
+ let mut candidate = None ;
158
+
159
+ let mut consider_ty = obligation. predicate . self_ty ( ) ;
160
+ while let ty:: Alias ( kind @ ( ty:: Projection | ty:: Opaque ) , alias_ty) = * consider_ty. kind ( ) {
161
+ if kind != ty:: Projection {
162
+ break ;
163
+ }
164
+
165
+ for clause in elaborate (
166
+ tcx,
167
+ tcx. explicit_implied_const_bounds ( alias_ty. def_id )
168
+ . iter_instantiated_copied ( tcx, alias_ty. args )
169
+ . map ( |( trait_ref, _) | {
170
+ trait_ref. to_host_effect_clause ( tcx, obligation. predicate . constness )
171
+ } ) ,
172
+ ) {
173
+ let bound_clause = clause. kind ( ) ;
174
+ let ty:: ClauseKind :: HostEffect ( data) = bound_clause. skip_binder ( ) else {
175
+ unreachable ! ( "should not elaborate non-HostEffect from HostEffect" )
176
+ } ;
177
+ let data = bound_clause. rebind ( data) ;
89
178
if data. skip_binder ( ) . trait_ref . def_id != obligation. predicate . trait_ref . def_id {
90
179
continue ;
91
180
}
@@ -97,21 +186,39 @@ fn evaluate_host_effect_from_bounds<'tcx>(
97
186
continue ;
98
187
}
99
188
100
- let is_match = infcx. probe ( |_| match_candidate ( infcx, obligation, data) . is_ok ( ) ) ;
189
+ let is_match =
190
+ infcx. probe ( |_| match_candidate ( selcx, obligation, data, true , |_, _| { } ) . is_ok ( ) ) ;
101
191
102
192
if is_match {
103
193
if candidate. is_some ( ) {
104
194
return Err ( EvaluationFailure :: Ambiguous ) ;
105
195
} else {
106
- candidate = Some ( data) ;
196
+ candidate = Some ( ( data, alias_ty ) ) ;
107
197
}
108
198
}
109
199
}
200
+
201
+ consider_ty = alias_ty. self_ty ( ) ;
110
202
}
111
203
112
- if let Some ( data) = candidate {
113
- Ok ( match_candidate ( infcx, obligation, data)
114
- . expect ( "candidate matched before, so it should match again" ) )
204
+ if let Some ( ( data, alias_ty) ) = candidate {
205
+ Ok ( match_candidate ( selcx, obligation, data, true , |selcx, nested| {
206
+ // An alias bound only holds if we also check the const conditions
207
+ // of the alias, so we need to register those, too.
208
+ let const_conditions = normalize_with_depth_to (
209
+ selcx,
210
+ obligation. param_env ,
211
+ obligation. cause . clone ( ) ,
212
+ obligation. recursion_depth ,
213
+ tcx. const_conditions ( alias_ty. def_id ) . instantiate ( tcx, alias_ty. args ) ,
214
+ nested,
215
+ ) ;
216
+ nested. extend ( const_conditions. into_iter ( ) . map ( |( trait_ref, _) | {
217
+ obligation
218
+ . with ( tcx, trait_ref. to_host_effect_clause ( tcx, obligation. predicate . constness ) )
219
+ } ) ) ;
220
+ } )
221
+ . expect ( "candidate matched before, so it should match again" ) )
115
222
} else {
116
223
Err ( EvaluationFailure :: NoSolution )
117
224
}
0 commit comments