patch 9.1.0988: Vim9: no error when using uninitialized var in new()

Commit: 
https://github.com/vim/vim/commit/b04af4cc9636ccbadc625e743a265a394bd48943
Author: Yegappan Lakshmanan <yegap...@yahoo.com>
Date:   Fri Jan 3 10:50:08 2025 +0100

    patch 9.1.0988: Vim9: no error when using uninitialized var in new()
    
    Problem:  Vim9: no error when using uninitialized var in new()
              (lifepillar, Aliaksei Budavei)
    Solution: Give an error if an uninitialized object variable is referenced
              in new() (Yegappan Lakshmanan)
    
    fixes: #14411
    fixes: #16344
    closes: #16374
    
    Signed-off-by: Yegappan Lakshmanan <yegap...@yahoo.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/errors.h b/src/errors.h
index 1e59597d9..ad36e33a6 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3616,8 +3616,10 @@ EXTERN char e_duplicate_enum_str[]
        INIT(= N_("E1428: Duplicate enum value: %s"));
 EXTERN char e_class_can_only_be_used_in_script[]
        INIT(= N_("E1429: Class can only be used in a script"));
+EXTERN char e_uninitialized_object_var_reference[]
+       INIT(= N_("E1430: Uninitialized object variable '%s' referenced"));
 #endif
-// E1429 - E1499 unused (reserved for Vim9 class support)
+// E1431 - E1499 unused (reserved for Vim9 class support)
 EXTERN char e_cannot_mix_positional_and_non_positional_str[]
        INIT(= N_("E1500: Cannot mix positional and non-positional arguments: 
%s"));
 EXTERN char e_fmt_arg_nr_unused_str[]
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 4a7962a6c..c7a0fbefa 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -11723,4 +11723,120 @@ def Test_use_object_method_in_a_method_call()
   v9.CheckSourceFailure(lines, 'E1326: Variable "NewCost" not found in object 
"Foo"')
 enddef
 
+" Test for referencing an object variable which is not yet initialized
+def Test_uninitialized_object_var()
+  var lines =<< trim END
+    vim9script
+    class Foo
+      const two: number = Foo.Two(this)
+      const one: number = 1
+
+      static def Two(that: Foo): number
+        return that.one + 2
+      enddef
+    endclass
+
+    echo Foo.Two(Foo.new())
+  END
+  v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'one' 
referenced")
+
+  lines =<< trim END
+    vim9script
+    class Foo
+      const one: number = Foo.One(this)
+
+      static def One(that: Foo): number
+        return 1
+      enddef
+    endclass
+
+    assert_equal(1, Foo.One(Foo.new()))
+  END
+  v9.CheckSourceSuccess(lines)
+
+  lines =<< trim END
+    vim9script
+    class Foo
+      const one: number = 1
+      const two: number = Foo.Two(this)
+
+      static def Two(that: Foo): number
+        return that.one + 1
+      enddef
+    endclass
+
+    assert_equal(2, Foo.Two(Foo.new()))
+  END
+  v9.CheckSourceSuccess(lines)
+
+  lines =<< trim END
+    vim9script
+    class Foo
+      const Id: func(any): any = ((_) => (v) => v)(this)
+
+      static def Id(that: Foo): func(any): any
+        return that.Id
+      enddef
+    endclass
+
+    assert_equal(5, Foo.Id(Foo.new())(5))
+    assert_equal(7, Foo.new().Id(7))
+  END
+  v9.CheckSourceSuccess(lines)
+
+  lines =<< trim END
+    vim9script
+    class Foo
+      const Id: func(any): any = ((that) => (_) => that)(this)
+
+      static def Id(that: Foo): func(any): any
+          return that.Id
+      enddef
+    endclass
+
+    const Id0: func(any): any = Foo.Id(Foo.new())
+    const Id1: func(any): any = Foo.new().Id
+  END
+  v9.CheckSourceSuccess(lines)
+
+  lines =<< trim END
+    vim9script
+    class Foo
+      const Id: any = Foo.Id(this)
+
+      static def Id(that: Foo): any
+          return that.Id
+      enddef
+    endclass
+
+    const Id2: any = Foo.Id(Foo.new())
+    const Id3: any = Foo.new().Id
+  END
+  v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'Id' 
referenced")
+
+  lines =<< trim END
+    vim9script
+
+    class Foo
+      var x: string = ''
+      var Y: func(): string = () => this.x
+    endclass
+
+    var foo = Foo.new('ok')
+    assert_equal('ok', foo.Y())
+  END
+  v9.CheckSourceSuccess(lines)
+
+  lines =<< trim END
+    vim9script
+
+    class Foo
+      var x: string = this.x
+    endclass
+
+    var foo = Foo.new('ok')
+  END
+  v9.CheckSourceFailure(lines, "E1430: Uninitialized object variable 'x' 
referenced")
+enddef
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/version.c b/src/version.c
index 1dbbca563..987aa9b3f 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    988,
 /**/
     987,
 /**/
diff --git a/src/vim9execute.c b/src/vim9execute.c
index de12d8e6a..dde95b511 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -4844,6 +4844,20 @@ exec_instructions(ectx_T *ectx)
                int arg_set = tv->v_type != VAR_UNKNOWN
                                && !(tv->v_type == VAR_SPECIAL
                                            && tv->vval.v_number == VVAL_NONE);
+
+               if (iptr->isn_type == ISN_JUMP_IF_ARG_NOT_SET && !arg_set)
+               {
+                   dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
+                                                       + ectx->ec_dfunc_idx;
+                   ufunc_T *ufunc = df->df_ufunc;
+                   // jump_arg_off is negative for arguments
+                   size_t argidx = ufunc->uf_def_args.ga_len
+                                       + iptr->isn_arg.jumparg.jump_arg_off
+                                       + STACK_FRAME_SIZE;
+                   type_T *t = ufunc->uf_arg_types[argidx];
+                   tv->v_type = t->tt_type;
+               }
+
                if (iptr->isn_type == ISN_JUMP_IF_ARG_SET ? arg_set : !arg_set)
                    ectx->ec_iidx = iptr->isn_arg.jumparg.jump_where;
                break;
@@ -5718,6 +5732,17 @@ exec_instructions(ectx_T *ectx)
 
                    // The members are located right after the object struct.
                    typval_T *mtv = ((typval_T *)(obj + 1)) + idx;
+                   if (mtv->v_type == VAR_UNKNOWN)
+                   {
+                       // Referencing an object variable (without a type)
+                       // which is not yet initialized.  So the type is not
+                       // yet known.
+                       ocmember_T *m = &obj->obj_class->class_obj_members[idx];
+                       SOURCING_LNUM = iptr->isn_lnum;
+                       semsg(_(e_uninitialized_object_var_reference),
+                               m->ocm_name);
+                       goto on_error;
+                   }
                    copy_tv(mtv, tv);
 
                    // Unreference the object after getting the member, it may

-- 
-- 
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 visit 
https://groups.google.com/d/msgid/vim_dev/E1tTeTN-004dnb-6B%40256bit.org.

Raspunde prin e-mail lui