@@ -12,16 +12,16 @@ use super::elaborate;
12
12
13
13
use crate :: infer:: TyCtxtInferExt ;
14
14
use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt ;
15
- use crate :: traits:: { self , Obligation , ObligationCause } ;
15
+ use crate :: traits:: { Obligation , ObligationCause } ;
16
16
use rustc_errors:: FatalError ;
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_span:: symbol:: Symbol ;
27
27
use rustc_span:: Span ;
@@ -195,7 +195,13 @@ fn predicates_reference_self(
195
195
. predicates
196
196
. iter ( )
197
197
. 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
+ } )
199
205
. collect ( )
200
206
}
201
207
@@ -204,20 +210,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
204
210
. in_definition_order ( )
205
211
. filter ( |item| item. kind == ty:: AssocKind :: Type )
206
212
. 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
+ } )
208
218
. collect ( )
209
219
}
210
220
211
221
fn predicate_references_self < ' tcx > (
212
222
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 ,
214
227
) -> 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 ( ) ) ;
217
228
match predicate. kind ( ) . skip_binder ( ) {
218
229
ty:: ClauseKind :: Trait ( ref data) => {
219
230
// 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)
221
232
}
222
233
ty:: ClauseKind :: Projection ( ref data) => {
223
234
// And similarly for projections. This should be redundant with
@@ -235,9 +246,9 @@ fn predicate_references_self<'tcx>(
235
246
//
236
247
// This is ALT2 in issue #56288, see that for discussion of the
237
248
// 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)
239
250
}
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) ,
241
252
242
253
ty:: ClauseKind :: WellFormed ( ..)
243
254
| ty:: ClauseKind :: TypeOutlives ( ..)
@@ -383,7 +394,12 @@ fn virtual_call_violations_for_method<'tcx>(
383
394
let mut errors = Vec :: new ( ) ;
384
395
385
396
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
+ ) {
387
403
let span = if let Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
388
404
kind : hir:: TraitItemKind :: Fn ( sig, _) ,
389
405
..
@@ -396,7 +412,12 @@ fn virtual_call_violations_for_method<'tcx>(
396
412
errors. push ( MethodViolationCode :: ReferencesSelfInput ( span) ) ;
397
413
}
398
414
}
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
+ ) {
400
421
errors. push ( MethodViolationCode :: ReferencesSelfOutput ) ;
401
422
}
402
423
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>(
482
503
return false ;
483
504
}
484
505
485
- contains_illegal_self_type_reference ( tcx, trait_def_id, pred)
506
+ contains_illegal_self_type_reference ( tcx, trait_def_id, pred, AllowSelfProjections :: Yes )
486
507
} ) {
487
508
errors. push ( MethodViolationCode :: WhereClauseReferencesSelf ) ;
488
509
}
@@ -711,10 +732,17 @@ fn receiver_is_dispatchable<'tcx>(
711
732
infcx. predicate_must_hold_modulo_regions ( & obligation)
712
733
}
713
734
735
+ #[ derive( Copy , Clone ) ]
736
+ enum AllowSelfProjections {
737
+ Yes ,
738
+ No ,
739
+ }
740
+
714
741
fn contains_illegal_self_type_reference < ' tcx , T : TypeVisitable < TyCtxt < ' tcx > > > (
715
742
tcx : TyCtxt < ' tcx > ,
716
743
trait_def_id : DefId ,
717
744
value : T ,
745
+ allow_self_projections : AllowSelfProjections ,
718
746
) -> bool {
719
747
// This is somewhat subtle. In general, we want to forbid
720
748
// references to `Self` in the argument and return types,
@@ -759,6 +787,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
759
787
tcx : TyCtxt < ' tcx > ,
760
788
trait_def_id : DefId ,
761
789
supertraits : Option < Vec < DefId > > ,
790
+ allow_self_projections : AllowSelfProjections ,
762
791
}
763
792
764
793
impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
@@ -780,38 +809,40 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
780
809
ControlFlow :: Continue ( ( ) )
781
810
}
782
811
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
+ }
793
821
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 ) ,
812
843
}
813
844
}
814
- _ => t. super_visit_with ( self ) , // walk contained types, if any
845
+ _ => t. super_visit_with ( self ) ,
815
846
}
816
847
}
817
848
@@ -823,7 +854,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
823
854
}
824
855
825
856
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
+ } )
827
863
. is_break ( )
828
864
}
829
865
0 commit comments