comparison src/userfunc.c @ 23527:27ca5534a408 v8.2.2306

patch 8.2.2306: Vim9: when using function reference type is not checked Commit: https://github.com/vim/vim/commit/32b3f820107139d7edf0c592bb06f090c3eb6c51 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Jan 6 21:59:39 2021 +0100 patch 8.2.2306: Vim9: when using function reference type is not checked Problem: Vim9: when using function reference type is not checked. Solution: When using a function reference lookup the type and check the argument types. (issue #7629)
author Bram Moolenaar <Bram@vim.org>
date Wed, 06 Jan 2021 22:00:06 +0100
parents 7e8703464f01
children f39a18a42aed
comparison
equal deleted inserted replaced
23526:22fd43db29c8 23527:27ca5534a408
725 /* 725 /*
726 * Check if "name" is a variable of type VAR_FUNC. If so, return the function 726 * Check if "name" is a variable of type VAR_FUNC. If so, return the function
727 * name it contains, otherwise return "name". 727 * name it contains, otherwise return "name".
728 * If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set 728 * If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set
729 * "partialp". 729 * "partialp".
730 * If "type" is not NULL and a Vim9 script-local variable is found look up the
731 * type of the variable.
730 */ 732 */
731 char_u * 733 char_u *
732 deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload) 734 deref_func_name(
735 char_u *name,
736 int *lenp,
737 partial_T **partialp,
738 type_T **type,
739 int no_autoload)
733 { 740 {
734 dictitem_T *v; 741 dictitem_T *v;
735 int cc; 742 int cc;
736 char_u *s; 743 char_u *s = NULL;
744 hashtab_T *ht;
737 745
738 if (partialp != NULL) 746 if (partialp != NULL)
739 *partialp = NULL; 747 *partialp = NULL;
740 748
741 cc = name[*lenp]; 749 cc = name[*lenp];
742 name[*lenp] = NUL; 750 name[*lenp] = NUL;
743 v = find_var(name, NULL, no_autoload); 751 v = find_var(name, &ht, no_autoload);
744 name[*lenp] = cc; 752 name[*lenp] = cc;
745 if (v != NULL && v->di_tv.v_type == VAR_FUNC) 753 if (v != NULL)
746 { 754 {
747 if (v->di_tv.vval.v_string == NULL) 755 if (v->di_tv.v_type == VAR_FUNC)
748 { 756 {
749 *lenp = 0; 757 if (v->di_tv.vval.v_string == NULL)
750 return (char_u *)""; // just in case 758 {
751 } 759 *lenp = 0;
752 s = v->di_tv.vval.v_string; 760 return (char_u *)""; // just in case
753 *lenp = (int)STRLEN(s); 761 }
754 return s; 762 s = v->di_tv.vval.v_string;
755 } 763 *lenp = (int)STRLEN(s);
756 764 }
757 if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) 765
758 { 766 if (v->di_tv.v_type == VAR_PARTIAL)
759 partial_T *pt = v->di_tv.vval.v_partial; 767 {
760 768 partial_T *pt = v->di_tv.vval.v_partial;
761 if (pt == NULL) 769
762 { 770 if (pt == NULL)
763 *lenp = 0; 771 {
764 return (char_u *)""; // just in case 772 *lenp = 0;
765 } 773 return (char_u *)""; // just in case
766 if (partialp != NULL) 774 }
767 *partialp = pt; 775 if (partialp != NULL)
768 s = partial_name(pt); 776 *partialp = pt;
769 *lenp = (int)STRLEN(s); 777 s = partial_name(pt);
770 return s; 778 *lenp = (int)STRLEN(s);
779 }
780
781 if (s != NULL)
782 {
783 if (type != NULL && ht == get_script_local_ht())
784 {
785 svar_T *sv = find_typval_in_script(&v->di_tv);
786
787 if (sv != NULL)
788 *type = sv->sv_type;
789 }
790 return s;
791 }
771 } 792 }
772 793
773 return name; 794 return name;
774 } 795 }
775 796
2385 argvars = argv; 2406 argvars = argv;
2386 argcount = partial->pt_argc + argcount_in; 2407 argcount = partial->pt_argc + argcount_in;
2387 } 2408 }
2388 } 2409 }
2389 2410
2411 if (error == FCERR_NONE && funcexe->check_type != NULL && funcexe->evaluate)
2412 {
2413 // Check that the argument types are OK for the types of the funcref.
2414 if (check_argument_types(funcexe->check_type, argvars, argcount,
2415 name) == FAIL)
2416 error = FCERR_OTHER;
2417 }
2418
2390 if (error == FCERR_NONE && funcexe->evaluate) 2419 if (error == FCERR_NONE && funcexe->evaluate)
2391 { 2420 {
2392 char_u *rfname = fname; 2421 char_u *rfname = fname;
2393 int is_global = FALSE; 2422 int is_global = FALSE;
2394 2423
2627 char_u **pp, 2656 char_u **pp,
2628 int *is_global, 2657 int *is_global,
2629 int skip, // only find the end, don't evaluate 2658 int skip, // only find the end, don't evaluate
2630 int flags, 2659 int flags,
2631 funcdict_T *fdp, // return: info about dictionary used 2660 funcdict_T *fdp, // return: info about dictionary used
2632 partial_T **partial) // return: partial of a FuncRef 2661 partial_T **partial, // return: partial of a FuncRef
2662 type_T **type) // return: type of funcref if not NULL
2633 { 2663 {
2634 char_u *name = NULL; 2664 char_u *name = NULL;
2635 char_u *start; 2665 char_u *start;
2636 char_u *end; 2666 char_u *end;
2637 int lead; 2667 int lead;
2731 2761
2732 // Check if the name is a Funcref. If so, use the value. 2762 // Check if the name is a Funcref. If so, use the value.
2733 if (lv.ll_exp_name != NULL) 2763 if (lv.ll_exp_name != NULL)
2734 { 2764 {
2735 len = (int)STRLEN(lv.ll_exp_name); 2765 len = (int)STRLEN(lv.ll_exp_name);
2736 name = deref_func_name(lv.ll_exp_name, &len, partial, 2766 name = deref_func_name(lv.ll_exp_name, &len, partial, type,
2737 flags & TFN_NO_AUTOLOAD); 2767 flags & TFN_NO_AUTOLOAD);
2738 if (name == lv.ll_exp_name) 2768 if (name == lv.ll_exp_name)
2739 name = NULL; 2769 name = NULL;
2740 } 2770 }
2741 else if (!(flags & TFN_NO_DEREF)) 2771 else if (!(flags & TFN_NO_DEREF))
2742 { 2772 {
2743 len = (int)(end - *pp); 2773 len = (int)(end - *pp);
2744 name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD); 2774 name = deref_func_name(*pp, &len, partial, type,
2775 flags & TFN_NO_AUTOLOAD);
2745 if (name == *pp) 2776 if (name == *pp)
2746 name = NULL; 2777 name = NULL;
2747 } 2778 }
2748 if (name != NULL) 2779 if (name != NULL)
2749 { 2780 {
3062 CLEAR_FIELD(fudi); 3093 CLEAR_FIELD(fudi);
3063 } 3094 }
3064 else 3095 else
3065 { 3096 {
3066 name = trans_function_name(&p, &is_global, eap->skip, 3097 name = trans_function_name(&p, &is_global, eap->skip,
3067 TFN_NO_AUTOLOAD, &fudi, NULL); 3098 TFN_NO_AUTOLOAD, &fudi, NULL, NULL);
3068 paren = (vim_strchr(p, '(') != NULL); 3099 paren = (vim_strchr(p, '(') != NULL);
3069 if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) 3100 if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
3070 { 3101 {
3071 /* 3102 /*
3072 * Return on an invalid expression in braces, unless the expression 3103 * Return on an invalid expression in braces, unless the expression
3477 || (eap->cmdidx == CMD_def && checkforcmd(&p, "def", 3))) 3508 || (eap->cmdidx == CMD_def && checkforcmd(&p, "def", 3)))
3478 { 3509 {
3479 if (*p == '!') 3510 if (*p == '!')
3480 p = skipwhite(p + 1); 3511 p = skipwhite(p + 1);
3481 p += eval_fname_script(p); 3512 p += eval_fname_script(p);
3482 vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL, NULL)); 3513 vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL,
3514 NULL, NULL));
3483 if (*skipwhite(p) == '(') 3515 if (*skipwhite(p) == '(')
3484 { 3516 {
3485 if (nesting == MAX_FUNC_NESTING - 1) 3517 if (nesting == MAX_FUNC_NESTING - 1)
3486 emsg(_(e_function_nesting_too_deep)); 3518 emsg(_(e_function_nesting_too_deep));
3487 else 3519 else
3614 */ 3646 */
3615 if (fudi.fd_dict == NULL) 3647 if (fudi.fd_dict == NULL)
3616 { 3648 {
3617 hashtab_T *ht; 3649 hashtab_T *ht;
3618 3650
3619 v = find_var(name, &ht, FALSE); 3651 v = find_var(name, &ht, TRUE);
3620 if (v != NULL && v->di_tv.v_type == VAR_FUNC) 3652 if (v != NULL && v->di_tv.v_type == VAR_FUNC)
3621 { 3653 {
3622 emsg_funcname(N_("E707: Function name conflicts with variable: %s"), 3654 emsg_funcname(N_("E707: Function name conflicts with variable: %s"),
3623 name); 3655 name);
3624 goto erret; 3656 goto erret;
4005 int is_global = FALSE; 4037 int is_global = FALSE;
4006 4038
4007 flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD; 4039 flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
4008 if (no_deref) 4040 if (no_deref)
4009 flag |= TFN_NO_DEREF; 4041 flag |= TFN_NO_DEREF;
4010 p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL); 4042 p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL, NULL);
4011 nm = skipwhite(nm); 4043 nm = skipwhite(nm);
4012 4044
4013 // Only accept "funcname", "funcname ", "funcname (..." and 4045 // Only accept "funcname", "funcname ", "funcname (..." and
4014 // "funcname(...", not "funcname!...". 4046 // "funcname(...", not "funcname!...".
4015 if (p != NULL && (*nm == NUL || *nm == '(')) 4047 if (p != NULL && (*nm == NUL || *nm == '('))
4025 char_u *nm = name; 4057 char_u *nm = name;
4026 char_u *p; 4058 char_u *p;
4027 int is_global = FALSE; 4059 int is_global = FALSE;
4028 4060
4029 p = trans_function_name(&nm, &is_global, FALSE, 4061 p = trans_function_name(&nm, &is_global, FALSE,
4030 TFN_INT|TFN_QUIET, NULL, NULL); 4062 TFN_INT|TFN_QUIET, NULL, NULL, NULL);
4031 4063
4032 if (p != NULL && *nm == NUL 4064 if (p != NULL && *nm == NUL
4033 && (!check || translated_function_exists(p, is_global))) 4065 && (!check || translated_function_exists(p, is_global)))
4034 return p; 4066 return p;
4035 4067
4095 char_u *name; 4127 char_u *name;
4096 funcdict_T fudi; 4128 funcdict_T fudi;
4097 int is_global = FALSE; 4129 int is_global = FALSE;
4098 4130
4099 p = eap->arg; 4131 p = eap->arg;
4100 name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi, NULL); 4132 name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi,
4133 NULL, NULL);
4101 vim_free(fudi.fd_newkey); 4134 vim_free(fudi.fd_newkey);
4102 if (name == NULL) 4135 if (name == NULL)
4103 { 4136 {
4104 if (fudi.fd_dict != NULL && !eap->skip) 4137 if (fudi.fd_dict != NULL && !eap->skip)
4105 emsg(_(e_funcref)); 4138 emsg(_(e_funcref));
4326 int doesrange; 4359 int doesrange;
4327 int failed = FALSE; 4360 int failed = FALSE;
4328 funcdict_T fudi; 4361 funcdict_T fudi;
4329 partial_T *partial = NULL; 4362 partial_T *partial = NULL;
4330 evalarg_T evalarg; 4363 evalarg_T evalarg;
4364 type_T *type = NULL;
4331 4365
4332 fill_evalarg_from_eap(&evalarg, eap, eap->skip); 4366 fill_evalarg_from_eap(&evalarg, eap, eap->skip);
4333 if (eap->skip) 4367 if (eap->skip)
4334 { 4368 {
4335 // trans_function_name() doesn't work well when skipping, use eval0() 4369 // trans_function_name() doesn't work well when skipping, use eval0()
4341 --emsg_skip; 4375 --emsg_skip;
4342 clear_evalarg(&evalarg, eap); 4376 clear_evalarg(&evalarg, eap);
4343 return; 4377 return;
4344 } 4378 }
4345 4379
4346 tofree = trans_function_name(&arg, NULL, eap->skip, 4380 tofree = trans_function_name(&arg, NULL, eap->skip, TFN_INT,
4347 TFN_INT, &fudi, &partial); 4381 &fudi, &partial, in_vim9script() ? &type : NULL);
4348 if (fudi.fd_newkey != NULL) 4382 if (fudi.fd_newkey != NULL)
4349 { 4383 {
4350 // Still need to give an error message for missing key. 4384 // Still need to give an error message for missing key.
4351 semsg(_(e_dictkey), fudi.fd_newkey); 4385 semsg(_(e_dictkey), fudi.fd_newkey);
4352 vim_free(fudi.fd_newkey); 4386 vim_free(fudi.fd_newkey);
4361 4395
4362 // If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its 4396 // If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
4363 // contents. For VAR_PARTIAL get its partial, unless we already have one 4397 // contents. For VAR_PARTIAL get its partial, unless we already have one
4364 // from trans_function_name(). 4398 // from trans_function_name().
4365 len = (int)STRLEN(tofree); 4399 len = (int)STRLEN(tofree);
4366 name = deref_func_name(tofree, &len, 4400 name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial,
4367 partial != NULL ? NULL : &partial, FALSE); 4401 in_vim9script() && type == NULL ? &type : NULL, FALSE);
4368 4402
4369 // Skip white space to allow ":call func ()". Not good, but required for 4403 // Skip white space to allow ":call func ()". Not good, but required for
4370 // backward compatibility. 4404 // backward compatibility.
4371 startarg = skipwhite(arg); 4405 startarg = skipwhite(arg);
4372 rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this 4406 rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
4414 funcexe.lastline = eap->line2; 4448 funcexe.lastline = eap->line2;
4415 funcexe.doesrange = &doesrange; 4449 funcexe.doesrange = &doesrange;
4416 funcexe.evaluate = !eap->skip; 4450 funcexe.evaluate = !eap->skip;
4417 funcexe.partial = partial; 4451 funcexe.partial = partial;
4418 funcexe.selfdict = fudi.fd_dict; 4452 funcexe.selfdict = fudi.fd_dict;
4453 funcexe.check_type = type;
4419 if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) 4454 if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL)
4420 { 4455 {
4421 failed = TRUE; 4456 failed = TRUE;
4422 break; 4457 break;
4423 } 4458 }