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