@@ -22,11 +22,12 @@ use rustc_middle::traits::specialization_graph::OverlapMode;
2222use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
2323use rustc_middle:: ty:: subst:: Subst ;
2424use rustc_middle:: ty:: visit:: TypeVisitable ;
25- use rustc_middle:: ty:: { self , ImplSubject , Ty , TyCtxt } ;
25+ use rustc_middle:: ty:: { self , ImplSubject , Ty , TyCtxt , TypeVisitor } ;
2626use rustc_span:: symbol:: sym;
2727use rustc_span:: DUMMY_SP ;
2828use std:: fmt:: Debug ;
2929use std:: iter;
30+ use std:: ops:: ControlFlow ;
3031
3132/// Whether we do the orphan check relative to this crate or
3233/// to some remote crate.
@@ -578,220 +579,146 @@ fn orphan_check_trait_ref<'tcx>(
578579 ) ;
579580 }
580581
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 ) )
603594 }
604595 }
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 ( ( ) ) ,
635597 }
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) )
639598}
640599
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 > {
655601 tcx : TyCtxt < ' tcx > ,
656- ty : Ty < ' tcx > ,
657602 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 ( ) ,
667618 }
668619 }
669- }
670620
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+ }
693625
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) )
696631 }
697- _ => return None ,
698- } ;
632+ }
699633
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+ }
701640}
702641
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 > ) ,
710645}
711646
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+ }
770652
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+ }
776689 }
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+ }
778719
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
796723 }
797724}
0 commit comments