@@ -12,17 +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:: { util , 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
20
use rustc_middle:: ty:: {
21
- self , EarlyBinder , ExistentialPredicateStableCmpExt as _, Ty , TyCtxt , TypeSuperVisitable ,
22
- TypeVisitable , TypeVisitor ,
21
+ self , EarlyBinder , ExistentialPredicateStableCmpExt as _, GenericArgs , Ty , TyCtxt ,
22
+ TypeFoldable , TypeFolder , TypeSuperFoldable , TypeSuperVisitable , TypeVisitable ,
23
+ TypeVisitableExt , TypeVisitor , Upcast ,
23
24
} ;
24
- use rustc_middle:: ty:: { GenericArg , GenericArgs } ;
25
- use rustc_middle:: ty:: { TypeVisitableExt , Upcast } ;
26
25
use rustc_span:: symbol:: Symbol ;
27
26
use rustc_span:: Span ;
28
27
use rustc_target:: abi:: Abi ;
@@ -195,7 +194,13 @@ fn predicates_reference_self(
195
194
. predicates
196
195
. iter ( )
197
196
. map ( |& ( predicate, sp) | ( predicate. instantiate_supertrait ( tcx, & trait_ref) , sp) )
198
- . filter_map ( |predicate| predicate_references_self ( tcx, predicate) )
197
+ . filter_map ( |( clause, sp) | {
198
+ // Super predicates cannot allow self projections, since they're
199
+ // impossible to make into existential bounds without eager resolution
200
+ // or something.
201
+ // e.g. `trait A: B<Item = Self::Assoc>`.
202
+ predicate_references_self ( tcx, trait_def_id, clause, sp, AllowSelfProjections :: No )
203
+ } )
199
204
. collect ( )
200
205
}
201
206
@@ -204,20 +209,25 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
204
209
. in_definition_order ( )
205
210
. filter ( |item| item. kind == ty:: AssocKind :: Type )
206
211
. flat_map ( |item| tcx. explicit_item_bounds ( item. def_id ) . instantiate_identity_iter_copied ( ) )
207
- . filter_map ( |c| predicate_references_self ( tcx, c) )
212
+ . filter_map ( |( clause, sp) | {
213
+ // Item bounds *can* have self projections, since they never get
214
+ // their self type erased.
215
+ predicate_references_self ( tcx, trait_def_id, clause, sp, AllowSelfProjections :: Yes )
216
+ } )
208
217
. collect ( )
209
218
}
210
219
211
220
fn predicate_references_self < ' tcx > (
212
221
tcx : TyCtxt < ' tcx > ,
213
- ( predicate, sp) : ( ty:: Clause < ' tcx > , Span ) ,
222
+ trait_def_id : DefId ,
223
+ predicate : ty:: Clause < ' tcx > ,
224
+ sp : Span ,
225
+ allow_self_projections : AllowSelfProjections ,
214
226
) -> 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
227
match predicate. kind ( ) . skip_binder ( ) {
218
228
ty:: ClauseKind :: Trait ( ref data) => {
219
229
// 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)
230
+ 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
231
}
222
232
ty:: ClauseKind :: Projection ( ref data) => {
223
233
// And similarly for projections. This should be redundant with
@@ -235,9 +245,9 @@ fn predicate_references_self<'tcx>(
235
245
//
236
246
// This is ALT2 in issue #56288, see that for discussion of the
237
247
// possible alternatives.
238
- data. projection_term . args [ 1 ..] . iter ( ) . any ( has_self_ty ) . then_some ( sp)
248
+ 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
249
}
240
- ty:: ClauseKind :: ConstArgHasType ( _ct, ty) => has_self_ty ( & ty . into ( ) ) . then_some ( sp) ,
250
+ ty:: ClauseKind :: ConstArgHasType ( _ct, ty) => contains_illegal_self_type_reference ( tcx , trait_def_id , ty , allow_self_projections ) . then_some ( sp) ,
241
251
242
252
ty:: ClauseKind :: WellFormed ( ..)
243
253
| ty:: ClauseKind :: TypeOutlives ( ..)
@@ -383,7 +393,12 @@ fn virtual_call_violations_for_method<'tcx>(
383
393
let mut errors = Vec :: new ( ) ;
384
394
385
395
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) ) {
396
+ if contains_illegal_self_type_reference (
397
+ tcx,
398
+ trait_def_id,
399
+ sig. rebind ( input_ty) ,
400
+ AllowSelfProjections :: Yes ,
401
+ ) {
387
402
let span = if let Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
388
403
kind : hir:: TraitItemKind :: Fn ( sig, _) ,
389
404
..
@@ -396,7 +411,12 @@ fn virtual_call_violations_for_method<'tcx>(
396
411
errors. push ( MethodViolationCode :: ReferencesSelfInput ( span) ) ;
397
412
}
398
413
}
399
- if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. output ( ) ) {
414
+ if contains_illegal_self_type_reference (
415
+ tcx,
416
+ trait_def_id,
417
+ sig. output ( ) ,
418
+ AllowSelfProjections :: Yes ,
419
+ ) {
400
420
errors. push ( MethodViolationCode :: ReferencesSelfOutput ) ;
401
421
}
402
422
if let Some ( code) = contains_illegal_impl_trait_in_trait ( tcx, method. def_id , sig. output ( ) ) {
@@ -482,7 +502,7 @@ fn virtual_call_violations_for_method<'tcx>(
482
502
return false ;
483
503
}
484
504
485
- contains_illegal_self_type_reference ( tcx, trait_def_id, pred)
505
+ contains_illegal_self_type_reference ( tcx, trait_def_id, pred, AllowSelfProjections :: Yes )
486
506
} ) {
487
507
errors. push ( MethodViolationCode :: WhereClauseReferencesSelf ) ;
488
508
}
@@ -711,120 +731,180 @@ fn receiver_is_dispatchable<'tcx>(
711
731
infcx. predicate_must_hold_modulo_regions ( & obligation)
712
732
}
713
733
734
+ #[ derive( Copy , Clone ) ]
735
+ enum AllowSelfProjections {
736
+ Yes ,
737
+ No ,
738
+ }
739
+
740
+ /// This is somewhat subtle. In general, we want to forbid
741
+ /// references to `Self` in the argument and return types,
742
+ /// since the value of `Self` is erased. However, there is one
743
+ /// exception: it is ok to reference `Self` in order to access
744
+ /// an associated type of the current trait, since we retain
745
+ /// the value of those associated types in the object type
746
+ /// itself.
747
+ ///
748
+ /// ```rust,ignore (example)
749
+ /// trait SuperTrait {
750
+ /// type X;
751
+ /// }
752
+ ///
753
+ /// trait Trait : SuperTrait {
754
+ /// type Y;
755
+ /// fn foo(&self, x: Self) // bad
756
+ /// fn foo(&self) -> Self // bad
757
+ /// fn foo(&self) -> Option<Self> // bad
758
+ /// fn foo(&self) -> Self::Y // OK, desugars to next example
759
+ /// fn foo(&self) -> <Self as Trait>::Y // OK
760
+ /// fn foo(&self) -> Self::X // OK, desugars to next example
761
+ /// fn foo(&self) -> <Self as SuperTrait>::X // OK
762
+ /// }
763
+ /// ```
764
+ ///
765
+ /// However, it is not as simple as allowing `Self` in a projected
766
+ /// type, because there are illegal ways to use `Self` as well:
767
+ ///
768
+ /// ```rust,ignore (example)
769
+ /// trait Trait : SuperTrait {
770
+ /// ...
771
+ /// fn foo(&self) -> <Self as SomeOtherTrait>::X;
772
+ /// }
773
+ /// ```
774
+ ///
775
+ /// Here we will not have the type of `X` recorded in the
776
+ /// object type, and we cannot resolve `Self as SomeOtherTrait`
777
+ /// without knowing what `Self` is.
714
778
fn contains_illegal_self_type_reference < ' tcx , T : TypeVisitable < TyCtxt < ' tcx > > > (
715
779
tcx : TyCtxt < ' tcx > ,
716
780
trait_def_id : DefId ,
717
781
value : T ,
782
+ allow_self_projections : AllowSelfProjections ,
718
783
) -> bool {
719
- // This is somewhat subtle. In general, we want to forbid
720
- // references to `Self` in the argument and return types,
721
- // since the value of `Self` is erased. However, there is one
722
- // exception: it is ok to reference `Self` in order to access
723
- // an associated type of the current trait, since we retain
724
- // the value of those associated types in the object type
725
- // itself.
726
- //
727
- // ```rust
728
- // trait SuperTrait {
729
- // type X;
730
- // }
731
- //
732
- // trait Trait : SuperTrait {
733
- // type Y;
734
- // fn foo(&self, x: Self) // bad
735
- // fn foo(&self) -> Self // bad
736
- // fn foo(&self) -> Option<Self> // bad
737
- // fn foo(&self) -> Self::Y // OK, desugars to next example
738
- // fn foo(&self) -> <Self as Trait>::Y // OK
739
- // fn foo(&self) -> Self::X // OK, desugars to next example
740
- // fn foo(&self) -> <Self as SuperTrait>::X // OK
741
- // }
742
- // ```
743
- //
744
- // However, it is not as simple as allowing `Self` in a projected
745
- // type, because there are illegal ways to use `Self` as well:
746
- //
747
- // ```rust
748
- // trait Trait : SuperTrait {
749
- // ...
750
- // fn foo(&self) -> <Self as SomeOtherTrait>::X;
751
- // }
752
- // ```
753
- //
754
- // Here we will not have the type of `X` recorded in the
755
- // object type, and we cannot resolve `Self as SomeOtherTrait`
756
- // without knowing what `Self` is.
757
-
758
- struct IllegalSelfTypeVisitor < ' tcx > {
759
- tcx : TyCtxt < ' tcx > ,
760
- trait_def_id : DefId ,
761
- supertraits : Option < Vec < DefId > > ,
762
- }
784
+ value
785
+ . visit_with ( & mut IllegalSelfTypeVisitor {
786
+ tcx,
787
+ trait_def_id,
788
+ supertraits : None ,
789
+ allow_self_projections,
790
+ } )
791
+ . is_break ( )
792
+ }
763
793
764
- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
765
- type Result = ControlFlow < ( ) > ;
794
+ struct IllegalSelfTypeVisitor < ' tcx > {
795
+ tcx : TyCtxt < ' tcx > ,
796
+ trait_def_id : DefId ,
797
+ supertraits : Option < Vec < ty:: TraitRef < ' tcx > > > ,
798
+ allow_self_projections : AllowSelfProjections ,
799
+ }
766
800
767
- fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
768
- match t. kind ( ) {
769
- ty:: Param ( _) => {
770
- if t == self . tcx . types . self_param {
771
- ControlFlow :: Break ( ( ) )
772
- } else {
773
- ControlFlow :: Continue ( ( ) )
774
- }
775
- }
776
- ty:: Alias ( ty:: Projection , ref data)
777
- if self . tcx . is_impl_trait_in_trait ( data. def_id ) =>
778
- {
779
- // We'll deny these later in their own pass
801
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for IllegalSelfTypeVisitor < ' tcx > {
802
+ type Result = ControlFlow < ( ) > ;
803
+
804
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
805
+ match t. kind ( ) {
806
+ ty:: Param ( _) => {
807
+ if t == self . tcx . types . self_param {
808
+ ControlFlow :: Break ( ( ) )
809
+ } else {
780
810
ControlFlow :: Continue ( ( ) )
781
811
}
782
- 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
+ }
813
+ ty:: Alias ( ty:: Projection , ref data) if self . tcx . is_impl_trait_in_trait ( data. def_id ) => {
814
+ // We'll deny these later in their own pass
815
+ ControlFlow :: Continue ( ( ) )
816
+ }
817
+ ty:: Alias ( ty:: Projection , ref data) => {
818
+ match self . allow_self_projections {
819
+ AllowSelfProjections :: Yes => {
820
+ // This is a projected type `<Foo as SomeTrait>::X`.
821
+
822
+ // Compute supertraits of current trait lazily.
823
+ if self . supertraits . is_none ( ) {
824
+ self . supertraits = Some (
825
+ util:: supertraits (
826
+ self . tcx ,
827
+ ty:: Binder :: dummy ( ty:: TraitRef :: identity (
828
+ self . tcx ,
829
+ self . trait_def_id ,
830
+ ) ) ,
831
+ )
832
+ . map ( |trait_ref| {
833
+ self . tcx . erase_regions (
834
+ self . tcx . instantiate_bound_regions_with_erased ( trait_ref) ,
835
+ )
836
+ } )
837
+ . collect ( ) ,
838
+ ) ;
839
+ }
793
840
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
841
+ // Determine whether the trait reference `Foo as
842
+ // SomeTrait` is in fact a supertrait of the
843
+ // current trait. In that case, this type is
844
+ // legal, because the type `X` will be specified
845
+ // in the object type. Note that we can just use
846
+ // direct equality here because all of these types
847
+ // are part of the formal parameter listing, and
848
+ // hence there should be no inference variables.
849
+ let is_supertrait_of_current_trait =
850
+ self . supertraits . as_ref ( ) . unwrap ( ) . contains (
851
+ & data. trait_ref ( self . tcx ) . fold_with (
852
+ & mut EraseEscapingBoundRegions {
853
+ tcx : self . tcx ,
854
+ binder : ty:: INNERMOST ,
855
+ } ,
856
+ ) ,
857
+ ) ;
858
+
859
+ if is_supertrait_of_current_trait {
860
+ ControlFlow :: Continue ( ( ) )
861
+ } else {
862
+ t. super_visit_with ( self )
863
+ }
812
864
}
865
+ AllowSelfProjections :: No => t. super_visit_with ( self ) ,
813
866
}
814
- _ => t. super_visit_with ( self ) , // walk contained types, if any
815
867
}
868
+ _ => t. super_visit_with ( self ) ,
816
869
}
870
+ }
817
871
818
- fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> Self :: Result {
819
- // Constants can only influence object safety if they are generic and reference `Self`.
820
- // This is only possible for unevaluated constants, so we walk these here.
821
- self . tcx . expand_abstract_consts ( ct) . super_visit_with ( self )
822
- }
872
+ fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> Self :: Result {
873
+ // Constants can only influence object safety if they are generic and reference `Self`.
874
+ // This is only possible for unevaluated constants, so we walk these here.
875
+ self . tcx . expand_abstract_consts ( ct) . super_visit_with ( self )
823
876
}
877
+ }
824
878
825
- value
826
- . visit_with ( & mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits : None } )
827
- . is_break ( )
879
+ struct EraseEscapingBoundRegions < ' tcx > {
880
+ tcx : TyCtxt < ' tcx > ,
881
+ binder : ty:: DebruijnIndex ,
882
+ }
883
+
884
+ impl < ' tcx > TypeFolder < TyCtxt < ' tcx > > for EraseEscapingBoundRegions < ' tcx > {
885
+ fn interner ( & self ) -> TyCtxt < ' tcx > {
886
+ self . tcx
887
+ }
888
+
889
+ fn fold_binder < T > ( & mut self , t : ty:: Binder < ' tcx , T > ) -> ty:: Binder < ' tcx , T >
890
+ where
891
+ T : TypeFoldable < TyCtxt < ' tcx > > ,
892
+ {
893
+ self . binder . shift_in ( 1 ) ;
894
+ let result = t. super_fold_with ( self ) ;
895
+ self . binder . shift_out ( 1 ) ;
896
+ result
897
+ }
898
+
899
+ fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
900
+ if let ty:: ReBound ( debruijn, _) = * r
901
+ && debruijn < self . binder
902
+ {
903
+ r
904
+ } else {
905
+ self . tcx . lifetimes . re_erased
906
+ }
907
+ }
828
908
}
829
909
830
910
pub fn contains_illegal_impl_trait_in_trait < ' tcx > (
0 commit comments