1+ use core:: ops:: ControlFlow ;
2+
13use rustc_abi:: { FieldIdx , VariantIdx } ;
24use rustc_apfloat:: Float ;
35use rustc_data_structures:: fx:: FxHashSet ;
@@ -187,7 +189,7 @@ impl<'tcx> ConstToPat<'tcx> {
187189
188190 if !inlined_const_as_pat. references_error ( ) {
189191 // Always check for `PartialEq` if we had no other errors yet.
190- 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 {
191193 let mut err = self . tcx . dcx ( ) . create_err ( TypeNotPartialEq { span : self . span , ty } ) ;
192194 extend_type_not_partial_eq ( self . tcx , typing_env, ty, & mut err) ;
193195 return self . mk_err ( err, ty) ;
@@ -221,12 +223,13 @@ impl<'tcx> ConstToPat<'tcx> {
221223 // Extremely important check for all ADTs! Make sure they opted-in to be used in
222224 // patterns.
223225 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) ;
226+ let PartialEqImplStatus {
227+ is_derived, structural_partial_eq, non_blanket_impl, ..
228+ } = type_has_partial_eq_impl ( self . tcx , self . typing_env , ty) ;
226229 let ( manual_partialeq_impl_span, manual_partialeq_impl_note) =
227- match ( structural , impl_def_id ) {
230+ match ( structural_partial_eq , non_blanket_impl ) {
228231 ( true , _) => ( None , false ) ,
229- ( _, Some ( def_id) ) if def_id. is_local ( ) && !derived => {
232+ ( _, Some ( def_id) ) if def_id. is_local ( ) && !is_derived => {
230233 ( Some ( tcx. def_span ( def_id) ) , false )
231234 }
232235 _ => ( None , true ) ,
@@ -385,40 +388,46 @@ fn extend_type_not_partial_eq<'tcx>(
385388 /// The type has no `PartialEq` implementation, neither manual or derived, but
386389 /// we don't have a span to point at, so we'll just add them as a `note`.
387390 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 ,
390391 }
391392
392393 impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UsedParamsNeedInstantiationVisitor < ' tcx > {
394+ type Result = ControlFlow < ( ) > ;
393395 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- } ;
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 ) ,
420430 }
421- ty. super_visit_with ( self )
422431 }
423432 }
424433 let mut v = UsedParamsNeedInstantiationVisitor {
@@ -428,10 +437,8 @@ fn extend_type_not_partial_eq<'tcx>(
428437 adts_without_partialeq : FxHashSet :: default ( ) ,
429438 manual : FxHashSet :: default ( ) ,
430439 without : FxHashSet :: default ( ) ,
431- has_escaping_bound_vars : false ,
432440 } ;
433- v. visit_ty ( ty) ;
434- if v. has_escaping_bound_vars {
441+ if v. visit_ty ( ty) . is_break ( ) {
435442 return ;
436443 }
437444 #[ allow( rustc:: potential_query_instability) ] // Span labels will be sorted by the rendering
@@ -445,31 +452,38 @@ fn extend_type_not_partial_eq<'tcx>(
445452 "must be annotated with `#[derive(PartialEq)]` to be usable in patterns" ,
446453 ) ;
447454 }
448- #[ allow( rustc:: potential_query_instability) ] // Span labels will be sorted by the rendering
449- 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 {
450459 err. note ( format ! (
451460 "`{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"
452461 ) ) ;
453462 }
454- #[ allow( rustc:: potential_query_instability) ] // Span labels will be sorted by the rendering
455- 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 {
456467 err. note ( format ! (
457468 "`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns"
458469 ) ) ;
459470 }
460471}
461472
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+
462481#[ instrument( level = "trace" , skip( tcx) , ret) ]
463482fn type_has_partial_eq_impl < ' tcx > (
464483 tcx : TyCtxt < ' tcx > ,
465484 typing_env : ty:: TypingEnv < ' tcx > ,
466485 ty : Ty < ' tcx > ,
467- ) -> (
468- /* has impl */ bool ,
469- /* is derived */ bool ,
470- /* structural partial eq */ bool ,
471- /* non-blanket impl */ Option < DefId > ,
472- ) {
486+ ) -> PartialEqImplStatus {
473487 let ( infcx, param_env) = tcx. infer_ctxt ( ) . build_with_typing_env ( typing_env) ;
474488 // double-check there even *is* a semantic `PartialEq` to dispatch to.
475489 //
@@ -479,10 +493,6 @@ fn type_has_partial_eq_impl<'tcx>(
479493 let partial_eq_trait_id = tcx. require_lang_item ( hir:: LangItem :: PartialEq , None ) ;
480494 let structural_partial_eq_trait_id = tcx. require_lang_item ( hir:: LangItem :: StructuralPeq , None ) ;
481495
482- if ty. has_escaping_bound_vars ( ) {
483- return ( false , false , false , None ) ;
484- }
485-
486496 let partial_eq_obligation = Obligation :: new (
487497 tcx,
488498 ObligationCause :: dummy ( ) ,
@@ -510,10 +520,10 @@ fn type_has_partial_eq_impl<'tcx>(
510520 // that patterns can only do things that the code could also do without patterns, but it is
511521 // needed for backwards compatibility. The actual pattern matching compares primitive values,
512522 // `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- )
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+ }
519529}
0 commit comments