@@ -12,16 +12,16 @@ use super::elaborate;
1212
1313use crate :: infer:: TyCtxtInferExt ;
1414use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt ;
15- use crate :: traits:: { self , Obligation , ObligationCause } ;
15+ use crate :: traits:: { 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 ;
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_span:: symbol:: Symbol ;
2727use rustc_span:: Span ;
@@ -195,7 +195,13 @@ fn predicates_reference_self(
195195 . predicates
196196 . iter ( )
197197 . map ( |& ( predicate, sp) | ( predicate. instantiate_supertrait ( tcx, trait_ref) , sp) )
198- . filter_map ( |predicate| predicate_references_self ( tcx, predicate) )
198+ . filter_map ( |( clause, sp) | {
199+ // Super predicates cannot allow self projections, since they're
200+ // impossible to make into existential bounds without eager resolution
201+ // or something.
202+ // e.g. `trait A: B<Item = Self::Assoc>`.
203+ predicate_references_self ( tcx, trait_def_id, clause, sp, AllowSelfProjections :: No )
204+ } )
199205 . collect ( )
200206}
201207
@@ -204,20 +210,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
204210 . in_definition_order ( )
205211 . filter ( |item| item. kind == ty:: AssocKind :: Type )
206212 . flat_map ( |item| tcx. explicit_item_bounds ( item. def_id ) . instantiate_identity_iter_copied ( ) )
207- . filter_map ( |c| predicate_references_self ( tcx, c) )
213+ . filter_map ( |( clause, sp) | {
214+ // Item bounds *can* have self projections, since they never get
215+ // their self type erased.
216+ predicate_references_self ( tcx, trait_def_id, clause, sp, AllowSelfProjections :: Yes )
217+ } )
208218 . collect ( )
209219}
210220
211221fn predicate_references_self < ' tcx > (
212222 tcx : TyCtxt < ' tcx > ,
213- ( predicate, sp) : ( ty:: Clause < ' tcx > , Span ) ,
223+ trait_def_id : DefId ,
224+ predicate : ty:: Clause < ' tcx > ,
225+ sp : Span ,
226+ allow_self_projections : AllowSelfProjections ,
214227) -> Option < Span > {
215- let self_ty = tcx. types . self_param ;
216- let has_self_ty = |arg : & GenericArg < ' tcx > | arg. walk ( ) . any ( |arg| arg == self_ty. into ( ) ) ;
217228 match predicate. kind ( ) . skip_binder ( ) {
218229 ty:: ClauseKind :: Trait ( ref data) => {
219230 // In the case of a trait predicate, we can skip the "self" type.
220- data. trait_ref . args [ 1 ..] . iter ( ) . any ( has_self_ty ) . then_some ( sp)
231+ data. trait_ref . args [ 1 ..] . iter ( ) . any ( | & arg| contains_illegal_self_type_reference ( tcx , trait_def_id , arg , allow_self_projections ) ) . then_some ( sp)
221232 }
222233 ty:: ClauseKind :: Projection ( ref data) => {
223234 // And similarly for projections. This should be redundant with
@@ -235,9 +246,9 @@ fn predicate_references_self<'tcx>(
235246 //
236247 // This is ALT2 in issue #56288, see that for discussion of the
237248 // possible alternatives.
238- data. projection_term . args [ 1 ..] . iter ( ) . any ( has_self_ty ) . then_some ( sp)
249+ data. projection_term . args [ 1 ..] . iter ( ) . any ( | & arg| contains_illegal_self_type_reference ( tcx , trait_def_id , arg , allow_self_projections ) ) . then_some ( sp)
239250 }
240- ty:: ClauseKind :: ConstArgHasType ( _ct, ty) => has_self_ty ( & ty . into ( ) ) . then_some ( sp) ,
251+ ty:: ClauseKind :: ConstArgHasType ( _ct, ty) => contains_illegal_self_type_reference ( tcx , trait_def_id , ty , allow_self_projections ) . then_some ( sp) ,
241252
242253 ty:: ClauseKind :: WellFormed ( ..)
243254 | ty:: ClauseKind :: TypeOutlives ( ..)
@@ -383,7 +394,12 @@ fn virtual_call_violations_for_method<'tcx>(
383394 let mut errors = Vec :: new ( ) ;
384395
385396 for ( i, & input_ty) in sig. skip_binder ( ) . inputs ( ) . iter ( ) . enumerate ( ) . skip ( 1 ) {
386- if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. rebind ( input_ty) ) {
397+ if contains_illegal_self_type_reference (
398+ tcx,
399+ trait_def_id,
400+ sig. rebind ( input_ty) ,
401+ AllowSelfProjections :: Yes ,
402+ ) {
387403 let span = if let Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
388404 kind : hir:: TraitItemKind :: Fn ( sig, _) ,
389405 ..
@@ -396,7 +412,12 @@ fn virtual_call_violations_for_method<'tcx>(
396412 errors. push ( MethodViolationCode :: ReferencesSelfInput ( span) ) ;
397413 }
398414 }
399- if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. output ( ) ) {
415+ if contains_illegal_self_type_reference (
416+ tcx,
417+ trait_def_id,
418+ sig. output ( ) ,
419+ AllowSelfProjections :: Yes ,
420+ ) {
400421 errors. push ( MethodViolationCode :: ReferencesSelfOutput ) ;
401422 }
402423 if let Some ( code) = contains_illegal_impl_trait_in_trait ( tcx, method. def_id , sig. output ( ) ) {
@@ -482,7 +503,7 @@ fn virtual_call_violations_for_method<'tcx>(
482503 return false ;
483504 }
484505
485- contains_illegal_self_type_reference ( tcx, trait_def_id, pred)
506+ contains_illegal_self_type_reference ( tcx, trait_def_id, pred, AllowSelfProjections :: Yes )
486507 } ) {
487508 errors. push ( MethodViolationCode :: WhereClauseReferencesSelf ) ;
488509 }
@@ -711,10 +732,17 @@ fn receiver_is_dispatchable<'tcx>(
711732 infcx. predicate_must_hold_modulo_regions ( & obligation)
712733}
713734
735+ #[ derive( Copy , Clone ) ]
736+ enum AllowSelfProjections {
737+ Yes ,
738+ No ,
739+ }
740+
714741fn contains_illegal_self_type_reference < ' tcx , T : TypeVisitable < TyCtxt < ' tcx > > > (
715742 tcx : TyCtxt < ' tcx > ,
716743 trait_def_id : DefId ,
717744 value : T ,
745+ allow_self_projections : AllowSelfProjections ,
718746) -> bool {
719747 // This is somewhat subtle. In general, we want to forbid
720748 // references to `Self` in the argument and return types,
@@ -759,6 +787,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
759787 tcx : TyCtxt < ' tcx > ,
760788 trait_def_id : DefId ,
761789 supertraits : Option < Vec < DefId > > ,
790+ allow_self_projections : AllowSelfProjections ,
762791 }
763792
764793 impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
@@ -780,38 +809,40 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
780809 ControlFlow :: Continue ( ( ) )
781810 }
782811 ty:: Alias ( ty:: Projection , ref data) => {
783- // This is a projected type `<Foo as SomeTrait>::X`.
784-
785- // Compute supertraits of current trait lazily.
786- if self . supertraits . is_none ( ) {
787- let trait_ref =
788- ty:: Binder :: dummy ( ty:: TraitRef :: identity ( self . tcx , self . trait_def_id ) ) ;
789- self . supertraits = Some (
790- traits:: supertraits ( self . tcx , trait_ref) . map ( |t| t. def_id ( ) ) . collect ( ) ,
791- ) ;
792- }
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+ }
793821
794- // Determine whether the trait reference `Foo as
795- // SomeTrait` is in fact a supertrait of the
796- // current trait. In that case, this type is
797- // legal, because the type `X` will be specified
798- // in the object type. Note that we can just use
799- // direct equality here because all of these types
800- // are part of the formal parameter listing, and
801- // hence there should be no inference variables.
802- let is_supertrait_of_current_trait = self
803- . supertraits
804- . as_ref ( )
805- . unwrap ( )
806- . contains ( & data. trait_ref ( self . tcx ) . def_id ) ;
807-
808- if is_supertrait_of_current_trait {
809- ControlFlow :: Continue ( ( ) ) // do not walk contained types, do not report error, do collect $200
810- } else {
811- t. super_visit_with ( self ) // DO walk contained types, POSSIBLY reporting an error
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+ }
842+ AllowSelfProjections :: No => t. super_visit_with ( self ) ,
812843 }
813844 }
814- _ => t. super_visit_with ( self ) , // walk contained types, if any
845+ _ => t. super_visit_with ( self ) ,
815846 }
816847 }
817848
@@ -823,7 +854,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
823854 }
824855
825856 value
826- . visit_with ( & mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits : None } )
857+ . visit_with ( & mut IllegalSelfTypeVisitor {
858+ tcx,
859+ trait_def_id,
860+ supertraits : None ,
861+ allow_self_projections,
862+ } )
827863 . is_break ( )
828864}
829865
0 commit comments