Patch 9.0.1559
Problem:    Function argument types not always checked and using v:none may
            cause an error.
Solution:   Check argument types once the function type is known.  Do not give
            an error for using v:none as an argument. (closes #12200)
Files:      src/userfunc.c, src/vim9type.c, src/testdir/test_vim9_func.vim


*** ../vim-9.0.1558/src/userfunc.c      2023-05-02 16:25:35.630819728 +0100
--- src/userfunc.c      2023-05-15 16:15:42.346367334 +0100
***************
*** 3596,3601 ****
--- 3596,3629 ----
  }
  
  /*
+  * Check the argument types "argvars[argcount]" for "name" using the
+  * information in "funcexe".  When "base_included" then "funcexe->fe_basetv"
+  * is already included in "argvars[]".
+  * Will do nothing if "funcexe->fe_check_type" is NULL or
+  * "funcexe->fe_evaluate" is FALSE;
+  * Returns an FCERR_ value.
+  */
+     static funcerror_T
+ may_check_argument_types(
+       funcexe_T   *funcexe,
+       typval_T    *argvars,
+       int         argcount,
+       int         base_included,
+       char_u      *name)
+ {
+     if (funcexe->fe_check_type != NULL && funcexe->fe_evaluate)
+     {
+       // Check that the argument types are OK for the types of the funcref.
+       if (check_argument_types(funcexe->fe_check_type,
+                         argvars, argcount,
+                         base_included ? NULL : funcexe->fe_basetv,
+                         name) == FAIL)
+           return FCERR_OTHER;
+     }
+     return FCERR_NONE;
+ }
+ 
+ /*
   * Call a function with its resolved parameters
   *
   * Return FAIL when the function can't be called,  OK otherwise.
***************
*** 3691,3705 ****
        }
      }
  
!     if (error == FCERR_NONE && funcexe->fe_check_type != NULL
!                                                      && funcexe->fe_evaluate)
!     {
!       // Check that the argument types are OK for the types of the funcref.
!       if (check_argument_types(funcexe->fe_check_type,
!                                        argvars, argcount, funcexe->fe_basetv,
!                                    (name != NULL) ? name : funcname) == FAIL)
!           error = FCERR_OTHER;
!     }
  
      if (error == FCERR_NONE && funcexe->fe_evaluate)
      {
--- 3719,3728 ----
        }
      }
  
!     if (error == FCERR_NONE)
!       // check the argument types if possible
!       error = may_check_argument_types(funcexe, argvars, argcount, FALSE,
!                                            (name != NULL) ? name : funcname);
  
      if (error == FCERR_NONE && funcexe->fe_evaluate)
      {
***************
*** 3761,3770 ****
                error = FCERR_DELETED;
            else if (fp != NULL)
            {
                if (funcexe->fe_argv_func != NULL)
                    // postponed filling in the arguments, do it now
                    argcount = funcexe->fe_argv_func(argcount, argvars,
!                                              argv_clear, fp);
  
                if (funcexe->fe_basetv != NULL)
                {
--- 3784,3803 ----
                error = FCERR_DELETED;
            else if (fp != NULL)
            {
+               int need_arg_check = FALSE;
+               if (funcexe->fe_check_type == NULL)
+               {
+                   funcexe->fe_check_type = fp->uf_func_type;
+                   need_arg_check = TRUE;
+               }
+ 
                if (funcexe->fe_argv_func != NULL)
+               {
                    // postponed filling in the arguments, do it now
                    argcount = funcexe->fe_argv_func(argcount, argvars,
!                                                              argv_clear, fp);
!                   need_arg_check = TRUE;
!               }
  
                if (funcexe->fe_basetv != NULL)
                {
***************
*** 3774,3782 ****
                    argcount++;
                    argvars = argv;
                    argv_base = 1;
                }
  
!               error = call_user_func_check(fp, argcount, argvars, rettv,
                                                            funcexe, selfdict);
            }
        }
--- 3807,3822 ----
                    argcount++;
                    argvars = argv;
                    argv_base = 1;
+                   need_arg_check = TRUE;
                }
  
!               // Check the argument types now that the function type and all
!               // argument values are known, if not done above.
!               if (need_arg_check)
!                   error = may_check_argument_types(funcexe, argvars, argcount,
!                                      TRUE, (name != NULL) ? name : funcname);
!               if (error == FCERR_NONE || error == FCERR_UNKNOWN)
!                   error = call_user_func_check(fp, argcount, argvars, rettv,
                                                            funcexe, selfdict);
            }
        }
*** ../vim-9.0.1558/src/vim9type.c      2023-03-07 17:13:47.317107770 +0000
--- src/vim9type.c      2023-05-15 15:54:10.556644165 +0100
***************
*** 970,976 ****
        }
        else
            expected = type->tt_args[i];
!       if (check_typval_arg_type(expected, tv, NULL, i + 1) == FAIL)
            return FAIL;
      }
      return OK;
--- 970,979 ----
        }
        else
            expected = type->tt_args[i];
! 
!       // check the type, unless the value is v:none
!       if ((tv->v_type != VAR_SPECIAL || tv->vval.v_number != VVAL_NONE)
!                  && check_typval_arg_type(expected, tv, NULL, i + 1) == FAIL)
            return FAIL;
      }
      return OK;
*** ../vim-9.0.1558/src/testdir/test_vim9_func.vim      2023-05-14 
19:59:55.269425158 +0100
--- src/testdir/test_vim9_func.vim      2023-05-15 16:21:32.050991057 +0100
***************
*** 778,783 ****
--- 778,815 ----
    END
    v9.CheckScriptSuccess(lines)
  
+   lines =<< trim END
+       vim9script
+ 
+       export def Floats(x: float, y = 2.0, z = 5.0)
+         g:result = printf("%.2f %.2f %.2f", x, y, z)
+       enddef
+   END
+   writefile(lines, 'Xlib.vim', 'D')
+ 
+   # test using a function reference in script-local variable
+   lines =<< trim END
+       vim9script
+ 
+       import './Xlib.vim'
+       const Floatfunc = Xlib.Floats
+       Floatfunc(1.0, v:none, 3.0)
+   END
+   v9.CheckScriptSuccess(lines)
+   assert_equal('1.00 2.00 3.00', g:result)
+   unlet g:result
+ 
+   # test calling the imported function
+   lines =<< trim END
+       vim9script
+ 
+       import './Xlib.vim'
+       Xlib.Floats(1.0, v:none, 3.0)
+   END
+   v9.CheckScriptSuccess(lines)
+   assert_equal('1.00 2.00 3.00', g:result)
+   unlet g:result
+ 
    # TODO: this should give an error for using a missing argument
    # lines =<< trim END
    #    vim9script
*** ../vim-9.0.1558/src/version.c       2023-05-14 22:05:09.813326337 +0100
--- src/version.c       2023-05-15 16:16:43.670499323 +0100
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1559,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
35. Your husband tells you he's had that beard for 2 months.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230515152311.0DA8D1C0571%40moolenaar.net.

Raspunde prin e-mail lui