@@ -18,9 +18,8 @@ use rustc_hir as hir;
1818use rustc_hir:: def_id:: DefId ;
1919use rustc_middle:: query:: Providers ;
2020use rustc_middle:: ty:: {
21- self , EarlyBinder , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor ,
21+ self , EarlyBinder , GenericArgs , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor ,
2222} ;
23- use rustc_middle:: ty:: { GenericArg , GenericArgs } ;
2423use rustc_middle:: ty:: { ToPredicate , TypeVisitableExt } ;
2524use rustc_session:: lint:: builtin:: WHERE_CLAUSES_OBJECT_SAFETY ;
2625use rustc_span:: symbol:: Symbol ;
@@ -264,7 +263,13 @@ fn predicates_reference_self(
264263 . predicates
265264 . iter ( )
266265 . map ( |& ( predicate, sp) | ( predicate. instantiate_supertrait ( tcx, & trait_ref) , sp) )
267- . filter_map ( |predicate| predicate_references_self ( tcx, predicate) )
266+ . filter_map ( |( clause, sp) | {
267+ // Super predicates cannot allow self projections, since they're
268+ // impossible to make into existential bounds without eager resolution
269+ // or something.
270+ // e.g. `trait A: B<Item = Self::Assoc>`.
271+ predicate_references_self ( tcx, trait_def_id, clause, sp, AllowSelfProjections :: No )
272+ } )
268273 . collect ( )
269274}
270275
@@ -273,20 +278,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
273278 . in_definition_order ( )
274279 . filter ( |item| item. kind == ty:: AssocKind :: Type )
275280 . flat_map ( |item| tcx. explicit_item_bounds ( item. def_id ) . instantiate_identity_iter_copied ( ) )
276- . filter_map ( |c| predicate_references_self ( tcx, c) )
281+ . filter_map ( |( clause, sp) | {
282+ // Item bounds *can* have self projections, since they never get
283+ // their self type erased.
284+ predicate_references_self ( tcx, trait_def_id, clause, sp, AllowSelfProjections :: Yes )
285+ } )
277286 . collect ( )
278287}
279288
280289fn predicate_references_self < ' tcx > (
281290 tcx : TyCtxt < ' tcx > ,
282- ( predicate, sp) : ( ty:: Clause < ' tcx > , Span ) ,
291+ trait_def_id : DefId ,
292+ predicate : ty:: Clause < ' tcx > ,
293+ sp : Span ,
294+ allow_self_projections : AllowSelfProjections ,
283295) -> Option < Span > {
284- let self_ty = tcx. types . self_param ;
285- let has_self_ty = |arg : & GenericArg < ' tcx > | arg. walk ( ) . any ( |arg| arg == self_ty. into ( ) ) ;
286296 match predicate. kind ( ) . skip_binder ( ) {
287297 ty:: ClauseKind :: Trait ( ref data) => {
288298 // In the case of a trait predicate, we can skip the "self" type.
289- data. trait_ref . args [ 1 ..] . iter ( ) . any ( has_self_ty ) . then_some ( sp)
299+ data. trait_ref . args [ 1 ..] . iter ( ) . any ( | & arg| contains_illegal_self_type_reference ( tcx , trait_def_id , arg , allow_self_projections ) ) . then_some ( sp)
290300 }
291301 ty:: ClauseKind :: Projection ( ref data) => {
292302 // And similarly for projections. This should be redundant with
@@ -304,9 +314,9 @@ fn predicate_references_self<'tcx>(
304314 //
305315 // This is ALT2 in issue #56288, see that for discussion of the
306316 // possible alternatives.
307- data. projection_ty . args [ 1 ..] . iter ( ) . any ( has_self_ty ) . then_some ( sp)
317+ data. projection_ty . args [ 1 ..] . iter ( ) . any ( | & arg| contains_illegal_self_type_reference ( tcx , trait_def_id , arg , allow_self_projections ) ) . then_some ( sp)
308318 }
309- ty:: ClauseKind :: ConstArgHasType ( _ct, ty) => has_self_ty ( & ty . into ( ) ) . then_some ( sp) ,
319+ ty:: ClauseKind :: ConstArgHasType ( _ct, ty) => contains_illegal_self_type_reference ( tcx , trait_def_id , ty , allow_self_projections ) . then_some ( sp) ,
310320
311321 ty:: ClauseKind :: WellFormed ( ..)
312322 | ty:: ClauseKind :: TypeOutlives ( ..)
@@ -452,7 +462,12 @@ fn virtual_call_violations_for_method<'tcx>(
452462 let mut errors = Vec :: new ( ) ;
453463
454464 for ( i, & input_ty) in sig. skip_binder ( ) . inputs ( ) . iter ( ) . enumerate ( ) . skip ( 1 ) {
455- if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. rebind ( input_ty) ) {
465+ if contains_illegal_self_type_reference (
466+ tcx,
467+ trait_def_id,
468+ sig. rebind ( input_ty) ,
469+ AllowSelfProjections :: Yes ,
470+ ) {
456471 let span = if let Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
457472 kind : hir:: TraitItemKind :: Fn ( sig, _) ,
458473 ..
@@ -465,7 +480,12 @@ fn virtual_call_violations_for_method<'tcx>(
465480 errors. push ( MethodViolationCode :: ReferencesSelfInput ( span) ) ;
466481 }
467482 }
468- if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. output ( ) ) {
483+ if contains_illegal_self_type_reference (
484+ tcx,
485+ trait_def_id,
486+ sig. output ( ) ,
487+ AllowSelfProjections :: Yes ,
488+ ) {
469489 errors. push ( MethodViolationCode :: ReferencesSelfOutput ) ;
470490 }
471491 if let Some ( code) = contains_illegal_impl_trait_in_trait ( tcx, method. def_id , sig. output ( ) ) {
@@ -602,7 +622,7 @@ fn virtual_call_violations_for_method<'tcx>(
602622 return false ;
603623 }
604624
605- contains_illegal_self_type_reference ( tcx, trait_def_id, pred)
625+ contains_illegal_self_type_reference ( tcx, trait_def_id, pred, AllowSelfProjections :: Yes )
606626 } ) {
607627 errors. push ( MethodViolationCode :: WhereClauseReferencesSelf ) ;
608628 }
@@ -783,10 +803,17 @@ fn receiver_is_dispatchable<'tcx>(
783803 infcx. predicate_must_hold_modulo_regions ( & obligation)
784804}
785805
806+ #[ derive( Copy , Clone ) ]
807+ enum AllowSelfProjections {
808+ Yes ,
809+ No ,
810+ }
811+
786812fn contains_illegal_self_type_reference < ' tcx , T : TypeVisitable < TyCtxt < ' tcx > > > (
787813 tcx : TyCtxt < ' tcx > ,
788814 trait_def_id : DefId ,
789815 value : T ,
816+ allow_self_projections : AllowSelfProjections ,
790817) -> bool {
791818 // This is somewhat subtle. In general, we want to forbid
792819 // references to `Self` in the argument and return types,
@@ -831,6 +858,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
831858 tcx : TyCtxt < ' tcx > ,
832859 trait_def_id : DefId ,
833860 supertraits : Option < Vec < DefId > > ,
861+ allow_self_projections : AllowSelfProjections ,
834862 }
835863
836864 impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
@@ -852,38 +880,42 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
852880 ControlFlow :: Continue ( ( ) )
853881 }
854882 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- }
883+ match self . allow_self_projections {
884+ AllowSelfProjections :: Yes => {
885+ // This is a projected type `<Foo as SomeTrait>::X`.
886+
887+ // Compute supertraits of current trait lazily.
888+ if self . supertraits . is_none ( ) {
889+ self . supertraits = Some (
890+ traits:: supertrait_def_ids ( self . tcx , self . trait_def_id )
891+ . collect ( ) ,
892+ ) ;
893+ }
865894
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
895+ // Determine whether the trait reference `Foo as
896+ // SomeTrait` is in fact a supertrait of the
897+ // current trait. In that case, this type is
898+ // legal, because the type `X` will be specified
899+ // in the object type. Note that we can just use
900+ // direct equality here because all of these types
901+ // are part of the formal parameter listing, and
902+ // hence there should be no inference variables.
903+ let is_supertrait_of_current_trait = self
904+ . supertraits
905+ . as_ref ( )
906+ . unwrap ( )
907+ . contains ( & data. trait_ref ( self . tcx ) . def_id ) ;
908+
909+ if is_supertrait_of_current_trait {
910+ ControlFlow :: Continue ( ( ) )
911+ } else {
912+ t. super_visit_with ( self )
913+ }
914+ }
915+ AllowSelfProjections :: No => t. super_visit_with ( self ) ,
884916 }
885917 }
886- _ => t. super_visit_with ( self ) , // walk contained types, if any
918+ _ => t. super_visit_with ( self ) ,
887919 }
888920 }
889921
@@ -895,7 +927,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
895927 }
896928
897929 value
898- . visit_with ( & mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits : None } )
930+ . visit_with ( & mut IllegalSelfTypeVisitor {
931+ tcx,
932+ trait_def_id,
933+ supertraits : None ,
934+ allow_self_projections,
935+ } )
899936 . is_break ( )
900937}
901938
0 commit comments