Patch 8.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)
Files: src/vim9instr.c, src/vim9compile.c, src/globals.h,
src/testdir/test_vim9_expr.vim
*** ../vim-8.2.4538/src/vim9instr.c 2022-03-08 19:43:51.688198945 +0000
--- src/vim9instr.c 2022-03-10 19:12:38.710964636 +0000
***************
*** 339,360 ****
}
/*
! * Get the instruction to use for comparing "type1" with "type2"
* Return ISN_DROP when failed.
*/
static isntype_T
! get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2)
{
isntype_T isntype = ISN_DROP;
! if (type1 == VAR_UNKNOWN)
! type1 = VAR_ANY;
! if (type2 == VAR_UNKNOWN)
! type2 = VAR_ANY;
! if (type1 == type2)
{
! switch (type1)
{
case VAR_BOOL: isntype = ISN_COMPAREBOOL; break;
case VAR_SPECIAL: isntype = ISN_COMPARESPECIAL; break;
--- 339,368 ----
}
/*
! * 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,
! 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 (vartype1 == VAR_UNKNOWN)
! vartype1 = VAR_ANY;
! if (vartype2 == VAR_UNKNOWN)
! vartype2 = VAR_ANY;
! if (vartype1 == vartype2)
{
! switch (vartype1)
{
case VAR_BOOL: isntype = ISN_COMPAREBOOL; break;
case VAR_SPECIAL: isntype = ISN_COMPARESPECIAL; break;
***************
*** 368,382 ****
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))
isntype = ISN_COMPAREANY;
! else if (type1 == VAR_SPECIAL || type2 == VAR_SPECIAL)
{
! switch (type1 == VAR_SPECIAL ? type2 : type1)
{
case VAR_BLOB: break;
case VAR_CHANNEL: break;
--- 376,403 ----
default: isntype = ISN_COMPAREANY; break;
}
}
! 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 (vartype1 == VAR_SPECIAL || vartype2 == VAR_SPECIAL)
{
! 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,393 ****
case VAR_PARTIAL: break;
case VAR_STRING: break;
default: semsg(_(e_cannot_compare_str_with_str),
! vartype_name(type1), vartype_name(type2));
return ISN_DROP;
}
isntype = ISN_COMPARENULL;
--- 408,414 ----
case VAR_PARTIAL: break;
case VAR_STRING: break;
default: semsg(_(e_cannot_compare_str_with_str),
! vartype_name(vartype1), vartype_name(vartype2));
return ISN_DROP;
}
isntype = ISN_COMPARENULL;
***************
*** 400,419 ****
|| isntype == ISN_COMPAREFLOAT))
{
semsg(_(e_cannot_use_str_with_str),
! exprtype == EXPR_IS ? "is" : "isnot" , vartype_name(type1));
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)))
|| ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
&& exprtype != EXPR_IS && exprtype != EXPR_ISNOT
! && (type1 == VAR_BLOB || type2 == VAR_BLOB
! || type1 == VAR_LIST || type2 == VAR_LIST))))
{
semsg(_(e_cannot_compare_str_with_str),
! vartype_name(type1), vartype_name(type2));
return ISN_DROP;
}
return isntype;
--- 421,440 ----
|| isntype == ISN_COMPAREFLOAT))
{
semsg(_(e_cannot_use_str_with_str),
! exprtype == EXPR_IS ? "is" : "isnot" , vartype_name(vartype1));
return ISN_DROP;
}
if (isntype == ISN_DROP
|| ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
! && (vartype1 == VAR_BOOL || vartype1 == VAR_SPECIAL
! || vartype2 == VAR_BOOL || vartype2 == VAR_SPECIAL)))
|| ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
&& exprtype != EXPR_IS && exprtype != EXPR_ISNOT
! && (vartype1 == VAR_BLOB || vartype2 == VAR_BLOB
! || vartype1 == VAR_LIST || vartype2 == VAR_LIST))))
{
semsg(_(e_cannot_compare_str_with_str),
! vartype_name(vartype1), vartype_name(vartype2));
return ISN_DROP;
}
return isntype;
***************
*** 422,428 ****
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)
return FAIL;
return OK;
}
--- 443,449 ----
int
check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2)
{
! if (get_compare_isn(type, tv1, tv2, NULL, NULL) == ISN_DROP)
return FAIL;
return OK;
}
***************
*** 436,452 ****
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);
if (isntype == ISN_DROP)
return FAIL;
--- 457,470 ----
isntype_T isntype;
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
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.
! 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,670 ****
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
! if ((isn = generate_instr_type(cctx, ISN_PUSHSPEC, &t_special)) == NULL)
return FAIL;
isn->isn_arg.number = number;
--- 682,689 ----
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
! if ((isn = generate_instr_type(cctx, ISN_PUSHSPEC,
! number == VVAL_NULL ? &t_null : &t_none)) == NULL)
return FAIL;
isn->isn_arg.number = number;
***************
*** 1475,1481 ****
type_T *actual;
actual = get_type_on_stack(cctx, argcount - i - 1);
! if (actual == &t_special
&& i >= regular_args - ufunc->uf_def_args.ga_len)
{
// assume v:none used for default argument value
--- 1494,1500 ----
type_T *actual;
actual = get_type_on_stack(cctx, argcount - i - 1);
! if (actual->tt_type == VAR_SPECIAL
&& i >= regular_args - ufunc->uf_def_args.ga_len)
{
// assume v:none used for default argument value
***************
*** 1606,1612 ****
expected = type->tt_args[
type->tt_argcount - 1]->tt_member;
else if (i >= type->tt_min_argcount
! && actual == &t_special)
expected = &t_any;
else
expected = type->tt_args[i];
--- 1625,1631 ----
expected = type->tt_args[
type->tt_argcount - 1]->tt_member;
else if (i >= type->tt_min_argcount
! && actual->tt_type == VAR_SPECIAL)
expected = &t_any;
else
expected = type->tt_args[i];
*** ../vim-8.2.4538/src/vim9compile.c 2022-03-08 13:18:10.809020782 +0000
--- src/vim9compile.c 2022-03-10 19:06:02.375695990 +0000
***************
*** 1799,1805 ****
return FAIL;
}
type = get_type_on_stack(cctx, 0);
! if ((dest_type != VAR_BLOB && type != &t_special)
&& need_type(type, &t_number,
-1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
--- 1799,1805 ----
return FAIL;
}
type = get_type_on_stack(cctx, 0);
! if ((dest_type != VAR_BLOB && type->tt_type != VAR_SPECIAL)
&& need_type(type, &t_number,
-1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
*** ../vim-8.2.4538/src/globals.h 2022-02-11 20:33:11.942342190 +0000
--- src/globals.h 2022-03-10 19:06:20.151664158 +0000
***************
*** 398,404 ****
EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL);
! EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_number_bool INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC|TTFLAG_BOOL_OK, NULL, NULL);
EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
--- 398,405 ----
EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL);
! EXTERN type_T t_null INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
! EXTERN type_T t_none INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL);
EXTERN type_T t_number_bool INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC|TTFLAG_BOOL_OK, NULL, NULL);
EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
*** ../vim-8.2.4538/src/testdir/test_vim9_expr.vim 2022-03-10 12:20:48.542552970 +0000
--- src/testdir/test_vim9_expr.vim 2022-03-10 19:21:06.485989124 +0000
***************
*** 828,835 ****
v9.CheckDefAndScriptFailure(['echo true != v:null'], 'E1072: Cannot compare bool with special')
v9.CheckDefAndScriptFailure(['echo v:null != true'], 'E1072: Cannot compare special with bool')
v9.CheckDefAndScriptFailure(['echo false == v:null'], 'E1072: Cannot compare bool with special')
! v9.CheckDefExecAndScriptFailure(['echo [] == v:none'], ['E1072: Cannot compare list with special', 'E691: Can only compare List with List'])
enddef
def Test_expr4_wrong_type()
--- 828,849 ----
v9.CheckDefAndScriptFailure(['echo true != v:null'], 'E1072: Cannot compare bool with special')
v9.CheckDefAndScriptFailure(['echo v:null != true'], 'E1072: Cannot compare special with bool')
v9.CheckDefAndScriptFailure(['echo false == v:null'], 'E1072: Cannot compare bool with special')
+ enddef
+
+ def Test_expr4_compare_none()
+ var lines =<< trim END
+ assert_false('' == v:none)
+ assert_false('text' == v:none)
+ assert_true(v:none == v:none)
+ assert_false(v:none == '')
+ assert_false(v:none == 'text')
+ assert_true(v:none == v:none)
+ END
+ v9.CheckDefAndScriptSuccess(lines)
! v9.CheckDefAndScriptFailure(['echo [] == v:none'], 'E1072: Cannot compare list with special')
! v9.CheckDefAndScriptFailure(['echo 123 == v:none'], 'E1072: Cannot compare number with special')
! v9.CheckDefAndScriptFailure(['echo 0z00 == v:none'], 'E1072: Cannot compare blob with special')
enddef
def Test_expr4_wrong_type()
*** ../vim-8.2.4538/src/version.c 2022-03-10 18:36:50.874611102 +0000
--- src/version.c 2022-03-10 19:21:40.625922704 +0000
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 4539,
/**/
--
hundred-and-one symptoms of being an internet addict:
225. You sign up for free subscriptions for all the computer magazines
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///