comparison src/vim9execute.c @ 19975:4e8e0ce576af v8.2.0543

patch 8.2.0543: Vim9: function with varargs does not work properly Commit: https://github.com/vim/vim/commit/1378fbc4591b77186c90beda37bdac628add4cb6 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Apr 11 20:50:33 2020 +0200 patch 8.2.0543: Vim9: function with varargs does not work properly Problem: Vim9: function with varargs does not work properly. Solution: Improve function type spec and add tests. Fix bugs.
author Bram Moolenaar <Bram@vim.org>
date Sat, 11 Apr 2020 21:00:04 +0200
parents 6765a88e72a5
children 014daa59ba50
comparison
equal deleted inserted replaced
19974:7b71d96d6582 19975:4e8e0ce576af
118 * - Index of next instruction in calling function 118 * - Index of next instruction in calling function
119 * - previous frame pointer 119 * - previous frame pointer
120 * - reserved space for local variables 120 * - reserved space for local variables
121 */ 121 */
122 static int 122 static int
123 call_dfunc(int cdf_idx, int argcount, ectx_T *ectx) 123 call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
124 { 124 {
125 int argcount = argcount_arg;
125 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx; 126 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
126 ufunc_T *ufunc = dfunc->df_ufunc; 127 ufunc_T *ufunc = dfunc->df_ufunc;
127 int optcount = ufunc_argcount(ufunc) - argcount; 128 int arg_to_add;
129 int vararg_count = 0;
128 int idx; 130 int idx;
129 131
130 if (dfunc->df_deleted) 132 if (dfunc->df_deleted)
131 { 133 {
132 emsg_funcname(e_func_deleted, ufunc->uf_name); 134 emsg_funcname(e_func_deleted, ufunc->uf_name);
133 return FAIL; 135 return FAIL;
134 } 136 }
135 137
136 if (ga_grow(&ectx->ec_stack, optcount + 3 + dfunc->df_varcount) == FAIL) 138 if (ufunc->uf_va_name != NULL)
137 return FAIL;
138
139 if (optcount < 0)
140 { 139 {
141 emsg("argument count wrong?"); 140 int iidx;
141 isn_T *iptr;
142
143 // Need to make a list out of the vararg arguments. There is a
144 // ISN_NEWLIST instruction at the start of the function body, we need
145 // to move the arguments below the stack frame and pass the count.
146 // Stack at time of call with 2 varargs:
147 // normal_arg
148 // optional_arg
149 // vararg_1
150 // vararg_2
151 // When starting execution:
152 // normal_arg
153 // optional_arg
154 // space list of varargs
155 // STACK_FRAME
156 // [local variables]
157 // vararg_1
158 // vararg_2
159 // TODO: This doesn't work if the same function is used for a default
160 // argument value. Forbid that somehow?
161 vararg_count = argcount - ufunc->uf_args.ga_len;
162 if (vararg_count < 0)
163 vararg_count = 0;
164 else
165 argcount -= vararg_count;
166 if (ufunc->uf_def_arg_idx == NULL)
167 iidx = 0;
168 else
169 iidx = ufunc->uf_def_arg_idx[ufunc->uf_def_args.ga_len];
170 iptr = &dfunc->df_instr[iidx];
171 if (iptr->isn_type != ISN_NEWLIST)
172 {
173 iemsg("Not a ISN_NEWLIST instruction");
174 return FAIL;
175 }
176 iptr->isn_arg.number = vararg_count;
177 }
178
179 arg_to_add = ufunc_argcount(ufunc) - argcount;
180 if (arg_to_add < 0)
181 {
182 iemsg("Argument count wrong?");
142 return FAIL; 183 return FAIL;
143 } 184 }
185 if (ga_grow(&ectx->ec_stack, arg_to_add + 3 + dfunc->df_varcount) == FAIL)
186 return FAIL;
187
188 if (vararg_count > 0)
189 {
190 int stack_added = arg_to_add + STACK_FRAME_SIZE + dfunc->df_varcount;
191
192 // Move the varargs to below the stack frame.
193 // TODO: use mch_memmove()
194 for (idx = 1; idx <= vararg_count; ++idx)
195 *STACK_TV_BOT(stack_added - idx) = *STACK_TV_BOT(-idx);
196 ectx->ec_stack.ga_len -= vararg_count;
197 }
144 198
145 // Reserve space for omitted optional arguments, filled in soon. 199 // Reserve space for omitted optional arguments, filled in soon.
146 // Also any empty varargs argument. 200 // Also room for a list of varargs, if there is one.
147 ectx->ec_stack.ga_len += optcount; 201 for (idx = 0; idx < arg_to_add; ++idx)
202 STACK_TV_BOT(idx)->v_type = VAR_UNKNOWN;
203 ectx->ec_stack.ga_len += arg_to_add;
148 204
149 // Store current execution state in stack frame for ISN_RETURN. 205 // Store current execution state in stack frame for ISN_RETURN.
150 // TODO: If the actual number of arguments doesn't match what the called 206 // TODO: If the actual number of arguments doesn't match what the called
151 // function expects things go bad. 207 // function expects things go bad.
152 STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx; 208 STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx;
155 ectx->ec_frame = ectx->ec_stack.ga_len; 211 ectx->ec_frame = ectx->ec_stack.ga_len;
156 212
157 // Initialize local variables 213 // Initialize local variables
158 for (idx = 0; idx < dfunc->df_varcount; ++idx) 214 for (idx = 0; idx < dfunc->df_varcount; ++idx)
159 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN; 215 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN;
160 ectx->ec_stack.ga_len += STACK_FRAME_SIZE + dfunc->df_varcount; 216 ectx->ec_stack.ga_len += STACK_FRAME_SIZE + dfunc->df_varcount
217 + vararg_count;
161 218
162 // Set execution state to the start of the called function. 219 // Set execution state to the start of the called function.
163 ectx->ec_dfunc_idx = cdf_idx; 220 ectx->ec_dfunc_idx = cdf_idx;
164 ectx->ec_instr = dfunc->df_instr; 221 ectx->ec_instr = dfunc->df_instr;
165 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); 222 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1);
428 485
429 // Get pointer to item at the bottom of the stack, -1 is the bottom. 486 // Get pointer to item at the bottom of the stack, -1 is the bottom.
430 #undef STACK_TV_BOT 487 #undef STACK_TV_BOT
431 #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx) 488 #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx)
432 489
433 // Get pointer to local variable on the stack. 490 // Get pointer to a local variable on the stack. Negative for arguments.
434 #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx) 491 #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx)
435 492
436 vim_memset(&ectx, 0, sizeof(ectx)); 493 vim_memset(&ectx, 0, sizeof(ectx));
437 ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); 494 ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
438 if (ga_grow(&ectx.ec_stack, 20) == FAIL) 495 if (ga_grow(&ectx.ec_stack, 20) == FAIL)