To: vim_dev@googlegroups.com Subject: Patch 8.2.1388 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1388 Problem: Vim9: += only works for numbers. Solution: Use += as concatenate for a list. (closes #6646) Files: src/vim9compile.c, src/testdir/test_vim9_script.vim *** ../vim-8.2.1387/src/vim9compile.c 2020-08-05 15:43:40.513333228 +0200 --- src/vim9compile.c 2020-08-07 20:42:40.221109198 +0200 *************** *** 776,781 **** --- 776,828 ---- return OK; } + static int + generate_add_instr( + cctx_T *cctx, + vartype_T vartype, + type_T *type1, + type_T *type2) + { + isn_T *isn = generate_instr_drop(cctx, + vartype == VAR_NUMBER ? ISN_OPNR + : vartype == VAR_LIST ? ISN_ADDLIST + : vartype == VAR_BLOB ? ISN_ADDBLOB + #ifdef FEAT_FLOAT + : vartype == VAR_FLOAT ? ISN_OPFLOAT + #endif + : ISN_OPANY, 1); + + if (vartype != VAR_LIST && vartype != VAR_BLOB + && type1->tt_type != VAR_ANY + && type2->tt_type != VAR_ANY + && check_number_or_float( + type1->tt_type, type2->tt_type, (char_u *)"+") == FAIL) + return FAIL; + + if (isn != NULL) + isn->isn_arg.op.op_type = EXPR_ADD; + return isn == NULL ? FAIL : OK; + } + + /* + * Get the type to use for an instruction for an operation on "type1" and + * "type2". If they are matching use a type-specific instruction. Otherwise + * fall back to runtime type checking. + */ + static vartype_T + operator_type(type_T *type1, type_T *type2) + { + if (type1->tt_type == type2->tt_type + && (type1->tt_type == VAR_NUMBER + || type1->tt_type == VAR_LIST + #ifdef FEAT_FLOAT + || type1->tt_type == VAR_FLOAT + #endif + || type1->tt_type == VAR_BLOB)) + return type1->tt_type; + return VAR_ANY; + } + /* * Generate an instruction with two arguments. The instruction depends on the * type of the arguments. *************** *** 791,829 **** RETURN_OK_IF_SKIP(cctx); ! // Get the known type of the two items on the stack. If they are matching ! // use a type-specific instruction. Otherwise fall back to runtime type ! // checking. type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]; type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! vartype = VAR_ANY; ! if (type1->tt_type == type2->tt_type ! && (type1->tt_type == VAR_NUMBER ! || type1->tt_type == VAR_LIST ! #ifdef FEAT_FLOAT ! || type1->tt_type == VAR_FLOAT ! #endif ! || type1->tt_type == VAR_BLOB)) ! vartype = type1->tt_type; switch (*op) { ! case '+': if (vartype != VAR_LIST && vartype != VAR_BLOB ! && type1->tt_type != VAR_ANY ! && type2->tt_type != VAR_ANY ! && check_number_or_float( ! type1->tt_type, type2->tt_type, op) == FAIL) return FAIL; - isn = generate_instr_drop(cctx, - vartype == VAR_NUMBER ? ISN_OPNR - : vartype == VAR_LIST ? ISN_ADDLIST - : vartype == VAR_BLOB ? ISN_ADDBLOB - #ifdef FEAT_FLOAT - : vartype == VAR_FLOAT ? ISN_OPFLOAT - #endif - : ISN_OPANY, 1); - if (isn != NULL) - isn->isn_arg.op.op_type = EXPR_ADD; break; case '-': --- 838,853 ---- RETURN_OK_IF_SKIP(cctx); ! // Get the known type of the two items on the stack. type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]; type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! vartype = operator_type(type1, type2); switch (*op) { ! case '+': ! if (generate_add_instr(cctx, vartype, type1, type2) == FAIL) return FAIL; break; case '-': *************** *** 5699,5713 **** type_T *stacktype; // TODO: if type is known use float or any operation if (*op == '.') expected = &t_string; stacktype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (need_type(stacktype, expected, -1, cctx, FALSE) == FAIL) goto theend; if (*op == '.') ! generate_instr_drop(cctx, ISN_CONCAT, 1); else { isn_T *isn = generate_instr_drop(cctx, ISN_OPNR, 1); --- 5723,5750 ---- type_T *stacktype; // TODO: if type is known use float or any operation + // TODO: check operator matches variable type if (*op == '.') expected = &t_string; + else if (*op == '+') + expected = member_type; stacktype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (need_type(stacktype, expected, -1, cctx, FALSE) == FAIL) goto theend; if (*op == '.') ! { ! if (generate_instr_drop(cctx, ISN_CONCAT, 1) == NULL) ! goto theend; ! } ! else if (*op == '+') ! { ! if (generate_add_instr(cctx, ! operator_type(member_type, stacktype), ! member_type, stacktype) == FAIL) ! goto theend; ! } else { isn_T *isn = generate_instr_drop(cctx, ISN_OPNR, 1); *************** *** 5716,5722 **** goto theend; switch (*op) { - case '+': isn->isn_arg.op.op_type = EXPR_ADD; break; case '-': isn->isn_arg.op.op_type = EXPR_SUB; break; case '*': isn->isn_arg.op.op_type = EXPR_MULT; break; case '/': isn->isn_arg.op.op_type = EXPR_DIV; break; --- 5753,5758 ---- *** ../vim-8.2.1387/src/testdir/test_vim9_script.vim 2020-08-07 19:28:04.929546817 +0200 --- src/testdir/test_vim9_script.vim 2020-08-07 20:44:50.340790556 +0200 *************** *** 126,138 **** $SOME_ENV_VAR ..= 'more' assert_equal('somemore', $SOME_ENV_VAR) ! call CheckDefFailure(['$SOME_ENV_VAR += "more"'], 'E1013:') call CheckDefFailure(['$SOME_ENV_VAR += 123'], 'E1013:') @a = 'areg' @a ..= 'add' assert_equal('aregadd', @a) ! call CheckDefFailure(['@a += "more"'], 'E1013:') call CheckDefFailure(['@a += 123'], 'E1013:') lines =<< trim END --- 126,138 ---- $SOME_ENV_VAR ..= 'more' assert_equal('somemore', $SOME_ENV_VAR) ! call CheckDefFailure(['$SOME_ENV_VAR += "more"'], 'E1051:') call CheckDefFailure(['$SOME_ENV_VAR += 123'], 'E1013:') @a = 'areg' @a ..= 'add' assert_equal('aregadd', @a) ! call CheckDefFailure(['@a += "more"'], 'E1051:') call CheckDefFailure(['@a += 123'], 'E1013:') lines =<< trim END *************** *** 146,152 **** v:errmsg = 'none' v:errmsg ..= 'again' assert_equal('noneagain', v:errmsg) ! call CheckDefFailure(['v:errmsg += "more"'], 'E1013:') call CheckDefFailure(['v:errmsg += 123'], 'E1013:') # single letter variables --- 146,152 ---- v:errmsg = 'none' v:errmsg ..= 'again' assert_equal('noneagain', v:errmsg) ! call CheckDefFailure(['v:errmsg += "more"'], 'E1051:') call CheckDefFailure(['v:errmsg += 123'], 'E1013:') # single letter variables *************** *** 224,229 **** --- 224,236 ---- assert_equal([1, 88, 99], list2) list2[-3] = 77 assert_equal([77, 88, 99], list2) + list2 += [100] + assert_equal([77, 88, 99, 100], list2) + + list3 += ['end'] + assert_equal(['sdf', 'asdf', 'end'], list3) + + call CheckDefExecFailure(['let ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:') call CheckDefExecFailure(['let [v1, v2] = [1, 2]'], 'E1092:') *** ../vim-8.2.1387/src/version.c 2020-08-07 19:28:04.933546818 +0200 --- src/version.c 2020-08-07 20:14:26.370055787 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1388, /**/ -- Drink wet cement and get really stoned. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///