patch 9.0.1883: Vim9: Calling an interface method using a child object fails

Commit: 
https://github.com/vim/vim/commit/cc0bcf4c9f4133750f5ee99c685ba995a1b840fd
Author: Yegappan Lakshmanan <yegap...@yahoo.com>
Date:   Fri Sep 8 19:12:03 2023 +0200

    patch 9.0.1883: Vim9: Calling an interface method using a child object fails
    
    Problem:  Vim9: Calling an interface method using a child object fails
    Solution: Search methods of parent class
    
    When a class implementing an interface is extended by another class and
    a child class instance is passed to a function that accepts the
    interface, calling an interface method doesn't work properly.
    
    closes: #13053
    
    Signed-off-by: Christian Brabandt <c...@256bit.org>
    Co-authored-by: Yegappan Lakshmanan <yegap...@yahoo.com>

diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index a6dd66bcc..a8c95a74d 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -4396,4 +4396,81 @@ def Test_class_member_access_using_object()
   v9.CheckScriptSuccess(lines)
 enddef
 
+" Test for using a interface method using a child object
+def Test_interface_method_from_child()
+  var lines =<< trim END
+    vim9script
+
+    interface A
+      def Foo(): string
+    endinterface
+
+    class B implements A
+      def Foo(): string
+        return 'foo'
+      enddef
+    endclass
+
+    class C extends B
+      def Bar(): string
+        return 'bar'
+      enddef
+    endclass
+
+    def T1(a: A)
+      assert_equal('foo', a.Foo())
+    enddef
+
+    def T2(b: B)
+      assert_equal('foo', b.Foo())
+    enddef
+
+    var c = C.new()
+    T1(c)
+    T2(c)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
+" Test for using an interface method using a child object when it is overridden
+" by the child class.
+" FIXME: This test fails.
+" def Test_interface_overridden_method_from_child()
+"   var lines =<< trim END
+"     vim9script
+"
+"     interface A
+"       def Foo(): string
+"     endinterface
+"
+"     class B implements A
+"       def Foo(): string
+"         return 'b-foo'
+"       enddef
+"     endclass
+"
+"     class C extends B
+"       def Bar(): string
+"         return 'bar'
+"       enddef
+"       def Foo(): string
+"         return 'c-foo'
+"       enddef
+"     endclass
+"
+"     def T1(a: A)
+"       assert_equal('c-foo', a.Foo())
+"     enddef
+"
+"     def T2(b: B)
+"       assert_equal('c-foo', b.Foo())
+"     enddef
+"
+"     var c = C.new()
+"     T1(c)
+"     T2(c)
+"   END
+"   v9.CheckScriptSuccess(lines)
+" enddef
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/version.c b/src/version.c
index e525ff657..da48158d3 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1883,
 /**/
     1882,
 /**/
diff --git a/src/vim9class.c b/src/vim9class.c
index a65173d61..9328ee713 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -237,16 +237,28 @@ object_index_from_itf_index(class_T *itf, int is_method, 
int idx, class_T *cl,
     if (cl == itf)
        return idx;
 
-    itf2class_T *i2c = NULL;
-    int searching = TRUE;
+    itf2class_T                *i2c = NULL;
+    int                        searching = TRUE;
+    int                        method_offset = 0;
+
     for (class_T *super = cl; super != NULL && searching;
                                                super = super->class_extends)
+    {
        for (i2c = itf->class_itf2class; i2c != NULL; i2c = i2c->i2c_next)
+       {
            if (i2c->i2c_class == super && i2c->i2c_is_method == is_method)
            {
                searching = FALSE;
                break;
            }
+       }
+       if (searching && is_method)
+           // The parent class methods are stored after the current class
+           // methods.
+           method_offset += is_static
+                               ? super->class_class_function_count_child
+                               : super->class_obj_method_count_child;
+    }
     if (i2c == NULL)
     {
        siemsg("class %s not found on interface %s",
@@ -273,7 +285,9 @@ object_index_from_itf_index(class_T *itf, int is_method, 
int idx, class_T *cl,
     {
        // A table follows the i2c for the class
        int *table = (int *)(i2c + 1);
-       return table[idx];
+       // "method_offset" is 0, if method is in the current class.  If method
+       // is in a parent class, then it is non-zero.
+       return table[idx] + method_offset;
     }
 }
 

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qef4X-003VVq-9Y%40256bit.org.

Raspunde prin e-mail lui