summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-12-22 13:18:39 +0000
committerBram Moolenaar <Bram@vim.org>2021-12-22 13:18:39 +0000
commitfa46ead31abe66494da775921feefece02ce6d95 (patch)
tree61932b619ca1b7c096e4001b23608652310970ea
parent1b5f7a6202406b7d7ac804960602350e42b8be80 (diff)
downloadvim-git-fa46ead31abe66494da775921feefece02ce6d95.tar.gz
patch 8.2.3869: Vim9: type checking for "any" is inconsistentv8.2.3869
Problem: Vim9: type checking for "any" is inconsistent. Solution: Always use a runtime type check for using "any" for a more specific type.
-rw-r--r--src/testdir/test_vim9_func.vim16
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c14
-rw-r--r--src/vim9expr.c3
-rw-r--r--src/vim9type.c26
5 files changed, 35 insertions, 26 deletions
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 81fa7e49c..935079f7a 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -548,7 +548,7 @@ def Test_call_default_args()
END
CheckScriptFailure(lines, 'E1001: Variable not found: b')
- # using script variable requires matching type or type cast
+ # using script variable requires matching type or type cast when executed
lines =<< trim END
vim9script
var a: any
@@ -557,18 +557,8 @@ def Test_call_default_args()
enddef
defcompile
END
- CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got any')
-
- lines =<< trim END
- vim9script
- var a: any
- def Func(arg: string = <string>a)
- echo arg
- enddef
- a = 'works'
- Func()
- END
- CheckScriptSuccess(lines)
+ CheckScriptSuccess(lines + ['a = "text"', 'Func()'])
+ CheckScriptFailure(lines + ['a = 123', 'Func()'], 'E1013: Argument 1: type mismatch, expected string but got number')
# using global variable does not require type cast
lines =<< trim END
diff --git a/src/version.c b/src/version.c
index 782267f4b..c5877df99 100644
--- a/src/version.c
+++ b/src/version.c
@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 3869,
+/**/
3868,
/**/
3867,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 50fe7e257..7565cfb01 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -366,8 +366,11 @@ use_typecheck(type_T *actual, type_T *expected)
|| (actual->tt_type == VAR_FUNC
&& (expected->tt_type == VAR_FUNC
|| expected->tt_type == VAR_PARTIAL)
- && (actual->tt_member == &t_any || actual->tt_argcount < 0)
- && ((actual->tt_member == &t_void)
+ && (actual->tt_member == &t_any
+ || actual->tt_member == &t_unknown
+ || actual->tt_argcount < 0)
+ && (actual->tt_member == &t_unknown ||
+ (actual->tt_member == &t_void)
== (expected->tt_member == &t_void))))
return TRUE;
if ((actual->tt_type == VAR_LIST || actual->tt_type == VAR_DICT)
@@ -412,8 +415,7 @@ need_type_where(
// If the actual type can be the expected type add a runtime check.
// If it's a constant a runtime check makes no sense.
- if (ret == MAYBE || ((!actual_is_const || actual == &t_any)
- && use_typecheck(actual, expected)))
+ if (!actual_is_const && ret == MAYBE && use_typecheck(actual, expected))
{
generate_TYPECHECK(cctx, expected, offset, where.wt_index);
return OK;
@@ -2547,8 +2549,8 @@ compile_def_function(
did_set_arg_type = TRUE;
ufunc->uf_arg_types[arg_idx] = val_type;
}
- else if (check_type(ufunc->uf_arg_types[arg_idx], val_type,
- TRUE, where) == FAIL)
+ else if (need_type_where(val_type, ufunc->uf_arg_types[arg_idx],
+ -1, where, &cctx, FALSE, FALSE) == FAIL)
goto erret;
if (generate_STORE(&cctx, ISN_STORE, i - count - off, NULL) == FAIL)
diff --git a/src/vim9expr.c b/src/vim9expr.c
index 6fe8e2af1..6a1faf839 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -415,7 +415,7 @@ compile_load(
// Global, Buffer-local, Window-local and Tabpage-local
// variables can be defined later, thus we don't check if it
// exists, give an error at runtime.
- res = generate_LOAD(cctx, isn_type, 0, name, &t_unknown);
+ res = generate_LOAD(cctx, isn_type, 0, name, &t_any);
}
}
}
@@ -2846,6 +2846,7 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
type_T **typep;
generate_ppconst(cctx, ppconst);
+ ppconst->pp_is_const = FALSE;
// If the types differ, the result has a more generic type.
typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
diff --git a/src/vim9type.c b/src/vim9type.c
index 438c51197..4542e1e08 100644
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -477,7 +477,19 @@ check_typval_type(type_T *expected, typval_T *actual_tv, where_T where)
ga_init2(&type_list, sizeof(type_T *), 10);
actual_type = typval2type(actual_tv, get_copyID(), &type_list, TRUE);
if (actual_type != NULL)
- res = check_type(expected, actual_type, TRUE, where);
+ {
+ res = check_type_maybe(expected, actual_type, TRUE, where);
+ if (res == MAYBE && !(actual_type->tt_type == VAR_FUNC
+ && actual_type->tt_member == &t_unknown))
+ {
+ // If a type check is needed that means assigning "any" or
+ // "unknown" to a more specific type, which fails here.
+ // Execpt when it looks like a lambda, since they have an
+ // incomplete type.
+ type_mismatch_where(expected, actual_type, where);
+ res = FAIL;
+ }
+ }
clear_type_list(&type_list);
return res;
}
@@ -567,9 +579,11 @@ check_type_maybe(
{
// tt_type should match, except that a "partial" can be assigned to a
// variable with type "func".
- // And "unknown" (using global variable) needs a runtime type check.
+ // And "unknown" (using global variable) and "any" need a runtime type
+ // check.
if (!(expected->tt_type == actual->tt_type
|| actual->tt_type == VAR_UNKNOWN
+ || actual->tt_type == VAR_ANY
|| (expected->tt_type == VAR_FUNC
&& actual->tt_type == VAR_PARTIAL)))
{
@@ -585,10 +599,10 @@ check_type_maybe(
{
// "unknown" is used for an empty list or dict
if (actual->tt_member != NULL && actual->tt_member != &t_unknown)
- ret = check_type(expected->tt_member, actual->tt_member,
+ ret = check_type_maybe(expected->tt_member, actual->tt_member,
FALSE, where);
}
- else if (expected->tt_type == VAR_FUNC)
+ else if (expected->tt_type == VAR_FUNC && actual != &t_any)
{
// If the return type is unknown it can be anything, including
// nothing, thus there is no point in checking.
@@ -596,8 +610,8 @@ check_type_maybe(
{
if (actual->tt_member != NULL
&& actual->tt_member != &t_unknown)
- ret = check_type(expected->tt_member, actual->tt_member,
- FALSE, where);
+ ret = check_type_maybe(expected->tt_member,
+ actual->tt_member, FALSE, where);
else
ret = MAYBE;
}