@@ -15,6 +15,7 @@ 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:: traits:: Obligation ;
18
19
use rustc_middle:: bug;
19
20
use rustc_middle:: query:: LocalCrate ;
20
21
use rustc_middle:: ty:: print:: PrintTraitRefExt as _;
@@ -224,29 +225,38 @@ pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool
224
225
tcx. features ( ) . specialization ( ) || tcx. features ( ) . min_specialization ( )
225
226
}
226
227
227
- /// Is `impl1 ` a specialization of `impl2 `?
228
+ /// Is `specializing_impl_def_id ` a specialization of `parent_impl_def_id `?
228
229
///
229
- /// Specialization is determined by the sets of types to which the impls apply;
230
- /// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies
231
- /// to.
230
+ /// For every type that could apply to `specializing_impl_def_id`, we prove that
231
+ /// the `parent_impl_def_id` also applies (i.e. it has a valid impl header and
232
+ /// its where-clauses hold).
233
+ ///
234
+ /// For the purposes of const traits, we also check that the specializing
235
+ /// impl is not more restrictive than the parent impl. That is, if the
236
+ /// `parent_impl_def_id` is a const impl (conditionally based off of some `~const`
237
+ /// bounds), then `specializing_impl_def_id` must also be const for the same
238
+ /// set of types.
232
239
#[ instrument( skip( tcx) , level = "debug" ) ]
233
- pub ( super ) fn specializes ( tcx : TyCtxt < ' _ > , ( impl1_def_id, impl2_def_id) : ( DefId , DefId ) ) -> bool {
240
+ pub ( super ) fn specializes (
241
+ tcx : TyCtxt < ' _ > ,
242
+ ( specializing_impl_def_id, parent_impl_def_id) : ( DefId , DefId ) ,
243
+ ) -> bool {
234
244
// We check that the specializing impl comes from a crate that has specialization enabled,
235
245
// or if the specializing impl is marked with `allow_internal_unstable`.
236
246
//
237
247
// We don't really care if the specialized impl (the parent) is in a crate that has
238
248
// specialization enabled, since it's not being specialized, and it's already been checked
239
249
// for coherence.
240
- if !tcx. specialization_enabled_in ( impl1_def_id . krate ) {
241
- let span = tcx. def_span ( impl1_def_id ) ;
250
+ if !tcx. specialization_enabled_in ( specializing_impl_def_id . krate ) {
251
+ let span = tcx. def_span ( specializing_impl_def_id ) ;
242
252
if !span. allows_unstable ( sym:: specialization)
243
253
&& !span. allows_unstable ( sym:: min_specialization)
244
254
{
245
255
return false ;
246
256
}
247
257
}
248
258
249
- let impl1_trait_header = tcx. impl_trait_header ( impl1_def_id ) . unwrap ( ) ;
259
+ let specializing_impl_trait_header = tcx. impl_trait_header ( specializing_impl_def_id ) . unwrap ( ) ;
250
260
251
261
// We determine whether there's a subset relationship by:
252
262
//
@@ -261,27 +271,123 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
261
271
// See RFC 1210 for more details and justification.
262
272
263
273
// Currently we do not allow e.g., a negative impl to specialize a positive one
264
- if impl1_trait_header . polarity != tcx. impl_polarity ( impl2_def_id ) {
274
+ if specializing_impl_trait_header . polarity != tcx. impl_polarity ( parent_impl_def_id ) {
265
275
return false ;
266
276
}
267
277
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 ) ;
278
+ // create a parameter environment corresponding to an identity instantiation of the specializing impl ,
279
+ // i.e. the most generic instantiation of the specializing impl .
280
+ let param_env = tcx. param_env ( specializing_impl_def_id ) ;
271
281
272
- // Create an infcx, taking the predicates of impl1 as assumptions:
282
+ // Create an infcx, taking the predicates of the specializing impl as assumptions:
273
283
let infcx = tcx. infer_ctxt ( ) . build ( TypingMode :: non_body_analysis ( ) ) ;
274
284
275
- // Attempt to prove that impl2 applies, given all of the above.
276
- fulfill_implication (
277
- & infcx,
285
+ let specializing_impl_trait_ref =
286
+ specializing_impl_trait_header. trait_ref . instantiate_identity ( ) ;
287
+ let cause = & ObligationCause :: dummy ( ) ;
288
+ debug ! (
289
+ "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)" ,
290
+ param_env, specializing_impl_trait_ref, parent_impl_def_id
291
+ ) ;
292
+
293
+ // Attempt to prove that the parent impl applies, given all of the above.
294
+
295
+ let ocx = ObligationCtxt :: new ( & infcx) ;
296
+ let specializing_impl_trait_ref = ocx. normalize ( cause, param_env, specializing_impl_trait_ref) ;
297
+
298
+ if !ocx. select_all_or_error ( ) . is_empty ( ) {
299
+ infcx. dcx ( ) . span_delayed_bug (
300
+ infcx. tcx . def_span ( specializing_impl_def_id) ,
301
+ format ! ( "failed to fully normalize {specializing_impl_trait_ref}" ) ,
302
+ ) ;
303
+ return false ;
304
+ }
305
+
306
+ let parent_args = infcx. fresh_args_for_item ( DUMMY_SP , parent_impl_def_id) ;
307
+ let parent_impl_trait_ref = ocx. normalize (
308
+ cause,
278
309
param_env,
279
- impl1_trait_header. trait_ref . instantiate_identity ( ) ,
280
- impl1_def_id,
281
- impl2_def_id,
282
- & ObligationCause :: dummy ( ) ,
283
- )
284
- . is_ok ( )
310
+ infcx
311
+ . tcx
312
+ . impl_trait_ref ( parent_impl_def_id)
313
+ . expect ( "expected source impl to be a trait impl" )
314
+ . instantiate ( infcx. tcx , parent_args) ,
315
+ ) ;
316
+
317
+ // do the impls unify? If not, no specialization.
318
+ let Ok ( ( ) ) = ocx. eq ( cause, param_env, specializing_impl_trait_ref, parent_impl_trait_ref)
319
+ else {
320
+ return false ;
321
+ } ;
322
+
323
+ // Now check that the source trait ref satisfies all the where clauses of the target impl.
324
+ // This is not just for correctness; we also need this to constrain any params that may
325
+ // only be referenced via projection predicates.
326
+ let predicates = ocx. normalize (
327
+ cause,
328
+ param_env,
329
+ infcx. tcx . predicates_of ( parent_impl_def_id) . instantiate ( infcx. tcx , parent_args) ,
330
+ ) ;
331
+ let obligations = predicates_for_generics ( |_, _| cause. clone ( ) , param_env, predicates) ;
332
+ ocx. register_obligations ( obligations) ;
333
+
334
+ let errors = ocx. select_all_or_error ( ) ;
335
+ if !errors. is_empty ( ) {
336
+ // no dice!
337
+ debug ! (
338
+ "fulfill_implication: for impls on {:?} and {:?}, \
339
+ could not fulfill: {:?} given {:?}",
340
+ specializing_impl_trait_ref,
341
+ parent_impl_trait_ref,
342
+ errors,
343
+ param_env. caller_bounds( )
344
+ ) ;
345
+ return false ;
346
+ }
347
+
348
+ // If the parent impl is const, then the specializing impl must be const,
349
+ // and it must not be *more restrictive* than the parent impl (that is,
350
+ // it cannot be const in fewer cases than the parent impl).
351
+ if tcx. is_conditionally_const ( parent_impl_def_id) {
352
+ if !tcx. is_conditionally_const ( specializing_impl_def_id) {
353
+ return false ;
354
+ }
355
+
356
+ let const_conditions = ocx. normalize (
357
+ cause,
358
+ param_env,
359
+ infcx. tcx . const_conditions ( parent_impl_def_id) . instantiate ( infcx. tcx , parent_args) ,
360
+ ) ;
361
+ ocx. register_obligations ( const_conditions. into_iter ( ) . map ( |( trait_ref, _) | {
362
+ Obligation :: new (
363
+ infcx. tcx ,
364
+ cause. clone ( ) ,
365
+ param_env,
366
+ trait_ref. to_host_effect_clause ( infcx. tcx , ty:: BoundConstness :: Maybe ) ,
367
+ )
368
+ } ) ) ;
369
+
370
+ let errors = ocx. select_all_or_error ( ) ;
371
+ if !errors. is_empty ( ) {
372
+ // no dice!
373
+ debug ! (
374
+ "fulfill_implication: for impls on {:?} and {:?}, \
375
+ could not fulfill: {:?} given {:?}",
376
+ specializing_impl_trait_ref,
377
+ parent_impl_trait_ref,
378
+ errors,
379
+ param_env. caller_bounds( )
380
+ ) ;
381
+ return false ;
382
+ }
383
+ }
384
+
385
+ debug ! (
386
+ "fulfill_implication: an impl for {:?} specializes {:?}" ,
387
+ specializing_impl_trait_ref, parent_impl_trait_ref
388
+ ) ;
389
+
390
+ true
285
391
}
286
392
287
393
/// Query provider for `specialization_graph_of`.
0 commit comments