]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.2106: Vim9: class, enum and type alias can be used as value v9.1.2106
authorYegappan Lakshmanan <yegappan@yahoo.com>
Fri, 23 Jan 2026 19:17:29 +0000 (19:17 +0000)
committerChristian Brabandt <cb@256bit.org>
Fri, 23 Jan 2026 19:17:29 +0000 (19:17 +0000)
Problem:  Vim9: class, enum and type alias can be used as value in an
          expression (kennypete)
Solution: Abort expression evaluation if class, enum or type alias is
          used in an expression (Yegappan Lakshmanan)

related: #19173
closes:  #19238

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/eval.c
src/testdir/test_vim9_expr.vim
src/version.c
src/vim9expr.c

index 4a9f5821ba6544e2f7d052bcf5b6bda0126db609..9678ea7f67a30e2e2abc9b3ad8e2bdfe2caef8a6 100644 (file)
@@ -3646,7 +3646,15 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
            int         error = FALSE;
 
            if (op_falsy)
+           {
+               // Is this typeval supported with the falsy operator?
+               if (check_typval_is_value(rettv) == FAIL)
+               {
+                   clear_tv(rettv);
+                   return FAIL;
+               }
                result = tv2bool(rettv);
+           }
            else if (vim9script)
                result = tv_get_bool_chk(rettv, &error);
            else if (tv_get_number_chk(rettv, &error) != 0)
@@ -5376,7 +5384,15 @@ eval9_leader(
        while (VIM_ISWHITE(end_leader[-1]))
            --end_leader;
        if (vim9script && end_leader[-1] == '!')
+       {
+           // Is this typeval supported with the ! operator?
+           if (check_typval_is_value(rettv) == FAIL)
+           {
+               clear_tv(rettv);
+               return FAIL;
+           }
            val = tv2bool(rettv);
+       }
        else
            val = tv_get_number_chk(rettv, &error);
     }
index b663728849c2d4896729ec7128e7dfb143b4fc5f..4551ea5eb916a620d9101ecd974a521a087a0508 100644 (file)
@@ -280,6 +280,69 @@ def Test_expr1_falsy()
   END
   v9.CheckSourceScriptFailure(lines, 'E1405: Class "B" cannot be used as a value')
 
+  # Expression evaluation should stop after using a class with the falsy
+  # operator
+  lines =<< trim END
+    vim9script
+    class C
+    endclass
+    var output: string = 'pass'
+    try
+      echo C ?? 'falsy' !! execute("output = 'fail'")
+    catch /E1405:/
+    endtry
+    assert_equal('pass', output)
+  END
+  v9.CheckSourceScriptSuccess(lines)
+
+  # When using a class with the falsy operator, expression evaluation should
+  # be aborted in a function
+  g:falsy_output = 'pass'
+  lines =<< trim END
+    vim9script
+    class C
+    endclass
+    g:falsy_output = 'pass'
+    def Fn()
+      echo C ?? 'falsy' !! execute('g:falsy_output = "fail"')
+    enddef
+    Fn()
+  END
+  v9.CheckSourceScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
+  assert_equal('pass', g:falsy_output)
+  unlet g:falsy_output
+
+  # When using a class with the "!" operator, expression evaluation should be
+  # aborted
+  lines =<< trim END
+    vim9script
+    class C
+    endclass
+    var output: string = 'pass'
+    try
+      echo !C !! execute("output = 'fail'")
+    catch /E1405:/
+    endtry
+    assert_equal('pass', output)
+  END
+  v9.CheckSourceScriptSuccess(lines)
+
+  # When using a class with the "!" operator, expression evaluation should be
+  # aborted in a function
+  g:falsy_output = 'pass'
+  lines =<< trim END
+    vim9script
+    class C
+    endclass
+    def Fn()
+      echo !C !! execute('g:falsy_output = "fail"')
+    enddef
+    Fn()
+  END
+  v9.CheckSourceScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
+  assert_equal('pass', g:falsy_output)
+  unlet g:falsy_output
+
   lines =<< trim END
     vim9script
     echo null_class ?? 'falsy'
@@ -309,6 +372,68 @@ def Test_expr1_falsy()
   END
   v9.CheckSourceScriptFailure(lines, 'E1421: Enum "E2" cannot be used as a value')
 
+  # Expression evaluation should stop after using an enum with the falsy
+  # operator
+  lines =<< trim END
+    vim9script
+    enum E
+    endenum
+    var output: string = 'pass'
+    try
+      echo E ?? 'falsy' !! execute("output = 'fail'")
+    catch /E1421:/
+    endtry
+    assert_equal('pass', output)
+  END
+  v9.CheckSourceScriptSuccess(lines)
+
+  # When using a enum with the falsy operator, expression evaluation should
+  # be aborted in a function
+  g:falsy_output = 'pass'
+  lines =<< trim END
+    vim9script
+    enum E3
+    endenum
+    g:falsy_output = 'pass'
+    def Fn()
+      echo E3 ?? 'falsy' !! execute('g:falsy_output = "fail"')
+    enddef
+    Fn()
+  END
+  v9.CheckSourceScriptFailure(lines, 'E1421: Enum "E3" cannot be used as a value', 1)
+  assert_equal('pass', g:falsy_output)
+  unlet g:falsy_output
+
+  # Expression evaluation should stop after using an enum with the ! operator
+  lines =<< trim END
+    vim9script
+    enum E
+    endenum
+    var output: string = 'pass'
+    try
+      echo !E !! execute("output = 'fail'")
+    catch /E1421:/
+    endtry
+    assert_equal('pass', output)
+  END
+  v9.CheckSourceScriptSuccess(lines)
+
+  # When using a enum with the "!" operator, expression evaluation should be
+  # aborted in a function
+  g:falsy_output = 'pass'
+  lines =<< trim END
+    vim9script
+    enum E4
+    endenum
+    def Fn()
+      echo !E4 !! execute('g:falsy_output = "fail"')
+    enddef
+    Fn()
+  END
+  v9.CheckSourceScriptFailure(lines, 'E1421: Enum "E4" cannot be used as a value', 1)
+  assert_equal('pass', g:falsy_output)
+  unlet g:falsy_output
+
   # typealias cannot be used with the falsy operator
   lines =<< trim END
     vim9script
@@ -324,6 +449,65 @@ def Test_expr1_falsy()
   END
   v9.CheckSourceScriptFailure(lines, 'E1403: Type alias "T2" cannot be used as a value')
 
+  # Expression evaluation should stop after using a typealias with the falsy
+  # operator
+  lines =<< trim END
+    vim9script
+    type T3 = dict<string>
+    var output: string = 'pass'
+    try
+      echo T3 ?? 'falsy' !! execute("output = 'fail'")
+    catch /E1403:/
+    endtry
+    assert_equal('pass', output)
+  END
+  v9.CheckSourceScriptSuccess(lines)
+
+  # When using a typealias with the falsy operator, expression evaluation
+  # should be aborted in a function
+  g:falsy_output = 'pass'
+  lines =<< trim END
+    vim9script
+    type T3 = dict<job>
+    g:falsy_output = 'pass'
+    def Fn()
+      echo T3 ?? 'falsy' !! execute('g:falsy_output = "fail"')
+    enddef
+    Fn()
+  END
+  v9.CheckSourceScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
+  assert_equal('pass', g:falsy_output)
+  unlet g:falsy_output
+
+  # Expression evaluation should stop after using a typealias with the !
+  # operator
+  lines =<< trim END
+    vim9script
+    type T3 = dict<string>
+    var output: string = 'pass'
+    try
+      echo !T3 !! execute("output = 'fail'")
+    catch /E1403:/
+    endtry
+    assert_equal('pass', output)
+  END
+  v9.CheckSourceScriptSuccess(lines)
+
+  # When using a typealias with the "!" operator, expression evaluation should
+  # be aborted in a function
+  g:falsy_output = 'pass'
+  lines =<< trim END
+    vim9script
+    type T4 = list<number>
+    def Fn()
+      echo !T4 !! execute('g:falsy_output = "fail"')
+    enddef
+    Fn()
+  END
+  v9.CheckSourceScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
+  assert_equal('pass', g:falsy_output)
+  unlet g:falsy_output
+
   var msg = "White space required before and after '??'"
   call v9.CheckDefAndScriptFailure(["var x = 1?? 'one' : 'two'"], msg, 1)
   call v9.CheckDefAndScriptFailure(["var x = 1 ??'one' : 'two'"], msg, 1)
index 1852977ac8c3464fb4cc5a7f817ea2764e55c58c..5017e1d7b90373ef7f6be42f4b89698715ae7fff 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2106,
 /**/
     2105,
 /**/
index c8353ab981f3b2881f72a41d9744024c385a72c9..ebab9ec136650237d87073e5df1c66efbb2b7102 100644 (file)
@@ -2430,6 +2430,8 @@ compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end)
                    invert = !invert;
                --p;
            }
+           if (check_type_is_value(get_type_on_stack(cctx, 0)) == FAIL)
+               return FAIL;
            if (generate_2BOOL(cctx, invert, -1) == FAIL)
                return FAIL;
        }
@@ -3948,7 +3950,11 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
            generate_JUMP(cctx, op_falsy
                                   ? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0);
            if (op_falsy)
+           {
                type1 = get_type_on_stack(cctx, -1);
+               if (check_type_is_value(type1) == FAIL)
+                   return FAIL;
+           }
        }
 
        // evaluate the second expression; any type is accepted