# HG changeset patch # User Bram Moolenaar # Date 1586115925 -7200 # Node ID 1f42c49c3d299fbba72bb561650816c97ab960cd # Parent 05ac81e3e8739177f9bc4dc987aa102bc6009c95 patch 8.2.0517: Vim9: cannot separate "func" and "func(): void" Commit: https://github.com/vim/vim/commit/4c68375057c25e99656bc996d3fa5c6b0b6a7e6a Author: Bram Moolenaar Date: Sun Apr 5 21:38:23 2020 +0200 patch 8.2.0517: Vim9: cannot separate "func" and "func(): void" Problem: Vim9: cannot separate "func" and "func(): void". Solution: Use VAR_ANY for "any" and VAR_UNKNOWN for "no type". diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1272,6 +1272,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char switch (tv1->v_type) { case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: case VAR_DICT: case VAR_FUNC: @@ -2967,6 +2968,7 @@ eval_index( emsg(_("E909: Cannot index a special variable")); return FAIL; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: if (evaluate) return FAIL; @@ -3073,6 +3075,7 @@ eval_index( switch (rettv->v_type) { case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: case VAR_FUNC: case VAR_PARTIAL: @@ -3668,7 +3671,7 @@ get_lit_string_tv(char_u **arg, typval_T } /* - * Return the function name of the partial. + * Return the function name of partial "pt". */ char_u * partial_name(partial_T *pt) @@ -3856,6 +3859,7 @@ tv_equal( return tv1->vval.v_string == tv2->vval.v_string; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: break; } @@ -4570,6 +4574,7 @@ echo_string_core( case VAR_NUMBER: case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: *tofree = NULL; r = tv_get_string_buf(tv, numbuf); @@ -5422,6 +5427,7 @@ free_tv(typval_T *varp) #endif case VAR_NUMBER: case VAR_FLOAT: + case VAR_ANY: case VAR_UNKNOWN: case VAR_VOID: case VAR_BOOL: @@ -5486,6 +5492,7 @@ clear_tv(typval_T *varp) varp->vval.v_channel = NULL; #endif case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: break; } @@ -5565,6 +5572,7 @@ tv_get_number_chk(typval_T *varp, int *d emsg(_("E974: Using a Blob as a Number")); break; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: internal_error_no_abort("tv_get_number(UNKNOWN)"); break; @@ -5619,6 +5627,7 @@ tv_get_float(typval_T *varp) emsg(_("E975: Using a Blob as a Float")); break; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: internal_error_no_abort("tv_get_float(UNKNOWN)"); break; @@ -5742,6 +5751,7 @@ tv_get_string_buf_chk(typval_T *varp, ch #endif break; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: emsg(_(e_inval_string)); break; @@ -5891,6 +5901,7 @@ copy_tv(typval_T *from, typval_T *to) } break; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: internal_error_no_abort("copy_tv(UNKNOWN)"); break; @@ -5970,6 +5981,7 @@ item_copy( ret = FAIL; break; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: internal_error_no_abort("item_copy(UNKNOWN)"); ret = FAIL; diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2042,6 +2042,7 @@ f_empty(typval_T *argvars, typval_T *ret break; #endif case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: internal_error_no_abort("f_empty(UNKNOWN)"); n = TRUE; @@ -5217,6 +5218,7 @@ f_len(typval_T *argvars, typval_T *rettv rettv->vval.v_number = dict_len(argvars[0].vval.v_dict); break; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: case VAR_BOOL: case VAR_SPECIAL: @@ -8805,6 +8807,7 @@ f_type(typval_T *argvars, typval_T *rett case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break; case VAR_BLOB: n = VAR_TYPE_BLOB; break; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: internal_error_no_abort("f_type(UNKNOWN)"); n = -1; diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -1668,6 +1668,7 @@ item_lock(typval_T *tv, int deep, int lo switch (tv->v_type) { case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: case VAR_NUMBER: case VAR_BOOL: diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -379,7 +379,8 @@ EXTERN sctx_T current_sctx INIT4(0, 0, 0 // Commonly used types. -EXTERN type_T t_any INIT6(VAR_UNKNOWN, 0, 0, 0, NULL, NULL); +EXTERN type_T t_unknown INIT6(VAR_UNKNOWN, 0, 0, 0, NULL, NULL); +EXTERN type_T t_any INIT6(VAR_ANY, 0, 0, 0, NULL, NULL); EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, 0, NULL, NULL); EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, 0, NULL, NULL); EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, 0, NULL, NULL); @@ -390,6 +391,7 @@ EXTERN type_T t_blob INIT6(VAR_BLOB, 0, EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, 0, NULL, NULL); EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, 0, NULL, NULL); +EXTERN type_T t_func_unknown INIT6(VAR_FUNC, -1, 0, 0, &t_unknown, NULL); EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, 0, &t_void, NULL); EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, 0, &t_any, NULL); EXTERN type_T t_func_number INIT6(VAR_FUNC, -1, 0, 0, &t_number, NULL); @@ -401,8 +403,8 @@ EXTERN type_T t_func_0_string INIT6(VAR_ EXTERN type_T t_list_any INIT6(VAR_LIST, 0, 0, 0, &t_any, NULL); EXTERN type_T t_dict_any INIT6(VAR_DICT, 0, 0, 0, &t_any, NULL); -EXTERN type_T t_list_empty INIT6(VAR_LIST, 0, 0, 0, &t_void, NULL); -EXTERN type_T t_dict_empty INIT6(VAR_DICT, 0, 0, 0, &t_void, NULL); +EXTERN type_T t_list_empty INIT6(VAR_LIST, 0, 0, 0, &t_unknown, NULL); +EXTERN type_T t_dict_empty INIT6(VAR_DICT, 0, 0, 0, &t_unknown, NULL); EXTERN type_T t_list_bool INIT6(VAR_LIST, 0, 0, 0, &t_bool, NULL); EXTERN type_T t_list_number INIT6(VAR_LIST, 0, 0, 0, &t_number, NULL); diff --git a/src/if_py_both.h b/src/if_py_both.h --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -6390,6 +6390,7 @@ ConvertToPyObject(typval_T *tv) (char*) tv->vval.v_blob->bv_ga.ga_data, (Py_ssize_t) tv->vval.v_blob->bv_ga.ga_len); case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: case VAR_CHANNEL: case VAR_JOB: diff --git a/src/json.c b/src/json.c --- a/src/json.c +++ b/src/json.c @@ -351,6 +351,7 @@ json_encode_item(garray_T *gap, typval_T break; #endif case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: internal_error_no_abort("json_encode_item()"); return FAIL; diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1321,8 +1321,9 @@ typedef struct cctx_S cctx_T; typedef enum { - VAR_UNKNOWN = 0, // not set, also used for "any" type - VAR_VOID, // no value + VAR_UNKNOWN = 0, // not set, any type or "void" allowed + VAR_ANY, // used for "any" type + VAR_VOID, // no value (function not returning anything) VAR_BOOL, // "v_number" is used: VVAL_TRUE or VVAL_FALSE VAR_SPECIAL, // "v_number" is used: VVAL_NULL or VVAL_NONE VAR_NUMBER, // "v_number" is used diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -386,6 +386,27 @@ def Test_func_type() Ref1 = FuncNoArgNoRet Ref1() assert_equal(11, funcResult) + + let Ref2: func + funcResult = 0 + Ref2 = FuncNoArgNoRet + Ref2() + assert_equal(11, funcResult) + + funcResult = 0 + Ref2 = FuncOneArgNoRet + Ref2(12) + assert_equal(12, funcResult) + + funcResult = 0 + Ref2 = FuncNoArgRetNumber + assert_equal(1234, Ref2()) + assert_equal(22, funcResult) + + funcResult = 0 + Ref2 = FuncOneArgRetNumber + assert_equal(13, Ref2(13)) + assert_equal(13, funcResult) enddef def Test_func_type_fails() diff --git a/src/testing.c b/src/testing.c --- a/src/testing.c +++ b/src/testing.c @@ -764,6 +764,7 @@ f_test_refcount(typval_T *argvars, typva switch (argvars[0].v_type) { case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: case VAR_NUMBER: case VAR_BOOL: diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 517, +/**/ 516, /**/ 515, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -249,9 +249,10 @@ get_list_type(type_T *member_type, garra type_T *type; // recognize commonly used types - if (member_type->tt_type == VAR_UNKNOWN) + if (member_type->tt_type == VAR_ANY) return &t_list_any; - if (member_type->tt_type == VAR_VOID) + if (member_type->tt_type == VAR_VOID + || member_type->tt_type == VAR_UNKNOWN) return &t_list_empty; if (member_type->tt_type == VAR_BOOL) return &t_list_bool; @@ -277,9 +278,10 @@ get_dict_type(type_T *member_type, garra type_T *type; // recognize commonly used types - if (member_type->tt_type == VAR_UNKNOWN) + if (member_type->tt_type == VAR_ANY) return &t_dict_any; - if (member_type->tt_type == VAR_VOID) + if (member_type->tt_type == VAR_VOID + || member_type->tt_type == VAR_UNKNOWN) return &t_dict_empty; if (member_type->tt_type == VAR_BOOL) return &t_dict_bool; @@ -482,9 +484,9 @@ may_generate_2STRING(int offset, cctx_T static int check_number_or_float(vartype_T type1, vartype_T type2, char_u *op) { - if (!((type1 == VAR_NUMBER || type1 == VAR_FLOAT || type1 == VAR_UNKNOWN) + if (!((type1 == VAR_NUMBER || type1 == VAR_FLOAT || type1 == VAR_ANY) && (type2 == VAR_NUMBER || type2 == VAR_FLOAT - || type2 == VAR_UNKNOWN))) + || type2 == VAR_ANY))) { if (*op == '+') emsg(_("E1035: wrong argument type for +")); @@ -515,7 +517,7 @@ generate_two_op(cctx_T *cctx, char_u *op // checking. type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]; type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]; - vartype = VAR_UNKNOWN; + vartype = VAR_ANY; if (type1->tt_type == type2->tt_type && (type1->tt_type == VAR_NUMBER || type1->tt_type == VAR_LIST @@ -528,8 +530,8 @@ generate_two_op(cctx_T *cctx, char_u *op switch (*op) { case '+': if (vartype != VAR_LIST && vartype != VAR_BLOB - && type1->tt_type != VAR_UNKNOWN - && type2->tt_type != VAR_UNKNOWN + && type1->tt_type != VAR_ANY + && type2->tt_type != VAR_ANY && check_number_or_float( type1->tt_type, type2->tt_type, op) == FAIL) return FAIL; @@ -563,9 +565,9 @@ generate_two_op(cctx_T *cctx, char_u *op ? EXPR_MULT : *op == '/'? EXPR_DIV : EXPR_SUB; break; - case '%': if ((type1->tt_type != VAR_UNKNOWN + case '%': if ((type1->tt_type != VAR_ANY && type1->tt_type != VAR_NUMBER) - || (type2->tt_type != VAR_UNKNOWN + || (type2->tt_type != VAR_ANY && type2->tt_type != VAR_NUMBER)) { emsg(_("E1035: % requires number arguments")); @@ -579,7 +581,7 @@ generate_two_op(cctx_T *cctx, char_u *op } // correct type of result - if (vartype == VAR_UNKNOWN) + if (vartype == VAR_ANY) { type_T *type = &t_any; @@ -614,6 +616,11 @@ generate_COMPARE(cctx_T *cctx, exptype_T // checking. type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]->tt_type; type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type; + if (type1 == VAR_UNKNOWN) + type1 = VAR_ANY; + if (type2 == VAR_UNKNOWN) + type2 = VAR_ANY; + if (type1 == type2) { switch (type1) @@ -631,7 +638,7 @@ generate_COMPARE(cctx_T *cctx, exptype_T default: isntype = ISN_COMPAREANY; break; } } - else if (type1 == VAR_UNKNOWN || type2 == VAR_UNKNOWN + else if (type1 == VAR_ANY || type2 == VAR_ANY || ((type1 == VAR_NUMBER || type1 == VAR_FLOAT) && (type2 == VAR_NUMBER || type2 ==VAR_FLOAT))) isntype = ISN_COMPAREANY; @@ -1723,8 +1730,9 @@ equal_type(type_T *type1, type_T *type2) return FALSE; switch (type1->tt_type) { + case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: - case VAR_UNKNOWN: case VAR_SPECIAL: case VAR_BOOL: case VAR_NUMBER: @@ -1785,6 +1793,7 @@ vartype_name(vartype_T type) switch (type) { case VAR_UNKNOWN: break; + case VAR_ANY: return "any"; case VAR_VOID: return "void"; case VAR_SPECIAL: return "special"; case VAR_BOOL: return "bool"; @@ -1799,7 +1808,7 @@ vartype_name(vartype_T type) case VAR_FUNC: return "func"; case VAR_PARTIAL: return "partial"; } - return "any"; + return "unknown"; } /* @@ -2396,7 +2405,7 @@ check_type(type_T *expected, type_T *act { int ret = OK; - if (expected->tt_type != VAR_UNKNOWN) + if (expected->tt_type != VAR_UNKNOWN && expected->tt_type != VAR_ANY) { if (expected->tt_type != actual->tt_type) { @@ -2406,13 +2415,14 @@ check_type(type_T *expected, type_T *act } if (expected->tt_type == VAR_DICT || expected->tt_type == VAR_LIST) { - // void is used for an empty list or dict - if (actual->tt_member != &t_void) + // "unknown" is used for an empty list or dict + if (actual->tt_member != &t_unknown) ret = check_type(expected->tt_member, actual->tt_member, FALSE); } else if (expected->tt_type == VAR_FUNC) { - if (expected->tt_member != &t_any) + if (expected->tt_member != &t_any + && expected->tt_member != &t_unknown) ret = check_type(expected->tt_member, actual->tt_member, FALSE); if (ret == OK && expected->tt_argcount != -1 && (actual->tt_argcount < expected->tt_min_argcount @@ -2436,7 +2446,7 @@ need_type(type_T *actual, type_T *expect { if (check_type(expected, actual, FALSE)) return OK; - if (actual->tt_type != VAR_UNKNOWN) + if (actual->tt_type != VAR_ANY && actual->tt_type != VAR_UNKNOWN) { type_mismatch(expected, actual); return FAIL; @@ -3642,7 +3652,8 @@ compile_return(char_u *arg, int set_retu { // "set_return_type" cannot be TRUE, only used for a lambda which // always has an argument. - if (cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_VOID) + if (cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_VOID + && cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_UNKNOWN) { emsg(_("E1003: Missing return value")); return NULL; @@ -3936,7 +3947,7 @@ compile_assignment(char_u *arg, exarg_T } if (oplen == 3 && !heredoc && dest != dest_global - && type->tt_type != VAR_STRING && type->tt_type != VAR_UNKNOWN) + && type->tt_type != VAR_STRING && type->tt_type != VAR_ANY) { emsg(_("E1019: Can only concatenate to string")); goto theend; @@ -4115,6 +4126,7 @@ compile_assignment(char_u *arg, exarg_T break; case VAR_NUMBER: case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: case VAR_SPECIAL: // cannot happen generate_PUSHNR(cctx, 0); @@ -4903,7 +4915,7 @@ compile_for(char_u *arg, cctx_T *cctx) drop_scope(cctx); return NULL; } - if (vartype->tt_member->tt_type != VAR_UNKNOWN) + if (vartype->tt_member->tt_type != VAR_ANY) { lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + var_idx; diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2239,6 +2239,7 @@ tv2bool(typval_T *tv) case VAR_BLOB: return tv->vval.v_blob != NULL && tv->vval.v_blob->bv_ga.ga_len > 0; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: break; } diff --git a/src/viminfo.c b/src/viminfo.c --- a/src/viminfo.c +++ b/src/viminfo.c @@ -1344,6 +1344,7 @@ write_viminfo_varlist(FILE *fp) case VAR_SPECIAL: s = "XPL"; break; case VAR_UNKNOWN: + case VAR_ANY: case VAR_VOID: case VAR_FUNC: case VAR_PARTIAL: