comparison src/vim9instr.c @ 30333:fc0830246f49 v9.0.0502

patch 9.0.0502: a closure in a nested loop in a :def function does not work Commit: https://github.com/vim/vim/commit/cc34181f9994d64f8c8fa2f5845eaf0cc963067f Author: Bram Moolenaar <Bram@vim.org> Date: Mon Sep 19 15:54:34 2022 +0100 patch 9.0.0502: a closure in a nested loop in a :def function does not work Problem: A closure in a nested loop in a :def function does not work. Solution: Use an array of loopvars, one per loop level.
author Bram Moolenaar <Bram@vim.org>
date Mon, 19 Sep 2022 17:00:07 +0200
parents 029c59bf78f1
children 72e6073a2822
comparison
equal deleted inserted replaced
30332:462d122636b3 30333:fc0830246f49
995 int 995 int
996 generate_LOADOUTER( 996 generate_LOADOUTER(
997 cctx_T *cctx, 997 cctx_T *cctx,
998 int idx, 998 int idx,
999 int nesting, 999 int nesting,
1000 int loop_depth,
1000 int loop_idx, 1001 int loop_idx,
1001 type_T *type) 1002 type_T *type)
1002 { 1003 {
1003 isn_T *isn; 1004 isn_T *isn;
1004 1005
1006 if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL) 1007 if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL)
1007 return FAIL; 1008 return FAIL;
1008 if (nesting == 1 && loop_idx >= 0 && idx >= loop_idx) 1009 if (nesting == 1 && loop_idx >= 0 && idx >= loop_idx)
1009 { 1010 {
1010 // Load a variable defined in a loop. A copy will be made at the end 1011 // Load a variable defined in a loop. A copy will be made at the end
1011 // of the loop. TODO: how about deeper nesting? 1012 // of the loop.
1012 isn->isn_arg.outer.outer_idx = idx - loop_idx; 1013 isn->isn_arg.outer.outer_idx = idx - loop_idx;
1013 isn->isn_arg.outer.outer_depth = OUTER_LOOP_DEPTH; 1014 isn->isn_arg.outer.outer_depth = -loop_depth - 1;
1014 } 1015 }
1015 else 1016 else
1016 { 1017 {
1017 isn->isn_arg.outer.outer_idx = idx; 1018 isn->isn_arg.outer.outer_idx = idx;
1018 isn->isn_arg.outer.outer_depth = nesting; 1019 isn->isn_arg.outer.outer_depth = nesting;
1205 isn_T **isnp) 1206 isn_T **isnp)
1206 { 1207 {
1207 isn_T *isn; 1208 isn_T *isn;
1208 type_T *type; 1209 type_T *type;
1209 funcref_extra_T *extra; 1210 funcref_extra_T *extra;
1210 short loop_var_idx; 1211 loopvarinfo_T loopinfo;
1211 short loop_var_count; 1212 int has_vars;
1212 1213
1213 RETURN_OK_IF_SKIP(cctx); 1214 RETURN_OK_IF_SKIP(cctx);
1214 if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) 1215 if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
1215 return FAIL; 1216 return FAIL;
1216 if (isnp != NULL) 1217 if (isnp != NULL)
1217 *isnp = isn; 1218 *isnp = isn;
1218 1219
1219 loop_var_count = get_loop_var_info(cctx, &loop_var_idx); 1220 has_vars = get_loop_var_info(cctx, &loopinfo);
1220 if (ufunc->uf_def_status == UF_NOT_COMPILED || loop_var_count > 0) 1221 if (ufunc->uf_def_status == UF_NOT_COMPILED || has_vars)
1221 { 1222 {
1222 extra = ALLOC_CLEAR_ONE(funcref_extra_T); 1223 extra = ALLOC_CLEAR_ONE(funcref_extra_T);
1223 if (extra == NULL) 1224 if (extra == NULL)
1224 return FAIL; 1225 return FAIL;
1225 isn->isn_arg.funcref.fr_extra = extra; 1226 isn->isn_arg.funcref.fr_extra = extra;
1226 extra->fre_loop_var_idx = loop_var_idx; 1227 extra->fre_loopvar_info = loopinfo;
1227 extra->fre_loop_var_count = loop_var_count;
1228 } 1228 }
1229 if (ufunc->uf_def_status == UF_NOT_COMPILED) 1229 if (ufunc->uf_def_status == UF_NOT_COMPILED)
1230 extra->fre_func_name = vim_strsave(ufunc->uf_name); 1230 extra->fre_func_name = vim_strsave(ufunc->uf_name);
1231 else 1231 else
1232 isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx; 1232 isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx;
1233
1234 // Reserve an extra variable to keep track of the number of closures
1235 // created.
1233 cctx->ctx_has_closure = 1; 1236 cctx->ctx_has_closure = 1;
1234 1237
1235 // If the referenced function is a closure, it may use items further up in 1238 // If the referenced function is a closure, it may use items further up in
1236 // the nested context, including this one. But not a function defined at 1239 // the nested context, including this one. But not a function defined at
1237 // the script level. 1240 // the script level.
1250 */ 1253 */
1251 int 1254 int
1252 generate_NEWFUNC( 1255 generate_NEWFUNC(
1253 cctx_T *cctx, 1256 cctx_T *cctx,
1254 char_u *lambda_name, 1257 char_u *lambda_name,
1255 char_u *func_name, 1258 char_u *func_name)
1256 short loop_var_idx,
1257 short loop_var_count)
1258 { 1259 {
1259 isn_T *isn; 1260 isn_T *isn;
1260 int ret = OK; 1261 int ret = OK;
1261 1262
1262 if (cctx->ctx_skip != SKIP_YES) 1263 if (cctx->ctx_skip != SKIP_YES)
1269 1270
1270 if (arg == NULL) 1271 if (arg == NULL)
1271 ret = FAIL; 1272 ret = FAIL;
1272 else 1273 else
1273 { 1274 {
1275 // Reserve an extra variable to keep track of the number of
1276 // closures created.
1277 cctx->ctx_has_closure = 1;
1278
1274 isn->isn_arg.newfunc.nf_arg = arg; 1279 isn->isn_arg.newfunc.nf_arg = arg;
1275 arg->nfa_lambda = lambda_name; 1280 arg->nfa_lambda = lambda_name;
1276 arg->nfa_global = func_name; 1281 arg->nfa_global = func_name;
1277 arg->nfa_loop_var_idx = loop_var_idx; 1282 (void)get_loop_var_info(cctx, &arg->nfa_loopvar_info);
1278 arg->nfa_loop_var_count = loop_var_count;
1279 return OK; 1283 return OK;
1280 } 1284 }
1281 } 1285 }
1282 } 1286 }
1283 vim_free(lambda_name); 1287 vim_free(lambda_name);
1369 isn_T *isn; 1373 isn_T *isn;
1370 1374
1371 RETURN_OK_IF_SKIP(cctx); 1375 RETURN_OK_IF_SKIP(cctx);
1372 if ((isn = generate_instr(cctx, ISN_FOR)) == NULL) 1376 if ((isn = generate_instr(cctx, ISN_FOR)) == NULL)
1373 return FAIL; 1377 return FAIL;
1374 isn->isn_arg.forloop.for_idx = loop_idx; 1378 isn->isn_arg.forloop.for_loop_idx = loop_idx;
1375 1379
1376 // type doesn't matter, will be stored next 1380 // type doesn't matter, will be stored next
1377 return push_type_stack(cctx, &t_any); 1381 return push_type_stack(cctx, &t_any);
1378 } 1382 }
1379 1383
1380 int 1384 int
1381 generate_ENDLOOP( 1385 generate_ENDLOOP(cctx_T *cctx, loop_info_T *loop_info)
1382 cctx_T *cctx,
1383 int funcref_idx,
1384 int prev_local_count)
1385 { 1386 {
1386 isn_T *isn; 1387 isn_T *isn;
1387 1388
1388 RETURN_OK_IF_SKIP(cctx); 1389 RETURN_OK_IF_SKIP(cctx);
1389 if ((isn = generate_instr(cctx, ISN_ENDLOOP)) == NULL) 1390 if ((isn = generate_instr(cctx, ISN_ENDLOOP)) == NULL)
1390 return FAIL; 1391 return FAIL;
1391 isn->isn_arg.endloop.end_funcref_idx = funcref_idx; 1392 isn->isn_arg.endloop.end_depth = loop_info->li_depth;
1392 isn->isn_arg.endloop.end_var_idx = prev_local_count; 1393 isn->isn_arg.endloop.end_funcref_idx = loop_info->li_funcref_idx;
1394 isn->isn_arg.endloop.end_var_idx = loop_info->li_local_count;
1393 isn->isn_arg.endloop.end_var_count = 1395 isn->isn_arg.endloop.end_var_count =
1394 cctx->ctx_locals.ga_len - prev_local_count; 1396 cctx->ctx_locals.ga_len - loop_info->li_local_count;
1395 return OK; 1397 return OK;
1396 } 1398 }
1397 1399
1398 /* 1400 /*
1399 * Generate an ISN_TRYCONT instruction. 1401 * Generate an ISN_TRYCONT instruction.