0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 9.0.1184: interface of an object is not recognized when checking type

Problem:    Interface of an object is not recognized when checking type.
Solution:   Use the interface implemented by an object.
This commit is contained in:
Bram Moolenaar
2023-01-12 15:01:32 +00:00
parent 0233bdfa2b
commit a94bd9d939
5 changed files with 66 additions and 1 deletions

View File

@@ -1500,6 +1500,7 @@ struct class_S
// interfaces declared for the class // interfaces declared for the class
int class_interface_count; int class_interface_count;
char_u **class_interfaces; // allocated array of names char_u **class_interfaces; // allocated array of names
class_T **class_interfaces_cl; // interfaces (counts as reference)
// class members: "static varname" // class members: "static varname"
int class_class_member_count; int class_class_member_count;

View File

@@ -455,6 +455,24 @@ def Test_object_type()
var o: One = Two.new() var o: One = Two.new()
END END
v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object<One> but got object<Two>') 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 enddef
def Test_class_member() def Test_class_member()

View File

@@ -695,6 +695,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1184,
/**/ /**/
1183, 1183,
/**/ /**/

View File

@@ -582,9 +582,13 @@ early_ret:
} }
VIM_CLEAR(extends); VIM_CLEAR(extends);
class_T **intf_classes = NULL;
// Check all "implements" entries are valid. // Check all "implements" entries are valid.
if (success && ga_impl.ga_len > 0) 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) for (int i = 0; i < ga_impl.ga_len && success; ++i)
{ {
char_u *impl = ((char_u **)ga_impl.ga_data)[i]; char_u *impl = ((char_u **)ga_impl.ga_data)[i];
@@ -605,8 +609,11 @@ early_ret:
success = FALSE; success = FALSE;
} }
// check the members of the interface match the members of the class
class_T *ifcl = tv.vval.v_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) for (int loop = 1; loop <= 2 && success; ++loop)
{ {
// loop == 1: check class members // loop == 1: check class members
@@ -717,6 +724,9 @@ early_ret:
cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i]; cl->class_interfaces[i] = ((char_u **)ga_impl.ga_data)[i];
VIM_CLEAR(ga_impl.ga_data); VIM_CLEAR(ga_impl.ga_data);
ga_impl.ga_len = 0; ga_impl.ga_len = 0;
cl->class_interfaces_cl = intf_classes;
intf_classes = NULL;
} }
// Add class and object members to "cl". // Add class and object members to "cl".
@@ -930,6 +940,18 @@ cleanup:
{ {
vim_free(cl->class_name); vim_free(cl->class_name);
vim_free(cl->class_class_functions); 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_members);
vim_free(cl->class_obj_methods); vim_free(cl->class_obj_methods);
vim_free(cl); vim_free(cl);
@@ -937,6 +959,13 @@ cleanup:
vim_free(extends); vim_free(extends);
class_unref(extends_cl); 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); ga_clear_strings(&ga_impl);
for (int round = 1; round <= 2; ++round) for (int round = 1; round <= 2; ++round)
@@ -1321,8 +1350,13 @@ class_unref(class_T *cl)
class_unref(cl->class_extends); class_unref(cl->class_extends);
for (int i = 0; i < cl->class_interface_count; ++i) for (int i = 0; i < cl->class_interface_count; ++i)
{
vim_free(((char_u **)cl->class_interfaces)[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);
vim_free(cl->class_interfaces_cl);
for (int i = 0; i < cl->class_class_member_count; ++i) for (int i = 0; i < cl->class_class_member_count; ++i)
{ {

View File

@@ -876,11 +876,21 @@ check_type_maybe(
} }
else if (expected->tt_type == VAR_OBJECT) else if (expected->tt_type == VAR_OBJECT)
{ {
// check the class, base class or an implemented interface matches
class_T *cl; class_T *cl;
for (cl = (class_T *)actual->tt_member; cl != NULL; for (cl = (class_T *)actual->tt_member; cl != NULL;
cl = cl->class_extends) cl = cl->class_extends)
{
if ((class_T *)expected->tt_member == cl) if ((class_T *)expected->tt_member == cl)
break; 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) if (cl == NULL)
ret = FAIL; ret = FAIL;
} }