]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1184: interface of an object is not recognized when checking type v9.0.1184
authorBram Moolenaar <Bram@vim.org>
Thu, 12 Jan 2023 15:01:32 +0000 (15:01 +0000)
committerBram Moolenaar <Bram@vim.org>
Thu, 12 Jan 2023 15:01:32 +0000 (15:01 +0000)
Problem:    Interface of an object is not recognized when checking type.
Solution:   Use the interface implemented by an object.

src/structs.h
src/testdir/test_vim9_class.vim
src/version.c
src/vim9class.c
src/vim9type.c

index 89ed23dbdbb6749994e185df43c02378eebc0736..80dc4730efb9657ebd3cdfd7f8ecc9b8b848d7ec 100644 (file)
@@ -1500,6 +1500,7 @@ struct class_S
     // interfaces declared for the class
     int                class_interface_count;
     char_u     **class_interfaces;     // allocated array of names
+    class_T    **class_interfaces_cl;  // interfaces (counts as reference)
 
     // class members: "static varname"
     int                class_class_member_count;
index 139a632ed38b62a7aad1aa611e54556a5ce38828..74df0f4394e8ae0fa6ca839036e38ca4a5fccc8d 100644 (file)
@@ -455,6 +455,24 @@ def Test_object_type()
       var o: One = Two.new()
   END
   v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<One> but got object<Two>')
+
+  lines =<< trim END
+      vim9script
+
+      interface One
+        def GetMember(): number
+      endinterface
+      class Two implements One
+        this.one = 1
+        def GetMember(): number
+          return this.one
+        enddef
+      endclass
+
+      var o: One = Two.new(5)
+      assert_equal(5, o.GetMember())
+  END
+  v9.CheckScriptSuccess(lines)
 enddef
 
 def Test_class_member()
index be6600a37cdec30309617cfb1c78818c76919f79..e0d5bffa0b11f3a1f0aef80c774d5467f0f65f77 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1184,
 /**/
     1183,
 /**/
index 0970619b91f5d6362e3be6c283d03e9a6d99c8c1..a60e70d2a05844680be097efefb2f80ab8e876bc 100644 (file)
@@ -582,9 +582,13 @@ early_ret:
     }
     VIM_CLEAR(extends);
 
+    class_T **intf_classes = NULL;
+
     // Check all "implements" entries are valid.
     if (success && ga_impl.ga_len > 0)
     {
+       intf_classes = ALLOC_CLEAR_MULT(class_T *, ga_impl.ga_len);
+
        for (int i = 0; i < ga_impl.ga_len && success; ++i)
        {
            char_u *impl = ((char_u **)ga_impl.ga_data)[i];
@@ -605,8 +609,11 @@ early_ret:
                success = FALSE;
            }
 
-           // check the members of the interface match the members of the class
            class_T *ifcl = tv.vval.v_class;
+           intf_classes[i] = ifcl;
+           ++ifcl->class_refcount;
+
+           // check the members of the interface match the members of the class
            for (int loop = 1; loop <= 2 && success; ++loop)
            {
                // loop == 1: check class members
@@ -717,6 +724,9 @@ early_ret:
                cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i];
            VIM_CLEAR(ga_impl.ga_data);
            ga_impl.ga_len = 0;
+
+           cl->class_interfaces_cl = intf_classes;
+           intf_classes = NULL;
        }
 
        // Add class and object members to "cl".
@@ -930,6 +940,18 @@ cleanup:
     {
        vim_free(cl->class_name);
        vim_free(cl->class_class_functions);
+       if (cl->class_interfaces != NULL)
+       {
+           for (int i = 0; i < cl->class_interface_count; ++i)
+               vim_free(cl->class_interfaces[i]);
+           vim_free(cl->class_interfaces);
+       }
+       if (cl->class_interfaces_cl != NULL)
+       {
+           for (int i = 0; i < cl->class_interface_count; ++i)
+               class_unref(cl->class_interfaces_cl[i]);
+           vim_free(cl->class_interfaces_cl);
+       }
        vim_free(cl->class_obj_members);
        vim_free(cl->class_obj_methods);
        vim_free(cl);
@@ -937,6 +959,13 @@ cleanup:
 
     vim_free(extends);
     class_unref(extends_cl);
+
+    if (intf_classes != NULL)
+    {
+       for (int i = 0; i < ga_impl.ga_len; ++i)
+           class_unref(intf_classes[i]);
+       vim_free(intf_classes);
+    }
     ga_clear_strings(&ga_impl);
 
     for (int round = 1; round <= 2; ++round)
@@ -1321,8 +1350,13 @@ class_unref(class_T *cl)
        class_unref(cl->class_extends);
 
        for (int i = 0; i < cl->class_interface_count; ++i)
+       {
            vim_free(((char_u **)cl->class_interfaces)[i]);
+           if (cl->class_interfaces_cl[i] != NULL)
+               class_unref(cl->class_interfaces_cl[i]);
+       }
        vim_free(cl->class_interfaces);
+       vim_free(cl->class_interfaces_cl);
 
        for (int i = 0; i < cl->class_class_member_count; ++i)
        {
index 5d3f815b50dc80cfeee201e8f6f0b2c05cb5101f..02b674d23c3e17c163c492a45a85a547952b8c35 100644 (file)
@@ -876,11 +876,21 @@ check_type_maybe(
        }
        else if (expected->tt_type == VAR_OBJECT)
        {
+           // check the class, base class or an implemented interface matches
            class_T *cl;
            for (cl = (class_T *)actual->tt_member; cl != NULL;
                                                        cl = cl->class_extends)
+           {
                if ((class_T *)expected->tt_member == cl)
                    break;
+               int i;
+               for (i = cl->class_interface_count - 1; i >= 0; --i)
+                   if ((class_T *)expected->tt_member
+                                                == cl->class_interfaces_cl[i])
+                       break;
+               if (i >= 0)
+                   break;
+           }
            if (cl == NULL)
                ret = FAIL;
        }