@@ -80,6 +80,7 @@ use rustc_span::Span;
80
80
use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
81
81
use rustc_trait_selection:: traits:: outlives_bounds:: InferCtxtExt as _;
82
82
use rustc_trait_selection:: traits:: { self , translate_substs, wf, ObligationCtxt } ;
83
+ use tracing:: instrument;
83
84
84
85
pub ( super ) fn check_min_specialization ( tcx : TyCtxt < ' _ > , impl_def_id : LocalDefId ) {
85
86
if let Some ( node) = parent_specialization_node ( tcx, impl_def_id) {
@@ -103,13 +104,11 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
103
104
}
104
105
105
106
/// Check that `impl1` is a sound specialization
107
+ #[ instrument( level = "debug" , skip( tcx) ) ]
106
108
fn check_always_applicable ( tcx : TyCtxt < ' _ > , impl1_def_id : LocalDefId , impl2_node : Node ) {
107
109
if let Some ( ( impl1_substs, impl2_substs) ) = get_impl_substs ( tcx, impl1_def_id, impl2_node) {
108
110
let impl2_def_id = impl2_node. def_id ( ) ;
109
- debug ! (
110
- "check_always_applicable(\n impl1_def_id={:?},\n impl2_def_id={:?},\n impl2_substs={:?}\n )" ,
111
- impl1_def_id, impl2_def_id, impl2_substs
112
- ) ;
111
+ debug ! ( ?impl2_def_id, ?impl2_substs) ;
113
112
114
113
let parent_substs = if impl2_node. is_from_trait ( ) {
115
114
impl2_substs. to_vec ( )
@@ -280,13 +279,13 @@ fn check_static_lifetimes<'tcx>(
280
279
///
281
280
/// Each predicate `P` must be:
282
281
///
283
- /// * global (not reference any parameters)
284
- /// * `T: Tr` predicate where `Tr` is an always-applicable trait
285
- /// * on the base `impl impl2`
286
- /// * Currently this check is done using syntactic equality, which is
287
- /// conservative but generally sufficient.
288
- /// * a well-formed predicate of a type argument of the trait being implemented,
282
+ /// * Global (not reference any parameters).
283
+ /// * A `T: Tr` predicate where `Tr` is an always-applicable trait.
284
+ /// * Present on the base impl `impl2`.
285
+ /// * This check is done using the `trait_predicates_eq` function below.
286
+ /// * A well-formed predicate of a type argument of the trait being implemented,
289
287
/// including the `Self`-type.
288
+ #[ instrument( level = "debug" , skip( tcx) ) ]
290
289
fn check_predicates < ' tcx > (
291
290
tcx : TyCtxt < ' tcx > ,
292
291
impl1_def_id : LocalDefId ,
@@ -322,10 +321,7 @@ fn check_predicates<'tcx>(
322
321
. map ( |obligation| obligation. predicate )
323
322
. collect ( )
324
323
} ;
325
- debug ! (
326
- "check_always_applicable(\n impl1_predicates={:?},\n impl2_predicates={:?}\n )" ,
327
- impl1_predicates, impl2_predicates,
328
- ) ;
324
+ debug ! ( ?impl1_predicates, ?impl2_predicates) ;
329
325
330
326
// Since impls of always applicable traits don't get to assume anything, we
331
327
// can also assume their supertraits apply.
@@ -373,25 +369,52 @@ fn check_predicates<'tcx>(
373
369
) ;
374
370
375
371
for ( predicate, span) in impl1_predicates {
376
- if !impl2_predicates. contains ( & predicate) {
372
+ if !impl2_predicates. iter ( ) . any ( |pred2| trait_predicates_eq ( predicate, * pred2 ) ) {
377
373
check_specialization_on ( tcx, predicate, span)
378
374
}
379
375
}
380
376
}
381
377
378
+ /// Checks whether two predicates are the same for the purposes of specialization.
379
+ ///
380
+ /// This is slightly more complicated than simple syntactic equivalence, since
381
+ /// we want to equate `T: Tr` with `T: ~const Tr` so this can work:
382
+ ///
383
+ /// #[rustc_specialization_trait]
384
+ /// trait Specialize { }
385
+ ///
386
+ /// impl<T: ~const Bound> const Tr for T { }
387
+ /// impl<T: Bound + Specialize> Tr for T { }
388
+ fn trait_predicates_eq < ' tcx > (
389
+ predicate1 : ty:: Predicate < ' tcx > ,
390
+ predicate2 : ty:: Predicate < ' tcx > ,
391
+ ) -> bool {
392
+ let predicate_kind_without_constness = |kind : ty:: PredicateKind < ' tcx > | match kind {
393
+ ty:: PredicateKind :: Trait ( ty:: TraitPredicate { trait_ref, constness : _, polarity } ) => {
394
+ ty:: PredicateKind :: Trait ( ty:: TraitPredicate {
395
+ trait_ref,
396
+ constness : ty:: BoundConstness :: NotConst ,
397
+ polarity,
398
+ } )
399
+ }
400
+ _ => kind,
401
+ } ;
402
+
403
+ let pred1_kind_not_const = predicate1. kind ( ) . map_bound ( predicate_kind_without_constness) ;
404
+ let pred2_kind_not_const = predicate2. kind ( ) . map_bound ( predicate_kind_without_constness) ;
405
+
406
+ pred1_kind_not_const == pred2_kind_not_const
407
+ }
408
+
409
+ #[ instrument( level = "debug" , skip( tcx) ) ]
382
410
fn check_specialization_on < ' tcx > ( tcx : TyCtxt < ' tcx > , predicate : ty:: Predicate < ' tcx > , span : Span ) {
383
- debug ! ( "can_specialize_on(predicate = {:?})" , predicate) ;
384
411
match predicate. kind ( ) . skip_binder ( ) {
385
412
// Global predicates are either always true or always false, so we
386
413
// are fine to specialize on.
387
414
_ if predicate. is_global ( ) => ( ) ,
388
415
// We allow specializing on explicitly marked traits with no associated
389
416
// items.
390
- ty:: PredicateKind :: Trait ( ty:: TraitPredicate {
391
- trait_ref,
392
- constness : ty:: BoundConstness :: NotConst ,
393
- polarity : _,
394
- } ) => {
417
+ ty:: PredicateKind :: Trait ( ty:: TraitPredicate { trait_ref, constness : _, polarity : _ } ) => {
395
418
if !matches ! (
396
419
trait_predicate_kind( tcx, predicate) ,
397
420
Some ( TraitSpecializationKind :: Marker )
0 commit comments