changeset 31698:9fba3e8bbadc v9.0.1181

patch 9.0.1181: class inheritance and typing insufficiently tested Commit: https://github.com/vim/vim/commit/6481accd4086845cfce7548e06cb797c80587a98 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Wed, 11 Jan 2023 22:15:02 +0100
parents 5b7ae9350da9
children 328436625302
files src/testdir/test_vim9_class.vim src/version.c src/vim9type.c
diffstat 3 files changed, 88 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- 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<One> but got object<Two>')
+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<Point> 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
 
 
--- 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,
--- 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;