@@ -187,7 +187,7 @@ impl<'tcx> ConstToPat<'tcx> {
187
187
188
188
if !inlined_const_as_pat. references_error ( ) {
189
189
// Always check for `PartialEq` if we had no other errors yet.
190
- if !type_has_partial_eq_impl ( self . tcx , typing_env, ty) . 0 {
190
+ if !type_has_partial_eq_impl ( self . tcx , typing_env, ty) . has_impl {
191
191
let mut err = self . tcx . dcx ( ) . create_err ( TypeNotPartialEq { span : self . span , ty } ) ;
192
192
extend_type_not_partial_eq ( self . tcx , typing_env, ty, & mut err) ;
193
193
return self . mk_err ( err, ty) ;
@@ -221,12 +221,13 @@ impl<'tcx> ConstToPat<'tcx> {
221
221
// Extremely important check for all ADTs! Make sure they opted-in to be used in
222
222
// patterns.
223
223
debug ! ( "adt_def {:?} has !type_marked_structural for cv.ty: {:?}" , adt_def, ty) ;
224
- let ( _impls_partial_eq, derived, structural, impl_def_id) =
225
- type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
224
+ let PartialEqImplStatus {
225
+ is_derived, structural_partial_eq, non_blanket_impl, ..
226
+ } = type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
226
227
let ( manual_partialeq_impl_span, manual_partialeq_impl_note) =
227
- match ( structural , impl_def_id ) {
228
+ match ( structural_partial_eq , non_blanket_impl ) {
228
229
( true , _) => ( None , false ) ,
229
- ( _, Some ( def_id) ) if def_id. is_local ( ) && !derived => {
230
+ ( _, Some ( def_id) ) if def_id. is_local ( ) && !is_derived => {
230
231
( Some ( tcx. def_span ( def_id) ) , false )
231
232
}
232
233
_ => ( None , true ) ,
@@ -385,40 +386,50 @@ fn extend_type_not_partial_eq<'tcx>(
385
386
/// The type has no `PartialEq` implementation, neither manual or derived, but
386
387
/// we don't have a span to point at, so we'll just add them as a `note`.
387
388
without : FxHashSet < Ty < ' tcx > > ,
388
- /// If any of the subtypes has escaping bounds (`for<'a>`), we won't emit a note.
389
- has_escaping_bound_vars : bool ,
389
+ /// If any of the subtypes has escaping bounds (`for<'a>`) or involves a trait object, we
390
+ /// won't emit a note.
391
+ should_note : bool ,
390
392
}
391
393
392
394
impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UsedParamsNeedInstantiationVisitor < ' tcx > {
393
- fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> Self :: Result {
394
- if ty. has_escaping_bound_vars ( ) {
395
- self . has_escaping_bound_vars = true ;
396
- } else if let ty:: Adt ( def, _args) = ty. kind ( ) {
397
- let ty_def_id = def. did ( ) ;
398
- let ty_def_span = self . tcx . def_span ( ty_def_id) ;
399
- let ( impls_partial_eq, derived, structural, impl_def_id) =
400
- type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
401
- match ( impls_partial_eq, derived, structural, impl_def_id) {
402
- ( _, _, true , _) => { }
403
- ( true , false , _, Some ( def_id) ) if def_id. is_local ( ) => {
404
- self . adts_with_manual_partialeq . insert ( self . tcx . def_span ( def_id) ) ;
405
- }
406
- ( true , false , _, _) if ty_def_id. is_local ( ) => {
407
- self . adts_with_manual_partialeq . insert ( ty_def_span) ;
408
- }
409
- ( false , _, _, _) if ty_def_id. is_local ( ) => {
410
- self . adts_without_partialeq . insert ( ty_def_span) ;
411
- }
412
- ( true , false , _, _) => {
413
- self . manual . insert ( ty) ;
414
- }
415
- ( false , _, _, _) => {
416
- self . without . insert ( ty) ;
417
- }
418
- _ => { }
419
- } ;
395
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) {
396
+ match ty. kind ( ) {
397
+ ty:: Dynamic ( ..) => {
398
+ self . should_note = false ;
399
+ }
400
+ ty:: FnPtr ( ..) => { }
401
+ ty:: Adt ( def, _args) => {
402
+ let ty_def_id = def. did ( ) ;
403
+ let ty_def_span = self . tcx . def_span ( ty_def_id) ;
404
+ let PartialEqImplStatus {
405
+ has_impl,
406
+ is_derived,
407
+ structural_partial_eq,
408
+ non_blanket_impl,
409
+ } = type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
410
+ match ( has_impl, is_derived, structural_partial_eq, non_blanket_impl) {
411
+ ( _, _, true , _) => { }
412
+ ( true , false , _, Some ( def_id) ) if def_id. is_local ( ) => {
413
+ self . adts_with_manual_partialeq . insert ( self . tcx . def_span ( def_id) ) ;
414
+ }
415
+ ( true , false , _, _) if ty_def_id. is_local ( ) => {
416
+ self . adts_with_manual_partialeq . insert ( ty_def_span) ;
417
+ }
418
+ ( false , _, _, _) if ty_def_id. is_local ( ) => {
419
+ self . adts_without_partialeq . insert ( ty_def_span) ;
420
+ }
421
+ ( true , false , _, _) => {
422
+ self . manual . insert ( ty) ;
423
+ }
424
+ ( false , _, _, _) => {
425
+ self . without . insert ( ty) ;
426
+ }
427
+ _ => { }
428
+ } ;
429
+ ty. super_visit_with ( self ) ;
430
+ }
431
+ _ => ty. super_visit_with ( self ) ,
420
432
}
421
- ty. super_visit_with ( self )
422
433
}
423
434
}
424
435
let mut v = UsedParamsNeedInstantiationVisitor {
@@ -428,10 +439,10 @@ fn extend_type_not_partial_eq<'tcx>(
428
439
adts_without_partialeq : FxHashSet :: default ( ) ,
429
440
manual : FxHashSet :: default ( ) ,
430
441
without : FxHashSet :: default ( ) ,
431
- has_escaping_bound_vars : false ,
442
+ should_note : true ,
432
443
} ;
433
444
v. visit_ty ( ty) ;
434
- if v . has_escaping_bound_vars {
445
+ if !v . should_note {
435
446
return ;
436
447
}
437
448
#[ allow( rustc:: potential_query_instability) ] // Span labels will be sorted by the rendering
@@ -445,31 +456,38 @@ fn extend_type_not_partial_eq<'tcx>(
445
456
"must be annotated with `#[derive(PartialEq)]` to be usable in patterns" ,
446
457
) ;
447
458
}
448
- #[ allow( rustc:: potential_query_instability) ] // Span labels will be sorted by the rendering
449
- for ty in v. manual {
459
+ #[ allow( rustc:: potential_query_instability) ]
460
+ let mut manual: Vec < _ > = v. manual . into_iter ( ) . map ( |t| t. to_string ( ) ) . collect ( ) ;
461
+ manual. sort ( ) ;
462
+ for ty in manual {
450
463
err. note ( format ! (
451
464
"`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details"
452
465
) ) ;
453
466
}
454
- #[ allow( rustc:: potential_query_instability) ] // Span labels will be sorted by the rendering
455
- for ty in v. without {
467
+ #[ allow( rustc:: potential_query_instability) ]
468
+ let mut without: Vec < _ > = v. without . into_iter ( ) . map ( |t| t. to_string ( ) ) . collect ( ) ;
469
+ without. sort ( ) ;
470
+ for ty in without {
456
471
err. note ( format ! (
457
472
"`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns"
458
473
) ) ;
459
474
}
460
475
}
461
476
477
+ #[ derive( Debug ) ]
478
+ struct PartialEqImplStatus {
479
+ has_impl : bool ,
480
+ is_derived : bool ,
481
+ structural_partial_eq : bool ,
482
+ non_blanket_impl : Option < DefId > ,
483
+ }
484
+
462
485
#[ instrument( level = "trace" , skip( tcx) , ret) ]
463
486
fn type_has_partial_eq_impl < ' tcx > (
464
487
tcx : TyCtxt < ' tcx > ,
465
488
typing_env : ty:: TypingEnv < ' tcx > ,
466
489
ty : Ty < ' tcx > ,
467
- ) -> (
468
- /* has impl */ bool ,
469
- /* is derived */ bool ,
470
- /* structural partial eq */ bool ,
471
- /* non-blanket impl */ Option < DefId > ,
472
- ) {
490
+ ) -> PartialEqImplStatus {
473
491
let ( infcx, param_env) = tcx. infer_ctxt ( ) . build_with_typing_env ( typing_env) ;
474
492
// double-check there even *is* a semantic `PartialEq` to dispatch to.
475
493
//
@@ -479,10 +497,6 @@ fn type_has_partial_eq_impl<'tcx>(
479
497
let partial_eq_trait_id = tcx. require_lang_item ( hir:: LangItem :: PartialEq , None ) ;
480
498
let structural_partial_eq_trait_id = tcx. require_lang_item ( hir:: LangItem :: StructuralPeq , None ) ;
481
499
482
- if ty. has_escaping_bound_vars ( ) {
483
- return ( false , false , false , None ) ;
484
- }
485
-
486
500
let partial_eq_obligation = Obligation :: new (
487
501
tcx,
488
502
ObligationCause :: dummy ( ) ,
@@ -510,10 +524,10 @@ fn type_has_partial_eq_impl<'tcx>(
510
524
// that patterns can only do things that the code could also do without patterns, but it is
511
525
// needed for backwards compatibility. The actual pattern matching compares primitive values,
512
526
// `PartialEq::eq` never gets invoked, so there's no risk of us running non-const code.
513
- (
514
- infcx. predicate_must_hold_modulo_regions ( & partial_eq_obligation) ,
515
- automatically_derived,
516
- structural_peq,
517
- impl_def_id,
518
- )
527
+ PartialEqImplStatus {
528
+ has_impl : infcx. predicate_must_hold_modulo_regions ( & partial_eq_obligation) ,
529
+ is_derived : automatically_derived,
530
+ structural_partial_eq : structural_peq,
531
+ non_blanket_impl : impl_def_id,
532
+ }
519
533
}
0 commit comments