Problem: Vim9: cannot separate "func" and "func(): void".
Solution: Use VAR_ANY for "any" and VAR_UNKNOWN for "no type".
switch (tv1->v_type)
{
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
case VAR_DICT:
case VAR_FUNC:
emsg(_("E909: Cannot index a special variable"));
return FAIL;
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
if (evaluate)
return FAIL;
switch (rettv->v_type)
{
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
case VAR_FUNC:
case VAR_PARTIAL:
}
/*
- * Return the function name of the partial.
+ * Return the function name of partial "pt".
*/
char_u *
partial_name(partial_T *pt)
return tv1->vval.v_string == tv2->vval.v_string;
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
break;
}
case VAR_NUMBER:
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
*tofree = NULL;
r = tv_get_string_buf(tv, numbuf);
#endif
case VAR_NUMBER:
case VAR_FLOAT:
+ case VAR_ANY:
case VAR_UNKNOWN:
case VAR_VOID:
case VAR_BOOL:
varp->vval.v_channel = NULL;
#endif
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
break;
}
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;
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;
#endif
break;
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
emsg(_(e_inval_string));
break;
}
break;
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
internal_error_no_abort("copy_tv(UNKNOWN)");
break;
ret = FAIL;
break;
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
internal_error_no_abort("item_copy(UNKNOWN)");
ret = FAIL;
break;
#endif
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
internal_error_no_abort("f_empty(UNKNOWN)");
n = TRUE;
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:
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;
switch (tv->v_type)
{
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
case VAR_NUMBER:
case VAR_BOOL:
// 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);
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);
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);
(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:
break;
#endif
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
internal_error_no_abort("json_encode_item()");
return FAIL;
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
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()
switch (argvars[0].v_type)
{
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
case VAR_NUMBER:
case VAR_BOOL:
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 517,
/**/
516,
/**/
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;
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;
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 +"));
// 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
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;
? 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"));
}
// correct type of result
- if (vartype == VAR_UNKNOWN)
+ if (vartype == VAR_ANY)
{
type_T *type = &t_any;
// 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)
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;
return FALSE;
switch (type1->tt_type)
{
- case VAR_VOID:
case VAR_UNKNOWN:
+ case VAR_ANY:
+ case VAR_VOID:
case VAR_SPECIAL:
case VAR_BOOL:
case VAR_NUMBER:
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";
case VAR_FUNC: return "func";
case VAR_PARTIAL: return "partial";
}
- return "any";
+ return "unknown";
}
/*
{
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)
{
}
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
{
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;
{
// "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;
}
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;
break;
case VAR_NUMBER:
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
case VAR_SPECIAL: // cannot happen
generate_PUSHNR(cctx, 0);
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;
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;
}
case VAR_SPECIAL: s = "XPL"; break;
case VAR_UNKNOWN:
+ case VAR_ANY:
case VAR_VOID:
case VAR_FUNC:
case VAR_PARTIAL: