@@ -16,8 +16,10 @@ use crate::ty::{self, AdtKind, List, Ty, TyCtxt};
1616use rustc_hir as hir;
1717use rustc_hir:: def_id:: DefId ;
1818use rustc_span:: { Span , DUMMY_SP } ;
19+ use smallvec:: SmallVec ;
1920use syntax:: ast;
2021
22+ use std:: borrow:: Cow ;
2123use std:: fmt:: Debug ;
2224use std:: rc:: Rc ;
2325
@@ -737,3 +739,133 @@ where
737739 tcx : TyCtxt < ' tcx > ,
738740 ) -> Option < Self :: LiftedLiteral > ;
739741}
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