diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-03-10 19:23:28 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-03-10 19:23:28 +0000 |
commit | 53ba6ca5b27248680e368340707ad4b32a82591f (patch) | |
tree | 11bb97a5a313ac3abebcf96862c5d630e07a6e14 /src/vim9instr.c | |
parent | bf40e90dfeb1d3d0280077e65782beb3fee31c9f (diff) | |
download | vim-git-53ba6ca5b27248680e368340707ad4b32a82591f.tar.gz |
patch 8.2.4539: when comparing special v:none and v:null are handled the samev8.2.4539
Problem: When comparing special v:none and v:null are handled the same when
compiling.
Solution: Pass more information so that v:none can be handled differently at
compile time. (issue #9923)
Diffstat (limited to 'src/vim9instr.c')
-rw-r--r-- | src/vim9instr.c | 81 |
1 files changed, 50 insertions, 31 deletions
diff --git a/src/vim9instr.c b/src/vim9instr.c index e36ea16e2..9b176dfb5 100644 --- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -339,22 +339,30 @@ generate_two_op(cctx_T *cctx, char_u *op) } /* - * Get the instruction to use for comparing "type1" with "type2" + * Get the instruction to use for comparing two values with specified types. + * Either "tv1" and "tv2" are passed or "type1" and "type2". * Return ISN_DROP when failed. */ static isntype_T -get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2) +get_compare_isn( + exprtype_T exprtype, + typval_T *tv1, + typval_T *tv2, + type_T *type1, + type_T *type2) { isntype_T isntype = ISN_DROP; + vartype_T vartype1 = tv1 != NULL ? tv1->v_type : type1->tt_type; + vartype_T vartype2 = tv2 != NULL ? tv2->v_type : type2->tt_type; - if (type1 == VAR_UNKNOWN) - type1 = VAR_ANY; - if (type2 == VAR_UNKNOWN) - type2 = VAR_ANY; + if (vartype1 == VAR_UNKNOWN) + vartype1 = VAR_ANY; + if (vartype2 == VAR_UNKNOWN) + vartype2 = VAR_ANY; - if (type1 == type2) + if (vartype1 == vartype2) { - switch (type1) + switch (vartype1) { case VAR_BOOL: isntype = ISN_COMPAREBOOL; break; case VAR_SPECIAL: isntype = ISN_COMPARESPECIAL; break; @@ -368,15 +376,28 @@ get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2) default: isntype = ISN_COMPAREANY; break; } } - else if (type1 == VAR_ANY || type2 == VAR_ANY - || ((type1 == VAR_NUMBER || type1 == VAR_FLOAT) - && (type2 == VAR_NUMBER || type2 == VAR_FLOAT)) - || (type1 == VAR_FUNC && type2 == VAR_PARTIAL) - || (type1 == VAR_PARTIAL && type2 == VAR_FUNC)) + else if (vartype1 == VAR_ANY || vartype2 == VAR_ANY + || ((vartype1 == VAR_NUMBER || vartype1 == VAR_FLOAT) + && (vartype2 == VAR_NUMBER || vartype2 == VAR_FLOAT)) + || (vartype1 == VAR_FUNC && vartype2 == VAR_PARTIAL) + || (vartype1 == VAR_PARTIAL && vartype2 == VAR_FUNC)) isntype = ISN_COMPAREANY; - else if (type1 == VAR_SPECIAL || type2 == VAR_SPECIAL) + else if (vartype1 == VAR_SPECIAL || vartype2 == VAR_SPECIAL) { - switch (type1 == VAR_SPECIAL ? type2 : type1) + if ((vartype1 == VAR_SPECIAL + && (tv1 != NULL ? tv1->vval.v_number == VVAL_NONE + : type1 == &t_none) + && vartype2 != VAR_STRING) + || (vartype2 == VAR_SPECIAL + && (tv2 != NULL ? tv2->vval.v_number == VVAL_NONE + : type2 == &t_none) + && vartype1 != VAR_STRING)) + { + semsg(_(e_cannot_compare_str_with_str), + vartype_name(vartype1), vartype_name(vartype2)); + return ISN_DROP; + } + switch (vartype1 == VAR_SPECIAL ? vartype2 : vartype1) { case VAR_BLOB: break; case VAR_CHANNEL: break; @@ -387,7 +408,7 @@ get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2) case VAR_PARTIAL: break; case VAR_STRING: break; default: semsg(_(e_cannot_compare_str_with_str), - vartype_name(type1), vartype_name(type2)); + vartype_name(vartype1), vartype_name(vartype2)); return ISN_DROP; } isntype = ISN_COMPARENULL; @@ -400,20 +421,20 @@ get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2) || isntype == ISN_COMPAREFLOAT)) { semsg(_(e_cannot_use_str_with_str), - exprtype == EXPR_IS ? "is" : "isnot" , vartype_name(type1)); + exprtype == EXPR_IS ? "is" : "isnot" , vartype_name(vartype1)); return ISN_DROP; } if (isntype == ISN_DROP || ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL - && (type1 == VAR_BOOL || type1 == VAR_SPECIAL - || type2 == VAR_BOOL || type2 == VAR_SPECIAL))) + && (vartype1 == VAR_BOOL || vartype1 == VAR_SPECIAL + || vartype2 == VAR_BOOL || vartype2 == VAR_SPECIAL))) || ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL && exprtype != EXPR_IS && exprtype != EXPR_ISNOT - && (type1 == VAR_BLOB || type2 == VAR_BLOB - || type1 == VAR_LIST || type2 == VAR_LIST)))) + && (vartype1 == VAR_BLOB || vartype2 == VAR_BLOB + || vartype1 == VAR_LIST || vartype2 == VAR_LIST)))) { semsg(_(e_cannot_compare_str_with_str), - vartype_name(type1), vartype_name(type2)); + vartype_name(vartype1), vartype_name(vartype2)); return ISN_DROP; } return isntype; @@ -422,7 +443,7 @@ get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2) int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2) { - if (get_compare_isn(type, tv1->v_type, tv2->v_type) == ISN_DROP) + if (get_compare_isn(type, tv1, tv2, NULL, NULL) == ISN_DROP) return FAIL; return OK; } @@ -436,17 +457,14 @@ generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic) isntype_T isntype; isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; - vartype_T type1; - vartype_T type2; RETURN_OK_IF_SKIP(cctx); // Get the known type of the two items on the stack. If they are matching // use a type-specific instruction. Otherwise fall back to runtime type // checking. - type1 = get_type_on_stack(cctx, 1)->tt_type; - type2 = get_type_on_stack(cctx, 0)->tt_type; - isntype = get_compare_isn(exprtype, type1, type2); + isntype = get_compare_isn(exprtype, NULL, NULL, + get_type_on_stack(cctx, 1), get_type_on_stack(cctx, 0)); if (isntype == ISN_DROP) return FAIL; @@ -664,7 +682,8 @@ generate_PUSHSPEC(cctx_T *cctx, varnumber_T number) isn_T *isn; RETURN_OK_IF_SKIP(cctx); - if ((isn = generate_instr_type(cctx, ISN_PUSHSPEC, &t_special)) == NULL) + if ((isn = generate_instr_type(cctx, ISN_PUSHSPEC, + number == VVAL_NULL ? &t_null : &t_none)) == NULL) return FAIL; isn->isn_arg.number = number; @@ -1475,7 +1494,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) type_T *actual; actual = get_type_on_stack(cctx, argcount - i - 1); - if (actual == &t_special + if (actual->tt_type == VAR_SPECIAL && i >= regular_args - ufunc->uf_def_args.ga_len) { // assume v:none used for default argument value @@ -1606,7 +1625,7 @@ generate_PCALL( expected = type->tt_args[ type->tt_argcount - 1]->tt_member; else if (i >= type->tt_min_argcount - && actual == &t_special) + && actual->tt_type == VAR_SPECIAL) expected = &t_any; else expected = type->tt_args[i]; |