Mercurial > vim
comparison src/vim9instr.c @ 31920:f1a5e67e9a1b v9.0.1292
patch 9.0.1292: :defer may call the wrong method for an object
Commit: https://github.com/vim/vim/commit/313e4724c3b4f6d7454b45b89da08f83a2a0c77e
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Feb 8 20:55:27 2023 +0000
patch 9.0.1292: :defer may call the wrong method for an object
Problem: :defer may call the wrong method for an object. (Ernie Rael)
Solution: When en object is from a class that extends or implements, figure
out the method to call at runtime. (closes #11910)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Wed, 08 Feb 2023 22:00:06 +0100 |
parents | b7a8611dd9fc |
children | e8c60d35fce3 |
comparison
equal
deleted
inserted
replaced
31919:b1b8848f5bb3 | 31920:f1a5e67e9a1b |
---|---|
1326 return push_type_stack2(cctx, type, decl_type); | 1326 return push_type_stack2(cctx, type, decl_type); |
1327 } | 1327 } |
1328 | 1328 |
1329 /* | 1329 /* |
1330 * Generate an ISN_FUNCREF instruction. | 1330 * Generate an ISN_FUNCREF instruction. |
1331 * For "obj.Method" "cl" is the class of the object (can be an interface or a | |
1332 * base class) and "fi" the index of the method on that class. | |
1331 * "isnp" is set to the instruction, so that fr_dfunc_idx can be set later. | 1333 * "isnp" is set to the instruction, so that fr_dfunc_idx can be set later. |
1332 */ | 1334 */ |
1333 int | 1335 int |
1334 generate_FUNCREF( | 1336 generate_FUNCREF( |
1335 cctx_T *cctx, | 1337 cctx_T *cctx, |
1336 ufunc_T *ufunc, | 1338 ufunc_T *ufunc, |
1339 class_T *cl, | |
1340 int fi, | |
1337 isn_T **isnp) | 1341 isn_T **isnp) |
1338 { | 1342 { |
1339 isn_T *isn; | 1343 isn_T *isn; |
1340 type_T *type; | 1344 type_T *type; |
1341 funcref_extra_T *extra; | 1345 funcref_extra_T *extra; |
1347 return FAIL; | 1351 return FAIL; |
1348 if (isnp != NULL) | 1352 if (isnp != NULL) |
1349 *isnp = isn; | 1353 *isnp = isn; |
1350 | 1354 |
1351 has_vars = get_loop_var_info(cctx, &loopinfo); | 1355 has_vars = get_loop_var_info(cctx, &loopinfo); |
1352 if (ufunc->uf_def_status == UF_NOT_COMPILED || has_vars) | 1356 if (ufunc->uf_def_status == UF_NOT_COMPILED || has_vars || cl != NULL) |
1353 { | 1357 { |
1354 extra = ALLOC_CLEAR_ONE(funcref_extra_T); | 1358 extra = ALLOC_CLEAR_ONE(funcref_extra_T); |
1355 if (extra == NULL) | 1359 if (extra == NULL) |
1356 return FAIL; | 1360 return FAIL; |
1357 isn->isn_arg.funcref.fr_extra = extra; | 1361 isn->isn_arg.funcref.fr_extra = extra; |
1358 extra->fre_loopvar_info = loopinfo; | 1362 extra->fre_loopvar_info = loopinfo; |
1359 } | 1363 if (cl != NULL) |
1360 if (ufunc->uf_def_status == UF_NOT_COMPILED) | 1364 { |
1365 extra->fre_class = cl; | |
1366 ++cl->class_refcount; | |
1367 extra->fre_method_idx = fi; | |
1368 } | |
1369 } | |
1370 if (ufunc->uf_def_status == UF_NOT_COMPILED || cl != NULL) | |
1361 extra->fre_func_name = vim_strsave(ufunc->uf_name); | 1371 extra->fre_func_name = vim_strsave(ufunc->uf_name); |
1362 else | 1372 if (ufunc->uf_def_status != UF_NOT_COMPILED && cl == NULL) |
1363 { | 1373 { |
1364 if (isnp == NULL && ufunc->uf_def_status == UF_TO_BE_COMPILED) | 1374 if (isnp == NULL && ufunc->uf_def_status == UF_TO_BE_COMPILED) |
1365 // compile the function now, we need the uf_dfunc_idx value | 1375 // compile the function now, we need the uf_dfunc_idx value |
1366 (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL); | 1376 (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL); |
1367 isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx; | 1377 isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx; |
2482 if (name != NULL) | 2492 if (name != NULL) |
2483 { | 2493 { |
2484 func_unref(name); | 2494 func_unref(name); |
2485 vim_free(name); | 2495 vim_free(name); |
2486 } | 2496 } |
2497 if (extra->fre_class != NULL) | |
2498 class_unref(extra->fre_class); | |
2487 vim_free(extra); | 2499 vim_free(extra); |
2488 } | 2500 } |
2489 } | 2501 } |
2490 break; | 2502 break; |
2491 | 2503 |