]> granicus.if.org Git - vim/commitdiff
patch 8.2.2846: Vim9: "echo Func()" does not give an error for using void v8.2.2846
authorBram Moolenaar <Bram@vim.org>
Sun, 9 May 2021 21:19:22 +0000 (23:19 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 9 May 2021 21:19:22 +0000 (23:19 +0200)
Problem:    Vim9: "echo Func()" does not give an error for a function without
            a return value.
Solution:   Give an error.  Be more specific about why a value is invalid.

src/errors.h
src/eval.c
src/evalfunc.c
src/globals.h
src/testdir/test_vim9_cmd.vim
src/typval.c
src/version.c
src/vim9compile.c
src/vim9execute.c

index 3d12c1d6337aaf3e097c83622a992611477cf94e..2a0a536c84f67f6fd9abc65db563297887b3fd50 100644 (file)
@@ -31,6 +31,8 @@ EXTERN char e_cannot_slice_dictionary[]
        INIT(= N_("E719: Cannot slice a Dictionary"));
 EXTERN char e_assert_fails_second_arg[]
        INIT(= N_("E856: \"assert_fails()\" second argument must be a string or a list with one or two strings"));
+EXTERN char e_using_invalid_value_as_string_str[]
+       INIT(= N_("E908: using an invalid value as a String: %s"));
 EXTERN char e_cannot_index_special_variable[]
        INIT(= N_("E909: Cannot index a special variable"));
 #endif
@@ -409,3 +411,5 @@ EXTERN char e_cannot_nest_redir[]
        INIT(= N_("E1185: Cannot nest :redir"));
 EXTERN char e_missing_redir_end[]
        INIT(= N_("E1185: Missing :redir END"));
+EXTERN char e_expression_does_not_result_in_value_str[]
+       INIT(= N_("E1186: Expression does not result in a value: %s"));
index bf9e8ee7215b115eae1875ea8667faf67a30350b..aa3d0a1ec8790aeaa4835858ba9618e8fb82200c 100644 (file)
@@ -2951,7 +2951,8 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
                if (vim9script && (var2.v_type == VAR_VOID
                        || var2.v_type == VAR_CHANNEL
                        || var2.v_type == VAR_JOB))
-                   emsg(_(e_inval_string));
+                   semsg(_(e_using_invalid_value_as_string_str),
+                                                  vartype_name(var2.v_type));
 #ifdef FEAT_FLOAT
                else if (vim9script && var2.v_type == VAR_FLOAT)
                {
@@ -6110,7 +6111,7 @@ ex_echo(exarg_T *eap)
 {
     char_u     *arg = eap->arg;
     typval_T   rettv;
-    char_u     *p;
+    char_u     *arg_start;
     int                needclr = TRUE;
     int                atstart = TRUE;
     int                did_emsg_before = did_emsg;
@@ -6127,7 +6128,7 @@ ex_echo(exarg_T *eap)
        // still need to be cleared. E.g., "echo 22,44".
        need_clr_eos = needclr;
 
-       p = arg;
+       arg_start = arg;
        if (eval1(&arg, &rettv, &evalarg) == FAIL)
        {
            /*
@@ -6137,14 +6138,21 @@ ex_echo(exarg_T *eap)
             */
            if (!aborting() && did_emsg == did_emsg_before
                                          && called_emsg == called_emsg_before)
-               semsg(_(e_invexpr2), p);
+               semsg(_(e_invexpr2), arg_start);
            need_clr_eos = FALSE;
            break;
        }
        need_clr_eos = FALSE;
 
        if (!eap->skip)
+       {
+           if (rettv.v_type == VAR_VOID)
+           {
+               semsg(_(e_expression_does_not_result_in_value_str), arg_start);
+               break;
+           }
            echo_one(&rettv, eap->cmdidx == CMD_echo, &atstart, &needclr);
+       }
 
        clear_tv(&rettv);
        arg = skipwhite(arg);
@@ -6218,7 +6226,8 @@ ex_execute(exarg_T *eap)
            {
                if (rettv.v_type == VAR_CHANNEL || rettv.v_type == VAR_JOB)
                {
-                   emsg(_(e_inval_string));
+                   semsg(_(e_using_invalid_value_as_string_str),
+                                                 vartype_name(rettv.v_type));
                    p = NULL;
                }
                else
index a0caf3dce8bf738289eb68339d307efeaeb93de5..6a2244961e98a81b995c30402f40fc76a986590f 100644 (file)
@@ -3175,7 +3175,8 @@ execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
     else if (argvars[arg_off].v_type == VAR_JOB
            || argvars[arg_off].v_type == VAR_CHANNEL)
     {
-       emsg(_(e_inval_string));
+       semsg(_(e_using_invalid_value_as_string_str),
+                                      vartype_name(argvars[arg_off].v_type));
        return;
     }
     else
index b6541a4f4ffc0392b0367cd20ccb16f2b6672db2..0a6b87a7807280950faba0b9518ba3740b1b05d1 100644 (file)
@@ -1728,7 +1728,6 @@ EXTERN char e_list_end[]  INIT(= N_("E697: Missing end of List ']': %s"));
 EXTERN char e_listdictarg[]    INIT(= N_("E712: Argument of %s must be a List or Dictionary"));
 EXTERN char e_listdictblobarg[]        INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob"));
 EXTERN char e_modulus[]                INIT(= N_("E804: Cannot use '%' with Float"));
-EXTERN char e_inval_string[]   INIT(= N_("E908: using an invalid value as a String"));
 EXTERN char e_const_option[]   INIT(= N_("E996: Cannot lock an option"));
 EXTERN char e_unknown_option[] INIT(= N_("E113: Unknown option: %s"));
 EXTERN char e_letunexp[]       INIT(= N_("E18: Unexpected characters in :let"));
index 080fe20cc1e0abb561bfae280d5bffcac075b13e..87832ce2eb01a88dfd44414fa1f248a8f2646563 100644 (file)
@@ -1282,5 +1282,28 @@ def Test_redir_to_var()
   CheckDefFailure(lines, 'E1141:')
 enddef
 
+def Test_echo_void()
+  var lines =<< trim END
+      vim9script
+      def NoReturn()
+        echo 'nothing'
+      enddef
+      echo NoReturn()
+  END
+  CheckScriptFailure(lines, 'E1186:', 5)
+
+  lines =<< trim END
+      vim9script
+      def NoReturn()
+        echo 'nothing'
+      enddef
+      def Try()
+        echo NoReturn()
+      enddef
+      defcompile
+  END
+  CheckScriptFailure(lines, 'E1186:', 1)
+enddef
+
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index 9ca35699d595bc7d9c94a9d36f573bc26b86b2ce..3d1bd7f53f773a257cebfb6ff4bce5de2ea745b1 100644 (file)
@@ -522,7 +522,8 @@ tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict)
        case VAR_ANY:
        case VAR_VOID:
        case VAR_INSTR:
-           emsg(_(e_inval_string));
+           semsg(_(e_using_invalid_value_as_string_str),
+                                                 vartype_name(varp->v_type));
            break;
     }
     return NULL;
index e8827c460201c51751bd9184ccac382769052628..4843be1318c14e6adb5bccb0d30424b38fffbcf0 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2846,
 /**/
     2845,
 /**/
index fd32660e07fb89ca48900ee0db6a6ddffa52a99d..39c36dfb24fdd55a44dd8ca26e82f9a8387ed2dd 100644 (file)
@@ -8375,15 +8375,31 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx)
 {
     char_u     *p = arg;
     char_u     *prev = arg;
+    char_u     *expr_start;
     int                count = 0;
     int                start_ctx_lnum = cctx->ctx_lnum;
+    garray_T   *stack = &cctx->ctx_type_stack;
+    type_T     *type;
 
     for (;;)
     {
        if (ends_excmd2(prev, p))
            break;
+       expr_start = p;
        if (compile_expr0(&p, cctx) == FAIL)
            return NULL;
+
+       if (cctx->ctx_skip != SKIP_YES)
+       {
+           // check for non-void type
+           type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+           if (type->tt_type == VAR_VOID)
+           {
+               semsg(_(e_expression_does_not_result_in_value_str), expr_start);
+               return NULL;
+           }
+       }
+
        ++count;
        prev = p;
        p = skipwhite(p);
index 29cd5fc67ae3a2b075545e6ac8ec42713356a67a..ae4142b0cedffef65f832a56df91977ad5850367 100644 (file)
@@ -1578,7 +1578,8 @@ exec_instructions(ectx_T *ectx)
                                                      || tv->v_type == VAR_JOB)
                            {
                                SOURCING_LNUM = iptr->isn_lnum;
-                               emsg(_(e_inval_string));
+                               semsg(_(e_using_invalid_value_as_string_str),
+                                                   vartype_name(tv->v_type));
                                break;
                            }
                            else