@@ -12,17 +12,16 @@ use super::elaborate;
1212
1313use crate :: infer:: TyCtxtInferExt ;
1414use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt ;
15- use crate :: traits:: { Obligation , ObligationCause } ;
15+ use crate :: traits:: { util , Obligation , ObligationCause } ;
1616use rustc_errors:: FatalError ;
1717use rustc_hir as hir;
1818use rustc_hir:: def_id:: DefId ;
1919use rustc_middle:: query:: Providers ;
20- use rustc_middle:: ty:: GenericArgs ;
2120use rustc_middle:: ty:: {
22- self , EarlyBinder , ExistentialPredicateStableCmpExt as _, Ty , TyCtxt , TypeSuperVisitable ,
23- TypeVisitable , TypeVisitor ,
21+ self , EarlyBinder , ExistentialPredicateStableCmpExt as _, GenericArgs , Ty , TyCtxt ,
22+ TypeFoldable , TypeFolder , TypeSuperFoldable , TypeSuperVisitable , TypeVisitable ,
23+ TypeVisitableExt , TypeVisitor , Upcast ,
2424} ;
25- use rustc_middle:: ty:: { TypeVisitableExt , Upcast } ;
2625use rustc_span:: symbol:: Symbol ;
2726use rustc_span:: Span ;
2827use rustc_target:: abi:: Abi ;
@@ -738,129 +737,174 @@ enum AllowSelfProjections {
738737 No ,
739738}
740739
740+ /// This is somewhat subtle. In general, we want to forbid
741+ /// references to `Self` in the argument and return types,
742+ /// since the value of `Self` is erased. However, there is one
743+ /// exception: it is ok to reference `Self` in order to access
744+ /// an associated type of the current trait, since we retain
745+ /// the value of those associated types in the object type
746+ /// itself.
747+ ///
748+ /// ```rust,ignore (example)
749+ /// trait SuperTrait {
750+ /// type X;
751+ /// }
752+ ///
753+ /// trait Trait : SuperTrait {
754+ /// type Y;
755+ /// fn foo(&self, x: Self) // bad
756+ /// fn foo(&self) -> Self // bad
757+ /// fn foo(&self) -> Option<Self> // bad
758+ /// fn foo(&self) -> Self::Y // OK, desugars to next example
759+ /// fn foo(&self) -> <Self as Trait>::Y // OK
760+ /// fn foo(&self) -> Self::X // OK, desugars to next example
761+ /// fn foo(&self) -> <Self as SuperTrait>::X // OK
762+ /// }
763+ /// ```
764+ ///
765+ /// However, it is not as simple as allowing `Self` in a projected
766+ /// type, because there are illegal ways to use `Self` as well:
767+ ///
768+ /// ```rust,ignore (example)
769+ /// trait Trait : SuperTrait {
770+ /// ...
771+ /// fn foo(&self) -> <Self as SomeOtherTrait>::X;
772+ /// }
773+ /// ```
774+ ///
775+ /// Here we will not have the type of `X` recorded in the
776+ /// object type, and we cannot resolve `Self as SomeOtherTrait`
777+ /// without knowing what `Self` is.
741778fn contains_illegal_self_type_reference < ' tcx , T : TypeVisitable < TyCtxt < ' tcx > > > (
742779 tcx : TyCtxt < ' tcx > ,
743780 trait_def_id : DefId ,
744781 value : T ,
745782 allow_self_projections : AllowSelfProjections ,
746783) -> bool {
747- // This is somewhat subtle. In general, we want to forbid
748- // references to `Self` in the argument and return types,
749- // since the value of `Self` is erased. However, there is one
750- // exception: it is ok to reference `Self` in order to access
751- // an associated type of the current trait, since we retain
752- // the value of those associated types in the object type
753- // itself.
754- //
755- // ```rust
756- // trait SuperTrait {
757- // type X;
758- // }
759- //
760- // trait Trait : SuperTrait {
761- // type Y;
762- // fn foo(&self, x: Self) // bad
763- // fn foo(&self) -> Self // bad
764- // fn foo(&self) -> Option<Self> // bad
765- // fn foo(&self) -> Self::Y // OK, desugars to next example
766- // fn foo(&self) -> <Self as Trait>::Y // OK
767- // fn foo(&self) -> Self::X // OK, desugars to next example
768- // fn foo(&self) -> <Self as SuperTrait>::X // OK
769- // }
770- // ```
771- //
772- // However, it is not as simple as allowing `Self` in a projected
773- // type, because there are illegal ways to use `Self` as well:
774- //
775- // ```rust
776- // trait Trait : SuperTrait {
777- // ...
778- // fn foo(&self) -> <Self as SomeOtherTrait>::X;
779- // }
780- // ```
781- //
782- // Here we will not have the type of `X` recorded in the
783- // object type, and we cannot resolve `Self as SomeOtherTrait`
784- // without knowing what `Self` is.
785-
786- struct IllegalSelfTypeVisitor < ' tcx > {
787- tcx : TyCtxt < ' tcx > ,
788- trait_def_id : DefId ,
789- supertraits : Option < Vec < DefId > > ,
790- allow_self_projections : AllowSelfProjections ,
791- }
784+ value
785+ . visit_with ( & mut IllegalSelfTypeVisitor {
786+ tcx,
787+ trait_def_id,
788+ supertraits : None ,
789+ allow_self_projections,
790+ } )
791+ . is_break ( )
792+ }
792793
793- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
794- type Result = ControlFlow < ( ) > ;
794+ struct IllegalSelfTypeVisitor < ' tcx > {
795+ tcx : TyCtxt < ' tcx > ,
796+ trait_def_id : DefId ,
797+ supertraits : Option < Vec < ty:: TraitRef < ' tcx > > > ,
798+ allow_self_projections : AllowSelfProjections ,
799+ }
795800
796- fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
797- match t. kind ( ) {
798- ty:: Param ( _) => {
799- if t == self . tcx . types . self_param {
800- ControlFlow :: Break ( ( ) )
801- } else {
802- ControlFlow :: Continue ( ( ) )
803- }
804- }
805- ty:: Alias ( ty:: Projection , ref data)
806- if self . tcx . is_impl_trait_in_trait ( data. def_id ) =>
807- {
808- // We'll deny these later in their own pass
801+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
802+ type Result = ControlFlow < ( ) > ;
803+
804+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
805+ match t. kind ( ) {
806+ ty:: Param ( _) => {
807+ if t == self . tcx . types . self_param {
808+ ControlFlow :: Break ( ( ) )
809+ } else {
809810 ControlFlow :: Continue ( ( ) )
810811 }
811- ty:: Alias ( ty:: Projection , ref data) => {
812- match self . allow_self_projections {
813- AllowSelfProjections :: Yes => {
814- // This is a projected type `<Foo as SomeTrait>::X`.
815-
816- // Compute supertraits of current trait lazily.
817- if self . supertraits . is_none ( ) {
818- self . supertraits =
819- Some ( self . tcx . supertrait_def_ids ( self . trait_def_id ) . collect ( ) ) ;
820- }
812+ }
813+ ty:: Alias ( ty:: Projection , ref data) if self . tcx . is_impl_trait_in_trait ( data. def_id ) => {
814+ // We'll deny these later in their own pass
815+ ControlFlow :: Continue ( ( ) )
816+ }
817+ ty:: Alias ( ty:: Projection , ref data) => {
818+ match self . allow_self_projections {
819+ AllowSelfProjections :: Yes => {
820+ // This is a projected type `<Foo as SomeTrait>::X`.
821+
822+ // Compute supertraits of current trait lazily.
823+ if self . supertraits . is_none ( ) {
824+ self . supertraits = Some (
825+ util:: supertraits (
826+ self . tcx ,
827+ ty:: Binder :: dummy ( ty:: TraitRef :: identity (
828+ self . tcx ,
829+ self . trait_def_id ,
830+ ) ) ,
831+ )
832+ . map ( |trait_ref| {
833+ self . tcx . erase_regions (
834+ self . tcx . instantiate_bound_regions_with_erased ( trait_ref) ,
835+ )
836+ } )
837+ . collect ( ) ,
838+ ) ;
839+ }
821840
822- // Determine whether the trait reference `Foo as
823- // SomeTrait` is in fact a supertrait of the
824- // current trait. In that case, this type is
825- // legal, because the type `X` will be specified
826- // in the object type. Note that we can just use
827- // direct equality here because all of these types
828- // are part of the formal parameter listing, and
829- // hence there should be no inference variables.
830- let is_supertrait_of_current_trait = self
831- . supertraits
832- . as_ref ( )
833- . unwrap ( )
834- . contains ( & data. trait_ref ( self . tcx ) . def_id ) ;
835-
836- if is_supertrait_of_current_trait {
837- ControlFlow :: Continue ( ( ) )
838- } else {
839- t. super_visit_with ( self )
840- }
841+ // Determine whether the trait reference `Foo as
842+ // SomeTrait` is in fact a supertrait of the
843+ // current trait. In that case, this type is
844+ // legal, because the type `X` will be specified
845+ // in the object type. Note that we can just use
846+ // direct equality here because all of these types
847+ // are part of the formal parameter listing, and
848+ // hence there should be no inference variables.
849+ let is_supertrait_of_current_trait =
850+ self . supertraits . as_ref ( ) . unwrap ( ) . contains (
851+ & data. trait_ref ( self . tcx ) . fold_with (
852+ & mut EraseEscapingBoundRegions {
853+ tcx : self . tcx ,
854+ binder : ty:: INNERMOST ,
855+ } ,
856+ ) ,
857+ ) ;
858+
859+ if is_supertrait_of_current_trait {
860+ ControlFlow :: Continue ( ( ) )
861+ } else {
862+ t. super_visit_with ( self )
841863 }
842- AllowSelfProjections :: No => t. super_visit_with ( self ) ,
843864 }
865+ AllowSelfProjections :: No => t. super_visit_with ( self ) ,
844866 }
845- _ => t. super_visit_with ( self ) ,
846867 }
868+ _ => t. super_visit_with ( self ) ,
847869 }
870+ }
848871
849- fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> Self :: Result {
850- // Constants can only influence object safety if they are generic and reference `Self`.
851- // This is only possible for unevaluated constants, so we walk these here.
852- self . tcx . expand_abstract_consts ( ct) . super_visit_with ( self )
853- }
872+ fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> Self :: Result {
873+ // Constants can only influence object safety if they are generic and reference `Self`.
874+ // This is only possible for unevaluated constants, so we walk these here.
875+ self . tcx . expand_abstract_consts ( ct) . super_visit_with ( self )
854876 }
877+ }
855878
856- value
857- . visit_with ( & mut IllegalSelfTypeVisitor {
858- tcx,
859- trait_def_id,
860- supertraits : None ,
861- allow_self_projections,
862- } )
863- . is_break ( )
879+ struct EraseEscapingBoundRegions < ' tcx > {
880+ tcx : TyCtxt < ' tcx > ,
881+ binder : ty:: DebruijnIndex ,
882+ }
883+
884+ impl < ' tcx > TypeFolder < TyCtxt < ' tcx > > for EraseEscapingBoundRegions < ' tcx > {
885+ fn interner ( & self ) -> TyCtxt < ' tcx > {
886+ self . tcx
887+ }
888+
889+ fn fold_binder < T > ( & mut self , t : ty:: Binder < ' tcx , T > ) -> ty:: Binder < ' tcx , T >
890+ where
891+ T : TypeFoldable < TyCtxt < ' tcx > > ,
892+ {
893+ self . binder . shift_in ( 1 ) ;
894+ let result = t. super_fold_with ( self ) ;
895+ self . binder . shift_out ( 1 ) ;
896+ result
897+ }
898+
899+ fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
900+ if let ty:: ReBound ( debruijn, _) = * r
901+ && debruijn < self . binder
902+ {
903+ r
904+ } else {
905+ self . tcx . lifetimes . re_erased
906+ }
907+ }
864908}
865909
866910pub fn contains_illegal_impl_trait_in_trait < ' tcx > (
0 commit comments