diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b541af23af..247948ffe9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4387,7 +4387,7 @@ bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) if (d1 != d2) { return false; } - } else if (!tv_dict_equal(d1, d2, ic, true)) { + } else if (!tv_dict_equal(d1, d2, ic)) { return false; } @@ -4399,7 +4399,7 @@ bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) } for (int i = 0; i < a1; i++) { if (!tv_equal(tv1->vval.v_partial->pt_argv + i, - tv2->vval.v_partial->pt_argv + i, ic, true)) { + tv2->vval.v_partial->pt_argv + i, ic)) { return false; } } @@ -9063,7 +9063,7 @@ int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic) return FAIL; } else { // Compare two Lists for being equal or unequal. - n1 = tv_list_equal(typ1->vval.v_list, typ2->vval.v_list, ic, false); + n1 = tv_list_equal(typ1->vval.v_list, typ2->vval.v_list, ic); if (type == EXPR_NEQUAL) { n1 = !n1; } @@ -9086,7 +9086,7 @@ int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic) return FAIL; } else { // Compare two Dictionaries for being equal or unequal. - n1 = tv_dict_equal(typ1->vval.v_dict, typ2->vval.v_dict, ic, false); + n1 = tv_dict_equal(typ1->vval.v_dict, typ2->vval.v_dict, ic); if (type == EXPR_NEQUAL) { n1 = !n1; } @@ -9107,14 +9107,14 @@ int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic) if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC) { // strings are considered the same if their value is // the same - n1 = tv_equal(typ1, typ2, ic, false); + n1 = tv_equal(typ1, typ2, ic); } else if (typ1->v_type == VAR_PARTIAL && typ2->v_type == VAR_PARTIAL) { n1 = typ1->vval.v_partial == typ2->vval.v_partial; } else { n1 = false; } } else { - n1 = tv_equal(typ1, typ2, ic, false); + n1 = tv_equal(typ1, typ2, ic); } if (type == EXPR_NEQUAL || type == EXPR_ISNOT) { n1 = !n1; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 9cb504c074..e28e46d057 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -953,7 +953,7 @@ static varnumber_T count_list(list_T *l, typval_T *needle, int64_t idx, bool ic) varnumber_T n = 0; for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { - if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic, false)) { + if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic)) { n++; } } @@ -973,7 +973,7 @@ static varnumber_T count_dict(dict_T *d, typval_T *needle, bool ic) varnumber_T n = 0; TV_DICT_ITER(d, di, { - if (tv_equal(&di->di_tv, needle, ic, false)) { + if (tv_equal(&di->di_tv, needle, ic)) { n++; } }); @@ -3770,7 +3770,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) typval_T tv; tv.v_type = VAR_NUMBER; tv.vval.v_number = tv_blob_get(b, idx); - if (tv_equal(&tv, &argvars[1], ic, false)) { + if (tv_equal(&tv, &argvars[1], ic)) { rettv->vval.v_number = idx; return; } @@ -3807,7 +3807,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) { - if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic, false)) { + if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic)) { rettv->vval.v_number = idx; break; } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index f9eb5c33c0..0d6de3c3e5 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1460,10 +1460,9 @@ void f_uniq(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// @param[in] l1 First list to compare. /// @param[in] l2 Second list to compare. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. /// /// @return True if lists are equal, false otherwise. -bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, const bool recursive) +bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT { if (l1 == l2) { @@ -1485,8 +1484,7 @@ bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, const bool for (; item1 != NULL && item2 != NULL ; (item1 = TV_LIST_ITEM_NEXT(l1, item1), item2 = TV_LIST_ITEM_NEXT(l2, item2))) { - if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic, - recursive)) { + if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic)) { return false; } } @@ -2679,8 +2677,9 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action /// @param[in] d1 First dictionary. /// @param[in] d2 Second dictionary. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. -bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool recursive) +/// +/// @return True if dictionaries are equal, false otherwise. +bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT { if (d1 == d2) { @@ -2702,7 +2701,7 @@ bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool if (di2 == NULL) { return false; } - if (!tv_equal(&di1->di_tv, &di2->di_tv, ic, recursive)) { + if (!tv_equal(&di1->di_tv, &di2->di_tv, ic)) { return false; } }); @@ -3838,10 +3837,9 @@ static int tv_equal_recurse_limit; /// @param[in] tv1 First value to compare. /// @param[in] tv2 Second value to compare. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. /// /// @return true if values are equal. -bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const bool recursive) +bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { // TODO(ZyX-I): Make this not recursive @@ -3857,7 +3855,7 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const boo // Reduce the limit every time running into it. That should work fine for // deeply linked structures that are not recursively linked and catch // recursiveness quickly. - if (!recursive) { + if (recursive_cnt == 0) { tv_equal_recurse_limit = 1000; } if (recursive_cnt >= tv_equal_recurse_limit) { @@ -3868,15 +3866,13 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const boo switch (tv1->v_type) { case VAR_LIST: { recursive_cnt++; - const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, - true); + const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic); recursive_cnt--; return r; } case VAR_DICT: { recursive_cnt++; - const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, - true); + const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic); recursive_cnt--; return r; } diff --git a/src/nvim/testing.c b/src/nvim/testing.c index 8041cc2e33..4dc8984fa9 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -198,7 +198,7 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, const char *e if (!HASHITEM_EMPTY(hi)) { dictitem_T *item2 = tv_dict_find(got_d, hi->hi_key, -1); if (item2 == NULL - || !tv_equal(&TV_DICT_HI2DI(hi)->di_tv, &item2->di_tv, false, false)) { + || !tv_equal(&TV_DICT_HI2DI(hi)->di_tv, &item2->di_tv, false)) { // item of exp_d not present in got_d or values differ. const size_t key_len = strlen(hi->hi_key); tv_dict_add_tv(exp_tv->vval.v_dict, hi->hi_key, key_len, &TV_DICT_HI2DI(hi)->di_tv); @@ -271,8 +271,7 @@ static int assert_equal_common(typval_T *argvars, assert_type_T atype) { garray_T ga; - if (tv_equal(&argvars[0], &argvars[1], false, false) - != (atype == ASSERT_EQUAL)) { + if (tv_equal(&argvars[0], &argvars[1], false) != (atype == ASSERT_EQUAL)) { prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], atype); diff --git a/test/old/testdir/test_listdict.vim b/test/old/testdir/test_listdict.vim index 6c22dc0784..35d63c87d0 100644 --- a/test/old/testdir/test_listdict.vim +++ b/test/old/testdir/test_listdict.vim @@ -1055,6 +1055,19 @@ func Test_listdict_compare() call assert_fails('echo {} =~ {}', 'E736:') endfunc +func Test_recursive_listdict_compare() + let l1 = [0, 1] + let l1[0] = l1 + let l2 = [0, 1] + let l2[0] = l2 + call assert_true(l1 == l2) + let d1 = {0: 0, 1: 1} + let d1[0] = d1 + let d2 = {0: 0, 1: 1} + let d2[0] = d2 + call assert_true(d1 == d2) +endfunc + " compare complex recursively linked list and dict func Test_listdict_compare_complex() let lines =<< trim END diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index 4e3b461396..14fd7986e7 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -1267,26 +1267,19 @@ describe('typval.c', function() local l2 = list() -- NULL lists are equal to empty lists - eq(true, lib.tv_list_equal(l, nil, true, false)) - eq(true, lib.tv_list_equal(nil, l, false, false)) - eq(true, lib.tv_list_equal(nil, l, false, true)) - eq(true, lib.tv_list_equal(l, nil, true, true)) + eq(true, lib.tv_list_equal(l, nil, true)) + eq(true, lib.tv_list_equal(nil, l, false)) -- NULL lists are equal themselves - eq(true, lib.tv_list_equal(nil, nil, true, false)) - eq(true, lib.tv_list_equal(nil, nil, false, false)) - eq(true, lib.tv_list_equal(nil, nil, false, true)) - eq(true, lib.tv_list_equal(nil, nil, true, true)) + eq(true, lib.tv_list_equal(nil, nil, true)) + eq(true, lib.tv_list_equal(nil, nil, false)) -- As well as empty lists - eq(true, lib.tv_list_equal(l, l, true, false)) - eq(true, lib.tv_list_equal(l, l2, false, false)) - eq(true, lib.tv_list_equal(l2, l, false, true)) - eq(true, lib.tv_list_equal(l2, l2, true, true)) + eq(true, lib.tv_list_equal(l, l, true)) + eq(true, lib.tv_list_equal(l, l2, false)) + eq(true, lib.tv_list_equal(l2, l, false)) + eq(true, lib.tv_list_equal(l2, l2, true)) end) - -- Must not use recursive=true argument in the following tests because it - -- indicates that tv_equal_recurse_limit and recursive_cnt were set which - -- is essential. This argument will be set when comparing inner lists. itp('compares lists correctly when case is not ignored', function() local l1 = list('abc', { 1, 2, 'Abc' }, 'def') local l2 = list('abc', { 1, 2, 'Abc' }) @@ -1298,15 +1291,15 @@ describe('typval.c', function() local l8 = list('abc', nil, 'def') local l9 = list('abc', { 1, 2, nil }, 'def') - eq(true, lib.tv_list_equal(l1, l1, false, false)) - eq(false, lib.tv_list_equal(l1, l2, false, false)) - eq(false, lib.tv_list_equal(l1, l3, false, false)) - eq(false, lib.tv_list_equal(l1, l4, false, false)) - eq(false, lib.tv_list_equal(l1, l5, false, false)) - eq(true, lib.tv_list_equal(l1, l6, false, false)) - eq(false, lib.tv_list_equal(l1, l7, false, false)) - eq(false, lib.tv_list_equal(l1, l8, false, false)) - eq(false, lib.tv_list_equal(l1, l9, false, false)) + eq(true, lib.tv_list_equal(l1, l1, false)) + eq(false, lib.tv_list_equal(l1, l2, false)) + eq(false, lib.tv_list_equal(l1, l3, false)) + eq(false, lib.tv_list_equal(l1, l4, false)) + eq(false, lib.tv_list_equal(l1, l5, false)) + eq(true, lib.tv_list_equal(l1, l6, false)) + eq(false, lib.tv_list_equal(l1, l7, false)) + eq(false, lib.tv_list_equal(l1, l8, false)) + eq(false, lib.tv_list_equal(l1, l9, false)) end) itp('compares lists correctly when case is ignored', function() local l1 = list('abc', { 1, 2, 'Abc' }, 'def') @@ -1319,15 +1312,15 @@ describe('typval.c', function() local l8 = list('abc', nil, 'def') local l9 = list('abc', { 1, 2, nil }, 'def') - eq(true, lib.tv_list_equal(l1, l1, true, false)) - eq(false, lib.tv_list_equal(l1, l2, true, false)) - eq(true, lib.tv_list_equal(l1, l3, true, false)) - eq(false, lib.tv_list_equal(l1, l4, true, false)) - eq(true, lib.tv_list_equal(l1, l5, true, false)) - eq(true, lib.tv_list_equal(l1, l6, true, false)) - eq(true, lib.tv_list_equal(l1, l7, true, false)) - eq(false, lib.tv_list_equal(l1, l8, true, false)) - eq(false, lib.tv_list_equal(l1, l9, true, false)) + eq(true, lib.tv_list_equal(l1, l1, true)) + eq(false, lib.tv_list_equal(l1, l2, true)) + eq(true, lib.tv_list_equal(l1, l3, true)) + eq(false, lib.tv_list_equal(l1, l4, true)) + eq(true, lib.tv_list_equal(l1, l5, true)) + eq(true, lib.tv_list_equal(l1, l6, true)) + eq(true, lib.tv_list_equal(l1, l7, true)) + eq(false, lib.tv_list_equal(l1, l8, true)) + eq(false, lib.tv_list_equal(l1, l9, true)) end) end) describe('find', function() @@ -2448,8 +2441,8 @@ describe('typval.c', function() end) end) describe('equal()', function() - local function tv_dict_equal(d1, d2, ic, recursive) - return lib.tv_dict_equal(d1, d2, ic or false, recursive or false) + local function tv_dict_equal(d1, d2, ic) + return lib.tv_dict_equal(d1, d2, ic or false) end itp('works', function() eq(true, tv_dict_equal(nil, nil)) @@ -2494,7 +2487,6 @@ describe('typval.c', function() eq(true, tv_dict_equal(d_kupper_upper, d_kupper_lower, true)) eq(false, tv_dict_equal(d_kupper_upper, d_lower, true)) eq(false, tv_dict_equal(d_kupper_upper, d_upper, true)) - eq(true, tv_dict_equal(d_upper, d_upper, true, true)) alloc_log:check({}) end) end) @@ -2923,26 +2915,19 @@ describe('typval.c', function() local nl = lua2typvalt(null_list) -- NULL lists are equal to empty lists - eq(true, lib.tv_equal(l, nl, true, false)) - eq(true, lib.tv_equal(nl, l, false, false)) - eq(true, lib.tv_equal(nl, l, false, true)) - eq(true, lib.tv_equal(l, nl, true, true)) + eq(true, lib.tv_equal(l, nl, true)) + eq(true, lib.tv_equal(nl, l, false)) -- NULL lists are equal themselves - eq(true, lib.tv_equal(nl, nl, true, false)) - eq(true, lib.tv_equal(nl, nl, false, false)) - eq(true, lib.tv_equal(nl, nl, false, true)) - eq(true, lib.tv_equal(nl, nl, true, true)) + eq(true, lib.tv_equal(nl, nl, true)) + eq(true, lib.tv_equal(nl, nl, false)) -- As well as empty lists - eq(true, lib.tv_equal(l, l, true, false)) - eq(true, lib.tv_equal(l, l2, false, false)) - eq(true, lib.tv_equal(l2, l, false, true)) - eq(true, lib.tv_equal(l2, l2, true, true)) + eq(true, lib.tv_equal(l, l, true)) + eq(true, lib.tv_equal(l, l2, false)) + eq(true, lib.tv_equal(l2, l, false)) + eq(true, lib.tv_equal(l2, l2, true)) end) - -- Must not use recursive=true argument in the following tests because it - -- indicates that tv_equal_recurse_limit and recursive_cnt were set which - -- is essential. This argument will be set when comparing inner lists. itp('compares lists correctly when case is not ignored', function() local l1 = lua2typvalt({ 'abc', { 1, 2, 'Abc' }, 'def' }) local l2 = lua2typvalt({ 'abc', { 1, 2, 'Abc' } }) @@ -2954,15 +2939,15 @@ describe('typval.c', function() local l8 = lua2typvalt({ 'abc', nil, 'def' }) local l9 = lua2typvalt({ 'abc', { 1, 2, nil }, 'def' }) - eq(true, lib.tv_equal(l1, l1, false, false)) - eq(false, lib.tv_equal(l1, l2, false, false)) - eq(false, lib.tv_equal(l1, l3, false, false)) - eq(false, lib.tv_equal(l1, l4, false, false)) - eq(false, lib.tv_equal(l1, l5, false, false)) - eq(true, lib.tv_equal(l1, l6, false, false)) - eq(false, lib.tv_equal(l1, l7, false, false)) - eq(false, lib.tv_equal(l1, l8, false, false)) - eq(false, lib.tv_equal(l1, l9, false, false)) + eq(true, lib.tv_equal(l1, l1, false)) + eq(false, lib.tv_equal(l1, l2, false)) + eq(false, lib.tv_equal(l1, l3, false)) + eq(false, lib.tv_equal(l1, l4, false)) + eq(false, lib.tv_equal(l1, l5, false)) + eq(true, lib.tv_equal(l1, l6, false)) + eq(false, lib.tv_equal(l1, l7, false)) + eq(false, lib.tv_equal(l1, l8, false)) + eq(false, lib.tv_equal(l1, l9, false)) end) itp('compares lists correctly when case is ignored', function() local l1 = lua2typvalt({ 'abc', { 1, 2, 'Abc' }, 'def' }) @@ -2975,18 +2960,18 @@ describe('typval.c', function() local l8 = lua2typvalt({ 'abc', nil, 'def' }) local l9 = lua2typvalt({ 'abc', { 1, 2, nil }, 'def' }) - eq(true, lib.tv_equal(l1, l1, true, false)) - eq(false, lib.tv_equal(l1, l2, true, false)) - eq(true, lib.tv_equal(l1, l3, true, false)) - eq(false, lib.tv_equal(l1, l4, true, false)) - eq(true, lib.tv_equal(l1, l5, true, false)) - eq(true, lib.tv_equal(l1, l6, true, false)) - eq(true, lib.tv_equal(l1, l7, true, false)) - eq(false, lib.tv_equal(l1, l8, true, false)) - eq(false, lib.tv_equal(l1, l9, true, false)) + eq(true, lib.tv_equal(l1, l1, true)) + eq(false, lib.tv_equal(l1, l2, true)) + eq(true, lib.tv_equal(l1, l3, true)) + eq(false, lib.tv_equal(l1, l4, true)) + eq(true, lib.tv_equal(l1, l5, true)) + eq(true, lib.tv_equal(l1, l6, true)) + eq(true, lib.tv_equal(l1, l7, true)) + eq(false, lib.tv_equal(l1, l8, true)) + eq(false, lib.tv_equal(l1, l9, true)) end) - local function tv_equal(d1, d2, ic, recursive) - return lib.tv_equal(d1, d2, ic or false, recursive or false) + local function tv_equal(d1, d2, ic) + return lib.tv_equal(d1, d2, ic or false) end itp('works with dictionaries', function() local nd = lua2typvalt(null_dict) @@ -3033,7 +3018,6 @@ describe('typval.c', function() eq(true, tv_equal(d_kupper_upper, d_kupper_lower, true)) eq(false, tv_equal(d_kupper_upper, d_lower, true)) eq(false, tv_equal(d_kupper_upper, d_upper, true)) - eq(true, tv_equal(d_upper, d_upper, true, true)) alloc_log:check({}) end) end)