@@ -17,11 +17,11 @@ use rustc_errors::{DelayDm, FatalError, MultiSpan};
1717use rustc_hir as hir;
1818use rustc_hir:: def_id:: DefId ;
1919use rustc_middle:: query:: Providers ;
20+ use rustc_middle:: ty:: GenericArgs ;
2021use rustc_middle:: ty:: {
2122 self , EarlyBinder , ExistentialPredicateStableCmpExt as _, Ty , TyCtxt , TypeSuperVisitable ,
2223 TypeVisitable , TypeVisitor ,
2324} ;
24- use rustc_middle:: ty:: { GenericArg , GenericArgs } ;
2525use rustc_middle:: ty:: { TypeVisitableExt , Upcast } ;
2626use rustc_session:: lint:: builtin:: WHERE_CLAUSES_OBJECT_SAFETY ;
2727use rustc_span:: symbol:: Symbol ;
@@ -265,7 +265,13 @@ fn predicates_reference_self(
265265 . predicates
266266 . iter ( )
267267 . map ( |& ( predicate, sp) | ( predicate. instantiate_supertrait ( tcx, & trait_ref) , sp) )
268- . filter_map ( |predicate| predicate_references_self ( tcx, predicate) )
268+ . filter_map ( |( clause, sp) | {
269+ // Super predicates cannot allow self projections, since they're
270+ // impossible to make into existential bounds without eager resolution
271+ // or something.
272+ // e.g. `trait A: B<Item = Self::Assoc>`.
273+ predicate_references_self ( tcx, trait_def_id, clause, sp, AllowSelfProjections :: No )
274+ } )
269275 . collect ( )
270276}
271277
@@ -274,20 +280,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
274280 . in_definition_order ( )
275281 . filter ( |item| item. kind == ty:: AssocKind :: Type )
276282 . flat_map ( |item| tcx. explicit_item_bounds ( item. def_id ) . instantiate_identity_iter_copied ( ) )
277- . filter_map ( |c| predicate_references_self ( tcx, c) )
283+ . filter_map ( |( clause, sp) | {
284+ // Item bounds *can* have self projections, since they never get
285+ // their self type erased.
286+ predicate_references_self ( tcx, trait_def_id, clause, sp, AllowSelfProjections :: Yes )
287+ } )
278288 . collect ( )
279289}
280290
281291fn predicate_references_self < ' tcx > (
282292 tcx : TyCtxt < ' tcx > ,
283- ( predicate, sp) : ( ty:: Clause < ' tcx > , Span ) ,
293+ trait_def_id : DefId ,
294+ predicate : ty:: Clause < ' tcx > ,
295+ sp : Span ,
296+ allow_self_projections : AllowSelfProjections ,
284297) -> Option < Span > {
285- let self_ty = tcx. types . self_param ;
286- let has_self_ty = |arg : & GenericArg < ' tcx > | arg. walk ( ) . any ( |arg| arg == self_ty. into ( ) ) ;
287298 match predicate. kind ( ) . skip_binder ( ) {
288299 ty:: ClauseKind :: Trait ( ref data) => {
289300 // In the case of a trait predicate, we can skip the "self" type.
290- data. trait_ref . args [ 1 ..] . iter ( ) . any ( has_self_ty ) . then_some ( sp)
301+ data. trait_ref . args [ 1 ..] . iter ( ) . any ( | & arg| contains_illegal_self_type_reference ( tcx , trait_def_id , arg , allow_self_projections ) ) . then_some ( sp)
291302 }
292303 ty:: ClauseKind :: Projection ( ref data) => {
293304 // And similarly for projections. This should be redundant with
@@ -305,9 +316,9 @@ fn predicate_references_self<'tcx>(
305316 //
306317 // This is ALT2 in issue #56288, see that for discussion of the
307318 // possible alternatives.
308- data. projection_term . args [ 1 ..] . iter ( ) . any ( has_self_ty ) . then_some ( sp)
319+ data. projection_term . args [ 1 ..] . iter ( ) . any ( | & arg| contains_illegal_self_type_reference ( tcx , trait_def_id , arg , allow_self_projections ) ) . then_some ( sp)
309320 }
310- ty:: ClauseKind :: ConstArgHasType ( _ct, ty) => has_self_ty ( & ty . into ( ) ) . then_some ( sp) ,
321+ ty:: ClauseKind :: ConstArgHasType ( _ct, ty) => contains_illegal_self_type_reference ( tcx , trait_def_id , ty , allow_self_projections ) . then_some ( sp) ,
311322
312323 ty:: ClauseKind :: WellFormed ( ..)
313324 | ty:: ClauseKind :: TypeOutlives ( ..)
@@ -453,7 +464,12 @@ fn virtual_call_violations_for_method<'tcx>(
453464 let mut errors = Vec :: new ( ) ;
454465
455466 for ( i, & input_ty) in sig. skip_binder ( ) . inputs ( ) . iter ( ) . enumerate ( ) . skip ( 1 ) {
456- if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. rebind ( input_ty) ) {
467+ if contains_illegal_self_type_reference (
468+ tcx,
469+ trait_def_id,
470+ sig. rebind ( input_ty) ,
471+ AllowSelfProjections :: Yes ,
472+ ) {
457473 let span = if let Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
458474 kind : hir:: TraitItemKind :: Fn ( sig, _) ,
459475 ..
@@ -466,7 +482,12 @@ fn virtual_call_violations_for_method<'tcx>(
466482 errors. push ( MethodViolationCode :: ReferencesSelfInput ( span) ) ;
467483 }
468484 }
469- if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. output ( ) ) {
485+ if contains_illegal_self_type_reference (
486+ tcx,
487+ trait_def_id,
488+ sig. output ( ) ,
489+ AllowSelfProjections :: Yes ,
490+ ) {
470491 errors. push ( MethodViolationCode :: ReferencesSelfOutput ) ;
471492 }
472493 if let Some ( code) = contains_illegal_impl_trait_in_trait ( tcx, method. def_id , sig. output ( ) ) {
@@ -603,7 +624,7 @@ fn virtual_call_violations_for_method<'tcx>(
603624 return false ;
604625 }
605626
606- contains_illegal_self_type_reference ( tcx, trait_def_id, pred)
627+ contains_illegal_self_type_reference ( tcx, trait_def_id, pred, AllowSelfProjections :: Yes )
607628 } ) {
608629 errors. push ( MethodViolationCode :: WhereClauseReferencesSelf ) ;
609630 }
@@ -783,10 +804,17 @@ fn receiver_is_dispatchable<'tcx>(
783804 infcx. predicate_must_hold_modulo_regions ( & obligation)
784805}
785806
807+ #[ derive( Copy , Clone ) ]
808+ enum AllowSelfProjections {
809+ Yes ,
810+ No ,
811+ }
812+
786813fn contains_illegal_self_type_reference < ' tcx , T : TypeVisitable < TyCtxt < ' tcx > > > (
787814 tcx : TyCtxt < ' tcx > ,
788815 trait_def_id : DefId ,
789816 value : T ,
817+ allow_self_projections : AllowSelfProjections ,
790818) -> bool {
791819 // This is somewhat subtle. In general, we want to forbid
792820 // references to `Self` in the argument and return types,
@@ -831,6 +859,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
831859 tcx : TyCtxt < ' tcx > ,
832860 trait_def_id : DefId ,
833861 supertraits : Option < Vec < DefId > > ,
862+ allow_self_projections : AllowSelfProjections ,
834863 }
835864
836865 impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
@@ -852,38 +881,42 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
852881 ControlFlow :: Continue ( ( ) )
853882 }
854883 ty:: Alias ( ty:: Projection , ref data) => {
855- // This is a projected type `<Foo as SomeTrait>::X`.
856-
857- // Compute supertraits of current trait lazily.
858- if self . supertraits . is_none ( ) {
859- let trait_ref =
860- ty:: Binder :: dummy ( ty:: TraitRef :: identity ( self . tcx , self . trait_def_id ) ) ;
861- self . supertraits = Some (
862- traits:: supertraits ( self . tcx , trait_ref) . map ( |t| t. def_id ( ) ) . collect ( ) ,
863- ) ;
864- }
884+ match self . allow_self_projections {
885+ AllowSelfProjections :: Yes => {
886+ // This is a projected type `<Foo as SomeTrait>::X`.
887+
888+ // Compute supertraits of current trait lazily.
889+ if self . supertraits . is_none ( ) {
890+ self . supertraits = Some (
891+ traits:: supertrait_def_ids ( self . tcx , self . trait_def_id )
892+ . collect ( ) ,
893+ ) ;
894+ }
865895
866- // Determine whether the trait reference `Foo as
867- // SomeTrait` is in fact a supertrait of the
868- // current trait. In that case, this type is
869- // legal, because the type `X` will be specified
870- // in the object type. Note that we can just use
871- // direct equality here because all of these types
872- // are part of the formal parameter listing, and
873- // hence there should be no inference variables.
874- let is_supertrait_of_current_trait = self
875- . supertraits
876- . as_ref ( )
877- . unwrap ( )
878- . contains ( & data. trait_ref ( self . tcx ) . def_id ) ;
879-
880- if is_supertrait_of_current_trait {
881- ControlFlow :: Continue ( ( ) ) // do not walk contained types, do not report error, do collect $200
882- } else {
883- t. super_visit_with ( self ) // DO walk contained types, POSSIBLY reporting an error
896+ // Determine whether the trait reference `Foo as
897+ // SomeTrait` is in fact a supertrait of the
898+ // current trait. In that case, this type is
899+ // legal, because the type `X` will be specified
900+ // in the object type. Note that we can just use
901+ // direct equality here because all of these types
902+ // are part of the formal parameter listing, and
903+ // hence there should be no inference variables.
904+ let is_supertrait_of_current_trait = self
905+ . supertraits
906+ . as_ref ( )
907+ . unwrap ( )
908+ . contains ( & data. trait_ref ( self . tcx ) . def_id ) ;
909+
910+ if is_supertrait_of_current_trait {
911+ ControlFlow :: Continue ( ( ) )
912+ } else {
913+ t. super_visit_with ( self )
914+ }
915+ }
916+ AllowSelfProjections :: No => t. super_visit_with ( self ) ,
884917 }
885918 }
886- _ => t. super_visit_with ( self ) , // walk contained types, if any
919+ _ => t. super_visit_with ( self ) ,
887920 }
888921 }
889922
@@ -895,7 +928,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
895928 }
896929
897930 value
898- . visit_with ( & mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits : None } )
931+ . visit_with ( & mut IllegalSelfTypeVisitor {
932+ tcx,
933+ trait_def_id,
934+ supertraits : None ,
935+ allow_self_projections,
936+ } )
899937 . is_break ( )
900938}
901939
0 commit comments