mirror of
https://github.com/neovim/neovim.git
synced 2025-09-19 17:58:18 +00:00
vim-patch:7.4.1875
Problem: Comparing functions and partials doesn't work well.
Solution: Add tests. (Nikolai Pavlov) Compare the dict and arguments in the
partial.
8e759ba865
This commit is contained in:

committed by
James McCoy

parent
b42347da45
commit
6c5dd6827f
105
src/nvim/eval.c
105
src/nvim/eval.c
@@ -3771,7 +3771,26 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
|
||||
clear_tv(&var2);
|
||||
return FAIL;
|
||||
}
|
||||
n1 = tv_equal(rettv, &var2, false, false);
|
||||
if ((rettv->v_type == VAR_PARTIAL
|
||||
&& rettv->vval.v_partial == NULL)
|
||||
|| (var2.v_type == VAR_PARTIAL
|
||||
&& var2.vval.v_partial == NULL)) {
|
||||
// when a partial is NULL assume not equal
|
||||
n1 = false;
|
||||
} else if (type_is) {
|
||||
if (rettv->v_type == VAR_FUNC && var2.v_type == VAR_FUNC) {
|
||||
// strings are considered the same if their value is
|
||||
// the same
|
||||
n1 = tv_equal(rettv, &var2, ic, false);
|
||||
} else if (rettv->v_type == VAR_PARTIAL
|
||||
&& var2.v_type == VAR_PARTIAL) {
|
||||
n1 = (rettv->vval.v_partial == var2.vval.v_partial);
|
||||
} else {
|
||||
n1 = false;
|
||||
}
|
||||
} else {
|
||||
n1 = tv_equal(rettv, &var2, ic, false);
|
||||
}
|
||||
if (type == TYPE_NEQUAL) {
|
||||
n1 = !n1;
|
||||
}
|
||||
@@ -5151,6 +5170,61 @@ dict_equal (
|
||||
|
||||
static int tv_equal_recurse_limit;
|
||||
|
||||
static int func_equal(
|
||||
typval_T *tv1,
|
||||
typval_T *tv2,
|
||||
int ic // ignore case
|
||||
) {
|
||||
char_u *s1, *s2;
|
||||
dict_T *d1, *d2;
|
||||
int a1, a2;
|
||||
int i;
|
||||
|
||||
// empty and NULL function name considered the same
|
||||
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
|
||||
: tv1->vval.v_partial->pt_name;
|
||||
if (s1 != NULL && *s1 == NUL) {
|
||||
s1 = NULL;
|
||||
}
|
||||
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
|
||||
: tv2->vval.v_partial->pt_name;
|
||||
if (s2 != NULL && *s2 == NUL) {
|
||||
s2 = NULL;
|
||||
}
|
||||
if (s1 == NULL || s2 == NULL) {
|
||||
if (s1 != s2) {
|
||||
return false;
|
||||
}
|
||||
} else if (STRCMP(s1, s2) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// empty dict and NULL dict is different
|
||||
d1 = tv1->v_type == VAR_FUNC ? NULL : tv1->vval.v_partial->pt_dict;
|
||||
d2 = tv2->v_type == VAR_FUNC ? NULL : tv2->vval.v_partial->pt_dict;
|
||||
if (d1 == NULL || d2 == NULL) {
|
||||
if (d1 != d2) {
|
||||
return false;
|
||||
}
|
||||
} else if (!dict_equal(d1, d2, ic, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// empty list and no list considered the same
|
||||
a1 = tv1->v_type == VAR_FUNC ? 0 : tv1->vval.v_partial->pt_argc;
|
||||
a2 = tv2->v_type == VAR_FUNC ? 0 : tv2->vval.v_partial->pt_argc;
|
||||
if (a1 != a2) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < a1; i++) {
|
||||
if (!tv_equal(tv1->vval.v_partial->pt_argv + i,
|
||||
tv2->vval.v_partial->pt_argv + i, ic, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if "tv1" and "tv2" have the same value.
|
||||
* Compares the items just like "==" would compare them, but strings and
|
||||
@@ -5169,21 +5243,6 @@ tv_equal (
|
||||
static int recursive_cnt = 0; /* catch recursive loops */
|
||||
int r;
|
||||
|
||||
// For VAR_FUNC and VAR_PARTIAL only compare the function name.
|
||||
if ((tv1->v_type == VAR_FUNC
|
||||
|| (tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial != NULL))
|
||||
&& (tv2->v_type == VAR_FUNC
|
||||
|| (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial != NULL))) {
|
||||
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
|
||||
: tv1->vval.v_partial->pt_name;
|
||||
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
|
||||
: tv2->vval.v_partial->pt_name;
|
||||
return (s1 != NULL && s2 != NULL && STRCMP(s1, s2) == 0);
|
||||
}
|
||||
if (tv1->v_type != tv2->v_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Catch lists and dicts that have an endless loop by limiting
|
||||
* recursiveness to a limit. We guess they are equal then.
|
||||
* A fixed limit has the problem of still taking an awful long time.
|
||||
@@ -5197,6 +5256,20 @@ tv_equal (
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// For VAR_FUNC and VAR_PARTIAL only compare the function name.
|
||||
if ((tv1->v_type == VAR_FUNC
|
||||
|| (tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial != NULL))
|
||||
&& (tv2->v_type == VAR_FUNC
|
||||
|| (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial != NULL))) {
|
||||
recursive_cnt++;
|
||||
r = func_equal(tv1, tv2, ic);
|
||||
recursive_cnt--;
|
||||
return r;
|
||||
}
|
||||
if (tv1->v_type != tv2->v_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (tv1->v_type) {
|
||||
case VAR_LIST:
|
||||
++recursive_cnt;
|
||||
|
@@ -265,3 +265,66 @@ func Test_get_partial_items()
|
||||
call assert_equal([], get(Func, 'args'))
|
||||
call assert_true(empty( get(Func, 'dict')))
|
||||
endfunc
|
||||
|
||||
func Test_compare_partials()
|
||||
let d1 = {}
|
||||
let d2 = {}
|
||||
|
||||
function d1.f1() dict
|
||||
endfunction
|
||||
|
||||
function d1.f2() dict
|
||||
endfunction
|
||||
|
||||
let F1 = get(d1, 'f1')
|
||||
let F2 = get(d1, 'f2')
|
||||
|
||||
let F1d1 = function(F1, d1)
|
||||
let F2d1 = function(F2, d2)
|
||||
let F1d1a1 = function(F1d1, [1])
|
||||
let F1d1a12 = function(F1d1, [1, 2])
|
||||
let F1a1 = function(F1, [1])
|
||||
let F1a2 = function(F1, [2])
|
||||
let F1d2 = function(F1, d2)
|
||||
let d3 = {'f1': F1, 'f2': F2}
|
||||
let F1d3 = function(F1, d3)
|
||||
let F1ad1 = function(F1, [d1])
|
||||
let F1ad3 = function(F1, [d3])
|
||||
|
||||
call assert_match('^function(''\d\+'')$', string(F1)) " Not a partial
|
||||
call assert_match('^function(''\d\+'')$', string(F2)) " Not a partial
|
||||
call assert_match('^function(''\d\+'', {.*})$', string(F1d1)) " A partial
|
||||
call assert_match('^function(''\d\+'', {.*})$', string(F2d1)) " A partial
|
||||
call assert_match('^function(''\d\+'', \[.*\])$', string(F1a1)) " No dict
|
||||
|
||||
" !=
|
||||
let X = F1
|
||||
call assert_false(F1 != X) " same function
|
||||
let X = F1d1
|
||||
call assert_false(F1d1 != X) " same partial
|
||||
let X = F1d1a1
|
||||
call assert_false(F1d1a1 != X) " same partial
|
||||
let X = F1a1
|
||||
call assert_false(F1a1 != X) " same partial
|
||||
|
||||
call assert_true(F1 != F2) " Different functions
|
||||
call assert_true(F1 != F1d1) " Partial /= non-partial
|
||||
call assert_true(F1d1a1 != F1d1a12) " Different number of arguments
|
||||
call assert_true(F1a1 != F1d1a12) " One has no dict
|
||||
call assert_true(F1a1 != F1a2) " Different arguments
|
||||
call assert_true(F1d2 != F1d1) " Different dictionaries
|
||||
call assert_false(F1d1 != F1d3) " Equal dictionaries, even though d1 isnot d3
|
||||
|
||||
" isnot, option 1
|
||||
call assert_true(F1 isnot# F2) " Different functions
|
||||
call assert_true(F1 isnot# F1d1) " Partial /= non-partial
|
||||
call assert_true(F1d1 isnot# F1d3) " d1 isnot d3, even though d1 == d3
|
||||
call assert_true(F1a1 isnot# F1d1a12) " One has no dict
|
||||
call assert_true(F1a1 isnot# F1a2) " Different number of arguments
|
||||
call assert_true(F1ad1 isnot# F1ad3) " In arguments d1 isnot d3
|
||||
|
||||
" isnot, option 2
|
||||
call assert_true(F1 isnot# F2) " Different functions
|
||||
call assert_true(F1 isnot# F1d1) " Partial /= non-partial
|
||||
call assert_true(d1.f1 isnot# d1.f1) " handle_subscript creates new partial each time
|
||||
endfunc
|
||||
|
@@ -565,7 +565,7 @@ static int included_patches[] = {
|
||||
// 1878 NA
|
||||
// 1877 NA
|
||||
// 1876,
|
||||
// 1875,
|
||||
1875,
|
||||
// 1874 NA
|
||||
// 1873 NA
|
||||
// 1872 NA
|
||||
|
Reference in New Issue
Block a user