@@ -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,220 +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
+ }
699
633
700
- Some ( iter:: once ( first_ty) . chain ( rest_tys) )
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
+ }
701
640
}
702
641
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 ( ) ,
709
- }
642
+ enum OrphanCheckEarlyExit < ' tcx > {
643
+ ParamTy ( Ty < ' tcx > ) ,
644
+ LocalTy ( Ty < ' tcx > ) ,
710
645
}
711
646
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
- ty:: Opaque ( ..) => {
743
- // This merits some explanation.
744
- // Normally, opaque types are not involved when performing
745
- // coherence checking, since it is illegal to directly
746
- // implement a trait on an opaque type. However, we might
747
- // end up looking at an opaque type during coherence checking
748
- // if an opaque type gets used within another type (e.g. as
749
- // a type parameter). This requires us to decide whether or
750
- // not an opaque type should be considered 'local' or not.
751
- //
752
- // We choose to treat all opaque types as non-local, even
753
- // those that appear within the same crate. This seems
754
- // somewhat surprising at first, but makes sense when
755
- // you consider that opaque types are supposed to hide
756
- // the underlying type *within the same crate*. When an
757
- // opaque type is used from outside the module
758
- // where it is declared, it should be impossible to observe
759
- // anything about it other than the traits that it implements.
760
- //
761
- // The alternative would be to look at the underlying type
762
- // to determine whether or not the opaque type itself should
763
- // be considered local. However, this could make it a breaking change
764
- // to switch the underlying ('defining') type from a local type
765
- // to a remote type. This would violate the rule that opaque
766
- // types should be completely opaque apart from the traits
767
- // that they implement, so we don't use this behavior.
768
- false
769
- }
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
651
+ }
770
652
771
- ty:: Dynamic ( ref tt, ..) => {
772
- if let Some ( principal) = tt. principal ( ) {
773
- def_id_is_local ( principal. def_id ( ) , in_crate)
774
- } else {
775
- 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
+ }
776
689
}
777
- }
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
+ }
778
719
779
- ty:: Error ( _) => true ,
780
-
781
- // These variants should never appear during coherence checking because they
782
- // cannot be named directly.
783
- //
784
- // They could be indirectly used through an opaque type. While using opaque types
785
- // in impls causes an error, this path can still be hit afterwards.
786
- //
787
- // See `test/ui/coherence/coherence-with-closure.rs` for an example where this
788
- // could happens.
789
- ty:: Closure ( ..) | ty:: Generator ( ..) | ty:: GeneratorWitness ( ..) => {
790
- tcx. sess . delay_span_bug (
791
- DUMMY_SP ,
792
- format ! ( "ty_is_local invoked on closure or generator: {:?}" , ty) ,
793
- ) ;
794
- true
795
- }
720
+ // FIXME: Constants should participate in orphan checking.
721
+ fn visit_const ( & mut self , _c : ty:: Const < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
722
+ ControlFlow :: CONTINUE
796
723
}
797
724
}
0 commit comments