Mercurial > vim
comparison src/vim9class.c @ 31843:ffa11e2757e7 v9.0.1254
patch 9.0.1254: calling a method on an interface does not work
Commit: https://github.com/vim/vim/commit/d0200c8631582bbb16a9b585e2ca7adccc84ccdd
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Jan 28 15:19:40 2023 +0000
patch 9.0.1254: calling a method on an interface does not work
Problem: Calling a method on an interface does not work.
Solution: At runtime figure out what method to call. (closes https://github.com/vim/vim/issues/11901)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 28 Jan 2023 16:30:04 +0100 |
parents | 3516e35f409f |
children | fe66019e7a23 |
comparison
equal
deleted
inserted
replaced
31842:1b6543beb560 | 31843:ffa11e2757e7 |
---|---|
199 /* | 199 /* |
200 * Convert a member index "idx" of interface "itf" to the member index of class | 200 * Convert a member index "idx" of interface "itf" to the member index of class |
201 * "cl" implementing that interface. | 201 * "cl" implementing that interface. |
202 */ | 202 */ |
203 int | 203 int |
204 object_index_from_itf_index(class_T *itf, int idx, class_T *cl) | 204 object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *cl) |
205 { | 205 { |
206 if (idx > itf->class_obj_member_count) | 206 if (idx > (is_method ? itf->class_obj_method_count |
207 : itf->class_obj_member_count)) | |
207 { | 208 { |
208 siemsg("index %d out of range for interface %s", idx, itf->class_name); | 209 siemsg("index %d out of range for interface %s", idx, itf->class_name); |
209 return 0; | 210 return 0; |
210 } | 211 } |
211 itf2class_T *i2c; | 212 itf2class_T *i2c; |
212 for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next) | 213 for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next) |
213 if (i2c->i2c_class == cl) | 214 if (i2c->i2c_class == cl && i2c->i2c_is_method == is_method) |
214 break; | 215 break; |
215 if (i2c == NULL) | 216 if (i2c == NULL) |
216 { | 217 { |
217 siemsg("class %s not found on interface %s", | 218 siemsg("class %s not found on interface %s", |
218 cl->class_name, itf->class_name); | 219 cl->class_name, itf->class_name); |
787 cl->class_refcount = 1; | 788 cl->class_refcount = 1; |
788 cl->class_name = vim_strnsave(name_start, name_end - name_start); | 789 cl->class_name = vim_strnsave(name_start, name_end - name_start); |
789 if (cl->class_name == NULL) | 790 if (cl->class_name == NULL) |
790 goto cleanup; | 791 goto cleanup; |
791 | 792 |
792 cl->class_extends = extends_cl; | 793 if (extends_cl != NULL) |
794 { | |
795 cl->class_extends = extends_cl; | |
796 extends_cl->class_flags |= CLASS_EXTENDED; | |
797 } | |
793 | 798 |
794 // Add class and object members to "cl". | 799 // Add class and object members to "cl". |
795 if (add_members_to_class(&classmembers, | 800 if (add_members_to_class(&classmembers, |
796 extends_cl == NULL ? NULL | 801 extends_cl == NULL ? NULL |
797 : extends_cl->class_class_members, | 802 : extends_cl->class_class_members, |
818 for (int i = 0; i < ga_impl.ga_len; ++i) | 823 for (int i = 0; i < ga_impl.ga_len; ++i) |
819 cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i]; | 824 cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i]; |
820 VIM_CLEAR(ga_impl.ga_data); | 825 VIM_CLEAR(ga_impl.ga_data); |
821 ga_impl.ga_len = 0; | 826 ga_impl.ga_len = 0; |
822 | 827 |
828 cl->class_interfaces_cl = intf_classes; | |
829 intf_classes = NULL; | |
830 } | |
831 | |
832 if (cl->class_interface_count > 0 || extends_cl != NULL) | |
833 { | |
823 // For each interface add a lookuptable for the member index on the | 834 // For each interface add a lookuptable for the member index on the |
824 // interface to the member index in this class. | 835 // interface to the member index in this class. |
825 for (int i = 0; i < cl->class_interface_count; ++i) | 836 // And a lookuptable for the object method index on the interface |
826 { | 837 // to the object method index in this class. |
827 class_T *ifcl = intf_classes[i]; | 838 // Also do this for the extended class, if any. |
839 for (int i = 0; i <= cl->class_interface_count; ++i) | |
840 { | |
841 class_T *ifcl = i < cl->class_interface_count | |
842 ? cl->class_interfaces_cl[i] | |
843 : extends_cl; | |
844 if (ifcl == NULL) | |
845 continue; | |
846 | |
847 // Table for members. | |
828 itf2class_T *if2cl = alloc_clear(sizeof(itf2class_T) | 848 itf2class_T *if2cl = alloc_clear(sizeof(itf2class_T) |
829 + ifcl->class_obj_member_count * sizeof(int)); | 849 + ifcl->class_obj_member_count * sizeof(int)); |
830 if (if2cl == NULL) | 850 if (if2cl == NULL) |
831 goto cleanup; | 851 goto cleanup; |
832 if2cl->i2c_next = ifcl->class_itf2class; | 852 if2cl->i2c_next = ifcl->class_itf2class; |
833 ifcl->class_itf2class = if2cl; | 853 ifcl->class_itf2class = if2cl; |
834 if2cl->i2c_class = cl; | 854 if2cl->i2c_class = cl; |
855 if2cl->i2c_is_method = FALSE; | |
835 | 856 |
836 for (int if_i = 0; if_i < ifcl->class_obj_member_count; ++if_i) | 857 for (int if_i = 0; if_i < ifcl->class_obj_member_count; ++if_i) |
837 for (int cl_i = 0; cl_i < cl->class_obj_member_count; ++cl_i) | 858 for (int cl_i = 0; cl_i < cl->class_obj_member_count; |
859 ++cl_i) | |
838 { | 860 { |
839 if (STRCMP(ifcl->class_obj_members[if_i].ocm_name, | 861 if (STRCMP(ifcl->class_obj_members[if_i].ocm_name, |
840 cl->class_obj_members[cl_i].ocm_name) == 0) | 862 cl->class_obj_members[cl_i].ocm_name) == 0) |
841 { | 863 { |
842 int *table = (int *)(if2cl + 1); | 864 int *table = (int *)(if2cl + 1); |
843 table[if_i] = cl_i; | 865 table[if_i] = cl_i; |
844 break; | 866 break; |
845 } | 867 } |
846 } | 868 } |
847 } | 869 |
848 | 870 // Table for methods. |
849 cl->class_interfaces_cl = intf_classes; | 871 if2cl = alloc_clear(sizeof(itf2class_T) |
850 intf_classes = NULL; | 872 + ifcl->class_obj_method_count * sizeof(int)); |
873 if (if2cl == NULL) | |
874 goto cleanup; | |
875 if2cl->i2c_next = ifcl->class_itf2class; | |
876 ifcl->class_itf2class = if2cl; | |
877 if2cl->i2c_class = cl; | |
878 if2cl->i2c_is_method = TRUE; | |
879 | |
880 for (int if_i = 0; if_i < ifcl->class_obj_method_count; ++if_i) | |
881 { | |
882 int done = FALSE; | |
883 for (int cl_i = 0; cl_i < objmethods.ga_len; ++cl_i) | |
884 { | |
885 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name, | |
886 ((ufunc_T **)objmethods.ga_data)[cl_i]->uf_name) | |
887 == 0) | |
888 { | |
889 int *table = (int *)(if2cl + 1); | |
890 table[if_i] = cl_i; | |
891 done = TRUE; | |
892 break; | |
893 } | |
894 } | |
895 | |
896 if (!done && extends_cl != NULL) | |
897 { | |
898 for (int cl_i = 0; | |
899 cl_i < extends_cl->class_obj_member_count; ++cl_i) | |
900 { | |
901 if (STRCMP(ifcl->class_obj_methods[if_i]->uf_name, | |
902 extends_cl->class_obj_methods[cl_i]->uf_name) | |
903 == 0) | |
904 { | |
905 int *table = (int *)(if2cl + 1); | |
906 table[if_i] = cl_i; | |
907 break; | |
908 } | |
909 } | |
910 } | |
911 } | |
912 } | |
851 } | 913 } |
852 | 914 |
853 if (is_class && cl->class_class_member_count > 0) | 915 if (is_class && cl->class_class_member_count > 0) |
854 { | 916 { |
855 // Allocate a typval for each class member and initialize it. | 917 // Allocate a typval for each class member and initialize it. |