@@ -18,9 +18,8 @@ use rustc_hir as hir;
18
18
use rustc_hir:: def_id:: DefId ;
19
19
use rustc_middle:: query:: Providers ;
20
20
use rustc_middle:: ty:: {
21
- self , EarlyBinder , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor ,
21
+ self , EarlyBinder , GenericArgs , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor ,
22
22
} ;
23
- use rustc_middle:: ty:: { GenericArg , GenericArgs } ;
24
23
use rustc_middle:: ty:: { ToPredicate , TypeVisitableExt } ;
25
24
use rustc_session:: lint:: builtin:: WHERE_CLAUSES_OBJECT_SAFETY ;
26
25
use rustc_span:: symbol:: Symbol ;
@@ -264,7 +263,13 @@ fn predicates_reference_self(
264
263
. predicates
265
264
. iter ( )
266
265
. 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
+ } )
268
273
. collect ( )
269
274
}
270
275
@@ -273,20 +278,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
273
278
. in_definition_order ( )
274
279
. filter ( |item| item. kind == ty:: AssocKind :: Type )
275
280
. 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
+ } )
277
286
. collect ( )
278
287
}
279
288
280
289
fn predicate_references_self < ' tcx > (
281
290
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 ,
283
295
) -> 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 ( ) ) ;
286
296
match predicate. kind ( ) . skip_binder ( ) {
287
297
ty:: ClauseKind :: Trait ( ref data) => {
288
298
// 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)
290
300
}
291
301
ty:: ClauseKind :: Projection ( ref data) => {
292
302
// And similarly for projections. This should be redundant with
@@ -304,9 +314,9 @@ fn predicate_references_self<'tcx>(
304
314
//
305
315
// This is ALT2 in issue #56288, see that for discussion of the
306
316
// 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)
308
318
}
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) ,
310
320
311
321
ty:: ClauseKind :: WellFormed ( ..)
312
322
| ty:: ClauseKind :: TypeOutlives ( ..)
@@ -452,7 +462,12 @@ fn virtual_call_violations_for_method<'tcx>(
452
462
let mut errors = Vec :: new ( ) ;
453
463
454
464
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
+ ) {
456
471
let span = if let Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
457
472
kind : hir:: TraitItemKind :: Fn ( sig, _) ,
458
473
..
@@ -465,7 +480,12 @@ fn virtual_call_violations_for_method<'tcx>(
465
480
errors. push ( MethodViolationCode :: ReferencesSelfInput ( span) ) ;
466
481
}
467
482
}
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
+ ) {
469
489
errors. push ( MethodViolationCode :: ReferencesSelfOutput ) ;
470
490
}
471
491
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>(
602
622
return false ;
603
623
}
604
624
605
- contains_illegal_self_type_reference ( tcx, trait_def_id, pred)
625
+ contains_illegal_self_type_reference ( tcx, trait_def_id, pred, AllowSelfProjections :: Yes )
606
626
} ) {
607
627
errors. push ( MethodViolationCode :: WhereClauseReferencesSelf ) ;
608
628
}
@@ -783,10 +803,17 @@ fn receiver_is_dispatchable<'tcx>(
783
803
infcx. predicate_must_hold_modulo_regions ( & obligation)
784
804
}
785
805
806
+ #[ derive( Copy , Clone ) ]
807
+ enum AllowSelfProjections {
808
+ Yes ,
809
+ No ,
810
+ }
811
+
786
812
fn contains_illegal_self_type_reference < ' tcx , T : TypeVisitable < TyCtxt < ' tcx > > > (
787
813
tcx : TyCtxt < ' tcx > ,
788
814
trait_def_id : DefId ,
789
815
value : T ,
816
+ allow_self_projections : AllowSelfProjections ,
790
817
) -> bool {
791
818
// This is somewhat subtle. In general, we want to forbid
792
819
// references to `Self` in the argument and return types,
@@ -831,6 +858,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
831
858
tcx : TyCtxt < ' tcx > ,
832
859
trait_def_id : DefId ,
833
860
supertraits : Option < Vec < DefId > > ,
861
+ allow_self_projections : AllowSelfProjections ,
834
862
}
835
863
836
864
impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
@@ -852,38 +880,42 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
852
880
ControlFlow :: Continue ( ( ) )
853
881
}
854
882
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
+ }
865
894
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 ) ,
884
916
}
885
917
}
886
- _ => t. super_visit_with ( self ) , // walk contained types, if any
918
+ _ => t. super_visit_with ( self ) ,
887
919
}
888
920
}
889
921
@@ -895,7 +927,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
895
927
}
896
928
897
929
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
+ } )
899
936
. is_break ( )
900
937
}
901
938
0 commit comments