# HG changeset patch # User Christian Brabandt # Date 1703176205 -3600 # Node ID ab6a70fad5b5ade6fd48f219fdb1d81b5a834369 # Parent f5c639a69421afae3ad0a2318d44f2347c90f3d3 patch 9.0.2184: Vim9: inconsistent :type/:class messages Commit: https://github.com/vim/vim/commit/e75fde6b043371a188660c3423e48b1b7fd7e14b Author: Ernie Rael Date: Thu Dec 21 17:18:54 2023 +0100 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 Signed-off-by: Christian Brabandt diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -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 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 case VAR_JOB: case VAR_CHANNEL: case VAR_INSTR: + case VAR_OBJECT: + break; case VAR_CLASS: - case VAR_OBJECT: case VAR_TYPEALIAS: - break; + check_typval_is_value(tv1); + return FAIL; case VAR_BLOB: if (*op != '+' || tv2->v_type != VAR_BLOB) @@ -2142,7 +2143,8 @@ tv_op(typval_T *tv1, typval_T *tv2, char } } - semsg(_(e_wrong_variable_type_for_str_equal), op); + if (check_typval_is_value(tv2) == OK) + semsg(_(e_wrong_variable_type_for_str_equal), op); return FAIL; } @@ -5019,11 +5021,14 @@ check_can_index(typval_T *rettv, int eva case VAR_JOB: case VAR_CHANNEL: case VAR_INSTR: + case VAR_OBJECT: + if (verbose) + emsg(_(e_cannot_index_special_variable)); + return FAIL; case VAR_CLASS: - case VAR_OBJECT: case VAR_TYPEALIAS: if (verbose) - emsg(_(e_cannot_index_special_variable)); + check_typval_is_value(rettv); return FAIL; case VAR_UNKNOWN: case VAR_ANY: diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -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) { diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -3090,18 +3090,18 @@ def Test_type_check() assert_fails('l = N', 'E1012: Type mismatch; expected list 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 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 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') @@ -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) diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -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 diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -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_objec 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_objec END v9.CheckScriptSuccess(lines) assert_match('\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 diff --git a/src/testdir/test_vim9_typealias.vim b/src/testdir/test_vim9_typealias.vim --- a/src/testdir/test_vim9_typealias.vim +++ b/src/testdir/test_vim9_typealias.vim @@ -18,7 +18,7 @@ def Test_typealias() assert_equal('typealias>', 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>', 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 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 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 diff --git a/src/typval.c b/src/typval.c --- a/src/typval.c +++ b/src/typval.c @@ -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 *er 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 *er 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 *v 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 *v 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) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2184, +/**/ 2183, /**/ 2182, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -168,7 +168,6 @@ typedef enum { ISN_COMPAREDICT, ISN_COMPAREFUNC, ISN_COMPAREANY, - ISN_COMPARECLASS, ISN_COMPAREOBJECT, // expression operations diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -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)) { diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -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 *inst 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 *inst 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; diff --git a/src/vim9instr.c b/src/vim9instr.c --- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -255,13 +255,18 @@ may_generate_2STRING(int offset, int tol } 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); @@ -409,6 +412,19 @@ generate_two_op(cctx_T *cctx, char_u *op } /* + * 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". * Return ISN_DROP when failed. @@ -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: diff --git a/src/vim9type.c b/src/vim9type.c --- a/src/vim9type.c +++ b/src/vim9type.c @@ -1871,7 +1871,10 @@ check_typval_is_value(typval_T *tv) return OK; if (tv->v_type == VAR_CLASS) { - semsg(_(e_using_class_as_value_str), tv->vval.v_class->class_name); + 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)