1
1
use crate :: traits:: { specialization_graph, translate_substs} ;
2
2
3
- use super :: infcx_ext:: InferCtxtExt ;
4
- use super :: {
5
- fixme_instantiate_canonical_query_response, CanonicalGoal , CanonicalResponse , Certainty ,
6
- EvalCtxt , Goal , QueryResult ,
7
- } ;
3
+ use super :: assembly:: { self , AssemblyCtxt } ;
4
+ use super :: { CanonicalGoal , EvalCtxt , Goal , QueryResult } ;
8
5
use rustc_errors:: ErrorGuaranteed ;
9
6
use rustc_hir:: def:: DefKind ;
10
7
use rustc_hir:: def_id:: DefId ;
11
- use rustc_infer:: infer:: canonical:: { CanonicalVarValues , OriginalQueryValues } ;
12
- use rustc_infer:: infer:: { InferCtxt , InferOk , TyCtxtInferExt } ;
8
+ use rustc_infer:: infer:: { InferCtxt , InferOk } ;
13
9
use rustc_infer:: traits:: query:: NoSolution ;
14
10
use rustc_infer:: traits:: specialization_graph:: LeafDef ;
15
11
use rustc_infer:: traits:: { ObligationCause , Reveal } ;
16
- use rustc_middle:: ty;
17
12
use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
18
13
use rustc_middle:: ty:: ProjectionPredicate ;
19
14
use rustc_middle:: ty:: TypeVisitable ;
15
+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
20
16
use rustc_span:: DUMMY_SP ;
21
17
use std:: iter;
22
18
23
- // FIXME: Deduplicate the candidate code between projection and trait goal.
24
-
25
- /// Similar to [super::trait_goals::Candidate] but for `Projection` goals.
26
- #[ derive( Debug , Clone ) ]
27
- struct Candidate < ' tcx > {
28
- source : CandidateSource ,
29
- result : CanonicalResponse < ' tcx > ,
30
- }
31
-
32
19
#[ allow( dead_code) ] // FIXME: implement and use all variants.
33
20
#[ derive( Debug , Clone , Copy ) ]
34
- enum CandidateSource {
21
+ pub ( super ) enum CandidateSource {
35
22
Impl ( DefId ) ,
36
23
ParamEnv ( usize ) ,
37
24
Builtin ,
38
25
}
39
26
27
+ type Candidate < ' tcx > = assembly:: Candidate < ' tcx , ProjectionPredicate < ' tcx > > ;
28
+
40
29
impl < ' tcx > EvalCtxt < ' tcx > {
41
30
pub ( super ) fn compute_projection_goal (
42
31
& mut self ,
43
32
goal : CanonicalGoal < ' tcx , ProjectionPredicate < ' tcx > > ,
44
33
) -> QueryResult < ' tcx > {
45
- let candidates = self . assemble_and_evaluate_project_candidates ( goal) ;
34
+ let candidates = AssemblyCtxt :: assemble_and_evaluate_candidates ( self , goal) ;
46
35
self . merge_project_candidates ( candidates)
47
36
}
48
37
49
- fn assemble_and_evaluate_project_candidates (
50
- & mut self ,
51
- goal : CanonicalGoal < ' tcx , ProjectionPredicate < ' tcx > > ,
52
- ) -> Vec < Candidate < ' tcx > > {
53
- let ( ref infcx, goal, var_values) =
54
- self . tcx . infer_ctxt ( ) . build_with_canonical ( DUMMY_SP , & goal) ;
55
- let mut acx = AssemblyCtxt { cx : self , infcx, var_values, candidates : Vec :: new ( ) } ;
56
-
57
- acx. assemble_candidates_after_normalizing_self_ty ( goal) ;
58
- acx. assemble_impl_candidates ( goal) ;
59
- acx. candidates
60
- }
61
-
62
38
fn merge_project_candidates (
63
39
& mut self ,
64
40
mut candidates : Vec < Candidate < ' tcx > > ,
@@ -112,83 +88,27 @@ impl<'tcx> EvalCtxt<'tcx> {
112
88
}
113
89
}
114
90
115
- /// Similar to [super::trait_goals::AssemblyCtxt] but for `Projection` goals.
116
- struct AssemblyCtxt < ' a , ' tcx > {
117
- cx : & ' a mut EvalCtxt < ' tcx > ,
118
- infcx : & ' a InferCtxt < ' tcx > ,
119
- var_values : CanonicalVarValues < ' tcx > ,
120
- candidates : Vec < Candidate < ' tcx > > ,
121
- }
91
+ impl < ' tcx > assembly:: GoalKind < ' tcx > for ProjectionPredicate < ' tcx > {
92
+ type CandidateSource = CandidateSource ;
122
93
123
- impl < ' tcx > AssemblyCtxt < ' _ , ' tcx > {
124
- fn try_insert_candidate ( & mut self , source : CandidateSource , certainty : Certainty ) {
125
- match self . infcx . make_canonical_response ( self . var_values . clone ( ) , certainty) {
126
- Ok ( result) => self . candidates . push ( Candidate { source, result } ) ,
127
- Err ( NoSolution ) => debug ! ( ?source, ?certainty, "failed leakcheck" ) ,
128
- }
94
+ fn self_ty ( self ) -> Ty < ' tcx > {
95
+ self . self_ty ( )
129
96
}
130
97
131
- fn assemble_candidates_after_normalizing_self_ty (
132
- & mut self ,
133
- goal : Goal < ' tcx , ProjectionPredicate < ' tcx > > ,
134
- ) {
135
- let tcx = self . cx . tcx ;
136
- let & ty:: Alias ( ty:: Projection , projection_ty) = goal. predicate . projection_ty . self_ty ( ) . kind ( ) else {
137
- return
138
- } ;
139
- self . infcx . probe ( |_| {
140
- let normalized_ty = self . infcx . next_ty_infer ( ) ;
141
- let normalizes_to_goal = goal. with (
142
- tcx,
143
- ty:: Binder :: dummy ( ty:: ProjectionPredicate {
144
- projection_ty,
145
- term : normalized_ty. into ( ) ,
146
- } ) ,
147
- ) ;
148
- let normalization_certainty =
149
- match self . cx . evaluate_goal ( & self . infcx , normalizes_to_goal) {
150
- Ok ( ( _, certainty) ) => certainty,
151
- Err ( NoSolution ) => return ,
152
- } ;
153
-
154
- // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
155
- // This doesn't work as long as we use `CandidateSource` in both winnowing and to resolve associated items.
156
- let goal = goal. with ( tcx, goal. predicate . with_self_ty ( tcx, normalized_ty) ) ;
157
- let mut orig_values = OriginalQueryValues :: default ( ) ;
158
- let goal = self . infcx . canonicalize_query ( goal, & mut orig_values) ;
159
- let normalized_candidates = self . cx . assemble_and_evaluate_project_candidates ( goal) ;
160
- // Map each candidate from being canonical wrt the current inference context to being
161
- // canonical wrt the caller.
162
- for Candidate { source, result } in normalized_candidates {
163
- self . infcx . probe ( |_| {
164
- let candidate_certainty = fixme_instantiate_canonical_query_response (
165
- self . infcx ,
166
- & orig_values,
167
- result,
168
- ) ;
169
- self . try_insert_candidate (
170
- source,
171
- normalization_certainty. unify_and ( candidate_certainty) ,
172
- )
173
- } )
174
- }
175
- } )
98
+ fn with_self_ty ( self , tcx : TyCtxt < ' tcx > , self_ty : Ty < ' tcx > ) -> Self {
99
+ self . with_self_ty ( tcx, self_ty)
176
100
}
177
101
178
- fn assemble_impl_candidates ( & mut self , goal : Goal < ' tcx , ProjectionPredicate < ' tcx > > ) {
179
- self . cx . tcx . for_each_relevant_impl (
180
- goal. predicate . trait_def_id ( self . cx . tcx ) ,
181
- goal. predicate . self_ty ( ) ,
182
- |impl_def_id| self . consider_impl_candidate ( goal, impl_def_id) ,
183
- ) ;
102
+ fn trait_def_id ( self , tcx : TyCtxt < ' tcx > ) -> DefId {
103
+ self . trait_def_id ( tcx)
184
104
}
185
105
186
106
fn consider_impl_candidate (
187
- & mut self ,
107
+ acx : & mut AssemblyCtxt < ' _ , ' tcx , ProjectionPredicate < ' tcx > > ,
188
108
goal : Goal < ' tcx , ProjectionPredicate < ' tcx > > ,
189
109
impl_def_id : DefId ,
190
110
) {
191
- let tcx = self . cx . tcx ;
111
+ let tcx = acx . cx . tcx ;
192
112
let goal_trait_ref = goal. predicate . projection_ty . trait_ref ( tcx) ;
193
113
let impl_trait_ref = tcx. bound_impl_trait_ref ( impl_def_id) . unwrap ( ) ;
194
114
let drcx = DeepRejectCtxt { treat_obligation_params : TreatParams :: AsPlaceholder } ;
@@ -198,11 +118,11 @@ impl<'tcx> AssemblyCtxt<'_, 'tcx> {
198
118
return ;
199
119
}
200
120
201
- self . infcx . probe ( |_| {
202
- let impl_substs = self . infcx . fresh_substs_for_item ( DUMMY_SP , impl_def_id) ;
121
+ acx . infcx . probe ( |_| {
122
+ let impl_substs = acx . infcx . fresh_substs_for_item ( DUMMY_SP , impl_def_id) ;
203
123
let impl_trait_ref = impl_trait_ref. subst ( tcx, impl_substs) ;
204
124
205
- let Ok ( InferOk { obligations, .. } ) = self
125
+ let Ok ( InferOk { obligations, .. } ) = acx
206
126
. infcx
207
127
. at ( & ObligationCause :: dummy ( ) , goal. param_env )
208
128
. define_opaque_types ( false )
@@ -213,9 +133,10 @@ impl<'tcx> AssemblyCtxt<'_, 'tcx> {
213
133
} ;
214
134
215
135
let nested_goals = obligations. into_iter ( ) . map ( |o| o. into ( ) ) . collect ( ) ;
216
- let Ok ( trait_ref_certainty) = self . cx . evaluate_all ( self . infcx , nested_goals) else { return } ;
136
+ let Ok ( trait_ref_certainty) = acx . cx . evaluate_all ( acx . infcx , nested_goals) else { return } ;
217
137
218
- let Some ( assoc_def) = self . fetch_eligible_assoc_item_def (
138
+ let Some ( assoc_def) = fetch_eligible_assoc_item_def (
139
+ acx. infcx ,
219
140
goal. param_env ,
220
141
goal_trait_ref,
221
142
goal. predicate . def_id ( ) ,
@@ -247,7 +168,7 @@ impl<'tcx> AssemblyCtxt<'_, 'tcx> {
247
168
impl_trait_ref. substs ,
248
169
) ;
249
170
let substs = translate_substs (
250
- self . infcx ,
171
+ acx . infcx ,
251
172
goal. param_env ,
252
173
impl_def_id,
253
174
impl_substs_with_gat,
@@ -267,7 +188,7 @@ impl<'tcx> AssemblyCtxt<'_, 'tcx> {
267
188
ty. map_bound ( |ty| ty. into ( ) )
268
189
} ;
269
190
270
- let Ok ( InferOk { obligations, .. } ) = self
191
+ let Ok ( InferOk { obligations, .. } ) = acx
271
192
. infcx
272
193
. at ( & ObligationCause :: dummy ( ) , goal. param_env )
273
194
. define_opaque_types ( false )
@@ -278,47 +199,46 @@ impl<'tcx> AssemblyCtxt<'_, 'tcx> {
278
199
} ;
279
200
280
201
let nested_goals = obligations. into_iter ( ) . map ( |o| o. into ( ) ) . collect ( ) ;
281
- let Ok ( rhs_certainty) = self . cx . evaluate_all ( self . infcx , nested_goals) else { return } ;
202
+ let Ok ( rhs_certainty) = acx . cx . evaluate_all ( acx . infcx , nested_goals) else { return } ;
282
203
283
204
let certainty = trait_ref_certainty. unify_and ( rhs_certainty) ;
284
- self . try_insert_candidate ( CandidateSource :: Impl ( impl_def_id) , certainty) ;
205
+ acx . try_insert_candidate ( CandidateSource :: Impl ( impl_def_id) , certainty) ;
285
206
} )
286
207
}
208
+ }
287
209
288
- /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
289
- ///
290
- /// FIXME: We should merge these 3 implementations as it's likely that they otherwise
291
- /// diverge.
292
- #[ instrument( level = "debug" , skip( self , param_env) , ret) ]
293
- fn fetch_eligible_assoc_item_def (
294
- & self ,
295
- param_env : ty:: ParamEnv < ' tcx > ,
296
- goal_trait_ref : ty:: TraitRef < ' tcx > ,
297
- trait_assoc_def_id : DefId ,
298
- impl_def_id : DefId ,
299
- ) -> Option < LeafDef > {
300
- let node_item =
301
- specialization_graph:: assoc_def ( self . cx . tcx , impl_def_id, trait_assoc_def_id)
302
- . map_err ( |ErrorGuaranteed { .. } | ( ) )
303
- . ok ( ) ?;
304
-
305
- let eligible = if node_item. is_final ( ) {
306
- // Non-specializable items are always projectable.
307
- true
210
+ /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
211
+ ///
212
+ /// FIXME: We should merge these 3 implementations as it's likely that they otherwise
213
+ /// diverge.
214
+ #[ instrument( level = "debug" , skip( infcx, param_env) , ret) ]
215
+ fn fetch_eligible_assoc_item_def < ' tcx > (
216
+ infcx : & InferCtxt < ' tcx > ,
217
+ param_env : ty:: ParamEnv < ' tcx > ,
218
+ goal_trait_ref : ty:: TraitRef < ' tcx > ,
219
+ trait_assoc_def_id : DefId ,
220
+ impl_def_id : DefId ,
221
+ ) -> Option < LeafDef > {
222
+ let node_item = specialization_graph:: assoc_def ( infcx. tcx , impl_def_id, trait_assoc_def_id)
223
+ . map_err ( |ErrorGuaranteed { .. } | ( ) )
224
+ . ok ( ) ?;
225
+
226
+ let eligible = if node_item. is_final ( ) {
227
+ // Non-specializable items are always projectable.
228
+ true
229
+ } else {
230
+ // Only reveal a specializable default if we're past type-checking
231
+ // and the obligation is monomorphic, otherwise passes such as
232
+ // transmute checking and polymorphic MIR optimizations could
233
+ // get a result which isn't correct for all monomorphizations.
234
+ if param_env. reveal ( ) == Reveal :: All {
235
+ let poly_trait_ref = infcx. resolve_vars_if_possible ( goal_trait_ref) ;
236
+ !poly_trait_ref. still_further_specializable ( )
308
237
} else {
309
- // Only reveal a specializable default if we're past type-checking
310
- // and the obligation is monomorphic, otherwise passes such as
311
- // transmute checking and polymorphic MIR optimizations could
312
- // get a result which isn't correct for all monomorphizations.
313
- if param_env. reveal ( ) == Reveal :: All {
314
- let poly_trait_ref = self . infcx . resolve_vars_if_possible ( goal_trait_ref) ;
315
- !poly_trait_ref. still_further_specializable ( )
316
- } else {
317
- debug ! ( ?node_item. item. def_id, "not eligible due to default" ) ;
318
- false
319
- }
320
- } ;
238
+ debug ! ( ?node_item. item. def_id, "not eligible due to default" ) ;
239
+ false
240
+ }
241
+ } ;
321
242
322
- if eligible { Some ( node_item) } else { None }
323
- }
243
+ if eligible { Some ( node_item) } else { None }
324
244
}
0 commit comments