@@ -22,11 +22,12 @@ use rustc_middle::traits::specialization_graph::OverlapMode;
22
22
use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
23
23
use rustc_middle:: ty:: subst:: Subst ;
24
24
use rustc_middle:: ty:: visit:: TypeVisitable ;
25
- use rustc_middle:: ty:: { self , ImplSubject , Ty , TyCtxt } ;
25
+ use rustc_middle:: ty:: { self , ImplSubject , Ty , TyCtxt , TypeVisitor } ;
26
26
use rustc_span:: symbol:: sym;
27
27
use rustc_span:: DUMMY_SP ;
28
28
use std:: fmt:: Debug ;
29
29
use std:: iter;
30
+ use std:: ops:: ControlFlow ;
30
31
31
32
/// Whether we do the orphan check relative to this crate or
32
33
/// to some remote crate.
@@ -578,192 +579,146 @@ fn orphan_check_trait_ref<'tcx>(
578
579
) ;
579
580
}
580
581
581
- // Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only
582
- // if at least one of the following is true:
583
- //
584
- // - Trait is a local trait
585
- // (already checked in orphan_check prior to calling this function)
586
- // - All of
587
- // - At least one of the types T0..=Tn must be a local type.
588
- // Let Ti be the first such type.
589
- // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
590
- //
591
- fn uncover_fundamental_ty < ' tcx > (
592
- tcx : TyCtxt < ' tcx > ,
593
- ty : Ty < ' tcx > ,
594
- in_crate : InCrate ,
595
- ) -> Vec < Ty < ' tcx > > {
596
- // FIXME: this is currently somewhat overly complicated,
597
- // but fixing this requires a more complicated refactor.
598
- if !contained_non_local_types ( tcx, ty, in_crate) . is_empty ( ) {
599
- if let Some ( inner_tys) = fundamental_ty_inner_tys ( tcx, ty) {
600
- return inner_tys
601
- . flat_map ( |ty| uncover_fundamental_ty ( tcx, ty, in_crate) )
602
- . collect ( ) ;
582
+ let mut checker = OrphanChecker :: new ( tcx, in_crate) ;
583
+ match trait_ref. visit_with ( & mut checker) {
584
+ ControlFlow :: Continue ( ( ) ) => Err ( OrphanCheckErr :: NonLocalInputType ( checker. non_local_tys ) ) ,
585
+ ControlFlow :: Break ( OrphanCheckEarlyExit :: ParamTy ( ty) ) => {
586
+ // Does there exist some local type after the `ParamTy`.
587
+ checker. search_first_local_ty = true ;
588
+ if let Some ( OrphanCheckEarlyExit :: LocalTy ( local_ty) ) =
589
+ trait_ref. visit_with ( & mut checker) . break_value ( )
590
+ {
591
+ Err ( OrphanCheckErr :: UncoveredTy ( ty, Some ( local_ty) ) )
592
+ } else {
593
+ Err ( OrphanCheckErr :: UncoveredTy ( ty, None ) )
603
594
}
604
595
}
605
-
606
- vec ! [ ty]
607
- }
608
-
609
- let mut non_local_spans = vec ! [ ] ;
610
- for ( i, input_ty) in trait_ref
611
- . substs
612
- . types ( )
613
- . flat_map ( |ty| uncover_fundamental_ty ( tcx, ty, in_crate) )
614
- . enumerate ( )
615
- {
616
- debug ! ( "orphan_check_trait_ref: check ty `{:?}`" , input_ty) ;
617
- let non_local_tys = contained_non_local_types ( tcx, input_ty, in_crate) ;
618
- if non_local_tys. is_empty ( ) {
619
- debug ! ( "orphan_check_trait_ref: ty_is_local `{:?}`" , input_ty) ;
620
- return Ok ( ( ) ) ;
621
- } else if let ty:: Param ( _) = input_ty. kind ( ) {
622
- debug ! ( "orphan_check_trait_ref: uncovered ty: `{:?}`" , input_ty) ;
623
- let local_type = trait_ref
624
- . substs
625
- . types ( )
626
- . flat_map ( |ty| uncover_fundamental_ty ( tcx, ty, in_crate) )
627
- . find ( |& ty| ty_is_local_constructor ( tcx, ty, in_crate) ) ;
628
-
629
- debug ! ( "orphan_check_trait_ref: uncovered ty local_type: `{:?}`" , local_type) ;
630
-
631
- return Err ( OrphanCheckErr :: UncoveredTy ( input_ty, local_type) ) ;
632
- }
633
-
634
- non_local_spans. extend ( non_local_tys. into_iter ( ) . map ( |input_ty| ( input_ty, i == 0 ) ) ) ;
596
+ ControlFlow :: Break ( OrphanCheckEarlyExit :: LocalTy ( _) ) => Ok ( ( ) ) ,
635
597
}
636
- // If we exit above loop, never found a local type.
637
- debug ! ( "orphan_check_trait_ref: no local type" ) ;
638
- Err ( OrphanCheckErr :: NonLocalInputType ( non_local_spans) )
639
598
}
640
599
641
- /// Returns a list of relevant non-local types for `ty`.
642
- ///
643
- /// This is just `ty` itself unless `ty` is `#[fundamental]`,
644
- /// in which case we recursively look into this type.
645
- ///
646
- /// If `ty` is local itself, this method returns an empty `Vec`.
647
- ///
648
- /// # Examples
649
- ///
650
- /// - `u32` is not local, so this returns `[u32]`.
651
- /// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`.
652
- /// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`.
653
- /// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local.
654
- fn contained_non_local_types < ' tcx > (
600
+ struct OrphanChecker < ' tcx > {
655
601
tcx : TyCtxt < ' tcx > ,
656
- ty : Ty < ' tcx > ,
657
602
in_crate : InCrate ,
658
- ) -> Vec < Ty < ' tcx > > {
659
- if ty_is_local_constructor ( tcx, ty, in_crate) {
660
- Vec :: new ( )
661
- } else {
662
- match fundamental_ty_inner_tys ( tcx, ty) {
663
- Some ( inner_tys) => {
664
- inner_tys. flat_map ( |ty| contained_non_local_types ( tcx, ty, in_crate) ) . collect ( )
665
- }
666
- None => vec ! [ ty] ,
603
+ in_self_ty : bool ,
604
+ /// Ignore orphan check failures and exclusively search for the first
605
+ /// local type.
606
+ search_first_local_ty : bool ,
607
+ non_local_tys : Vec < ( Ty < ' tcx > , bool ) > ,
608
+ }
609
+
610
+ impl < ' tcx > OrphanChecker < ' tcx > {
611
+ fn new ( tcx : TyCtxt < ' tcx > , in_crate : InCrate ) -> Self {
612
+ OrphanChecker {
613
+ tcx,
614
+ in_crate,
615
+ in_self_ty : true ,
616
+ search_first_local_ty : false ,
617
+ non_local_tys : Vec :: new ( ) ,
667
618
}
668
619
}
669
- }
670
620
671
- /// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the
672
- /// type parameters of the ADT, or `T`, respectively. For non-fundamental
673
- /// types, returns `None`.
674
- fn fundamental_ty_inner_tys < ' tcx > (
675
- tcx : TyCtxt < ' tcx > ,
676
- ty : Ty < ' tcx > ,
677
- ) -> Option < impl Iterator < Item = Ty < ' tcx > > > {
678
- let ( first_ty, rest_tys) = match * ty. kind ( ) {
679
- ty:: Ref ( _, ty, _) => ( ty, ty:: subst:: InternalSubsts :: empty ( ) . types ( ) ) ,
680
- ty:: Adt ( def, substs) if def. is_fundamental ( ) => {
681
- let mut types = substs. types ( ) ;
682
-
683
- // FIXME(eddyb) actually validate `#[fundamental]` up-front.
684
- match types. next ( ) {
685
- None => {
686
- tcx. sess . span_err (
687
- tcx. def_span ( def. did ( ) ) ,
688
- "`#[fundamental]` requires at least one type parameter" ,
689
- ) ;
690
-
691
- return None ;
692
- }
621
+ fn found_non_local_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < OrphanCheckEarlyExit < ' tcx > > {
622
+ self . non_local_tys . push ( ( t, self . in_self_ty ) ) ;
623
+ ControlFlow :: CONTINUE
624
+ }
693
625
694
- Some ( first_ty) => ( first_ty, types) ,
695
- }
626
+ fn found_param_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < OrphanCheckEarlyExit < ' tcx > > {
627
+ if self . search_first_local_ty {
628
+ ControlFlow :: CONTINUE
629
+ } else {
630
+ ControlFlow :: Break ( OrphanCheckEarlyExit :: ParamTy ( t) )
696
631
}
697
- _ => return None ,
698
- } ;
632
+ }
633
+
634
+ fn def_id_is_local ( & mut self , def_id : DefId ) -> bool {
635
+ match self . in_crate {
636
+ InCrate :: Local => def_id. is_local ( ) ,
637
+ InCrate :: Remote => false ,
638
+ }
639
+ }
640
+ }
699
641
700
- Some ( iter:: once ( first_ty) . chain ( rest_tys) )
642
+ enum OrphanCheckEarlyExit < ' tcx > {
643
+ ParamTy ( Ty < ' tcx > ) ,
644
+ LocalTy ( Ty < ' tcx > ) ,
701
645
}
702
646
703
- fn def_id_is_local ( def_id : DefId , in_crate : InCrate ) -> bool {
704
- match in_crate {
705
- // The type is local to *this* crate - it will not be
706
- // local in any other crate.
707
- InCrate :: Remote => false ,
708
- InCrate :: Local => def_id. is_local ( ) ,
647
+ impl < ' tcx > TypeVisitor < ' tcx > for OrphanChecker < ' tcx > {
648
+ type BreakTy = OrphanCheckEarlyExit < ' tcx > ;
649
+ fn visit_region ( & mut self , _r : ty:: Region < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
650
+ ControlFlow :: CONTINUE
709
651
}
710
- }
711
652
712
- fn ty_is_local_constructor ( tcx : TyCtxt < ' _ > , ty : Ty < ' _ > , in_crate : InCrate ) -> bool {
713
- debug ! ( "ty_is_local_constructor({:?})" , ty ) ;
714
-
715
- match * ty . kind ( ) {
716
- ty:: Bool
717
- | ty:: Char
718
- | ty:: Int ( ..)
719
- | ty:: Uint ( .. )
720
- | ty:: Float ( ..)
721
- | ty:: Str
722
- | ty:: FnDef ( ..)
723
- | ty:: FnPtr ( _ )
724
- | ty:: Array ( ..)
725
- | ty:: Slice ( .. )
726
- | ty:: RawPtr ( ..)
727
- | ty:: Ref ( ..)
728
- | ty :: Never
729
- | ty:: Tuple ( ..)
730
- | ty :: Param ( .. )
731
- | ty:: Projection ( ..) => false ,
732
-
733
- ty :: Placeholder ( .. ) | ty :: Bound ( .. ) | ty :: Infer ( .. ) => match in_crate {
734
- InCrate :: Local => false ,
735
- // The inference variable might be unified with a local
736
- // type in that remote crate.
737
- InCrate :: Remote => true ,
738
- } ,
739
-
740
- ty:: Adt ( def, _ ) => def_id_is_local ( def . did ( ) , in_crate ) ,
741
- ty :: Foreign ( did ) => def_id_is_local ( did, in_crate ) ,
742
-
743
- ty :: Dynamic ( ref tt , .. ) => {
744
- if let Some ( principal ) = tt . principal ( ) {
745
- def_id_is_local ( principal . def_id ( ) , in_crate )
746
- } else {
747
- false
653
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
654
+ let result = match * ty . kind ( ) {
655
+ ty :: Bool
656
+ | ty :: Char
657
+ | ty:: Int ( .. )
658
+ | ty:: Uint ( .. )
659
+ | ty:: Float ( ..)
660
+ | ty:: Str
661
+ | ty:: FnDef ( ..)
662
+ | ty:: FnPtr ( _ )
663
+ | ty:: Array ( ..)
664
+ | ty:: Slice ( .. )
665
+ | ty:: RawPtr ( ..)
666
+ | ty:: Never
667
+ | ty:: Tuple ( ..)
668
+ | ty:: Projection ( ..) => self . found_non_local_ty ( ty ) ,
669
+
670
+ ty:: Param ( ..) => self . found_param_ty ( ty ) ,
671
+
672
+ ty :: Placeholder ( .. ) | ty:: Bound ( ..) | ty :: Infer ( .. ) => match self . in_crate {
673
+ InCrate :: Local => self . found_non_local_ty ( ty ) ,
674
+ // The inference variable might be unified with a local
675
+ // type in that remote crate.
676
+ InCrate :: Remote => ControlFlow :: Break ( OrphanCheckEarlyExit :: LocalTy ( ty ) ) ,
677
+ } ,
678
+
679
+ // For fundamental types, we just look inside of them.
680
+ ty :: Ref ( _ , ty , _ ) => ty . visit_with ( self ) ,
681
+ ty:: Adt ( def, substs ) => {
682
+ if self . def_id_is_local ( def . did ( ) ) {
683
+ ControlFlow :: Break ( OrphanCheckEarlyExit :: LocalTy ( ty ) )
684
+ } else if def . is_fundamental ( ) {
685
+ substs . visit_with ( self )
686
+ } else {
687
+ self . found_non_local_ty ( ty )
688
+ }
748
689
}
749
- }
690
+ ty:: Foreign ( def_id) => {
691
+ if self . def_id_is_local ( def_id) {
692
+ ControlFlow :: Break ( OrphanCheckEarlyExit :: LocalTy ( ty) )
693
+ } else {
694
+ self . found_non_local_ty ( ty)
695
+ }
696
+ }
697
+ ty:: Dynamic ( tt, ..) => {
698
+ let principal = tt. principal ( ) . map ( |p| p. def_id ( ) ) ;
699
+ if principal. map_or ( false , |p| self . def_id_is_local ( p) ) {
700
+ ControlFlow :: Break ( OrphanCheckEarlyExit :: LocalTy ( ty) )
701
+ } else {
702
+ self . found_non_local_ty ( ty)
703
+ }
704
+ }
705
+ ty:: Error ( _) => ControlFlow :: Break ( OrphanCheckEarlyExit :: LocalTy ( ty) ) ,
706
+ ty:: Opaque ( ..) | ty:: Closure ( ..) | ty:: Generator ( ..) | ty:: GeneratorWitness ( ..) => {
707
+ self . tcx . sess . delay_span_bug (
708
+ DUMMY_SP ,
709
+ format ! ( "ty_is_local invoked on closure or generator: {:?}" , ty) ,
710
+ ) ;
711
+ ControlFlow :: Break ( OrphanCheckEarlyExit :: LocalTy ( ty) )
712
+ }
713
+ } ;
714
+ // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
715
+ // the first type we visit is always the self type.
716
+ self . in_self_ty = false ;
717
+ result
718
+ }
750
719
751
- ty:: Error ( _) => true ,
752
-
753
- // These variants should never appear during coherence checking because they
754
- // cannot be named directly.
755
- //
756
- // They could be indirectly used through an opaque type. While using opaque types
757
- // in impls causes an error, this path can still be hit afterwards.
758
- //
759
- // See `test/ui/coherence/coherence-with-closure.rs` for an example where this
760
- // could happens.
761
- ty:: Opaque ( ..) | ty:: Closure ( ..) | ty:: Generator ( ..) | ty:: GeneratorWitness ( ..) => {
762
- tcx. sess . delay_span_bug (
763
- DUMMY_SP ,
764
- format ! ( "ty_is_local invoked on closure or generator: {:?}" , ty) ,
765
- ) ;
766
- true
767
- }
720
+ // FIXME: Constants should participate in orphan checking.
721
+ fn visit_const ( & mut self , _c : ty:: Const < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
722
+ ControlFlow :: CONTINUE
768
723
}
769
724
}
0 commit comments