@@ -603,7 +603,23 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
603
603
for m in ms. iter ( ) {
604
604
check_method_body ( ccx, & impl_tpt. generics , None , * m) ;
605
605
}
606
- vtable:: resolve_impl ( ccx, it) ;
606
+
607
+ match * opt_trait_ref {
608
+ Some ( ref ast_trait_ref) => {
609
+ let impl_trait_ref =
610
+ ty:: node_id_to_trait_ref ( ccx. tcx , ast_trait_ref. ref_id ) ;
611
+ check_impl_methods_against_trait ( ccx,
612
+ it. span ,
613
+ & impl_tpt. generics ,
614
+ ast_trait_ref,
615
+ impl_trait_ref,
616
+ * ms) ;
617
+ vtable:: resolve_impl ( ccx, it, & impl_tpt. generics ,
618
+ impl_trait_ref) ;
619
+ }
620
+ None => { }
621
+ }
622
+
607
623
}
608
624
ast:: item_trait( _, _, ref trait_methods) => {
609
625
let trait_def = ty:: lookup_trait_def ( ccx. tcx , local_def ( it. id ) ) ;
@@ -707,6 +723,311 @@ fn check_method_body(ccx: @mut CrateCtxt,
707
723
param_env) ;
708
724
}
709
725
726
+ fn check_impl_methods_against_trait ( ccx : @mut CrateCtxt ,
727
+ impl_span : Span ,
728
+ impl_generics : & ty:: Generics ,
729
+ ast_trait_ref : & ast:: trait_ref ,
730
+ impl_trait_ref : & ty:: TraitRef ,
731
+ impl_methods : & [ @ast:: method ] ) {
732
+ // Locate trait methods
733
+ let tcx = ccx. tcx ;
734
+ let trait_methods = ty:: trait_methods ( tcx, impl_trait_ref. def_id ) ;
735
+
736
+ // Check existing impl methods to see if they are both present in trait
737
+ // and compatible with trait signature
738
+ for impl_method in impl_methods. iter ( ) {
739
+ let impl_method_def_id = local_def ( impl_method. id ) ;
740
+ let impl_method_ty = ty:: method ( ccx. tcx , impl_method_def_id) ;
741
+
742
+ // If this is an impl of a trait method, find the corresponding
743
+ // method definition in the trait.
744
+ let opt_trait_method_ty =
745
+ trait_methods. iter ( ) .
746
+ find ( |tm| tm. ident . name == impl_method_ty. ident . name ) ;
747
+ match opt_trait_method_ty {
748
+ Some ( trait_method_ty) => {
749
+ compare_impl_method ( ccx. tcx ,
750
+ impl_generics,
751
+ impl_method_ty,
752
+ impl_method. span ,
753
+ impl_method. body . id ,
754
+ * trait_method_ty,
755
+ & impl_trait_ref. substs ) ;
756
+ }
757
+ None => {
758
+ tcx. sess . span_err (
759
+ impl_method. span ,
760
+ format ! ( "method `{}` is not a member of trait `{}`" ,
761
+ tcx. sess. str_of( impl_method_ty. ident) ,
762
+ pprust:: path_to_str( & ast_trait_ref. path,
763
+ tcx. sess. intr( ) ) ) ) ;
764
+ }
765
+ }
766
+ }
767
+
768
+ // Check for missing methods from trait
769
+ let provided_methods = ty:: provided_trait_methods ( tcx,
770
+ impl_trait_ref. def_id ) ;
771
+ let mut missing_methods = ~[ ] ;
772
+ for trait_method in trait_methods. iter ( ) {
773
+ let is_implemented =
774
+ impl_methods. iter ( ) . any (
775
+ |m| m. ident . name == trait_method. ident . name ) ;
776
+ let is_provided =
777
+ provided_methods. iter ( ) . any (
778
+ |m| m. ident . name == trait_method. ident . name ) ;
779
+ if !is_implemented && !is_provided {
780
+ missing_methods. push (
781
+ format ! ( "`{}`" , ccx. tcx. sess. str_of( trait_method. ident) ) ) ;
782
+ }
783
+ }
784
+
785
+ if !missing_methods. is_empty ( ) {
786
+ tcx. sess . span_err (
787
+ impl_span,
788
+ format ! ( "not all trait methods implemented, missing: {}" ,
789
+ missing_methods. connect( ", " ) ) ) ;
790
+ }
791
+ }
792
+
793
+ /**
794
+ * Checks that a method from an impl/class conforms to the signature of
795
+ * the same method as declared in the trait.
796
+ *
797
+ * # Parameters
798
+ *
799
+ * - impl_generics: the generics declared on the impl itself (not the method!)
800
+ * - impl_m: type of the method we are checking
801
+ * - impl_m_span: span to use for reporting errors
802
+ * - impl_m_body_id: id of the method body
803
+ * - trait_m: the method in the trait
804
+ * - trait_substs: the substitutions used on the type of the trait
805
+ * - self_ty: the self type of the impl
806
+ */
807
+ pub fn compare_impl_method ( tcx : ty:: ctxt ,
808
+ impl_generics : & ty:: Generics ,
809
+ impl_m : @ty:: Method ,
810
+ impl_m_span : Span ,
811
+ impl_m_body_id : ast:: NodeId ,
812
+ trait_m : & ty:: Method ,
813
+ trait_substs : & ty:: substs ) {
814
+ debug ! ( "compare_impl_method()" ) ;
815
+ let infcx = infer:: new_infer_ctxt ( tcx) ;
816
+
817
+ let impl_tps = impl_generics. type_param_defs . len ( ) ;
818
+
819
+ // Try to give more informative error messages about self typing
820
+ // mismatches. Note that any mismatch will also be detected
821
+ // below, where we construct a canonical function type that
822
+ // includes the self parameter as a normal parameter. It's just
823
+ // that the error messages you get out of this code are a bit more
824
+ // inscrutable, particularly for cases where one method has no
825
+ // self.
826
+ match ( & trait_m. explicit_self , & impl_m. explicit_self ) {
827
+ ( & ast:: sty_static, & ast:: sty_static) => { }
828
+ ( & ast:: sty_static, _) => {
829
+ tcx. sess . span_err (
830
+ impl_m_span,
831
+ format ! ( "method `{}` has a `{}` declaration in the impl, \
832
+ but not in the trait",
833
+ tcx. sess. str_of( trait_m. ident) ,
834
+ pprust:: explicit_self_to_str( & impl_m. explicit_self,
835
+ tcx. sess. intr( ) ) ) ) ;
836
+ return ;
837
+ }
838
+ ( _, & ast:: sty_static) => {
839
+ tcx. sess . span_err (
840
+ impl_m_span,
841
+ format ! ( "method `{}` has a `{}` declaration in the trait, \
842
+ but not in the impl",
843
+ tcx. sess. str_of( trait_m. ident) ,
844
+ pprust:: explicit_self_to_str( & trait_m. explicit_self,
845
+ tcx. sess. intr( ) ) ) ) ;
846
+ return ;
847
+ }
848
+ _ => {
849
+ // Let the type checker catch other errors below
850
+ }
851
+ }
852
+
853
+ let num_impl_m_type_params = impl_m. generics . type_param_defs . len ( ) ;
854
+ let num_trait_m_type_params = trait_m. generics . type_param_defs . len ( ) ;
855
+ if num_impl_m_type_params != num_trait_m_type_params {
856
+ tcx. sess . span_err (
857
+ impl_m_span,
858
+ format ! ( "method `{}` has {} type parameter(s), but its trait \
859
+ declaration has {} type parameter(s)",
860
+ tcx. sess. str_of( trait_m. ident) ,
861
+ num_impl_m_type_params,
862
+ num_trait_m_type_params) ) ;
863
+ return ;
864
+ }
865
+
866
+ if impl_m. fty . sig . inputs . len ( ) != trait_m. fty . sig . inputs . len ( ) {
867
+ tcx. sess . span_err (
868
+ impl_m_span,
869
+ format ! ( "method `{}` has {} parameter(s) \
870
+ but the trait has {} parameter(s)",
871
+ tcx. sess. str_of( trait_m. ident) ,
872
+ impl_m. fty. sig. inputs. len( ) ,
873
+ trait_m. fty. sig. inputs. len( ) ) ) ;
874
+ return ;
875
+ }
876
+
877
+ for ( i, trait_param_def) in trait_m. generics . type_param_defs . iter ( ) . enumerate ( ) {
878
+ // For each of the corresponding impl ty param's bounds...
879
+ let impl_param_def = & impl_m. generics . type_param_defs [ i] ;
880
+
881
+ // Check that the impl does not require any builtin-bounds
882
+ // that the trait does not guarantee:
883
+ let extra_bounds =
884
+ impl_param_def. bounds . builtin_bounds -
885
+ trait_param_def. bounds . builtin_bounds ;
886
+ if !extra_bounds. is_empty ( ) {
887
+ tcx. sess . span_err (
888
+ impl_m_span,
889
+ format ! ( "in method `{}`, \
890
+ type parameter {} requires `{}`, \
891
+ which is not required by \
892
+ the corresponding type parameter \
893
+ in the trait declaration",
894
+ tcx. sess. str_of( trait_m. ident) ,
895
+ i,
896
+ extra_bounds. user_string( tcx) ) ) ;
897
+ return ;
898
+ }
899
+
900
+ // FIXME(#2687)---we should be checking that the bounds of the
901
+ // trait imply the bounds of the subtype, but it appears we
902
+ // are...not checking this.
903
+ if impl_param_def. bounds . trait_bounds . len ( ) !=
904
+ trait_param_def. bounds . trait_bounds . len ( )
905
+ {
906
+ tcx. sess . span_err (
907
+ impl_m_span,
908
+ format ! ( "in method `{}`, \
909
+ type parameter {} has {} trait bound(s), but the \
910
+ corresponding type parameter in \
911
+ the trait declaration has {} trait bound(s)",
912
+ tcx. sess. str_of( trait_m. ident) ,
913
+ i, impl_param_def. bounds. trait_bounds. len( ) ,
914
+ trait_param_def. bounds. trait_bounds. len( ) ) ) ;
915
+ return ;
916
+ }
917
+ }
918
+
919
+ // Create a substitution that maps the type parameters on the impl
920
+ // to themselves and which replace any references to bound regions
921
+ // in the self type with free regions. So, for example, if the
922
+ // impl type is "&'self str", then this would replace the self
923
+ // type with a free region `self`.
924
+ let dummy_impl_tps: ~[ ty:: t ] =
925
+ impl_generics. type_param_defs . iter ( ) . enumerate ( ) .
926
+ map ( |( i, t) | ty:: mk_param ( tcx, i, t. def_id ) ) .
927
+ collect ( ) ;
928
+ let dummy_method_tps: ~[ ty:: t ] =
929
+ impl_m. generics . type_param_defs . iter ( ) . enumerate ( ) .
930
+ map ( |( i, t) | ty:: mk_param ( tcx, i + impl_tps, t. def_id ) ) .
931
+ collect ( ) ;
932
+ let dummy_impl_regions: OptVec < ty:: Region > =
933
+ impl_generics. region_param_defs . iter ( ) .
934
+ map ( |l| ty:: re_free ( ty:: FreeRegion {
935
+ scope_id : impl_m_body_id,
936
+ bound_region : ty:: br_named ( l. def_id , l. ident ) } ) ) .
937
+ collect ( ) ;
938
+ let dummy_substs = ty:: substs {
939
+ tps : vec:: append ( dummy_impl_tps, dummy_method_tps) ,
940
+ regions : ty:: NonerasedRegions ( dummy_impl_regions) ,
941
+ self_ty : None } ;
942
+
943
+ // We are going to create a synthetic fn type that includes
944
+ // both the method's self argument and its normal arguments.
945
+ // So a method like `fn(&self, a: uint)` would be converted
946
+ // into a function `fn(self: &T, a: uint)`.
947
+ let mut trait_fn_args = ~[ ] ;
948
+ let mut impl_fn_args = ~[ ] ;
949
+
950
+ // For both the trait and the impl, create an argument to
951
+ // represent the self argument (unless this is a static method).
952
+ // This argument will have the *transformed* self type.
953
+ for & t in trait_m. transformed_self_ty . iter ( ) {
954
+ trait_fn_args. push ( t) ;
955
+ }
956
+ for & t in impl_m. transformed_self_ty . iter ( ) {
957
+ impl_fn_args. push ( t) ;
958
+ }
959
+
960
+ // Add in the normal arguments.
961
+ trait_fn_args. push_all ( trait_m. fty . sig . inputs ) ;
962
+ impl_fn_args. push_all ( impl_m. fty . sig . inputs ) ;
963
+
964
+ // Create a bare fn type for trait/impl that includes self argument
965
+ let trait_fty =
966
+ ty:: mk_bare_fn ( tcx,
967
+ ty:: BareFnTy {
968
+ purity : trait_m. fty . purity ,
969
+ abis : trait_m. fty . abis ,
970
+ sig : ty:: FnSig {
971
+ binder_id : trait_m. fty . sig . binder_id ,
972
+ inputs : trait_fn_args,
973
+ output : trait_m. fty . sig . output ,
974
+ variadic : false
975
+ }
976
+ } ) ;
977
+ let impl_fty =
978
+ ty:: mk_bare_fn ( tcx,
979
+ ty:: BareFnTy {
980
+ purity : impl_m. fty . purity ,
981
+ abis : impl_m. fty . abis ,
982
+ sig : ty:: FnSig {
983
+ binder_id : impl_m. fty . sig . binder_id ,
984
+ inputs : impl_fn_args,
985
+ output : impl_m. fty . sig . output ,
986
+ variadic : false
987
+ }
988
+ } ) ;
989
+
990
+ // Perform substitutions so that the trait/impl methods are expressed
991
+ // in terms of the same set of type/region parameters:
992
+ // - replace trait type parameters with those from `trait_substs`,
993
+ // except with any reference to bound self replaced with `dummy_self_r`
994
+ // - replace method parameters on the trait with fresh, dummy parameters
995
+ // that correspond to the parameters we will find on the impl
996
+ // - replace self region with a fresh, dummy region
997
+ let impl_fty = {
998
+ debug ! ( "impl_fty (pre-subst): {}" , ppaux:: ty_to_str( tcx, impl_fty) ) ;
999
+ impl_fty. subst ( tcx, & dummy_substs)
1000
+ } ;
1001
+ debug ! ( "impl_fty (post-subst): {}" , ppaux:: ty_to_str( tcx, impl_fty) ) ;
1002
+ let trait_fty = {
1003
+ let substs { regions : trait_regions,
1004
+ tps : trait_tps,
1005
+ self_ty : self_ty } = trait_substs. subst ( tcx, & dummy_substs) ;
1006
+ let substs = substs {
1007
+ regions : trait_regions,
1008
+ tps : vec:: append ( trait_tps, dummy_method_tps) ,
1009
+ self_ty : self_ty,
1010
+ } ;
1011
+ debug ! ( "trait_fty (pre-subst): {} substs={}" ,
1012
+ trait_fty. repr( tcx) , substs. repr( tcx) ) ;
1013
+ trait_fty. subst ( tcx, & substs)
1014
+ } ;
1015
+ debug ! ( "trait_fty (post-subst): {}" , trait_fty. repr( tcx) ) ;
1016
+
1017
+ match infer:: mk_subty ( infcx, false , infer:: MethodCompatCheck ( impl_m_span) ,
1018
+ impl_fty, trait_fty) {
1019
+ result:: Ok ( ( ) ) => { }
1020
+ result:: Err ( ref terr) => {
1021
+ tcx. sess . span_err (
1022
+ impl_m_span,
1023
+ format ! ( "method `{}` has an incompatible type: {}" ,
1024
+ tcx. sess. str_of( trait_m. ident) ,
1025
+ ty:: type_err_to_str( tcx, terr) ) ) ;
1026
+ ty:: note_and_explain_type_err ( tcx, terr) ;
1027
+ }
1028
+ }
1029
+ }
1030
+
710
1031
impl AstConv for FnCtxt {
711
1032
fn tcx ( & self ) -> ty:: ctxt { self . ccx . tcx }
712
1033
0 commit comments