@@ -15,24 +15,24 @@ use rustc_data_structures::fx::FxIndexSet;
15
15
use rustc_errors:: codes:: * ;
16
16
use rustc_errors:: { Diag , EmissionGuarantee } ;
17
17
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
18
- use rustc_infer:: infer:: DefineOpaqueTypes ;
19
18
use rustc_middle:: bug;
20
19
use rustc_middle:: query:: LocalCrate ;
21
20
use rustc_middle:: ty:: print:: PrintTraitRefExt as _;
22
- use rustc_middle:: ty:: {
23
- self , GenericArgsRef , ImplSubject , Ty , TyCtxt , TypeVisitableExt , TypingMode ,
24
- } ;
21
+ use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt , TypingMode } ;
25
22
use rustc_session:: lint:: builtin:: { COHERENCE_LEAK_CHECK , ORDER_DEPENDENT_TRAIT_OBJECTS } ;
26
23
use rustc_span:: { DUMMY_SP , ErrorGuaranteed , Span , sym} ;
24
+ use rustc_type_ir:: solve:: NoSolution ;
27
25
use specialization_graph:: GraphExt ;
28
26
use tracing:: { debug, instrument} ;
29
27
30
- use super :: { SelectionContext , util} ;
31
28
use crate :: error_reporting:: traits:: to_pretty_impl_header;
32
29
use crate :: errors:: NegativePositiveConflict ;
33
- use crate :: infer:: { InferCtxt , InferOk , TyCtxtInferExt } ;
30
+ use crate :: infer:: { InferCtxt , TyCtxtInferExt } ;
34
31
use crate :: traits:: select:: IntercrateAmbiguityCause ;
35
- use crate :: traits:: { FutureCompatOverlapErrorKind , ObligationCause , ObligationCtxt , coherence} ;
32
+ use crate :: traits:: {
33
+ FutureCompatOverlapErrorKind , ObligationCause , ObligationCtxt , coherence,
34
+ predicates_for_generics,
35
+ } ;
36
36
37
37
/// Information pertinent to an overlapping impl error.
38
38
#[ derive( Debug ) ]
@@ -87,9 +87,14 @@ pub fn translate_args<'tcx>(
87
87
source_args : GenericArgsRef < ' tcx > ,
88
88
target_node : specialization_graph:: Node ,
89
89
) -> GenericArgsRef < ' tcx > {
90
- translate_args_with_cause ( infcx, param_env, source_impl, source_args, target_node, |_, _| {
91
- ObligationCause :: dummy ( )
92
- } )
90
+ translate_args_with_cause (
91
+ infcx,
92
+ param_env,
93
+ source_impl,
94
+ source_args,
95
+ target_node,
96
+ & ObligationCause :: dummy ( ) ,
97
+ )
93
98
}
94
99
95
100
/// Like [translate_args], but obligations from the parent implementation
@@ -104,7 +109,7 @@ pub fn translate_args_with_cause<'tcx>(
104
109
source_impl : DefId ,
105
110
source_args : GenericArgsRef < ' tcx > ,
106
111
target_node : specialization_graph:: Node ,
107
- cause : impl Fn ( usize , Span ) -> ObligationCause < ' tcx > ,
112
+ cause : & ObligationCause < ' tcx > ,
108
113
) -> GenericArgsRef < ' tcx > {
109
114
debug ! (
110
115
"translate_args({:?}, {:?}, {:?}, {:?})" ,
@@ -123,7 +128,7 @@ pub fn translate_args_with_cause<'tcx>(
123
128
}
124
129
125
130
fulfill_implication ( infcx, param_env, source_trait_ref, source_impl, target_impl, cause)
126
- . unwrap_or_else ( |( ) | {
131
+ . unwrap_or_else ( |_ | {
127
132
bug ! (
128
133
"When translating generic parameters from {source_impl:?} to \
129
134
{target_impl:?}, the expected specialization failed to hold"
@@ -137,6 +142,84 @@ pub fn translate_args_with_cause<'tcx>(
137
142
source_args. rebase_onto ( infcx. tcx , source_impl, target_args)
138
143
}
139
144
145
+ /// Attempt to fulfill all obligations of `target_impl` after unification with
146
+ /// `source_trait_ref`. If successful, returns the generic parameters for *all* the
147
+ /// generics of `target_impl`, including both those needed to unify with
148
+ /// `source_trait_ref` and those whose identity is determined via a where
149
+ /// clause in the impl.
150
+ fn fulfill_implication < ' tcx > (
151
+ infcx : & InferCtxt < ' tcx > ,
152
+ param_env : ty:: ParamEnv < ' tcx > ,
153
+ source_trait_ref : ty:: TraitRef < ' tcx > ,
154
+ source_impl : DefId ,
155
+ target_impl : DefId ,
156
+ cause : & ObligationCause < ' tcx > ,
157
+ ) -> Result < GenericArgsRef < ' tcx > , NoSolution > {
158
+ debug ! (
159
+ "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)" ,
160
+ param_env, source_trait_ref, target_impl
161
+ ) ;
162
+
163
+ let ocx = ObligationCtxt :: new ( infcx) ;
164
+ let source_trait_ref = ocx. normalize ( cause, param_env, source_trait_ref) ;
165
+
166
+ if !ocx. select_all_or_error ( ) . is_empty ( ) {
167
+ infcx. dcx ( ) . span_delayed_bug (
168
+ infcx. tcx . def_span ( source_impl) ,
169
+ format ! ( "failed to fully normalize {source_trait_ref}" ) ,
170
+ ) ;
171
+ return Err ( NoSolution ) ;
172
+ }
173
+
174
+ let target_args = infcx. fresh_args_for_item ( DUMMY_SP , target_impl) ;
175
+ let target_trait_ref = ocx. normalize (
176
+ cause,
177
+ param_env,
178
+ infcx
179
+ . tcx
180
+ . impl_trait_ref ( target_impl)
181
+ . expect ( "expected source impl to be a trait impl" )
182
+ . instantiate ( infcx. tcx , target_args) ,
183
+ ) ;
184
+
185
+ // do the impls unify? If not, no specialization.
186
+ ocx. eq ( cause, param_env, source_trait_ref, target_trait_ref) ?;
187
+
188
+ // Now check that the source trait ref satisfies all the where clauses of the target impl.
189
+ // This is not just for correctness; we also need this to constrain any params that may
190
+ // only be referenced via projection predicates.
191
+ let predicates = ocx. normalize (
192
+ cause,
193
+ param_env,
194
+ infcx. tcx . predicates_of ( target_impl) . instantiate ( infcx. tcx , target_args) ,
195
+ ) ;
196
+ let obligations = predicates_for_generics ( |_, _| cause. clone ( ) , param_env, predicates) ;
197
+ ocx. register_obligations ( obligations) ;
198
+
199
+ let errors = ocx. select_all_or_error ( ) ;
200
+ if !errors. is_empty ( ) {
201
+ // no dice!
202
+ debug ! (
203
+ "fulfill_implication: for impls on {:?} and {:?}, \
204
+ could not fulfill: {:?} given {:?}",
205
+ source_trait_ref,
206
+ target_trait_ref,
207
+ errors,
208
+ param_env. caller_bounds( )
209
+ ) ;
210
+ return Err ( NoSolution ) ;
211
+ }
212
+
213
+ debug ! (
214
+ "fulfill_implication: an impl for {:?} specializes {:?}" ,
215
+ source_trait_ref, target_trait_ref
216
+ ) ;
217
+
218
+ // Now resolve the *generic parameters* we built for the target earlier, replacing
219
+ // the inference variables inside with whatever we got from fulfillment.
220
+ Ok ( infcx. resolve_vars_if_possible ( target_args) )
221
+ }
222
+
140
223
pub ( super ) fn specialization_enabled_in ( tcx : TyCtxt < ' _ > , _: LocalCrate ) -> bool {
141
224
tcx. features ( ) . specialization ( ) || tcx. features ( ) . min_specialization ( )
142
225
}
@@ -182,99 +265,25 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
182
265
return false ;
183
266
}
184
267
185
- // create a parameter environment corresponding to a (placeholder) instantiation of impl1
186
- let penv = tcx. param_env ( impl1_def_id) ;
268
+ // create a parameter environment corresponding to an identity instantiation of impl1,
269
+ // i.e. the most generic instantiation of impl1.
270
+ let param_env = tcx. param_env ( impl1_def_id) ;
187
271
188
272
// Create an infcx, taking the predicates of impl1 as assumptions:
189
273
let infcx = tcx. infer_ctxt ( ) . build ( TypingMode :: non_body_analysis ( ) ) ;
190
274
191
275
// Attempt to prove that impl2 applies, given all of the above.
192
276
fulfill_implication (
193
277
& infcx,
194
- penv ,
278
+ param_env ,
195
279
impl1_trait_header. trait_ref . instantiate_identity ( ) ,
196
280
impl1_def_id,
197
281
impl2_def_id,
198
- |_ , _| ObligationCause :: dummy ( ) ,
282
+ & ObligationCause :: dummy ( ) ,
199
283
)
200
284
. is_ok ( )
201
285
}
202
286
203
- /// Attempt to fulfill all obligations of `target_impl` after unification with
204
- /// `source_trait_ref`. If successful, returns the generic parameters for *all* the
205
- /// generics of `target_impl`, including both those needed to unify with
206
- /// `source_trait_ref` and those whose identity is determined via a where
207
- /// clause in the impl.
208
- fn fulfill_implication < ' tcx > (
209
- infcx : & InferCtxt < ' tcx > ,
210
- param_env : ty:: ParamEnv < ' tcx > ,
211
- source_trait_ref : ty:: TraitRef < ' tcx > ,
212
- source_impl : DefId ,
213
- target_impl : DefId ,
214
- error_cause : impl Fn ( usize , Span ) -> ObligationCause < ' tcx > ,
215
- ) -> Result < GenericArgsRef < ' tcx > , ( ) > {
216
- debug ! (
217
- "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)" ,
218
- param_env, source_trait_ref, target_impl
219
- ) ;
220
-
221
- let ocx = ObligationCtxt :: new ( infcx) ;
222
- let source_trait_ref = ocx. normalize ( & ObligationCause :: dummy ( ) , param_env, source_trait_ref) ;
223
-
224
- if !ocx. select_all_or_error ( ) . is_empty ( ) {
225
- infcx. dcx ( ) . span_delayed_bug (
226
- infcx. tcx . def_span ( source_impl) ,
227
- format ! ( "failed to fully normalize {source_trait_ref}" ) ,
228
- ) ;
229
- }
230
-
231
- let source_trait_ref = infcx. resolve_vars_if_possible ( source_trait_ref) ;
232
- let source_trait = ImplSubject :: Trait ( source_trait_ref) ;
233
-
234
- let selcx = SelectionContext :: new ( infcx) ;
235
- let target_args = infcx. fresh_args_for_item ( DUMMY_SP , target_impl) ;
236
- let ( target_trait, obligations) =
237
- util:: impl_subject_and_oblig ( & selcx, param_env, target_impl, target_args, error_cause) ;
238
-
239
- // do the impls unify? If not, no specialization.
240
- let Ok ( InferOk { obligations : more_obligations, .. } ) = infcx
241
- . at ( & ObligationCause :: dummy ( ) , param_env)
242
- // Ok to use `Yes`, as all the generic params are already replaced by inference variables,
243
- // which will match the opaque type no matter if it is defining or not.
244
- // Any concrete type that would match the opaque would already be handled by coherence rules,
245
- // and thus either be ok to match here and already have errored, or it won't match, in which
246
- // case there is no issue anyway.
247
- . eq ( DefineOpaqueTypes :: Yes , source_trait, target_trait)
248
- else {
249
- debug ! ( "fulfill_implication: {:?} does not unify with {:?}" , source_trait, target_trait) ;
250
- return Err ( ( ) ) ;
251
- } ;
252
-
253
- // attempt to prove all of the predicates for impl2 given those for impl1
254
- // (which are packed up in penv)
255
- ocx. register_obligations ( obligations. chain ( more_obligations) ) ;
256
-
257
- let errors = ocx. select_all_or_error ( ) ;
258
- if !errors. is_empty ( ) {
259
- // no dice!
260
- debug ! (
261
- "fulfill_implication: for impls on {:?} and {:?}, \
262
- could not fulfill: {:?} given {:?}",
263
- source_trait,
264
- target_trait,
265
- errors,
266
- param_env. caller_bounds( )
267
- ) ;
268
- return Err ( ( ) ) ;
269
- }
270
-
271
- debug ! ( "fulfill_implication: an impl for {:?} specializes {:?}" , source_trait, target_trait) ;
272
-
273
- // Now resolve the *generic parameters* we built for the target earlier, replacing
274
- // the inference variables inside with whatever we got from fulfillment.
275
- Ok ( infcx. resolve_vars_if_possible ( target_args) )
276
- }
277
-
278
287
/// Query provider for `specialization_graph_of`.
279
288
pub ( super ) fn specialization_graph_provider (
280
289
tcx : TyCtxt < ' _ > ,
0 commit comments