@@ -13,9 +13,8 @@ use constrained_type_params::{identify_constrained_type_params, Parameter};
1313
1414use hir:: def_id:: DefId ;
1515use rustc:: traits:: { self , ObligationCauseCode } ;
16- use rustc:: ty:: { self , Lift , Ty , TyCtxt , TyKind , GenericParamDefKind , TypeFoldable } ;
16+ use rustc:: ty:: { self , Lift , Ty , TyCtxt , TyKind , GenericParamDefKind , TypeFoldable , ToPredicate } ;
1717use rustc:: ty:: subst:: { Subst , Substs } ;
18- use rustc:: ty:: util:: ExplicitSelf ;
1918use rustc:: util:: nodemap:: { FxHashSet , FxHashMap } ;
2019use rustc:: middle:: lang_items;
2120use rustc:: infer:: opaque_types:: may_define_existential_type;
@@ -749,72 +748,164 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
749748 & ty:: Binder :: bind ( self_ty)
750749 ) ;
751750
752- let self_arg_ty = sig. inputs ( ) [ 0 ] ;
751+ let receiver_ty = sig. inputs ( ) [ 0 ] ;
753752
754- let cause = fcx. cause ( span, ObligationCauseCode :: MethodReceiver ) ;
755- let self_arg_ty = fcx. normalize_associated_types_in ( span, & self_arg_ty) ;
756- let self_arg_ty = fcx. tcx . liberate_late_bound_regions (
753+ let receiver_ty = fcx. normalize_associated_types_in ( span, & receiver_ty) ;
754+ let receiver_ty = fcx. tcx . liberate_late_bound_regions (
757755 method. def_id ,
758- & ty:: Binder :: bind ( self_arg_ty )
756+ & ty:: Binder :: bind ( receiver_ty )
759757 ) ;
760758
761- let mut autoderef = fcx. autoderef ( span, self_arg_ty) . include_raw_pointers ( ) ;
762-
763- loop {
764- if let Some ( ( potential_self_ty, _) ) = autoderef. next ( ) {
765- debug ! ( "check_method_receiver: potential self type `{:?}` to match `{:?}`" ,
766- potential_self_ty, self_ty) ;
767-
768- if fcx. infcx . can_eq ( fcx. param_env , self_ty, potential_self_ty) . is_ok ( ) {
769- autoderef. finalize ( fcx) ;
770- if let Some ( mut err) = fcx. demand_eqtype_with_origin (
771- & cause, self_ty, potential_self_ty) {
772- err. emit ( ) ;
773- }
774- break
775- }
776- } else {
759+ if fcx. tcx . features ( ) . arbitrary_self_types {
760+ if !receiver_is_valid ( fcx, span, receiver_ty, self_ty, true ) {
761+ // report error, arbitrary_self_types was enabled
777762 fcx. tcx . sess . diagnostic ( ) . mut_span_err (
778- span, & format ! ( "invalid `self` type: {:?}" , self_arg_ty ) )
779- . note ( & format ! ( "type must be `{:?}` or a type that dereferences to it" , self_ty) )
763+ span, & format ! ( "invalid `self` type: {:?}" , receiver_ty )
764+ ) . note ( & format ! ( "type must be `{:?}` or a type that dereferences to it" , self_ty) )
780765 . help ( "consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`" )
781766 . code ( DiagnosticId :: Error ( "E0307" . into ( ) ) )
782767 . emit ( ) ;
783- return
784768 }
785- }
786-
787- let is_self_ty = |ty| fcx. infcx . can_eq ( fcx. param_env , self_ty, ty) . is_ok ( ) ;
788- let self_kind = ExplicitSelf :: determine ( self_arg_ty, is_self_ty) ;
789-
790- if !fcx. tcx . features ( ) . arbitrary_self_types {
791- match self_kind {
792- ExplicitSelf :: ByValue |
793- ExplicitSelf :: ByReference ( _, _) |
794- ExplicitSelf :: ByBox => ( ) ,
795-
796- ExplicitSelf :: ByRawPointer ( _) => {
769+ } else {
770+ if !receiver_is_valid ( fcx, span, receiver_ty, self_ty, false ) {
771+ if receiver_is_valid ( fcx, span, receiver_ty, self_ty, true ) {
772+ // report error, would have worked with arbitrary_self_types
797773 feature_gate:: feature_err (
798774 & fcx. tcx . sess . parse_sess ,
799775 "arbitrary_self_types" ,
800776 span,
801777 GateIssue :: Language ,
802- "raw pointer `self` is unstable" )
778+ & format ! (
779+ "`{}` cannot be used as the type of `self` without \
780+ the `arbitrary_self_types` feature",
781+ receiver_ty,
782+ ) ,
783+ ) . help ( "consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`" )
784+ . emit ( ) ;
785+ } else {
786+ // report error, would not have worked with arbitrary_self_types
787+ fcx. tcx . sess . diagnostic ( ) . mut_span_err (
788+ span, & format ! ( "invalid `self` type: {:?}" , receiver_ty)
789+ ) . note ( & format ! ( "type must be `{:?}` or a type that dereferences to it" , self_ty) )
803790 . help ( "consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`" )
791+ . code ( DiagnosticId :: Error ( "E0307" . into ( ) ) )
804792 . emit ( ) ;
805793 }
794+ }
795+ }
796+ }
806797
807- ExplicitSelf :: Other => {
808- feature_gate:: feature_err (
809- & fcx. tcx . sess . parse_sess ,
810- "arbitrary_self_types" ,
811- span,
812- GateIssue :: Language , "arbitrary `self` types are unstable" )
813- . help ( "consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`" )
814- . emit ( ) ;
798+ fn receiver_is_valid < ' fcx , ' tcx , ' gcx > (
799+ fcx : & FnCtxt < ' fcx , ' gcx , ' tcx > ,
800+ span : Span ,
801+ receiver_ty : Ty < ' tcx > ,
802+ self_ty : Ty < ' tcx > ,
803+ arbitrary_self_types_enabled : bool ,
804+ ) -> bool {
805+ let cause = fcx. cause ( span, traits:: ObligationCauseCode :: MethodReceiver ) ;
806+
807+ let can_eq_self = |ty| fcx. infcx . can_eq ( fcx. param_env , self_ty, ty) . is_ok ( ) ;
808+
809+ if can_eq_self ( receiver_ty) {
810+ if let Some ( mut err) = fcx. demand_eqtype_with_origin ( & cause, self_ty, receiver_ty) {
811+ err. emit ( ) ;
812+ }
813+ return true
814+ }
815+
816+ let mut autoderef = fcx. autoderef ( span, receiver_ty) ;
817+
818+ if arbitrary_self_types_enabled {
819+ autoderef = autoderef. include_raw_pointers ( ) ;
820+ }
821+
822+ // skip the first type, we know its not equal to `self_ty`
823+ autoderef. next ( ) ;
824+
825+ let potential_self_ty = loop {
826+ if let Some ( ( potential_self_ty, _) ) = autoderef. next ( ) {
827+ debug ! ( "receiver_is_valid: potential self type `{:?}` to match `{:?}`" ,
828+ potential_self_ty, self_ty) ;
829+
830+ if can_eq_self ( potential_self_ty) {
831+ break potential_self_ty
832+ }
833+ } else {
834+ debug ! ( "receiver_is_valid: type `{:?}` does not deref to `{:?}`" ,
835+ receiver_ty, self_ty) ;
836+ return false
837+ }
838+ } ;
839+
840+ if !arbitrary_self_types_enabled {
841+ // check that receiver_ty: Receiver<Target=self_ty>
842+
843+ let receiver_trait_def_id = match fcx. tcx . lang_items ( ) . receiver_trait ( ) {
844+ Some ( did) => did,
845+ None => {
846+ debug ! ( "receiver_is_valid: missing Receiver trait" ) ;
847+ return false
815848 }
849+ } ;
850+
851+ let receiver_trait_ref = ty:: TraitRef {
852+ def_id : receiver_trait_def_id,
853+ substs : fcx. tcx . mk_substs_trait ( receiver_ty, & [ ] ) ,
854+ } ;
855+
856+ let receiver_obligation = traits:: Obligation :: new (
857+ cause. clone ( ) ,
858+ fcx. param_env ,
859+ receiver_trait_ref. to_predicate ( )
860+ ) ;
861+
862+ if !fcx. predicate_must_hold ( & receiver_obligation) {
863+ debug ! ( "receiver_is_valid: type `{:?}` does not implement `Receiver` trait" ,
864+ receiver_ty) ;
865+ return false
866+ }
867+
868+ let deref_trait_def_id = match fcx. tcx . lang_items ( ) . deref_trait ( ) {
869+ Some ( did) => did,
870+ None => {
871+ debug ! ( "receiver_is_valid: missing Deref trait" ) ;
872+ return false
873+ }
874+ } ;
875+
876+ let deref_trait_ref = ty:: TraitRef {
877+ def_id : deref_trait_def_id,
878+ substs : fcx. tcx . mk_substs_trait ( receiver_ty, & [ ] ) ,
879+ } ;
880+
881+ let projection_ty = ty:: ProjectionTy :: from_ref_and_name (
882+ fcx. tcx , deref_trait_ref, ast:: Ident :: from_str ( "Target" )
883+ ) ;
884+
885+ let projection_predicate = ty:: Binder :: dummy ( ty:: ProjectionPredicate {
886+ projection_ty, ty : self_ty
887+ } ) . to_predicate ( ) ;
888+
889+ let deref_obligation = traits:: Obligation :: new (
890+ cause. clone ( ) ,
891+ fcx. param_env ,
892+ projection_predicate,
893+ ) ;
894+
895+ if !fcx. predicate_must_hold ( & deref_obligation) {
896+ debug ! ( "receiver_is_valid: type `{:?}` does not directly deref to `{:?}`" ,
897+ receiver_ty, self_ty) ;
898+ return false
816899 }
817900 }
901+
902+ if let Some ( mut err) = fcx. demand_eqtype_with_origin ( & cause, self_ty, potential_self_ty) {
903+ err. emit ( ) ;
904+ }
905+
906+ autoderef. finalize ( fcx) ;
907+
908+ true
818909}
819910
820911fn check_variances_for_type_defn < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
0 commit comments