@@ -452,22 +452,23 @@ fn prove_negated_obligation<'tcx>(
452
452
/// This both checks whether any downstream or sibling crates could
453
453
/// implement it and whether an upstream crate can add this impl
454
454
/// without breaking backwards compatibility.
455
- #[ instrument( level = "debug" , skip( tcx) , ret) ]
456
- pub fn trait_ref_is_knowable < ' tcx > (
455
+ #[ instrument( level = "debug" , skip( tcx, lazily_normalize_ty ) , ret) ]
456
+ pub fn trait_ref_is_knowable < ' tcx , E : Debug > (
457
457
tcx : TyCtxt < ' tcx > ,
458
458
trait_ref : ty:: TraitRef < ' tcx > ,
459
- ) -> Result < ( ) , Conflict > {
459
+ mut lazily_normalize_ty : impl FnMut ( Ty < ' tcx > ) -> Result < Ty < ' tcx > , E > ,
460
+ ) -> Result < Result < ( ) , Conflict > , E > {
460
461
if Some ( trait_ref. def_id ) == tcx. lang_items ( ) . fn_ptr_trait ( ) {
461
462
// The only types implementing `FnPtr` are function pointers,
462
463
// so if there's no impl of `FnPtr` in the current crate,
463
464
// then such an impl will never be added in the future.
464
- return Ok ( ( ) ) ;
465
+ return Ok ( Ok ( ( ) ) ) ;
465
466
}
466
467
467
- if orphan_check_trait_ref ( trait_ref, InCrate :: Remote ) . is_ok ( ) {
468
+ if orphan_check_trait_ref ( trait_ref, InCrate :: Remote , & mut lazily_normalize_ty ) ? . is_ok ( ) {
468
469
// A downstream or cousin crate is allowed to implement some
469
470
// substitution of this trait-ref.
470
- return Err ( Conflict :: Downstream ) ;
471
+ return Ok ( Err ( Conflict :: Downstream ) ) ;
471
472
}
472
473
473
474
if trait_ref_is_local_or_fundamental ( tcx, trait_ref) {
@@ -476,7 +477,7 @@ pub fn trait_ref_is_knowable<'tcx>(
476
477
// allowed to implement a substitution of this trait ref, which
477
478
// means impls could only come from dependencies of this crate,
478
479
// which we already know about.
479
- return Ok ( ( ) ) ;
480
+ return Ok ( Ok ( ( ) ) ) ;
480
481
}
481
482
482
483
// This is a remote non-fundamental trait, so if another crate
@@ -487,10 +488,10 @@ pub fn trait_ref_is_knowable<'tcx>(
487
488
// and if we are an intermediate owner, then we don't care
488
489
// about future-compatibility, which means that we're OK if
489
490
// we are an owner.
490
- if orphan_check_trait_ref ( trait_ref, InCrate :: Local ) . is_ok ( ) {
491
- Ok ( ( ) )
491
+ if orphan_check_trait_ref ( trait_ref, InCrate :: Local , & mut lazily_normalize_ty ) ? . is_ok ( ) {
492
+ Ok ( Ok ( ( ) ) )
492
493
} else {
493
- Err ( Conflict :: Upstream )
494
+ Ok ( Err ( Conflict :: Upstream ) )
494
495
}
495
496
}
496
497
@@ -526,7 +527,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
526
527
return Ok ( ( ) ) ;
527
528
}
528
529
529
- orphan_check_trait_ref ( trait_ref, InCrate :: Local )
530
+ orphan_check_trait_ref :: < ! > ( trait_ref, InCrate :: Local , |ty| Ok ( ty ) ) . unwrap ( )
530
531
}
531
532
532
533
/// Checks whether a trait-ref is potentially implementable by a crate.
@@ -615,21 +616,23 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
615
616
///
616
617
/// Note that this function is never called for types that have both type
617
618
/// parameters and inference variables.
618
- #[ instrument( level = "trace" , ret) ]
619
- fn orphan_check_trait_ref < ' tcx > (
619
+ #[ instrument( level = "trace" , skip ( lazily_normalize_ty ) , ret) ]
620
+ fn orphan_check_trait_ref < ' tcx , E : Debug > (
620
621
trait_ref : ty:: TraitRef < ' tcx > ,
621
622
in_crate : InCrate ,
622
- ) -> Result < ( ) , OrphanCheckErr < ' tcx > > {
623
+ lazily_normalize_ty : impl FnMut ( Ty < ' tcx > ) -> Result < Ty < ' tcx > , E > ,
624
+ ) -> Result < Result < ( ) , OrphanCheckErr < ' tcx > > , E > {
623
625
if trait_ref. has_infer ( ) && trait_ref. has_param ( ) {
624
626
bug ! (
625
627
"can't orphan check a trait ref with both params and inference variables {:?}" ,
626
628
trait_ref
627
629
) ;
628
630
}
629
631
630
- let mut checker = OrphanChecker :: new ( in_crate) ;
631
- match trait_ref. visit_with ( & mut checker) {
632
+ let mut checker = OrphanChecker :: new ( in_crate, lazily_normalize_ty ) ;
633
+ Ok ( match trait_ref. visit_with ( & mut checker) {
632
634
ControlFlow :: Continue ( ( ) ) => Err ( OrphanCheckErr :: NonLocalInputType ( checker. non_local_tys ) ) ,
635
+ ControlFlow :: Break ( OrphanCheckEarlyExit :: NormalizationFailure ( err) ) => return Err ( err) ,
633
636
ControlFlow :: Break ( OrphanCheckEarlyExit :: ParamTy ( ty) ) => {
634
637
// Does there exist some local type after the `ParamTy`.
635
638
checker. search_first_local_ty = true ;
@@ -642,34 +645,39 @@ fn orphan_check_trait_ref<'tcx>(
642
645
}
643
646
}
644
647
ControlFlow :: Break ( OrphanCheckEarlyExit :: LocalTy ( _) ) => Ok ( ( ) ) ,
645
- }
648
+ } )
646
649
}
647
650
648
- struct OrphanChecker < ' tcx > {
651
+ struct OrphanChecker < ' tcx , F > {
649
652
in_crate : InCrate ,
650
653
in_self_ty : bool ,
654
+ lazily_normalize_ty : F ,
651
655
/// Ignore orphan check failures and exclusively search for the first
652
656
/// local type.
653
657
search_first_local_ty : bool ,
654
658
non_local_tys : Vec < ( Ty < ' tcx > , bool ) > ,
655
659
}
656
660
657
- impl < ' tcx > OrphanChecker < ' tcx > {
658
- fn new ( in_crate : InCrate ) -> Self {
661
+ impl < ' tcx , F , E > OrphanChecker < ' tcx , F >
662
+ where
663
+ F : FnOnce ( Ty < ' tcx > ) -> Result < Ty < ' tcx > , E > ,
664
+ {
665
+ fn new ( in_crate : InCrate , lazily_normalize_ty : F ) -> Self {
659
666
OrphanChecker {
660
667
in_crate,
661
668
in_self_ty : true ,
669
+ lazily_normalize_ty,
662
670
search_first_local_ty : false ,
663
671
non_local_tys : Vec :: new ( ) ,
664
672
}
665
673
}
666
674
667
- fn found_non_local_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < OrphanCheckEarlyExit < ' tcx > > {
675
+ fn found_non_local_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < OrphanCheckEarlyExit < ' tcx , E > > {
668
676
self . non_local_tys . push ( ( t, self . in_self_ty ) ) ;
669
677
ControlFlow :: Continue ( ( ) )
670
678
}
671
679
672
- fn found_param_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < OrphanCheckEarlyExit < ' tcx > > {
680
+ fn found_param_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < OrphanCheckEarlyExit < ' tcx , E > > {
673
681
if self . search_first_local_ty {
674
682
ControlFlow :: Continue ( ( ) )
675
683
} else {
@@ -685,18 +693,28 @@ impl<'tcx> OrphanChecker<'tcx> {
685
693
}
686
694
}
687
695
688
- enum OrphanCheckEarlyExit < ' tcx > {
696
+ enum OrphanCheckEarlyExit < ' tcx , E > {
697
+ NormalizationFailure ( E ) ,
689
698
ParamTy ( Ty < ' tcx > ) ,
690
699
LocalTy ( Ty < ' tcx > ) ,
691
700
}
692
701
693
- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for OrphanChecker < ' tcx > {
694
- type BreakTy = OrphanCheckEarlyExit < ' tcx > ;
702
+ impl < ' tcx , F , E > TypeVisitor < TyCtxt < ' tcx > > for OrphanChecker < ' tcx , F >
703
+ where
704
+ F : FnMut ( Ty < ' tcx > ) -> Result < Ty < ' tcx > , E > ,
705
+ {
706
+ type BreakTy = OrphanCheckEarlyExit < ' tcx , E > ;
695
707
fn visit_region ( & mut self , _r : ty:: Region < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
696
708
ControlFlow :: Continue ( ( ) )
697
709
}
698
710
699
711
fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
712
+ // Need to lazily normalize here in with `-Ztrait-solver=next-coherence`.
713
+ let ty = match ( self . lazily_normalize_ty ) ( ty) {
714
+ Ok ( ty) => ty,
715
+ Err ( err) => return ControlFlow :: Break ( OrphanCheckEarlyExit :: NormalizationFailure ( err) ) ,
716
+ } ;
717
+
700
718
let result = match * ty. kind ( ) {
701
719
ty:: Bool
702
720
| ty:: Char
0 commit comments