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.