To: vim_dev@googlegroups.com Subject: Patch 8.2.0753 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0753 Problem: Vim9: expressions are evaluated in the discovery phase. Solution: Bail out if an expression is not a constant. Require a type for declared constants. Files: src/vim.h, src/evalvars.c, src/eval.c, src/ex_eval.c, src/evalfunc.c, src/userfunc.c, src/dict.c, src/list.c, src/vim9compile.c, src/testdir/test_vim9_script.vim, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.0752/src/vim.h 2020-05-10 13:42:39.377975569 +0200 --- src/vim.h 2020-05-14 21:50:28.850751170 +0200 *************** *** 2133,2139 **** // Flags for assignment functions. #define LET_IS_CONST 1 // ":const" #define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const" ! #define LET_REDEFINE 4 // variable can be redefined later #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff --- 2133,2139 ---- // Flags for assignment functions. #define LET_IS_CONST 1 // ":const" #define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const" ! #define LET_DISCOVERY 4 // discovery phase: variable can be redefined later #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff *************** *** 2662,2665 **** --- 2662,2669 ---- #define REPTERM_SPECIAL 4 #define REPTERM_NO_SIMPLIFY 8 + // Flags for expression evaluation. + #define EVAL_EVALUATE 1 // when missing don't actually evaluate + #define EVAL_CONSTANT 2 // when not a constant return FAIL + #endif // VIM__H *** ../vim-8.2.0752/src/evalvars.c 2020-05-13 22:44:18.142288807 +0200 --- src/evalvars.c 2020-05-14 22:30:44.303601302 +0200 *************** *** 433,439 **** if (p_verbose == 0) ++emsg_off; ! if (eval1(&p, &rettv, TRUE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); --- 433,439 ---- if (p_verbose == 0) ++emsg_off; ! if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); *************** *** 701,711 **** } /* ! * When "redefine" is TRUE the command will be executed again, redefining the ! * variable is OK then. */ void ! ex_let_const(exarg_T *eap, int redefine) { char_u *arg = eap->arg; char_u *expr = NULL; --- 701,714 ---- } /* ! * When "discovery" is TRUE the ":let" or ":const" is encountered during the ! * discovery phase of vim9script: ! * - The command will be executed again, redefining the variable is OK then. ! * - The expresion argument must be a constant. ! * - If no constant expression a type must be specified. */ void ! ex_let_const(exarg_T *eap, int discovery) { char_u *arg = eap->arg; char_u *expr = NULL; *************** *** 717,729 **** char_u *argend; int first = TRUE; int concat; int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0; // detect Vim9 assignment without ":let" or ":const" if (eap->arg == eap->cmd) flags |= LET_NO_COMMAND; ! if (redefine) ! flags |= LET_REDEFINE; argend = skip_var_list(arg, TRUE, &var_count, &semicolon); if (argend == NULL) --- 720,733 ---- char_u *argend; int first = TRUE; int concat; + int has_assign; int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0; // detect Vim9 assignment without ":let" or ":const" if (eap->arg == eap->cmd) flags |= LET_NO_COMMAND; ! if (discovery) ! flags |= LET_DISCOVERY; argend = skip_var_list(arg, TRUE, &var_count, &semicolon); if (argend == NULL) *************** *** 734,741 **** concat = expr[0] == '.' && ((expr[1] == '=' && current_sctx.sc_version < 2) || (expr[1] == '.' && expr[2] == '=')); ! if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%", *expr) != NULL ! && expr[1] == '=') || concat)) { // ":let" without "=": list variables if (*arg == '[') --- 738,746 ---- concat = expr[0] == '.' && ((expr[1] == '=' && current_sctx.sc_version < 2) || (expr[1] == '.' && expr[2] == '=')); ! has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL ! && expr[1] == '='); ! if (!has_assign && !concat && !discovery) { // ":let" without "=": list variables if (*arg == '[') *************** *** 779,810 **** } else { ! op[0] = '='; ! op[1] = NUL; ! if (*expr != '=') ! { ! if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) { ! op[0] = *expr; // +=, -=, *=, /=, %= or .= ! if (expr[0] == '.' && expr[1] == '.') // ..= ! ++expr; } ! expr = skipwhite(expr + 2); ! } ! else ! expr = skipwhite(expr + 1); ! if (eap->skip) ! ++emsg_skip; ! i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip); if (eap->skip) { if (i != FAIL) clear_tv(&rettv); --emsg_skip; } ! else if (i != FAIL) { (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count, flags, op); clear_tv(&rettv); --- 784,828 ---- } else { ! int eval_flags; ! int save_called_emsg = called_emsg; ! ! rettv.v_type = VAR_UNKNOWN; ! i = FAIL; ! if (has_assign || concat) ! { ! op[0] = '='; ! op[1] = NUL; ! if (*expr != '=') { ! if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) ! { ! op[0] = *expr; // +=, -=, *=, /=, %= or .= ! if (expr[0] == '.' && expr[1] == '.') // ..= ! ++expr; ! } ! expr = skipwhite(expr + 2); } ! else ! expr = skipwhite(expr + 1); ! if (eap->skip) ! ++emsg_skip; ! eval_flags = eap->skip ? 0 : EVAL_EVALUATE; ! if (discovery) ! eval_flags |= EVAL_CONSTANT; ! i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); ! } if (eap->skip) { if (i != FAIL) clear_tv(&rettv); --emsg_skip; } ! else if (i != FAIL || (discovery && save_called_emsg == called_emsg)) { + // In Vim9 script discovery "let v: bool = Func()" fails but is + // still a valid declaration. (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count, flags, op); clear_tv(&rettv); *************** *** 1112,1118 **** { // handle d.key, l[idx], f(expr) arg_subsc = arg; ! if (handle_subscript(&arg, &tv, TRUE, TRUE, name, &name) == FAIL) error = TRUE; else --- 1130,1136 ---- { // handle d.key, l[idx], f(expr) arg_subsc = arg; ! if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE, name, &name) == FAIL) error = TRUE; else *************** *** 1353,1359 **** lval_T lv; p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START); ! if (p != NULL && lv.ll_name != NULL) { if (endchars != NULL && vim_strchr(endchars, *skipwhite(lv.ll_name_end)) == NULL) --- 1371,1382 ---- lval_T lv; p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START); ! if ((flags & LET_DISCOVERY) && tv->v_type == VAR_UNKNOWN ! && lv.ll_type == NULL) ! { ! semsg(_("E1091: type missing for %s"), arg); ! } ! else if (p != NULL && lv.ll_name != NULL) { if (endchars != NULL && vim_strchr(endchars, *skipwhite(lv.ll_name_end)) == NULL) *************** *** 2981,2987 **** if (flags & LET_IS_CONST) di->di_tv.v_lock |= VAR_LOCKED; ! if (flags & LET_REDEFINE) di->di_flags |= DI_FLAGS_RELOAD; } --- 3004,3010 ---- if (flags & LET_IS_CONST) di->di_tv.v_lock |= VAR_LOCKED; ! if (flags & LET_DISCOVERY) di->di_flags |= DI_FLAGS_RELOAD; } *************** *** 3288,3294 **** if (n) { // handle d.key, l[idx], f(expr) ! n = (handle_subscript(&var, &tv, TRUE, FALSE, name, &name) == OK); if (n) clear_tv(&tv); } --- 3311,3318 ---- if (n) { // handle d.key, l[idx], f(expr) ! n = (handle_subscript(&var, &tv, EVAL_EVALUATE, ! FALSE, name, &name) == OK); if (n) clear_tv(&tv); } *** ../vim-8.2.0752/src/eval.c 2020-05-13 22:44:18.138288820 +0200 --- src/eval.c 2020-05-14 21:16:02.096820874 +0200 *************** *** 48,59 **** } forinfo_T; static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); ! static int eval2(char_u **arg, typval_T *rettv, int evaluate); ! static int eval3(char_u **arg, typval_T *rettv, int evaluate); ! static int eval4(char_u **arg, typval_T *rettv, int evaluate); ! static int eval5(char_u **arg, typval_T *rettv, int evaluate); ! static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string); ! static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string); static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); --- 48,59 ---- } forinfo_T; static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); ! static int eval2(char_u **arg, typval_T *rettv, int flags); ! static int eval3(char_u **arg, typval_T *rettv, int flags); ! static int eval4(char_u **arg, typval_T *rettv, int flags); ! static int eval5(char_u **arg, typval_T *rettv, int flags); ! static int eval6(char_u **arg, typval_T *rettv, int flags, int want_string); ! static int eval7(char_u **arg, typval_T *rettv, int flags, int want_string); static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); *************** *** 173,179 **** if (skip) ++emsg_skip; ! if (eval0(arg, &tv, nextcmd, !skip) == FAIL) *error = TRUE; else { --- 173,179 ---- if (skip) ++emsg_skip; ! if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) *error = TRUE; else { *************** *** 201,207 **** int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; ! ret = eval1(arg, rettv, evaluate); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has --- 201,207 ---- int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; ! ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has *************** *** 315,321 **** if (skip) ++emsg_skip; ! if (eval0(arg, &tv, nextcmd, !skip) == FAIL || skip) retval = NULL; else { --- 315,321 ---- if (skip) ++emsg_skip; ! if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) retval = NULL; else { *************** *** 338,344 **** typval_T rettv; *pp = skipwhite(*pp); ! return eval1(pp, &rettv, FALSE); } /* --- 338,344 ---- typval_T rettv; *pp = skipwhite(*pp); ! return eval1(pp, &rettv, 0); } /* *************** *** 360,366 **** char_u numbuf[NUMBUFLEN]; #endif ! if (eval0(arg, &tv, nextcmd, TRUE) == FAIL) retval = NULL; else { --- 360,366 ---- char_u numbuf[NUMBUFLEN]; #endif ! if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) retval = NULL; else { *************** *** 430,436 **** ++emsg_off; ! if (eval1(&p, &rettv, TRUE) == FAIL) retval = -1; else { --- 430,436 ---- ++emsg_off; ! if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) retval = -1; else { *************** *** 453,459 **** typval_T *tv; tv = ALLOC_ONE(typval_T); ! if (tv != NULL && eval0(arg, tv, nextcmd, TRUE) == FAIL) VIM_CLEAR(tv); return tv; --- 453,459 ---- typval_T *tv; tv = ALLOC_ONE(typval_T); ! if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL) VIM_CLEAR(tv); return tv; *************** *** 578,584 **** ++sandbox; ++textwinlock; *cp = NUL; ! if (eval0(arg, &tv, NULL, TRUE) == FAIL) retval = 0; else { --- 578,584 ---- ++sandbox; ++textwinlock; *cp = NUL; ! if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) retval = 0; else { *************** *** 766,772 **** else { empty1 = FALSE; ! if (eval1(&p, &var1, TRUE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { --- 766,772 ---- else { empty1 = FALSE; ! if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { *************** *** 803,809 **** else { lp->ll_empty2 = FALSE; ! if (eval1(&p, &var2, TRUE) == FAIL) // recursive! { clear_tv(&var1); return NULL; --- 803,810 ---- else { lp->ll_empty2 = FALSE; ! // recursive! ! if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) { clear_tv(&var1); return NULL; *************** *** 1433,1439 **** if (skip) ++emsg_skip; ! if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) { *errp = FALSE; if (!skip) --- 1434,1441 ---- if (skip) ++emsg_skip; ! if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) ! == OK) { *errp = FALSE; if (!skip) *************** *** 1694,1702 **** char_u *name, int name_len, typval_T *rettv, ! int evaluate, typval_T *basetv) // "expr" for "expr->name(arg)" { char_u *s = name; int len = name_len; partial_T *partial; --- 1696,1705 ---- char_u *name, int name_len, typval_T *rettv, ! int flags, typval_T *basetv) // "expr" for "expr->name(arg)" { + int evaluate = flags & EVAL_EVALUATE; char_u *s = name; int len = name_len; partial_T *partial; *************** *** 1712,1718 **** // Need to make a copy, in case evaluating the arguments makes // the name invalid. s = vim_strsave(s); ! if (s == NULL) ret = FAIL; else { --- 1715,1721 ---- // Need to make a copy, in case evaluating the arguments makes // the name invalid. s = vim_strsave(s); ! if (s == NULL || (flags & EVAL_CONSTANT)) ret = FAIL; else { *************** *** 1761,1766 **** --- 1764,1770 ---- * This calls eval1() and handles error message and nextcmd. * Put the result in "rettv" when returning OK and "evaluate" is TRUE. * Note: "rettv.v_lock" is not set. + * "flags" has EVAL_EVALUATE and similar flags. * Return OK or FAIL. */ int *************** *** 1768,1774 **** char_u *arg, typval_T *rettv, char_u **nextcmd, ! int evaluate) { int ret; char_u *p; --- 1772,1778 ---- char_u *arg, typval_T *rettv, char_u **nextcmd, ! int flags) { int ret; char_u *p; *************** *** 1776,1782 **** int called_emsg_before = called_emsg; p = skipwhite(arg); ! ret = eval1(&p, rettv, evaluate); if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) --- 1780,1786 ---- int called_emsg_before = called_emsg; p = skipwhite(arg); ! ret = eval1(&p, rettv, flags); if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) *************** *** 1787,1794 **** * exception, or we already gave a more specific error. * Also check called_emsg for when using assert_fails(). */ ! if (!aborting() && did_emsg == did_emsg_before ! && called_emsg == called_emsg_before) semsg(_(e_invexpr2), arg); ret = FAIL; } --- 1791,1800 ---- * exception, or we already gave a more specific error. * Also check called_emsg for when using assert_fails(). */ ! if (!aborting() ! && did_emsg == did_emsg_before ! && called_emsg == called_emsg_before ! && (flags & EVAL_CONSTANT) == 0) semsg(_(e_invexpr2), arg); ret = FAIL; } *************** *** 1810,1816 **** * Return OK or FAIL. */ int ! eval1(char_u **arg, typval_T *rettv, int evaluate) { int result; typval_T var2; --- 1816,1822 ---- * Return OK or FAIL. */ int ! eval1(char_u **arg, typval_T *rettv, int flags) { int result; typval_T var2; *************** *** 1818,1830 **** /* * Get the first variable. */ ! if (eval2(arg, rettv, evaluate) == FAIL) return FAIL; if ((*arg)[0] == '?') { result = FALSE; ! if (evaluate) { int error = FALSE; --- 1824,1838 ---- /* * Get the first variable. */ ! if (eval2(arg, rettv, flags) == FAIL) return FAIL; if ((*arg)[0] == '?') { + int evaluate = flags & EVAL_EVALUATE; + result = FALSE; ! if (flags & EVAL_EVALUATE) { int error = FALSE; *************** *** 1836,1845 **** } /* ! * Get the second variable. */ *arg = skipwhite(*arg + 1); ! if (eval1(arg, rettv, evaluate && result) == FAIL) // recursive! return FAIL; /* --- 1844,1853 ---- } /* ! * Get the second variable. Recursive! */ *arg = skipwhite(*arg + 1); ! if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) return FAIL; /* *************** *** 1854,1863 **** } /* ! * Get the third variable. */ *arg = skipwhite(*arg + 1); ! if (eval1(arg, &var2, evaluate && !result) == FAIL) // recursive! { if (evaluate && result) clear_tv(rettv); --- 1862,1871 ---- } /* ! * Get the third variable. Recursive! */ *arg = skipwhite(*arg + 1); ! if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { if (evaluate && result) clear_tv(rettv); *************** *** 1880,1886 **** * Return OK or FAIL. */ static int ! eval2(char_u **arg, typval_T *rettv, int evaluate) { typval_T var2; long result; --- 1888,1894 ---- * Return OK or FAIL. */ static int ! eval2(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; *************** *** 1890,1896 **** /* * Get the first variable. */ ! if (eval3(arg, rettv, evaluate) == FAIL) return FAIL; /* --- 1898,1904 ---- /* * Get the first variable. */ ! if (eval3(arg, rettv, flags) == FAIL) return FAIL; /* *************** *** 1900,1905 **** --- 1908,1915 ---- result = FALSE; while ((*arg)[0] == '|' && (*arg)[1] == '|') { + int evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) != 0) *************** *** 1914,1920 **** * Get the second variable. */ *arg = skipwhite(*arg + 2); ! if (eval3(arg, &var2, evaluate && !result) == FAIL) return FAIL; /* --- 1924,1931 ---- * Get the second variable. */ *arg = skipwhite(*arg + 2); ! if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) ! == FAIL) return FAIL; /* *************** *** 1948,1954 **** * Return OK or FAIL. */ static int ! eval3(char_u **arg, typval_T *rettv, int evaluate) { typval_T var2; long result; --- 1959,1965 ---- * Return OK or FAIL. */ static int ! eval3(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; *************** *** 1958,1964 **** /* * Get the first variable. */ ! if (eval4(arg, rettv, evaluate) == FAIL) return FAIL; /* --- 1969,1975 ---- /* * Get the first variable. */ ! if (eval4(arg, rettv, flags) == FAIL) return FAIL; /* *************** *** 1968,1973 **** --- 1979,1986 ---- result = TRUE; while ((*arg)[0] == '&' && (*arg)[1] == '&') { + int evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) *************** *** 1982,1988 **** * Get the second variable. */ *arg = skipwhite(*arg + 2); ! if (eval4(arg, &var2, evaluate && result) == FAIL) return FAIL; /* --- 1995,2001 ---- * Get the second variable. */ *arg = skipwhite(*arg + 2); ! if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) return FAIL; /* *************** *** 2025,2031 **** * Return OK or FAIL. */ static int ! eval4(char_u **arg, typval_T *rettv, int evaluate) { typval_T var2; char_u *p; --- 2038,2044 ---- * Return OK or FAIL. */ static int ! eval4(char_u **arg, typval_T *rettv, int flags) { typval_T var2; char_u *p; *************** *** 2037,2043 **** /* * Get the first variable. */ ! if (eval5(arg, rettv, evaluate) == FAIL) return FAIL; p = *arg; --- 2050,2056 ---- /* * Get the first variable. */ ! if (eval5(arg, rettv, flags) == FAIL) return FAIL; p = *arg; *************** *** 2105,2116 **** * Get the second variable. */ *arg = skipwhite(p + len); ! if (eval5(arg, &var2, evaluate) == FAIL) { clear_tv(rettv); return FAIL; } ! if (evaluate) { int ret = typval_compare(rettv, &var2, type, ic); --- 2118,2129 ---- * Get the second variable. */ *arg = skipwhite(p + len); ! if (eval5(arg, &var2, flags) == FAIL) { clear_tv(rettv); return FAIL; } ! if (flags & EVAL_EVALUATE) { int ret = typval_compare(rettv, &var2, type, ic); *************** *** 2172,2178 **** * Return OK or FAIL. */ static int ! eval5(char_u **arg, typval_T *rettv, int evaluate) { typval_T var2; int op; --- 2185,2191 ---- * Return OK or FAIL. */ static int ! eval5(char_u **arg, typval_T *rettv, int flags) { typval_T var2; int op; *************** *** 2188,2194 **** /* * Get the first variable. */ ! if (eval6(arg, rettv, evaluate, FALSE) == FAIL) return FAIL; /* --- 2201,2207 ---- /* * Get the first variable. */ ! if (eval6(arg, rettv, flags, FALSE) == FAIL) return FAIL; /* *************** *** 2217,2223 **** // we know that the first operand needs to be a string or number // without evaluating the 2nd operand. So check before to avoid // side effects after an error. ! if (evaluate && tv_get_string_chk(rettv) == NULL) { clear_tv(rettv); return FAIL; --- 2230,2236 ---- // we know that the first operand needs to be a string or number // without evaluating the 2nd operand. So check before to avoid // side effects after an error. ! if ((flags & EVAL_EVALUATE) && tv_get_string_chk(rettv) == NULL) { clear_tv(rettv); return FAIL; *************** *** 2230,2242 **** if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; *arg = skipwhite(*arg + 1); ! if (eval6(arg, &var2, evaluate, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } ! if (evaluate) { /* * Compute the result. --- 2243,2255 ---- if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; *arg = skipwhite(*arg + 1); ! if (eval6(arg, &var2, flags, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } ! if (flags & EVAL_EVALUATE) { /* * Compute the result. *************** *** 2358,2364 **** eval6( char_u **arg, typval_T *rettv, ! int evaluate, int want_string) // after "." operator { typval_T var2; --- 2371,2377 ---- eval6( char_u **arg, typval_T *rettv, ! int flags, int want_string) // after "." operator { typval_T var2; *************** *** 2373,2379 **** /* * Get the first variable. */ ! if (eval7(arg, rettv, evaluate, want_string) == FAIL) return FAIL; /* --- 2386,2392 ---- /* * Get the first variable. */ ! if (eval7(arg, rettv, flags, want_string) == FAIL) return FAIL; /* *************** *** 2385,2391 **** if (op != '*' && op != '/' && op != '%') break; ! if (evaluate) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) --- 2398,2404 ---- if (op != '*' && op != '/' && op != '%') break; ! if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) *************** *** 2408,2417 **** * Get the second variable. */ *arg = skipwhite(*arg + 1); ! if (eval7(arg, &var2, evaluate, FALSE) == FAIL) return FAIL; ! if (evaluate) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) --- 2421,2430 ---- * Get the second variable. */ *arg = skipwhite(*arg + 1); ! if (eval7(arg, &var2, flags, FALSE) == FAIL) return FAIL; ! if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) *************** *** 2528,2536 **** eval7( char_u **arg, typval_T *rettv, ! int evaluate, int want_string) // after "." operator { int len; char_u *s; char_u *start_leader, *end_leader; --- 2541,2550 ---- eval7( char_u **arg, typval_T *rettv, ! int flags, int want_string) // after "." operator { + int evaluate = flags & EVAL_EVALUATE; int len; char_u *s; char_u *start_leader, *end_leader; *************** *** 2595,2601 **** /* * List: [expr, expr] */ ! case '[': ret = get_list_tv(arg, rettv, evaluate, TRUE); break; /* --- 2609,2615 ---- /* * List: [expr, expr] */ ! case '[': ret = get_list_tv(arg, rettv, flags, TRUE); break; /* *************** *** 2604,2610 **** case '#': if ((*arg)[1] == '{') { ++*arg; ! ret = eval_dict(arg, rettv, evaluate, TRUE); } else ret = NOTDONE; --- 2618,2624 ---- case '#': if ((*arg)[1] == '{') { ++*arg; ! ret = eval_dict(arg, rettv, flags, TRUE); } else ret = NOTDONE; *************** *** 2616,2622 **** */ case '{': ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) ! ret = eval_dict(arg, rettv, evaluate, FALSE); break; /* --- 2630,2636 ---- */ case '{': ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) ! ret = eval_dict(arg, rettv, flags, FALSE); break; /* *************** *** 2649,2655 **** * nested expression: (expression). */ case '(': *arg = skipwhite(*arg + 1); ! ret = eval1(arg, rettv, evaluate); // recursive! if (**arg == ')') ++*arg; else if (ret == OK) --- 2663,2669 ---- * nested expression: (expression). */ case '(': *arg = skipwhite(*arg + 1); ! ret = eval1(arg, rettv, flags); // recursive! if (**arg == ')') ++*arg; else if (ret == OK) *************** *** 2680,2686 **** else { if (**arg == '(') // recursive! ! ret = eval_func(arg, s, len, rettv, evaluate, NULL); else if (evaluate) ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE); else --- 2694,2700 ---- else { if (**arg == '(') // recursive! ! ret = eval_func(arg, s, len, rettv, flags, NULL); else if (evaluate) ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE); else *************** *** 2697,2703 **** // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) ! ret = handle_subscript(arg, rettv, evaluate, TRUE, start_leader, &end_leader); /* --- 2711,2717 ---- // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) ! ret = handle_subscript(arg, rettv, flags, TRUE, start_leader, &end_leader); /* *************** *** 2919,2925 **** ret = FAIL; } else ! ret = eval_func(arg, name, len, rettv, evaluate, &base); } // Clear the funcref afterwards, so that deleting it while --- 2933,2940 ---- ret = FAIL; } else ! ret = eval_func(arg, name, len, rettv, ! evaluate ? EVAL_EVALUATE : 0, &base); } // Clear the funcref afterwards, so that deleting it while *************** *** 2939,2947 **** eval_index( char_u **arg, typval_T *rettv, ! int evaluate, int verbose) // give error messages { int empty1 = FALSE, empty2 = FALSE; typval_T var1, var2; long i; --- 2954,2963 ---- eval_index( char_u **arg, typval_T *rettv, ! int flags, int verbose) // give error messages { + int evaluate = flags & EVAL_EVALUATE; int empty1 = FALSE, empty2 = FALSE; typval_T var1, var2; long i; *************** *** 3010,3016 **** *arg = skipwhite(*arg + 1); if (**arg == ':') empty1 = TRUE; ! else if (eval1(arg, &var1, evaluate) == FAIL) // recursive! return FAIL; else if (evaluate && tv_get_string_chk(&var1) == NULL) { --- 3026,3032 ---- *arg = skipwhite(*arg + 1); if (**arg == ':') empty1 = TRUE; ! else if (eval1(arg, &var1, flags) == FAIL) // recursive! return FAIL; else if (evaluate && tv_get_string_chk(&var1) == NULL) { *************** *** 3028,3034 **** *arg = skipwhite(*arg + 1); if (**arg == ']') empty2 = TRUE; ! else if (eval1(arg, &var2, evaluate) == FAIL) // recursive! { if (!empty1) clear_tv(&var1); --- 3044,3050 ---- *arg = skipwhite(*arg + 1); if (**arg == ']') empty2 = TRUE; ! else if (eval1(arg, &var2, flags) == FAIL) // recursive! { if (!empty1) clear_tv(&var1); *************** *** 5310,5320 **** handle_subscript( char_u **arg, typval_T *rettv, ! int evaluate, // do more than finding the end int verbose, // give error messages char_u *start_leader, // start of '!' and '-' prefixes char_u **end_leaderp) // end of '!' and '-' prefixes { int ret = OK; dict_T *selfdict = NULL; --- 5326,5337 ---- handle_subscript( char_u **arg, typval_T *rettv, ! int flags, // do more than finding the end int verbose, // give error messages char_u *start_leader, // start of '!' and '-' prefixes char_u **end_leaderp) // end of '!' and '-' prefixes { + int evaluate = flags & EVAL_EVALUATE; int ret = OK; dict_T *selfdict = NULL; *************** *** 5374,5380 **** } else selfdict = NULL; ! if (eval_index(arg, rettv, evaluate, verbose) == FAIL) { clear_tv(rettv); ret = FAIL; --- 5391,5397 ---- } else selfdict = NULL; ! if (eval_index(arg, rettv, flags, verbose) == FAIL) { clear_tv(rettv); ret = FAIL; *************** *** 6108,6114 **** need_clr_eos = needclr; p = arg; ! if (eval1(&arg, &rettv, !eap->skip) == FAIL) { /* * Report the invalid expression unless the expression evaluation --- 6125,6131 ---- need_clr_eos = needclr; p = arg; ! if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) { /* * Report the invalid expression unless the expression evaluation *** ../vim-8.2.0752/src/ex_eval.c 2020-04-20 19:42:06.590078519 +0200 --- src/ex_eval.c 2020-05-14 19:53:59.925481766 +0200 *************** *** 879,885 **** { typval_T tv; ! if (eval0(eap->arg, &tv, &eap->nextcmd, !eap->skip) == OK) clear_tv(&tv); } --- 879,886 ---- { typval_T tv; ! if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) ! == OK) clear_tv(&tv); } *** ../vim-8.2.0752/src/evalfunc.c 2020-05-13 22:44:18.138288820 +0200 --- src/evalfunc.c 2020-05-14 20:03:45.391682200 +0200 *************** *** 2132,2138 **** s = skipwhite(s); p = s; ! if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) { if (p != NULL && !aborting()) semsg(_(e_invexpr2), p); --- 2132,2138 ---- s = skipwhite(s); p = s; ! if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL) { if (p != NULL && !aborting()) semsg(_(e_invexpr2), p); *** ../vim-8.2.0752/src/userfunc.c 2020-05-13 22:44:18.142288807 +0200 --- src/userfunc.c 2020-05-14 21:03:39.400346867 +0200 *************** *** 239,245 **** whitep = p; p = skipwhite(p); expr = p; ! if (eval1(&p, &rettv, FALSE) != FAIL) { if (ga_grow(default_args, 1) == FAIL) goto err_ret; --- 239,245 ---- whitep = p; p = skipwhite(p); expr = p; ! if (eval1(&p, &rettv, 0) != FAIL) { if (ga_grow(default_args, 1) == FAIL) goto err_ret; *************** *** 572,578 **** argp = skipwhite(argp + 1); // skip the '(' or ',' if (*argp == ')' || *argp == ',' || *argp == NUL) break; ! if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL) { ret = FAIL; break; --- 572,579 ---- argp = skipwhite(argp + 1); // skip the '(' or ',' if (*argp == ')' || *argp == ',' || *argp == NUL) break; ! if (eval1(&argp, &argvars[argcount], ! funcexe->evaluate ? EVAL_EVALUATE : 0) == FAIL) { ret = FAIL; break; *************** *** 1223,1229 **** default_expr = ((char_u **)(fp->uf_def_args.ga_data)) [ai + fp->uf_def_args.ga_len]; ! if (eval1(&default_expr, &def_rettv, TRUE) == FAIL) { default_arg_err = 1; break; --- 1224,1230 ---- default_expr = ((char_u **)(fp->uf_def_args.ga_data)) [ai + fp->uf_def_args.ga_len]; ! if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL) { default_arg_err = 1; break; *************** *** 1368,1374 **** // A Lambda always has the command "return {expr}". It is much faster // to evaluate {expr} directly. ++ex_nesting_level; ! (void)eval1(&p, rettv, TRUE); --ex_nesting_level; } else --- 1369,1375 ---- // A Lambda always has the command "return {expr}". It is much faster // to evaluate {expr} directly. ++ex_nesting_level; ! (void)eval1(&p, rettv, EVAL_EVALUATE); --ex_nesting_level; } else *************** *** 3623,3629 **** eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') ! && eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) { if (!eap->skip) returning = do_return(eap, FALSE, TRUE, &rettv); --- 3624,3631 ---- eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') ! && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) ! != FAIL) { if (!eap->skip) returning = do_return(eap, FALSE, TRUE, &rettv); *************** *** 3680,3686 **** // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif ++emsg_skip; ! if (eval0(eap->arg, &rettv, &eap->nextcmd, FALSE) != FAIL) clear_tv(&rettv); --emsg_skip; return; --- 3682,3688 ---- // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif ++emsg_skip; ! if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL) clear_tv(&rettv); --emsg_skip; return; *************** *** 3768,3775 **** dbg_check_breakpoint(eap); // Handle a function returning a Funcref, Dictionary or List. ! if (handle_subscript(&arg, &rettv, !eap->skip, TRUE, ! name, &name) == FAIL) { failed = TRUE; break; --- 3770,3777 ---- dbg_check_breakpoint(eap); // Handle a function returning a Funcref, Dictionary or List. ! if (handle_subscript(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE, ! TRUE, name, &name) == FAIL) { failed = TRUE; break; *** ../vim-8.2.0752/src/dict.c 2020-05-10 15:24:41.388262074 +0200 --- src/dict.c 2020-05-14 19:59:30.552480696 +0200 *************** *** 791,798 **** * Return OK or FAIL. Returns NOTDONE for {expr}. */ int ! eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) { dict_T *d = NULL; typval_T tvkey; typval_T tv; --- 791,799 ---- * Return OK or FAIL. Returns NOTDONE for {expr}. */ int ! eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) { + int evaluate = flags & EVAL_EVALUATE; dict_T *d = NULL; typval_T tvkey; typval_T tv; *************** *** 800,805 **** --- 801,807 ---- dictitem_T *item; char_u *start = skipwhite(*arg + 1); char_u buf[NUMBUFLEN]; + int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; /* * First check if it's not a curly-braces thing: {expr}. *************** *** 808,816 **** * first item. * But {} is an empty Dictionary. */ ! if (*start != '}') { ! if (eval1(&start, &tv, FALSE) == FAIL) // recursive! return FAIL; if (*start == '}') return NOTDONE; --- 810,818 ---- * first item. * But {} is an empty Dictionary. */ ! if (!vim9script && *start != '}') { ! if (eval1(&start, &tv, 0) == FAIL) // recursive! return FAIL; if (*start == '}') return NOTDONE; *************** *** 830,836 **** { if ((literal ? get_literal_key(arg, &tvkey) ! : eval1(arg, &tvkey, evaluate)) == FAIL) // recursive! goto failret; if (**arg != ':') --- 832,838 ---- { if ((literal ? get_literal_key(arg, &tvkey) ! : eval1(arg, &tvkey, flags)) == FAIL) // recursive! goto failret; if (**arg != ':') *************** *** 852,858 **** } *arg = skipwhite(*arg + 1); ! if (eval1(arg, &tv, evaluate) == FAIL) // recursive! { if (evaluate) clear_tv(&tvkey); --- 854,860 ---- } *arg = skipwhite(*arg + 1); ! if (eval1(arg, &tv, flags) == FAIL) // recursive! { if (evaluate) clear_tv(&tvkey); *** ../vim-8.2.0752/src/list.c 2020-05-13 22:44:18.142288807 +0200 --- src/list.c 2020-05-14 20:05:11.031407442 +0200 *************** *** 1046,1053 **** * Return OK or FAIL. */ int ! get_list_tv(char_u **arg, typval_T *rettv, int evaluate, int do_error) { list_T *l = NULL; typval_T tv; listitem_T *item; --- 1046,1054 ---- * Return OK or FAIL. */ int ! get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error) { + int evaluate = flags & EVAL_EVALUATE; list_T *l = NULL; typval_T tv; listitem_T *item; *************** *** 1062,1068 **** *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { ! if (eval1(arg, &tv, evaluate) == FAIL) // recursive! goto failret; if (evaluate) { --- 1063,1069 ---- *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { ! if (eval1(arg, &tv, flags) == FAIL) // recursive! goto failret; if (evaluate) { *** ../vim-8.2.0752/src/vim9compile.c 2020-05-10 23:20:01.297288962 +0200 --- src/vim9compile.c 2020-05-14 20:32:37.674124566 +0200 *************** *** 2869,2882 **** { // Can be "[1, 2, 3]->Func()". ! if (get_list_tv(&p, &rettv, FALSE, FALSE) == FAIL) p = arg; } else if (p == arg && *arg == '#' && arg[1] == '{') { // Can be "#{a: 1}->Func()". ++p; ! if (eval_dict(&p, &rettv, FALSE, TRUE) == FAIL) p = arg; } else if (p == arg && *arg == '{') --- 2869,2882 ---- { // Can be "[1, 2, 3]->Func()". ! if (get_list_tv(&p, &rettv, 0, FALSE) == FAIL) p = arg; } else if (p == arg && *arg == '#' && arg[1] == '{') { // Can be "#{a: 1}->Func()". ++p; ! if (eval_dict(&p, &rettv, 0, TRUE) == FAIL) p = arg; } else if (p == arg && *arg == '{') *************** *** 2886,2892 **** // Can be "{x -> ret}()". // Can be "{'a': 1}->Func()". if (ret == NOTDONE) ! ret = eval_dict(&p, &rettv, FALSE, FALSE); if (ret != OK) p = arg; } --- 2886,2892 ---- // Can be "{x -> ret}()". // Can be "{'a': 1}->Func()". if (ret == NOTDONE) ! ret = eval_dict(&p, &rettv, 0, FALSE); if (ret != OK) p = arg; } *** ../vim-8.2.0752/src/testdir/test_vim9_script.vim 2020-05-10 21:20:25.614465563 +0200 --- src/testdir/test_vim9_script.vim 2020-05-14 22:27:49.032145233 +0200 *************** *** 494,500 **** def Concat(arg: string): string return name .. arg enddef ! let g:result = Concat('bie') let g:localname = name export const CONST = 1234 --- 494,500 ---- def Concat(arg: string): string return name .. arg enddef ! let g:result: string = Concat('bie') let g:localname = name export const CONST = 1234 *************** *** 1633,1639 **** CheckScriptFailure([ 'vim9script', 'let g:var = 123', ! 'unlet g:var# comment', ], 'E108:') CheckScriptFailure([ --- 1633,1639 ---- CheckScriptFailure([ 'vim9script', 'let g:var = 123', ! 'unlet g:var# comment1', ], 'E108:') CheckScriptFailure([ *************** *** 1643,1649 **** CheckScriptSuccess([ 'vim9script', ! 'if 1 # comment', ' echo "yes"', 'elseif 2 #comment', ' echo "no"', --- 1643,1649 ---- CheckScriptSuccess([ 'vim9script', ! 'if 1 # comment2', ' echo "yes"', 'elseif 2 #comment', ' echo "no"', *************** *** 1652,1665 **** CheckScriptFailure([ 'vim9script', ! 'if 1# comment', ' echo "yes"', 'endif', ], 'E15:') CheckScriptFailure([ 'vim9script', ! 'if 0 # comment', ' echo "yes"', 'elseif 2#comment', ' echo "no"', --- 1652,1665 ---- CheckScriptFailure([ 'vim9script', ! 'if 1# comment3', ' echo "yes"', 'endif', ], 'E15:') CheckScriptFailure([ 'vim9script', ! 'if 0 # comment4', ' echo "yes"', 'elseif 2#comment', ' echo "no"', *************** *** 1668,1690 **** CheckScriptSuccess([ 'vim9script', ! 'let # comment', ]) CheckScriptFailure([ 'vim9script', ! 'let# comment', ! ], 'E121:') ! ! CheckScriptSuccess([ ! 'vim9script', ! 'let v:version # comment', ! ]) CheckScriptFailure([ 'vim9script', ! 'let v:version# comment', ! ], 'E121:') CheckScriptSuccess([ 'vim9script', --- 1668,1685 ---- CheckScriptSuccess([ 'vim9script', ! 'let v = 1 # comment5', ]) CheckScriptFailure([ 'vim9script', ! 'let v = 1# comment6', ! ], 'E15:') CheckScriptFailure([ 'vim9script', ! 'let v:version', ! ], 'E1091:') CheckScriptSuccess([ 'vim9script', *************** *** 1722,1727 **** --- 1717,1757 ---- delete('Xfinished') enddef + def Test_let_func_call() + let lines =<< trim END + vim9script + func GetValue() + if exists('g:count') + let g:count += 1 + else + let g:count = 1 + endif + return 'this' + endfunc + let val: string = GetValue() + END + writefile(lines, 'Xfinished') + source Xfinished + assert_equal(1, g:count) + + unlet g:count + delete('Xfinished') + enddef + + def Test_let_missing_type() + let lines =<< trim END + vim9script + func GetValue() + return 'this' + endfunc + let val = GetValue() + END + writefile(lines, 'Xfinished') + assert_fails('source Xfinished', 'E1091:') + + delete('Xfinished') + enddef + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new *** ../vim-8.2.0752/src/testdir/test_vim9_disassemble.vim 2020-05-09 22:50:04.755323771 +0200 --- src/testdir/test_vim9_disassemble.vim 2020-05-14 22:31:57.679372615 +0200 *************** *** 1054,1060 **** def FuncTwo(): string return 'two' enddef ! let g:res_FuncOne = execute('disass FuncOne') END writefile(lines, 'Xdisassemble') source Xdisassemble --- 1054,1060 ---- def FuncTwo(): string return 'two' enddef ! let g:res_FuncOne: string = execute('disass FuncOne') END writefile(lines, 'Xdisassemble') source Xdisassemble *** ../vim-8.2.0752/src/version.c 2020-05-13 23:24:06.801864054 +0200 --- src/version.c 2020-05-14 22:32:22.271295856 +0200 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 753, /**/ -- # echo reboot >universe # chmod +x universe # ./universe /// 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 ///