@@ -16,8 +16,10 @@ use crate::ty::{self, AdtKind, List, Ty, TyCtxt};
16
16
use rustc_hir as hir;
17
17
use rustc_hir:: def_id:: DefId ;
18
18
use rustc_span:: { Span , DUMMY_SP } ;
19
+ use smallvec:: SmallVec ;
19
20
use syntax:: ast;
20
21
22
+ use std:: borrow:: Cow ;
21
23
use std:: fmt:: Debug ;
22
24
use std:: rc:: Rc ;
23
25
@@ -737,3 +739,133 @@ where
737
739
tcx : TyCtxt < ' tcx > ,
738
740
) -> Option < Self :: LiftedLiteral > ;
739
741
}
742
+
743
+ #[ derive( Clone , Debug , PartialEq , Eq , Hash , HashStable ) ]
744
+ pub enum ObjectSafetyViolation {
745
+ /// `Self: Sized` declared on the trait.
746
+ SizedSelf ( SmallVec < [ Span ; 1 ] > ) ,
747
+
748
+ /// Supertrait reference references `Self` an in illegal location
749
+ /// (e.g., `trait Foo : Bar<Self>`).
750
+ SupertraitSelf ( SmallVec < [ Span ; 1 ] > ) ,
751
+
752
+ /// Method has something illegal.
753
+ Method ( ast:: Name , MethodViolationCode , Span ) ,
754
+
755
+ /// Associated const.
756
+ AssocConst ( ast:: Name , Span ) ,
757
+ }
758
+
759
+ impl ObjectSafetyViolation {
760
+ pub fn error_msg ( & self ) -> Cow < ' static , str > {
761
+ match * self {
762
+ ObjectSafetyViolation :: SizedSelf ( _) => "it requires `Self: Sized`" . into ( ) ,
763
+ ObjectSafetyViolation :: SupertraitSelf ( ref spans) => {
764
+ if spans. iter ( ) . any ( |sp| * sp != DUMMY_SP ) {
765
+ "it uses `Self` as a type parameter in this" . into ( )
766
+ } else {
767
+ "it cannot use `Self` as a type parameter in a supertrait or `where`-clause"
768
+ . into ( )
769
+ }
770
+ }
771
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: StaticMethod ( _) , _) => {
772
+ format ! ( "associated function `{}` has no `self` parameter" , name) . into ( )
773
+ }
774
+ ObjectSafetyViolation :: Method (
775
+ name,
776
+ MethodViolationCode :: ReferencesSelfInput ( _) ,
777
+ DUMMY_SP ,
778
+ ) => format ! ( "method `{}` references the `Self` type in its parameters" , name) . into ( ) ,
779
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: ReferencesSelfInput ( _) , _) => {
780
+ format ! ( "method `{}` references the `Self` type in this parameter" , name) . into ( )
781
+ }
782
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: ReferencesSelfOutput , _) => {
783
+ format ! ( "method `{}` references the `Self` type in its return type" , name) . into ( )
784
+ }
785
+ ObjectSafetyViolation :: Method (
786
+ name,
787
+ MethodViolationCode :: WhereClauseReferencesSelf ,
788
+ _,
789
+ ) => {
790
+ format ! ( "method `{}` references the `Self` type in its `where` clause" , name) . into ( )
791
+ }
792
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: Generic , _) => {
793
+ format ! ( "method `{}` has generic type parameters" , name) . into ( )
794
+ }
795
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: UndispatchableReceiver , _) => {
796
+ format ! ( "method `{}`'s `self` parameter cannot be dispatched on" , name) . into ( )
797
+ }
798
+ ObjectSafetyViolation :: AssocConst ( name, DUMMY_SP ) => {
799
+ format ! ( "it contains associated `const` `{}`" , name) . into ( )
800
+ }
801
+ ObjectSafetyViolation :: AssocConst ( ..) => "it contains this associated `const`" . into ( ) ,
802
+ }
803
+ }
804
+
805
+ pub fn solution ( & self ) -> Option < ( String , Option < ( String , Span ) > ) > {
806
+ Some ( match * self {
807
+ ObjectSafetyViolation :: SizedSelf ( _) | ObjectSafetyViolation :: SupertraitSelf ( _) => {
808
+ return None ;
809
+ }
810
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: StaticMethod ( sugg) , _) => (
811
+ format ! (
812
+ "consider turning `{}` into a method by giving it a `&self` argument or \
813
+ constraining it so it does not apply to trait objects",
814
+ name
815
+ ) ,
816
+ sugg. map ( |( sugg, sp) | ( sugg. to_string ( ) , sp) ) ,
817
+ ) ,
818
+ ObjectSafetyViolation :: Method (
819
+ name,
820
+ MethodViolationCode :: UndispatchableReceiver ,
821
+ span,
822
+ ) => (
823
+ format ! ( "consider changing method `{}`'s `self` parameter to be `&self`" , name)
824
+ . into ( ) ,
825
+ Some ( ( "&Self" . to_string ( ) , span) ) ,
826
+ ) ,
827
+ ObjectSafetyViolation :: AssocConst ( name, _)
828
+ | ObjectSafetyViolation :: Method ( name, ..) => {
829
+ ( format ! ( "consider moving `{}` to another trait" , name) , None )
830
+ }
831
+ } )
832
+ }
833
+
834
+ pub fn spans ( & self ) -> SmallVec < [ Span ; 1 ] > {
835
+ // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so
836
+ // diagnostics use a `note` instead of a `span_label`.
837
+ match self {
838
+ ObjectSafetyViolation :: SupertraitSelf ( spans)
839
+ | ObjectSafetyViolation :: SizedSelf ( spans) => spans. clone ( ) ,
840
+ ObjectSafetyViolation :: AssocConst ( _, span)
841
+ | ObjectSafetyViolation :: Method ( _, _, span)
842
+ if * span != DUMMY_SP =>
843
+ {
844
+ smallvec ! [ * span]
845
+ }
846
+ _ => smallvec ! [ ] ,
847
+ }
848
+ }
849
+ }
850
+
851
+ /// Reasons a method might not be object-safe.
852
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash , HashStable ) ]
853
+ pub enum MethodViolationCode {
854
+ /// e.g., `fn foo()`
855
+ StaticMethod ( Option < ( & ' static str , Span ) > ) ,
856
+
857
+ /// e.g., `fn foo(&self, x: Self)`
858
+ ReferencesSelfInput ( usize ) ,
859
+
860
+ /// e.g., `fn foo(&self) -> Self`
861
+ ReferencesSelfOutput ,
862
+
863
+ /// e.g., `fn foo(&self) where Self: Clone`
864
+ WhereClauseReferencesSelf ,
865
+
866
+ /// e.g., `fn foo<A>()`
867
+ Generic ,
868
+
869
+ /// the method's receiver (`self` argument) can't be dispatched on
870
+ UndispatchableReceiver ,
871
+ }
0 commit comments