# HG changeset patch # User Bram Moolenaar # Date 1673471702 -3600 # Node ID 9fba3e8bbadc554987923249f8e5ce3d2b6dfd48 # Parent 5b7ae9350da965f0694d5c7e6fd59df2a7ff6f1f patch 9.0.1181: class inheritance and typing insufficiently tested Commit: https://github.com/vim/vim/commit/6481accd4086845cfce7548e06cb797c80587a98 Author: Bram Moolenaar Date: Wed Jan 11 21:14:17 2023 +0000 patch 9.0.1181: class inheritance and typing insufficiently tested Problem: Class inheritance and typing insufficiently tested. Solution: Add more tests. Implement missing behavior. diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -419,6 +419,44 @@ def Test_class_object_compare() endfor enddef +def Test_object_type() + var lines =<< trim END + vim9script + + class One + this.one = 1 + endclass + class Two + this.two = 2 + endclass + class TwoMore extends Two + this.more = 9 + endclass + + var o: One = One.new() + var t: Two = Two.new() + var m: TwoMore = TwoMore.new() + var tm: Two = TwoMore.new() + + t = m + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + + class One + this.one = 1 + endclass + class Two + this.two = 2 + endclass + + var o: One = Two.new() + END + v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object but got object') +enddef + def Test_class_member() # check access rules var lines =<< trim END @@ -750,7 +788,7 @@ def Test_class_used_as_type() var p: Point p = 'text' END - v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object but got string') + v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected object but got string') enddef def Test_class_extends() @@ -895,6 +933,27 @@ def Test_class_extends() echo o.ToString() END v9.CheckScriptFailure(lines, 'E1358:') + + lines =<< trim END + vim9script + class Base + this.name: string + static def ToString(): string + return 'Base class' + enddef + endclass + + class Child extends Base + this.age: number + def ToString(): string + return Base.ToString() .. ': ' .. this.age + enddef + endclass + + var o = Child.new('John', 42) + assert_equal('Base class: 42', o.ToString()) + END + v9.CheckScriptSuccess(lines) enddef diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1181, +/**/ 1180, /**/ 1179, diff --git a/src/vim9type.c b/src/vim9type.c --- a/src/vim9type.c +++ b/src/vim9type.c @@ -874,6 +874,17 @@ check_type_maybe( // check the argument count at runtime ret = MAYBE; } + else if (expected->tt_type == VAR_OBJECT) + { + class_T *cl; + for (cl = (class_T *)actual->tt_member; cl != NULL; + cl = cl->class_extends) + if ((class_T *)expected->tt_member == cl) + break; + if (cl == NULL) + ret = FAIL; + } + if (ret == FAIL && give_msg) type_mismatch_where(expected, actual, where); } @@ -1601,13 +1612,12 @@ type_name(type_T *type, char **tofree) if (type == NULL) return "[unknown]"; name = vartype_name(type->tt_type); + if (type->tt_type == VAR_LIST || type->tt_type == VAR_DICT) { char *member_free; char *member_name = type_name(type->tt_member, &member_free); - size_t len; - - len = STRLEN(name) + STRLEN(member_name) + 3; + size_t len = STRLEN(name) + STRLEN(member_name) + 3; *tofree = alloc(len); if (*tofree != NULL) { @@ -1616,6 +1626,19 @@ type_name(type_T *type, char **tofree) return *tofree; } } + + if (type->tt_type == VAR_OBJECT || type->tt_type == VAR_CLASS) + { + char_u *class_name = ((class_T *)type->tt_member)->class_name; + size_t len = STRLEN(name) + STRLEN(class_name) + 3; + *tofree = alloc(len); + if (*tofree != NULL) + { + vim_snprintf(*tofree, len, "%s<%s>", name, class_name); + return *tofree; + } + } + if (type->tt_type == VAR_FUNC) { garray_T ga;