@@ -13,11 +13,10 @@ use crate::traits::outlives_bounds::InferCtxtExt as _;
1313use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt ;
1414use crate :: traits:: select:: { IntercrateAmbiguityCause , TreatInductiveCycleAs } ;
1515use crate :: traits:: structural_normalize:: StructurallyNormalizeExt ;
16- use crate :: traits:: util:: impl_subject_and_oblig;
1716use crate :: traits:: NormalizeExt ;
1817use crate :: traits:: SkipLeakCheck ;
1918use crate :: traits:: {
20- self , Obligation , ObligationCause , ObligationCtxt , PredicateObligation , PredicateObligations ,
19+ Obligation , ObligationCause , ObligationCtxt , PredicateObligation , PredicateObligations ,
2120 SelectionContext ,
2221} ;
2322use rustc_data_structures:: fx:: FxIndexSet ;
@@ -32,7 +31,7 @@ use rustc_middle::traits::DefiningAnchor;
3231use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
3332use rustc_middle:: ty:: print:: with_no_trimmed_paths;
3433use rustc_middle:: ty:: visit:: { TypeVisitable , TypeVisitableExt } ;
35- use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitor } ;
34+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitor } ;
3635use rustc_session:: lint:: builtin:: COINDUCTIVE_OVERLAP_IN_COHERENCE ;
3736use rustc_span:: symbol:: sym;
3837use rustc_span:: DUMMY_SP ;
@@ -399,53 +398,167 @@ fn impl_intersection_has_negative_obligation(
399398) -> bool {
400399 debug ! ( "negative_impl(impl1_def_id={:?}, impl2_def_id={:?})" , impl1_def_id, impl2_def_id) ;
401400
402- // Create an infcx, taking the predicates of impl1 as assumptions:
403- let infcx = tcx. infer_ctxt ( ) . build ( ) ;
404- // create a parameter environment corresponding to a (placeholder) instantiation of impl1
405- let impl_env = tcx. param_env ( impl1_def_id) ;
406- let subject1 = match traits:: fully_normalize (
407- & infcx,
408- ObligationCause :: dummy ( ) ,
409- impl_env,
410- tcx. impl_subject ( impl1_def_id) . instantiate_identity ( ) ,
411- ) {
412- Ok ( s) => s,
413- Err ( err) => {
414- tcx. sess . delay_span_bug (
415- tcx. def_span ( impl1_def_id) ,
416- format ! ( "failed to fully normalize {impl1_def_id:?}: {err:?}" ) ,
417- ) ;
418- return false ;
419- }
420- } ;
401+ let ref infcx = tcx. infer_ctxt ( ) . intercrate ( true ) . build ( ) ;
402+ let universe = infcx. create_next_universe ( ) ;
421403
422- // Attempt to prove that impl2 applies, given all of the above.
423- let selcx = & mut SelectionContext :: new ( & infcx) ;
424- let impl2_args = infcx. fresh_args_for_item ( DUMMY_SP , impl2_def_id) ;
425- let ( subject2, normalization_obligations) =
426- impl_subject_and_oblig ( selcx, impl_env, impl2_def_id, impl2_args, |_, _| {
427- ObligationCause :: dummy ( )
428- } ) ;
429-
430- // do the impls unify? If not, then it's not currently possible to prove any
431- // obligations about their intersection.
432- let Ok ( InferOk { obligations : equate_obligations, .. } ) =
433- infcx. at ( & ObligationCause :: dummy ( ) , impl_env) . eq ( DefineOpaqueTypes :: No , subject1, subject2)
404+ let impl1_header = fresh_impl_header ( infcx, impl1_def_id) ;
405+ let param_env =
406+ ty:: EarlyBinder :: bind ( tcx. param_env ( impl1_def_id) ) . instantiate ( tcx, impl1_header. impl_args ) ;
407+
408+ let impl2_header = fresh_impl_header ( infcx, impl2_def_id) ;
409+
410+ // Equate the headers to find their intersection (the general type, with infer vars,
411+ // that may apply both impls).
412+ let Some ( _equate_obligations) =
413+ equate_impl_headers ( infcx, param_env, & impl1_header, & impl2_header)
434414 else {
435- debug ! ( "explicit_disjoint: {:?} does not unify with {:?}" , subject1, subject2) ;
436415 return false ;
437416 } ;
438417
439- for obligation in normalization_obligations. into_iter ( ) . chain ( equate_obligations) {
440- if negative_impl_exists ( & infcx, & obligation, impl1_def_id) {
441- debug ! ( "overlap: obligation unsatisfiable {:?}" , obligation) ;
442- return true ;
418+ plug_infer_with_placeholders ( infcx, universe, ( impl1_header. impl_args , impl2_header. impl_args ) ) ;
419+
420+ for ( predicate, _) in util:: elaborate (
421+ tcx,
422+ tcx. predicates_of ( impl2_def_id) . instantiate ( tcx, impl2_header. impl_args ) ,
423+ ) {
424+ let Some ( negative_predicate) = predicate. as_predicate ( ) . flip_polarity ( tcx) else {
425+ continue ;
426+ } ;
427+
428+ let ref infcx = infcx. fork ( ) ;
429+ let ocx = ObligationCtxt :: new ( infcx) ;
430+
431+ ocx. register_obligation ( Obligation :: new (
432+ tcx,
433+ ObligationCause :: dummy ( ) ,
434+ param_env,
435+ negative_predicate,
436+ ) ) ;
437+
438+ if !ocx. select_all_or_error ( ) . is_empty ( ) {
439+ continue ;
443440 }
441+
442+ // FIXME: regions here too...
443+
444+ return true ;
444445 }
445446
446447 false
447448}
448449
450+ fn plug_infer_with_placeholders < ' tcx > (
451+ infcx : & InferCtxt < ' tcx > ,
452+ universe : ty:: UniverseIndex ,
453+ value : impl TypeVisitable < TyCtxt < ' tcx > > ,
454+ ) {
455+ struct PlugInferWithPlaceholder < ' a , ' tcx > {
456+ infcx : & ' a InferCtxt < ' tcx > ,
457+ universe : ty:: UniverseIndex ,
458+ var : ty:: BoundVar ,
459+ }
460+
461+ impl < ' tcx > PlugInferWithPlaceholder < ' _ , ' tcx > {
462+ fn next_var ( & mut self ) -> ty:: BoundVar {
463+ let var = self . var ;
464+ self . var = self . var + 1 ;
465+ var
466+ }
467+ }
468+
469+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for PlugInferWithPlaceholder < ' _ , ' tcx > {
470+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
471+ let ty = self . infcx . shallow_resolve ( ty) ;
472+ if ty. is_ty_var ( ) {
473+ let Ok ( InferOk { value : ( ) , obligations } ) =
474+ self . infcx . at ( & ObligationCause :: dummy ( ) , ty:: ParamEnv :: empty ( ) ) . eq (
475+ DefineOpaqueTypes :: No ,
476+ ty,
477+ Ty :: new_placeholder (
478+ self . infcx . tcx ,
479+ ty:: Placeholder {
480+ universe : self . universe ,
481+ bound : ty:: BoundTy {
482+ var : self . next_var ( ) ,
483+ kind : ty:: BoundTyKind :: Anon ,
484+ } ,
485+ } ,
486+ ) ,
487+ )
488+ else {
489+ bug ! ( )
490+ } ;
491+ assert_eq ! ( obligations, & [ ] ) ;
492+ ControlFlow :: Continue ( ( ) )
493+ } else {
494+ ty. super_visit_with ( self )
495+ }
496+ }
497+
498+ fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
499+ let ct = self . infcx . shallow_resolve ( ct) ;
500+ if ct. is_ct_infer ( ) {
501+ let Ok ( InferOk { value : ( ) , obligations } ) =
502+ self . infcx . at ( & ObligationCause :: dummy ( ) , ty:: ParamEnv :: empty ( ) ) . eq (
503+ DefineOpaqueTypes :: No ,
504+ ct,
505+ ty:: Const :: new_placeholder (
506+ self . infcx . tcx ,
507+ ty:: Placeholder { universe : self . universe , bound : self . next_var ( ) } ,
508+ ct. ty ( ) ,
509+ ) ,
510+ )
511+ else {
512+ bug ! ( )
513+ } ;
514+ assert_eq ! ( obligations, & [ ] ) ;
515+ ControlFlow :: Continue ( ( ) )
516+ } else {
517+ ct. super_visit_with ( self )
518+ }
519+ }
520+
521+ fn visit_region ( & mut self , r : ty:: Region < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
522+ if let ty:: ReVar ( vid) = * r {
523+ let r = self
524+ . infcx
525+ . inner
526+ . borrow_mut ( )
527+ . unwrap_region_constraints ( )
528+ . opportunistic_resolve_var ( self . infcx . tcx , vid) ;
529+ if r. is_var ( ) {
530+ let Ok ( InferOk { value : ( ) , obligations } ) =
531+ self . infcx . at ( & ObligationCause :: dummy ( ) , ty:: ParamEnv :: empty ( ) ) . eq (
532+ DefineOpaqueTypes :: No ,
533+ r,
534+ ty:: Region :: new_placeholder (
535+ self . infcx . tcx ,
536+ ty:: Placeholder {
537+ universe : self . universe ,
538+ bound : ty:: BoundRegion {
539+ var : self . next_var ( ) ,
540+ kind : ty:: BoundRegionKind :: BrAnon ,
541+ } ,
542+ } ,
543+ ) ,
544+ )
545+ else {
546+ bug ! ( )
547+ } ;
548+ assert_eq ! ( obligations, & [ ] ) ;
549+ }
550+ }
551+ ControlFlow :: Continue ( ( ) )
552+ }
553+ }
554+
555+ value. visit_with ( & mut PlugInferWithPlaceholder {
556+ infcx,
557+ universe,
558+ var : ty:: BoundVar :: from_u32 ( 0 ) ,
559+ } ) ;
560+ }
561+
449562/// Try to prove that a negative impl exist for the obligation or its supertraits.
450563///
451564/// If such a negative impl exists, then the obligation definitely must not hold
0 commit comments