patch 9.0.2184: Vim9: inconsistent :type/:class messages

Problem:  Vim9: inconsistent :type/:class messages
Solution: Update the Messages (Ernie Rael)

closes: #13706

Signed-off-by: Ernie Rael <errael@raelity.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Ernie Rael
2023-12-21 17:18:54 +01:00
committed by Christian Brabandt
parent 18ab6c3392
commit e75fde6b04
13 changed files with 92 additions and 90 deletions

View File

@ -1890,10 +1890,8 @@ set_var_lval(
if (eval_variable(lp->ll_name, (int)STRLEN(lp->ll_name),
lp->ll_sid, &tv, &di, EVAL_VAR_VERBOSE) == OK)
{
if (di != NULL && di->di_tv.v_type == VAR_TYPEALIAS)
if (di != NULL && check_typval_is_value(&di->di_tv) == FAIL)
{
semsg(_(e_cannot_modify_typealias),
di->di_tv.vval.v_typealias->ta_name);
clear_tv(&tv);
return;
}
@ -2007,9 +2005,10 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
char_u *s;
int failed = FALSE;
// Can't do anything with a Funcref or Dict on the right.
// Can't do anything with a Funcref or Dict or Type on the right.
// v:true and friends only work with "..=".
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT
&& tv2->v_type != VAR_CLASS && tv2->v_type != VAR_TYPEALIAS
&& ((tv2->v_type != VAR_BOOL && tv2->v_type != VAR_SPECIAL)
|| *op == '.'))
{
@ -2026,10 +2025,12 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
case VAR_JOB:
case VAR_CHANNEL:
case VAR_INSTR:
case VAR_CLASS:
case VAR_OBJECT:
case VAR_TYPEALIAS:
break;
case VAR_CLASS:
case VAR_TYPEALIAS:
check_typval_is_value(tv1);
return FAIL;
case VAR_BLOB:
if (*op != '+' || tv2->v_type != VAR_BLOB)
@ -2142,6 +2143,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
}
}
if (check_typval_is_value(tv2) == OK)
semsg(_(e_wrong_variable_type_for_str_equal), op);
return FAIL;
}
@ -5019,12 +5021,15 @@ check_can_index(typval_T *rettv, int evaluate, int verbose)
case VAR_JOB:
case VAR_CHANNEL:
case VAR_INSTR:
case VAR_CLASS:
case VAR_OBJECT:
case VAR_TYPEALIAS:
if (verbose)
emsg(_(e_cannot_index_special_variable));
return FAIL;
case VAR_CLASS:
case VAR_TYPEALIAS:
if (verbose)
check_typval_is_value(rettv);
return FAIL;
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:

View File

@ -3974,12 +3974,8 @@ set_var_const(
goto failed;
}
if (di->di_tv.v_type == VAR_TYPEALIAS)
{
semsg(_(e_cannot_modify_typealias),
di->di_tv.vval.v_typealias->ta_name);
if (check_typval_is_value(&di->di_tv) == FAIL)
goto failed;
}
if (var_in_vim9script && (flags & ASSIGN_FOR_LOOP) == 0)
{

View File

@ -3090,18 +3090,18 @@ def Test_type_check()
assert_fails('l = N', 'E1012: Type mismatch; expected list<number> but got number')
assert_fails('b = N', 'E1012: Type mismatch; expected blob but got number')
assert_fails('Fn = N', 'E1012: Type mismatch; expected func(...): unknown but got number')
assert_fails('A = N', 'E1012: Type mismatch; expected class<A> but got number')
assert_fails('A = N', 'E1405: Class "A" cannot be used as a value')
assert_fails('o = N', 'E1012: Type mismatch; expected object<A> but got number')
assert_fails('T = N', 'E1395: Type alias "T" cannot be modified')
assert_fails('T = N', 'E1403: Type alias "T" cannot be used as a value')
# Use a compound operator with different LHS types
assert_fails('d += N', 'E734: Wrong variable type for +=')
assert_fails('l += N', 'E734: Wrong variable type for +=')
assert_fails('b += N', 'E734: Wrong variable type for +=')
assert_fails('Fn += N', 'E734: Wrong variable type for +=')
assert_fails('A += N', 'E734: Wrong variable type for +=')
assert_fails('A += N', 'E1405: Class "A" cannot be used as a value')
assert_fails('o += N', 'E734: Wrong variable type for +=')
assert_fails('T += N', 'E1395: Type alias "T" cannot be modified')
assert_fails('T += N', 'E1403: Type alias "T" cannot be used as a value')
# Assign to a number variable
assert_fails('N = d', 'E1012: Type mismatch; expected number but got dict<number>')
@ -3144,9 +3144,9 @@ def Test_type_check()
assert_fails('l ..= S', 'E734: Wrong variable type for .=')
assert_fails('b ..= S', 'E734: Wrong variable type for .=')
assert_fails('Fn ..= S', 'E734: Wrong variable type for .=')
assert_fails('A ..= S', 'E734: Wrong variable type for .=')
assert_fails('A ..= S', 'E1405: Class "A" cannot be used as a value')
assert_fails('o ..= S', 'E734: Wrong variable type for .=')
assert_fails('T ..= S', 'E1395: Type alias "T" cannot be modified')
assert_fails('T ..= S', 'E1403: Type alias "T" cannot be used as a value')
END
v9.CheckSourceSuccess(lines)

View File

@ -242,7 +242,7 @@ def Test_class_basic()
if A
endif
END
v9.CheckSourceFailure(lines, 'E1319: Using a Class as a Number', 4)
v9.CheckSourceFailure(lines, 'E1405: Class "A" cannot be used as a value', 4)
# Test for using object as a bool
lines =<< trim END
@ -281,7 +281,7 @@ def Test_class_basic()
endclass
:exe 'call ' .. A
END
v9.CheckSourceFailure(lines, 'E1323: Using a Class as a String', 4)
v9.CheckSourceFailure(lines, 'E1405: Class "A" cannot be used as a value', 4)
# Test for using object as a string
lines =<< trim END

View File

@ -3193,7 +3193,7 @@ def Test_disassemble_ifargnotset()
unlet g:instr
enddef
" Disassemble instructions for ISN_COMPARECLASS and ISN_COMPAREOBJECT
" Disassemble instructions for ISN_COMPAREOBJECT
def Test_disassemble_compare_class_object()
var lines =<< trim END
vim9script
@ -3202,8 +3202,6 @@ def Test_disassemble_compare_class_object()
class B
endclass
def Foo(a: A, b: B)
if A == B
endif
if a == b
endif
enddef
@ -3211,19 +3209,13 @@ def Test_disassemble_compare_class_object()
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Foo\_s*' ..
'if A == B\_s*' ..
'0 LOADSCRIPT A-0 from .*\_s*' ..
'1 LOADSCRIPT B-1 from .*\_s*' ..
'2 COMPARECLASS ==\_s*' ..
'if a == b\_s*' ..
'0 LOAD arg\[-2\]\_s*' ..
'1 LOAD arg\[-1\]\_s*' ..
'2 COMPAREOBJECT ==\_s*' ..
'3 JUMP_IF_FALSE -> 4\_s*' ..
'endif\_s*' ..
'if a == b\_s*' ..
'4 LOAD arg\[-2\]\_s*' ..
'5 LOAD arg\[-1\]\_s*' ..
'6 COMPAREOBJECT ==\_s*' ..
'7 JUMP_IF_FALSE -> 8\_s*' ..
'endif\_s*' ..
'8 RETURN void', g:instr)
'4 RETURN void', g:instr)
unlet g:instr
enddef

View File

@ -18,7 +18,7 @@ def Test_typealias()
assert_equal('typealias<list<string>>', typename(ListOfStrings))
assert_equal(v:t_typealias, type(ListOfStrings))
assert_equal('ListOfStrings', string(ListOfStrings))
assert_equal(false, null == ListOfStrings)
assert_fails('var x = null == ListOfStrings', 'E1403: Type alias "ListOfStrings" cannot be used as a value')
END
v9.CheckSourceSuccess(lines)
@ -36,7 +36,7 @@ def Test_typealias()
assert_equal('typealias<list<string>>', typename(ListOfStrings))
assert_equal(v:t_typealias, type(ListOfStrings))
assert_equal('ListOfStrings', string(ListOfStrings))
assert_equal(false, null == ListOfStrings)
#assert_equal(false, null == ListOfStrings)
enddef
Bar()
END
@ -201,7 +201,7 @@ def Test_typealias()
type MyType = list<number>
MyType = [1, 2, 3]
END
v9.CheckSourceFailure(lines, 'E1395: Type alias "MyType" cannot be modified', 3)
v9.CheckSourceFailure(lines, 'E1403: Type alias "MyType" cannot be used as a value', 3)
# Assigning a type alias (def function level)
lines =<< trim END
@ -219,11 +219,11 @@ def Test_typealias()
vim9script
type MyType = list<number>
assert_fails('var m = MyType', 'E1403: Type alias "MyType" cannot be used as a value')
assert_fails('var i = MyType + 1', 'E1400: Using type alias "MyType" as a Number')
assert_fails('var f = 1.0 + MyType', 'E1400: Using type alias "MyType" as a Number')
assert_fails('MyType += 10', 'E1395: Type alias "MyType" cannot be modified')
assert_fails('var x = $"-{MyType}-"', 'E1402: Using type alias "MyType" as a String')
assert_fails('var x = MyType[1]', 'E909: Cannot index a special variable')
assert_fails('var i = MyType + 1', 'E1403: Type alias "MyType" cannot be used as a value')
assert_fails('var f = 1.0 + MyType', 'E1403: Type alias "MyType" cannot be used as a value')
assert_fails('MyType += 10', 'E1403: Type alias "MyType" cannot be used as a value')
assert_fails('var x = $"-{MyType}-"', 'E1403: Type alias "MyType" cannot be used as a value')
assert_fails('var x = MyType[1]', 'E1403: Type alias "MyType" cannot be used as a value')
END
v9.CheckSourceSuccess(lines)
@ -236,7 +236,7 @@ def Test_typealias()
enddef
Foo()
END
v9.CheckSourceFailure(lines, 'E1051: Wrong argument type for +', 1)
v9.CheckSourceFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
# Using type alias in an expression (def function level)
lines =<< trim END
@ -305,7 +305,7 @@ def Test_typealias()
var n: number
var x = A == n
END
v9.CheckSourceFailure(lines, 'E1072: Cannot compare typealias with number', 4)
v9.CheckSourceFailure(lines, 'E1403: Type alias "A" cannot be used as a value', 4)
# Comparing type alias with a number (def function level)
lines =<< trim END
@ -317,7 +317,7 @@ def Test_typealias()
enddef
Foo()
END
v9.CheckSourceFailure(lines, 'E1072: Cannot compare typealias with number', 2)
v9.CheckSourceFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 2)
# casting a number to a type alias (script level)
lines =<< trim END

View File

@ -262,7 +262,8 @@ tv_get_bool_or_number_chk(
emsg(_(e_using_blob_as_number));
break;
case VAR_CLASS:
emsg(_(e_using_class_as_number));
case VAR_TYPEALIAS:
check_typval_is_value(varp);
break;
case VAR_OBJECT:
emsg(_(e_using_object_as_number));
@ -270,10 +271,6 @@ tv_get_bool_or_number_chk(
case VAR_VOID:
emsg(_(e_cannot_use_void_value));
break;
case VAR_TYPEALIAS:
semsg(_(e_using_typealias_as_number),
varp->vval.v_typealias->ta_name);
break;
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_INSTR:
@ -383,7 +380,8 @@ tv_get_float_chk(typval_T *varp, int *error)
emsg(_(e_using_blob_as_float));
break;
case VAR_CLASS:
emsg(_(e_using_class_as_float));
case VAR_TYPEALIAS:
check_typval_is_value(varp);
break;
case VAR_OBJECT:
emsg(_(e_using_object_as_float));
@ -391,10 +389,6 @@ tv_get_float_chk(typval_T *varp, int *error)
case VAR_VOID:
emsg(_(e_cannot_use_void_value));
break;
case VAR_TYPEALIAS:
semsg(_(e_using_typealias_as_float),
varp->vval.v_typealias->ta_name);
break;
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_INSTR:
@ -1131,7 +1125,8 @@ tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict)
emsg(_(e_using_blob_as_string));
break;
case VAR_CLASS:
emsg(_(e_using_class_as_string));
case VAR_TYPEALIAS:
check_typval_is_value(varp);
break;
case VAR_OBJECT:
emsg(_(e_using_object_as_string));
@ -1159,10 +1154,6 @@ tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict)
case VAR_VOID:
emsg(_(e_cannot_use_void_value));
break;
case VAR_TYPEALIAS:
semsg(_(e_using_typealias_as_string),
varp->vval.v_typealias->ta_name);
break;
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_INSTR:
@ -1358,7 +1349,13 @@ typval_compare(
int res = 0;
int type_is = type == EXPR_IS || type == EXPR_ISNOT;
if (type_is && tv1->v_type != tv2->v_type)
if (check_typval_is_value(tv1) == FAIL
|| check_typval_is_value(tv2) == FAIL)
{
clear_tv(tv1);
return FAIL;
}
else if (type_is && tv1->v_type != tv2->v_type)
{
// For "is" a different type always means FALSE, for "isnot"
// it means TRUE.
@ -1397,15 +1394,6 @@ typval_compare(
}
n1 = res;
}
else if (tv1->v_type == VAR_CLASS || tv2->v_type == VAR_CLASS)
{
if (typval_compare_class(tv1, tv2, type, ic, &res) == FAIL)
{
clear_tv(tv1);
return FAIL;
}
n1 = res;
}
else if (tv1->v_type == VAR_OBJECT || tv2->v_type == VAR_OBJECT)
{
if (typval_compare_object(tv1, tv2, type, ic, &res) == FAIL)

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2184,
/**/
2183,
/**/

View File

@ -168,7 +168,6 @@ typedef enum {
ISN_COMPAREDICT,
ISN_COMPAREFUNC,
ISN_COMPAREANY,
ISN_COMPARECLASS,
ISN_COMPAREOBJECT,
// expression operations

View File

@ -550,6 +550,12 @@ need_type_where(
{
int ret;
if (expected->tt_type != VAR_CLASS && expected->tt_type != VAR_TYPEALIAS)
{
if (check_type_is_value(actual) == FAIL)
return FAIL;
}
if (expected == &t_bool && actual != &t_bool
&& (actual->tt_flags & TTFLAG_BOOL_OK))
{

View File

@ -5034,7 +5034,6 @@ exec_instructions(ectx_T *ectx)
case ISN_COMPAREFUNC:
case ISN_COMPARESTRING:
case ISN_COMPAREBLOB:
case ISN_COMPARECLASS:
case ISN_COMPAREOBJECT:
{
typval_T *tv1 = STACK_TV_BOT(-2);
@ -5069,11 +5068,6 @@ exec_instructions(ectx_T *ectx)
{
status = typval_compare_blob(tv1, tv2, exprtype, &res);
}
else if (iptr->isn_type == ISN_COMPARECLASS)
{
status = typval_compare_class(tv1, tv2,
exprtype, FALSE, &res);
}
else // ISN_COMPAREOBJECT
{
status = typval_compare_object(tv1, tv2,
@ -7206,7 +7200,6 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
case ISN_COMPARELIST:
case ISN_COMPAREDICT:
case ISN_COMPAREFUNC:
case ISN_COMPARECLASS:
case ISN_COMPAREOBJECT:
case ISN_COMPAREANY:
{
@ -7245,7 +7238,6 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
case ISN_COMPARELIST: type = "COMPARELIST"; break;
case ISN_COMPAREDICT: type = "COMPAREDICT"; break;
case ISN_COMPAREFUNC: type = "COMPAREFUNC"; break;
case ISN_COMPARECLASS: type = "COMPARECLASS"; break;
case ISN_COMPAREOBJECT:
type = "COMPAREOBJECT"; break;
case ISN_COMPAREANY: type = "COMPAREANY"; break;

View File

@ -255,13 +255,18 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
}
static int
check_number_or_float(vartype_T type1, vartype_T type2, char_u *op)
check_number_or_float(type_T *typ1, type_T *typ2, char_u *op)
{
vartype_T type1 = typ1->tt_type;
vartype_T type2 = typ2->tt_type;
if (!((type1 == VAR_NUMBER || type1 == VAR_FLOAT
|| type1 == VAR_ANY || type1 == VAR_UNKNOWN)
&& (type2 == VAR_NUMBER || type2 == VAR_FLOAT
|| type2 == VAR_ANY || type2 == VAR_UNKNOWN)))
{
if (check_type_is_value(typ1) == FAIL
|| check_type_is_value(typ2) == FAIL)
return FAIL;
if (*op == '+')
emsg(_(e_wrong_argument_type_for_plus));
else
@ -294,8 +299,7 @@ generate_add_instr(
&& type1->tt_type != VAR_UNKNOWN
&& type2->tt_type != VAR_ANY
&& type2->tt_type != VAR_UNKNOWN
&& check_number_or_float(
type1->tt_type, type2->tt_type, (char_u *)"+") == FAIL)
&& check_number_or_float(type1, type2, (char_u *)"+") == FAIL)
return FAIL;
if (isn != NULL)
@ -362,8 +366,7 @@ generate_two_op(cctx_T *cctx, char_u *op)
case '-':
case '*':
case '/': if (check_number_or_float(type1->tt_type, type2->tt_type,
op) == FAIL)
case '/': if (check_number_or_float(type1, type2, op) == FAIL)
return FAIL;
if (vartype == VAR_NUMBER)
isn = generate_instr_drop(cctx, ISN_OPNR, 1);
@ -408,6 +411,19 @@ generate_two_op(cctx_T *cctx, char_u *op)
return OK;
}
/*
* Choose correct error message for the specified type information.
*/
static isntype_T
compare_isn_not_values(typval_T *tv, type_T *type)
{
if (tv != NULL)
check_typval_is_value(tv);
else
check_type_is_value(type);
return ISN_DROP;
}
/*
* Get the instruction to use for comparing two values with specified types.
* Either "tv1" and "tv2" are passed or "type1" and "type2".
@ -425,6 +441,11 @@ get_compare_isn(
vartype_T vartype1 = tv1 != NULL ? tv1->v_type : type1->tt_type;
vartype_T vartype2 = tv2 != NULL ? tv2->v_type : type2->tt_type;
if (vartype1 == VAR_CLASS || vartype1 == VAR_TYPEALIAS)
return compare_isn_not_values(tv1, type1);
if (vartype2 == VAR_CLASS || vartype2 == VAR_TYPEALIAS)
return compare_isn_not_values(tv2, type2);
if (vartype1 == vartype2)
{
switch (vartype1)
@ -438,7 +459,6 @@ get_compare_isn(
case VAR_LIST: isntype = ISN_COMPARELIST; break;
case VAR_DICT: isntype = ISN_COMPAREDICT; break;
case VAR_FUNC: isntype = ISN_COMPAREFUNC; break;
case VAR_CLASS: isntype = ISN_COMPARECLASS; break;
case VAR_OBJECT: isntype = ISN_COMPAREOBJECT; break;
default: isntype = ISN_COMPAREANY; break;
}
@ -481,7 +501,7 @@ get_compare_isn(
}
if (!(exprtype == EXPR_IS || exprtype == EXPR_ISNOT
|| exprtype == EXPR_EQUAL || exprtype == EXPR_NEQUAL)
&& (isntype == ISN_COMPAREOBJECT || isntype == ISN_COMPARECLASS))
&& (isntype == ISN_COMPAREOBJECT))
{
semsg(_(e_invalid_operation_for_str), vartype_name(vartype1));
return ISN_DROP;
@ -2700,7 +2720,6 @@ delete_instr(isn_T *isn)
case ISN_COMPAREANY:
case ISN_COMPAREBLOB:
case ISN_COMPAREBOOL:
case ISN_COMPARECLASS:
case ISN_COMPAREDICT:
case ISN_COMPAREFLOAT:
case ISN_COMPAREFUNC:

View File

@ -1871,7 +1871,10 @@ check_typval_is_value(typval_T *tv)
return OK;
if (tv->v_type == VAR_CLASS)
{
if (tv->vval.v_class != NULL)
semsg(_(e_using_class_as_value_str), tv->vval.v_class->class_name);
else
emsg(e_using_class_as_var_val);
return FAIL;
}
else if (tv->v_type == VAR_TYPEALIAS)