1
+ use core:: ops:: ControlFlow ;
2
+
1
3
use rustc_abi:: { FieldIdx , VariantIdx } ;
2
4
use rustc_apfloat:: Float ;
3
5
use rustc_data_structures:: fx:: FxHashSet ;
@@ -8,7 +10,9 @@ use rustc_infer::infer::TyCtxtInferExt;
8
10
use rustc_infer:: traits:: Obligation ;
9
11
use rustc_middle:: mir:: interpret:: ErrorHandled ;
10
12
use rustc_middle:: thir:: { FieldPat , Pat , PatKind } ;
11
- use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitableExt , TypeVisitor , ValTree } ;
13
+ use rustc_middle:: ty:: {
14
+ self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitableExt , TypeVisitor , ValTree ,
15
+ } ;
12
16
use rustc_middle:: { mir, span_bug} ;
13
17
use rustc_span:: def_id:: DefId ;
14
18
use rustc_span:: { Span , sym} ;
@@ -185,7 +189,7 @@ impl<'tcx> ConstToPat<'tcx> {
185
189
186
190
if !inlined_const_as_pat. references_error ( ) {
187
191
// Always check for `PartialEq` if we had no other errors yet.
188
- if !type_has_partial_eq_impl ( self . tcx , typing_env, ty) . 0 {
192
+ if !type_has_partial_eq_impl ( self . tcx , typing_env, ty) . has_impl {
189
193
let mut err = self . tcx . dcx ( ) . create_err ( TypeNotPartialEq { span : self . span , ty } ) ;
190
194
extend_type_not_partial_eq ( self . tcx , typing_env, ty, & mut err) ;
191
195
return self . mk_err ( err, ty) ;
@@ -219,12 +223,13 @@ impl<'tcx> ConstToPat<'tcx> {
219
223
// Extremely important check for all ADTs! Make sure they opted-in to be used in
220
224
// patterns.
221
225
debug ! ( "adt_def {:?} has !type_marked_structural for cv.ty: {:?}" , adt_def, ty) ;
222
- let ( _impls_partial_eq, derived, structural, impl_def_id) =
223
- type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
226
+ let PartialEqImplStatus {
227
+ is_derived, structural_partial_eq, non_blanket_impl, ..
228
+ } = type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
224
229
let ( manual_partialeq_impl_span, manual_partialeq_impl_note) =
225
- match ( structural , impl_def_id ) {
230
+ match ( structural_partial_eq , non_blanket_impl ) {
226
231
( true , _) => ( None , false ) ,
227
- ( _, Some ( def_id) ) if def_id. is_local ( ) && !derived => {
232
+ ( _, Some ( def_id) ) if def_id. is_local ( ) && !is_derived => {
228
233
( Some ( tcx. def_span ( def_id) ) , false )
229
234
}
230
235
_ => ( None , true ) ,
@@ -379,52 +384,63 @@ fn extend_type_not_partial_eq<'tcx>(
379
384
adts_without_partialeq : FxHashSet < Span > ,
380
385
/// The user has written `impl PartialEq for Ty` which means it's non-structual,
381
386
/// but we don't have a span to point at, so we'll just add them as a `note`.
382
- manual : Vec < Ty < ' tcx > > ,
387
+ manual : FxHashSet < Ty < ' tcx > > ,
383
388
/// The type has no `PartialEq` implementation, neither manual or derived, but
384
389
/// we don't have a span to point at, so we'll just add them as a `note`.
385
- without : Vec < Ty < ' tcx > > ,
390
+ without : FxHashSet < Ty < ' tcx > > ,
386
391
}
387
392
388
393
impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UsedParamsNeedInstantiationVisitor < ' tcx > {
394
+ type Result = ControlFlow < ( ) > ;
389
395
fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> Self :: Result {
390
- if let ty:: Adt ( def, _args) = ty. kind ( ) {
391
- let ty_def_id = def. did ( ) ;
392
- let ty_def_span = self . tcx . def_span ( ty_def_id) ;
393
- let ( impls_partial_eq, derived, structural, impl_def_id) =
394
- type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
395
- match ( impls_partial_eq, derived, structural, impl_def_id) {
396
- ( _, _, true , _) => { }
397
- ( true , false , _, Some ( def_id) ) if def_id. is_local ( ) => {
398
- self . adts_with_manual_partialeq . insert ( self . tcx . def_span ( def_id) ) ;
399
- }
400
- ( true , false , _, _) if ty_def_id. is_local ( ) => {
401
- self . adts_with_manual_partialeq . insert ( ty_def_span) ;
402
- }
403
- ( false , _, _, _) if ty_def_id. is_local ( ) => {
404
- self . adts_without_partialeq . insert ( ty_def_span) ;
405
- }
406
- ( true , false , _, _) => {
407
- self . manual . push ( ty) ;
408
- }
409
- ( false , _, _, _) => {
410
- self . without . push ( ty) ;
411
- }
412
- _ => { }
413
- } ;
396
+ match ty. kind ( ) {
397
+ ty:: Dynamic ( ..) => return ControlFlow :: Break ( ( ) ) ,
398
+ ty:: FnPtr ( ..) => return ControlFlow :: Continue ( ( ) ) ,
399
+ ty:: Adt ( def, _args) => {
400
+ let ty_def_id = def. did ( ) ;
401
+ let ty_def_span = self . tcx . def_span ( ty_def_id) ;
402
+ let PartialEqImplStatus {
403
+ has_impl,
404
+ is_derived,
405
+ structural_partial_eq,
406
+ non_blanket_impl,
407
+ } = type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
408
+ match ( has_impl, is_derived, structural_partial_eq, non_blanket_impl) {
409
+ ( _, _, true , _) => { }
410
+ ( true , false , _, Some ( def_id) ) if def_id. is_local ( ) => {
411
+ self . adts_with_manual_partialeq . insert ( self . tcx . def_span ( def_id) ) ;
412
+ }
413
+ ( true , false , _, _) if ty_def_id. is_local ( ) => {
414
+ self . adts_with_manual_partialeq . insert ( ty_def_span) ;
415
+ }
416
+ ( false , _, _, _) if ty_def_id. is_local ( ) => {
417
+ self . adts_without_partialeq . insert ( ty_def_span) ;
418
+ }
419
+ ( true , false , _, _) => {
420
+ self . manual . insert ( ty) ;
421
+ }
422
+ ( false , _, _, _) => {
423
+ self . without . insert ( ty) ;
424
+ }
425
+ _ => { }
426
+ } ;
427
+ ty. super_visit_with ( self )
428
+ }
429
+ _ => ty. super_visit_with ( self ) ,
414
430
}
415
- use rustc_middle:: ty:: TypeSuperVisitable ;
416
- ty. super_visit_with ( self )
417
431
}
418
432
}
419
433
let mut v = UsedParamsNeedInstantiationVisitor {
420
434
tcx,
421
435
typing_env,
422
436
adts_with_manual_partialeq : FxHashSet :: default ( ) ,
423
437
adts_without_partialeq : FxHashSet :: default ( ) ,
424
- manual : vec ! [ ] ,
425
- without : vec ! [ ] ,
438
+ manual : FxHashSet :: default ( ) ,
439
+ without : FxHashSet :: default ( ) ,
426
440
} ;
427
- v. visit_ty ( ty) ;
441
+ if v. visit_ty ( ty) . is_break ( ) {
442
+ return ;
443
+ }
428
444
#[ allow( rustc:: potential_query_instability) ] // Span labels will be sorted by the rendering
429
445
for span in v. adts_with_manual_partialeq {
430
446
err. span_note ( span, "the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details" ) ;
@@ -436,29 +452,38 @@ fn extend_type_not_partial_eq<'tcx>(
436
452
"must be annotated with `#[derive(PartialEq)]` to be usable in patterns" ,
437
453
) ;
438
454
}
439
- for ty in v. manual {
455
+ #[ allow( rustc:: potential_query_instability) ]
456
+ let mut manual: Vec < _ > = v. manual . into_iter ( ) . map ( |t| t. to_string ( ) ) . collect ( ) ;
457
+ manual. sort ( ) ;
458
+ for ty in manual {
440
459
err. note ( format ! (
441
460
"`{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"
442
461
) ) ;
443
462
}
444
- for ty in v. without {
463
+ #[ allow( rustc:: potential_query_instability) ]
464
+ let mut without: Vec < _ > = v. without . into_iter ( ) . map ( |t| t. to_string ( ) ) . collect ( ) ;
465
+ without. sort ( ) ;
466
+ for ty in without {
445
467
err. note ( format ! (
446
468
"`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns"
447
469
) ) ;
448
470
}
449
471
}
450
472
473
+ #[ derive( Debug ) ]
474
+ struct PartialEqImplStatus {
475
+ has_impl : bool ,
476
+ is_derived : bool ,
477
+ structural_partial_eq : bool ,
478
+ non_blanket_impl : Option < DefId > ,
479
+ }
480
+
451
481
#[ instrument( level = "trace" , skip( tcx) , ret) ]
452
482
fn type_has_partial_eq_impl < ' tcx > (
453
483
tcx : TyCtxt < ' tcx > ,
454
484
typing_env : ty:: TypingEnv < ' tcx > ,
455
485
ty : Ty < ' tcx > ,
456
- ) -> (
457
- /* has impl */ bool ,
458
- /* is derived */ bool ,
459
- /* structural partial eq */ bool ,
460
- /* non-blanket impl */ Option < DefId > ,
461
- ) {
486
+ ) -> PartialEqImplStatus {
462
487
let ( infcx, param_env) = tcx. infer_ctxt ( ) . build_with_typing_env ( typing_env) ;
463
488
// double-check there even *is* a semantic `PartialEq` to dispatch to.
464
489
//
@@ -495,10 +520,10 @@ fn type_has_partial_eq_impl<'tcx>(
495
520
// that patterns can only do things that the code could also do without patterns, but it is
496
521
// needed for backwards compatibility. The actual pattern matching compares primitive values,
497
522
// `PartialEq::eq` never gets invoked, so there's no risk of us running non-const code.
498
- (
499
- infcx. predicate_must_hold_modulo_regions ( & partial_eq_obligation) ,
500
- automatically_derived,
501
- structural_peq,
502
- impl_def_id,
503
- )
523
+ PartialEqImplStatus {
524
+ has_impl : infcx. predicate_must_hold_modulo_regions ( & partial_eq_obligation) ,
525
+ is_derived : automatically_derived,
526
+ structural_partial_eq : structural_peq,
527
+ non_blanket_impl : impl_def_id,
528
+ }
504
529
}
0 commit comments