To: vim_dev@googlegroups.com Subject: Patch 8.2.3996 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3996 Problem: Vim9: type checking for list and dict lacks information about declared type. Solution: Add dv_decl_type and lv_decl_type. Refactor the type stack to store two types in each entry. Files: src/structs.h, src/dict.c, src/list.c, src/vim9type.c, src/proto/vim9type.pro, src/vim9instr.c, src/proto/vim9instr.pro, src/vim9compile.c, src/evalfunc.c, src/proto/evalfunc.pro, src/evalbuffer.c, src/proto/evalbuffer.pro, src/vim9expr.c, src/vim9cmds.c, src/testdir/test_vim9_assign.vim, src/testdir/test_vim9_builtin.vim *** ../vim-8.2.3995/src/structs.h 2021-12-26 12:07:24.798944010 +0000 --- src/structs.h 2022-01-04 11:18:01.739720715 +0000 *************** *** 1422,1427 **** --- 1422,1432 ---- type_T **tt_args; // func argument types, allocated }; + typedef struct { + type_T *type_curr; // current type, value type + type_T *type_decl; // declared type or equal to type_current + } type2_T; + #define TTFLAG_VARARGS 1 // func args ends with "..." #define TTFLAG_OPTARG 2 // func arg type with "?" #define TTFLAG_BOOL_OK 4 // can be converted to bool *************** *** 1507,1513 **** int lv_idx; // cached index of an item } mat; } lv_u; ! type_T *lv_type; // allocated by alloc_type() list_T *lv_copylist; // copied list used by deepcopy() list_T *lv_used_next; // next list in used lists list list_T *lv_used_prev; // previous list in used lists list --- 1512,1519 ---- int lv_idx; // cached index of an item } mat; } lv_u; ! type_T *lv_type; // current type, allocated by alloc_type() ! type_T *lv_decl_type; // declared type, allocated by alloc_type() list_T *lv_copylist; // copied list used by deepcopy() list_T *lv_used_next; // next list in used lists list list_T *lv_used_prev; // previous list in used lists list *************** *** 1571,1577 **** int dv_refcount; // reference count int dv_copyID; // ID used by deepcopy() hashtab_T dv_hashtab; // hashtab that refers to the items ! type_T *dv_type; // allocated by alloc_type() dict_T *dv_copydict; // copied dict used by deepcopy() dict_T *dv_used_next; // next dict in used dicts list dict_T *dv_used_prev; // previous dict in used dicts list --- 1577,1584 ---- int dv_refcount; // reference count int dv_copyID; // ID used by deepcopy() hashtab_T dv_hashtab; // hashtab that refers to the items ! type_T *dv_type; // current type, allocated by alloc_type() ! type_T *dv_decl_type; // declared type, allocated by alloc_type() dict_T *dv_copydict; // copied dict used by deepcopy() dict_T *dv_used_next; // next dict in used dicts list dict_T *dv_used_prev; // previous dict in used dicts list *** ../vim-8.2.3995/src/dict.c 2022-01-01 15:58:19.110486371 +0000 --- src/dict.c 2022-01-03 18:59:52.908832449 +0000 *************** *** 109,114 **** --- 109,116 ---- hashtab_free_contents(&d->dv_hashtab); free_type(d->dv_type); d->dv_type = NULL; + free_type(d->dv_decl_type); + d->dv_decl_type = NULL; } /* *************** *** 1354,1361 **** if (filtermap == FILTERMAP_MAP) { if (argtype != NULL && check_typval_arg_type( ! argtype->tt_member, &newtv, ! func_name, 0) == FAIL) { clear_tv(&newtv); break; --- 1356,1362 ---- if (filtermap == FILTERMAP_MAP) { if (argtype != NULL && check_typval_arg_type( ! argtype->tt_member, &newtv, func_name, 0) == FAIL) { clear_tv(&newtv); break; *** ../vim-8.2.3995/src/list.c 2022-01-03 16:52:24.616533342 +0000 --- src/list.c 2022-01-03 19:37:25.420117154 +0000 *************** *** 271,276 **** --- 271,277 ---- l->lv_used_next->lv_used_prev = l->lv_used_prev; free_type(l->lv_type); + free_type(l->lv_decl_type); vim_free(l); } *************** *** 1025,1030 **** --- 1026,1033 ---- // The type will change. free_type(l->lv_type); l->lv_type = NULL; + free_type(l->lv_decl_type); + l->lv_decl_type = NULL; } else { *************** *** 1220,1225 **** --- 1223,1229 ---- if (copy != NULL) { copy->lv_type = alloc_type(orig->lv_type); + copy->lv_decl_type = alloc_type(orig->lv_decl_type); if (copyID != 0) { // Do this before adding the items, because one of the items may *** ../vim-8.2.3995/src/vim9type.c 2022-01-03 12:27:59.355039941 +0000 --- src/vim9type.c 2022-01-04 14:41:54.598528101 +0000 *************** *** 1192,1229 **** } /* ! * Get the member type of a dict or list from the items on the stack. ! * "stack_top" points just after the last type on the type stack. * For a list "skip" is 1, for a dict "skip" is 2, keys are skipped. * Returns &t_void for an empty list or dict. * Otherwise finds the common type of all items. */ type_T * get_member_type_from_stack( - type_T **stack_top, int count, int skip, ! garray_T *type_gap) { ! int i; ! type_T *result; ! type_T *type; ! // Use "any" for an empty list or dict. if (count == 0) return &t_unknown; // Use the first value type for the list member type, then find the common // type from following items. ! result = *(stack_top -(count * skip) + skip - 1); for (i = 1; i < count; ++i) { if (result == &t_any) break; // won't get more common ! type = *(stack_top -((count - i) * skip) + skip - 1); common_type(type, result, &result, type_gap); } return result; } --- 1192,1301 ---- } /* ! * Push an entry onto the type stack. "type" used both for the current type ! * and the declared type. ! * Returns FAIL when out of memory. ! */ ! int ! push_type_stack(cctx_T *cctx, type_T *type) ! { ! return push_type_stack2(cctx, type, type); ! } ! ! /* ! * Push an entry onto the type stack. "type" is the current type, "decl_type" ! * is the declared type. ! * Returns FAIL when out of memory. ! */ ! int ! push_type_stack2(cctx_T *cctx, type_T *type, type_T *decl_type) ! { ! garray_T *stack = &cctx->ctx_type_stack; ! type2_T *typep; ! ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! typep = ((type2_T *)stack->ga_data) + stack->ga_len; ! typep->type_curr = type; ! typep->type_decl = decl_type; ! ++stack->ga_len; ! return OK; ! } ! ! /* ! * Set the type of the top of the stack to "type". ! */ ! void ! set_type_on_stack(cctx_T *cctx, type_T *type, int offset) ! { ! garray_T *stack = &cctx->ctx_type_stack; ! type2_T *typep = ((type2_T *)stack->ga_data) ! + stack->ga_len - 1 - offset; ! ! typep->type_curr = type; ! typep->type_decl = &t_any; ! } ! ! /* ! * Get the type from the type stack. If "offset" is zero the one at the top, ! * if "offset" is one the type above that, etc. ! * Returns &t_unknown if there is no such stack entry. ! */ ! type_T * ! get_type_on_stack(cctx_T *cctx, int offset) ! { ! garray_T *stack = &cctx->ctx_type_stack; ! ! if (offset + 1 > stack->ga_len) ! return &t_unknown; ! return (((type2_T *)stack->ga_data) + stack->ga_len - offset - 1) ! ->type_curr; ! } ! ! /* ! * Get the member type of a dict or list from the items on the stack of "cctx". ! * The declared type is stored in "decl_type". * For a list "skip" is 1, for a dict "skip" is 2, keys are skipped. * Returns &t_void for an empty list or dict. * Otherwise finds the common type of all items. */ type_T * get_member_type_from_stack( int count, int skip, ! type_T **decl_type, ! cctx_T *cctx) { ! garray_T *stack = &cctx->ctx_type_stack; ! type2_T *typep = ((type2_T *)stack->ga_data) + stack->ga_len; ! garray_T *type_gap = cctx->ctx_type_list; ! int i; ! type_T *result; ! type_T *decl_result; ! type_T *type; ! // Use "unknown" for an empty list or dict. if (count == 0) + { + *decl_type = &t_unknown; return &t_unknown; + } // Use the first value type for the list member type, then find the common // type from following items. ! result = (typep -(count * skip) + skip - 1)->type_curr; ! decl_result = (typep -(count * skip) + skip - 1)->type_decl; for (i = 1; i < count; ++i) { if (result == &t_any) break; // won't get more common ! type = (typep -((count - i) * skip) + skip - 1)->type_curr; common_type(type, result, &result, type_gap); + type = (typep -((count - i) * skip) + skip - 1)->type_decl; + common_type(type, decl_result, &decl_result, type_gap); } + *decl_type = decl_result; return result; } *** ../vim-8.2.3995/src/proto/vim9type.pro 2021-12-18 12:31:30.619693398 +0000 --- src/proto/vim9type.pro 2022-01-04 13:51:49.166645821 +0000 *************** *** 8,14 **** type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap); int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap); int need_convert_to_bool(type_T *type, typval_T *tv); ! type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int do_member); type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap); int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx); int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where); --- 8,14 ---- type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap); int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap); int need_convert_to_bool(type_T *type, typval_T *tv); ! type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags); type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap); int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx); int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where); *************** *** 22,28 **** type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error); int equal_type(type_T *type1, type_T *type2, int flags); void common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap); ! type_T *get_member_type_from_stack(type_T **stack_top, int count, int skip, garray_T *type_gap); char *vartype_name(vartype_T type); char *type_name(type_T *type, char **tofree); void f_typename(typval_T *argvars, typval_T *rettv); --- 22,32 ---- type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error); int equal_type(type_T *type1, type_T *type2, int flags); void common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap); ! int push_type_stack(cctx_T *cctx, type_T *type); ! int push_type_stack2(cctx_T *cctx, type_T *type, type_T *decl_type); ! void set_type_on_stack(cctx_T *cctx, type_T *type, int offset); ! type_T *get_type_on_stack(cctx_T *cctx, int offset); ! type_T *get_member_type_from_stack(int count, int skip, type_T **decl_type, cctx_T *cctx); char *vartype_name(vartype_T type); char *type_name(type_T *type, char **tofree); void f_typename(typval_T *argvars, typval_T *rettv); *** ../vim-8.2.3995/src/vim9instr.c 2022-01-01 14:19:44.056353820 +0000 --- src/vim9instr.c 2022-01-04 14:52:37.901473631 +0000 *************** *** 57,90 **** isn_T * generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop) { - garray_T *stack = &cctx->ctx_type_stack; - RETURN_NULL_IF_SKIP(cctx); ! stack->ga_len -= drop; return generate_instr(cctx, isn_type); } /* ! * Generate instruction "isn_type" and put "type" on the type stack. */ isn_T * ! generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; if ((isn = generate_instr(cctx, isn_type)) == NULL) return NULL; ! if (GA_GROW_FAILS(stack, 1)) return NULL; - ((type_T **)stack->ga_data)[stack->ga_len] = type == NULL ? &t_any : type; - ++stack->ga_len; return isn; } /* * Generate an ISN_DEBUG instruction. */ isn_T * --- 57,102 ---- isn_T * generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop) { RETURN_NULL_IF_SKIP(cctx); ! cctx->ctx_type_stack.ga_len -= drop; return generate_instr(cctx, isn_type); } /* ! * Generate instruction "isn_type" and put "type" on the type stack, ! * use "decl_type" for the declared type. */ isn_T * ! generate_instr_type2( ! cctx_T *cctx, ! isntype_T isn_type, ! type_T *type, ! type_T *decl_type) { isn_T *isn; if ((isn = generate_instr(cctx, isn_type)) == NULL) return NULL; ! if (push_type_stack2(cctx, type == NULL ? &t_any : type, ! decl_type == NULL ? &t_any : decl_type) == FAIL) return NULL; return isn; } /* + * Generate instruction "isn_type" and put "type" on the type stack. + * Uses "any" for the declared type, which works for constants. For declared + * variables use generate_instr_type2(). + */ + isn_T * + generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type) + { + return generate_instr_type2(cctx, isn_type, type, &t_any); + } + + /* * Generate an ISN_DEBUG instruction. */ isn_T * *************** *** 111,122 **** { isn_T *isn; isntype_T isntype = ISN_2STRING; ! garray_T *stack = &cctx->ctx_type_stack; ! type_T **type; RETURN_OK_IF_SKIP(cctx); ! type = ((type_T **)stack->ga_data) + stack->ga_len + offset; ! switch ((*type)->tt_type) { // nothing to be done case VAR_STRING: return OK; --- 123,133 ---- { isn_T *isn; isntype_T isntype = ISN_2STRING; ! type_T *type; RETURN_OK_IF_SKIP(cctx); ! type = get_type_on_stack(cctx, -1 - offset); ! switch (type->tt_type) { // nothing to be done case VAR_STRING: return OK; *************** *** 152,162 **** case VAR_JOB: case VAR_CHANNEL: case VAR_INSTR: ! to_string_error((*type)->tt_type); return FAIL; } ! *type = &t_string; if ((isn = generate_instr(cctx, isntype)) == NULL) return FAIL; isn->isn_arg.tostring.offset = offset; --- 163,173 ---- case VAR_JOB: case VAR_CHANNEL: case VAR_INSTR: ! to_string_error(type->tt_type); return FAIL; } ! set_type_on_stack(cctx, &t_string, -1 - offset); if ((isn = generate_instr(cctx, isntype)) == NULL) return FAIL; isn->isn_arg.tostring.offset = offset; *************** *** 193,199 **** type_T *type2, exprtype_T expr_type) { - garray_T *stack = &cctx->ctx_type_stack; isn_T *isn = generate_instr_drop(cctx, vartype == VAR_NUMBER ? ISN_OPNR : vartype == VAR_LIST ? ISN_ADDLIST --- 204,209 ---- *************** *** 225,231 **** if (vartype == VAR_LIST && type1->tt_type == VAR_LIST && type2->tt_type == VAR_LIST && type1->tt_member != type2->tt_member) ! (((type_T **)stack->ga_data)[stack->ga_len - 1]) = &t_list_any; return isn == NULL ? FAIL : OK; } --- 235,241 ---- if (vartype == VAR_LIST && type1->tt_type == VAR_LIST && type2->tt_type == VAR_LIST && type1->tt_member != type2->tt_member) ! set_type_on_stack(cctx, &t_list_any, 0); return isn == NULL ? FAIL : OK; } *************** *** 256,262 **** int generate_two_op(cctx_T *cctx, char_u *op) { - garray_T *stack = &cctx->ctx_type_stack; type_T *type1; type_T *type2; vartype_T vartype; --- 266,271 ---- *************** *** 265,272 **** 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) --- 274,281 ---- RETURN_OK_IF_SKIP(cctx); // Get the known type of the two items on the stack. ! type1 = get_type_on_stack(cctx, 1); ! type2 = get_type_on_stack(cctx, 0); vartype = operator_type(type1, type2); switch (*op) *************** *** 323,329 **** && (type2->tt_type == VAR_NUMBER || type2->tt_type == VAR_FLOAT)) type = &t_float; #endif ! ((type_T **)stack->ga_data)[stack->ga_len - 1] = type; } return OK; --- 332,338 ---- && (type2->tt_type == VAR_NUMBER || type2->tt_type == VAR_FLOAT)) type = &t_float; #endif ! set_type_on_stack(cctx, type, 0); } return OK; *************** *** 415,422 **** // 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]->tt_type; ! type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type; isntype = get_compare_isn(exprtype, type1, type2); if (isntype == ISN_DROP) return FAIL; --- 424,431 ---- // 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 = get_type_on_stack(cctx, 1)->tt_type; ! type2 = get_type_on_stack(cctx, 0)->tt_type; isntype = get_compare_isn(exprtype, type1, type2); if (isntype == ISN_DROP) return FAIL; *************** *** 430,436 **** if (stack->ga_len >= 2) { --stack->ga_len; ! ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool; } return OK; --- 439,445 ---- if (stack->ga_len >= 2) { --stack->ga_len; ! set_type_on_stack(cctx, &t_bool, 0); } return OK; *************** *** 444,450 **** generate_2BOOL(cctx_T *cctx, int invert, int offset) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL) --- 453,458 ---- *************** *** 453,459 **** isn->isn_arg.tobool.offset = offset; // type becomes bool ! ((type_T **)stack->ga_data)[stack->ga_len + offset] = &t_bool; return OK; } --- 461,467 ---- isn->isn_arg.tobool.offset = offset; // type becomes bool ! set_type_on_stack(cctx, &t_bool, -1 - offset); return OK; } *************** *** 465,478 **** generate_COND2BOOL(cctx_T *cctx) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_COND2BOOL)) == NULL) return FAIL; // type becomes bool ! ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool; return OK; } --- 473,485 ---- generate_COND2BOOL(cctx_T *cctx) { isn_T *isn; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_COND2BOOL)) == NULL) return FAIL; // type becomes bool ! set_type_on_stack(cctx, &t_bool, 0); return OK; } *************** *** 485,491 **** int argidx) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL) --- 492,497 ---- *************** *** 495,501 **** isn->isn_arg.type.ct_arg_idx = (int8_T)argidx; // type becomes expected ! ((type_T **)stack->ga_data)[stack->ga_len + offset] = expected; return OK; } --- 501,507 ---- isn->isn_arg.type.ct_arg_idx = (int8_T)argidx; // type becomes expected ! set_type_on_stack(cctx, expected, -1 - offset); return OK; } *************** *** 567,573 **** generate_PUSHNR(cctx_T *cctx, varnumber_T number) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHNR, &t_number)) == NULL) --- 573,578 ---- *************** *** 576,582 **** if (number == 0 || number == 1) // A 0 or 1 number can also be used as a bool. ! ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_number_bool; return OK; } --- 581,587 ---- if (number == 0 || number == 1) // A 0 or 1 number can also be used as a bool. ! set_type_on_stack(cctx, &t_number_bool, 0); return OK; } *************** *** 747,755 **** generate_GETITEM(cctx_T *cctx, int index, int with_op) { isn_T *isn; ! garray_T *stack = &cctx->ctx_type_stack; ! type_T *type = ((type_T **)stack->ga_data)[stack->ga_len ! - (with_op ? 2 : 1)]; type_T *item_type = &t_any; RETURN_OK_IF_SKIP(cctx); --- 752,758 ---- generate_GETITEM(cctx_T *cctx, int index, int with_op) { isn_T *isn; ! type_T *type = get_type_on_stack(cctx, with_op ? 1 : 0); type_T *item_type = &t_any; RETURN_OK_IF_SKIP(cctx); *************** *** 767,777 **** isn->isn_arg.getitem.gi_with_op = with_op; // add the item type to the type stack ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! ((type_T **)stack->ga_data)[stack->ga_len] = item_type; ! ++stack->ga_len; ! return OK; } /* --- 770,776 ---- isn->isn_arg.getitem.gi_with_op = with_op; // add the item type to the type stack ! return push_type_stack(cctx, item_type); } /* *************** *** 895,901 **** isn_T *isn; RETURN_OK_IF_SKIP(cctx); ! if ((isn = generate_instr_type(cctx, isn_type, type)) == NULL) return FAIL; if (name != NULL) isn->isn_arg.string = vim_strsave(name); --- 894,900 ---- isn_T *isn; RETURN_OK_IF_SKIP(cctx); ! if ((isn = generate_instr_type2(cctx, isn_type, type, type)) == NULL) return FAIL; if (name != NULL) isn->isn_arg.string = vim_strsave(name); *************** *** 918,924 **** isn_T *isn; RETURN_OK_IF_SKIP(cctx); ! if ((isn = generate_instr_type(cctx, ISN_LOADOUTER, type)) == NULL) return FAIL; isn->isn_arg.outer.outer_idx = idx; isn->isn_arg.outer.outer_depth = nesting; --- 917,923 ---- isn_T *isn; RETURN_OK_IF_SKIP(cctx); ! if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL) return FAIL; isn->isn_arg.outer.outer_idx = idx; isn->isn_arg.outer.outer_depth = nesting; *************** *** 1050,1083 **** generate_NEWLIST(cctx_T *cctx, int count) { isn_T *isn; ! garray_T *stack = &cctx->ctx_type_stack; type_T *type; ! type_T *member; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL) return FAIL; isn->isn_arg.number = count; ! // get the member type from all the items on the stack. ! if (count == 0) ! member = &t_unknown; ! else ! member = get_member_type_from_stack( ! ((type_T **)stack->ga_data) + stack->ga_len, count, 1, ! cctx->ctx_type_list); ! type = get_list_type(member, cctx->ctx_type_list); // drop the value types ! stack->ga_len -= count; // add the list type to the type stack ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! ((type_T **)stack->ga_data)[stack->ga_len] = type; ! ++stack->ga_len; ! ! return OK; } /* --- 1049,1075 ---- generate_NEWLIST(cctx_T *cctx, int count) { isn_T *isn; ! type_T *member_type; ! type_T *decl_member_type; type_T *type; ! type_T *decl_type; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL) return FAIL; isn->isn_arg.number = count; ! // Get the member type and the declared member type from all the items on ! // the stack. ! member_type = get_member_type_from_stack(count, 1, &decl_member_type, cctx); ! type = get_list_type(member_type, cctx->ctx_type_list); ! decl_type = get_list_type(decl_member_type, cctx->ctx_type_list); // drop the value types ! cctx->ctx_type_stack.ga_len -= count; // add the list type to the type stack ! return push_type_stack2(cctx, type, decl_type); } /* *************** *** 1087,1119 **** generate_NEWDICT(cctx_T *cctx, int count) { isn_T *isn; ! garray_T *stack = &cctx->ctx_type_stack; type_T *type; ! type_T *member; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL) return FAIL; isn->isn_arg.number = count; ! if (count == 0) ! member = &t_void; ! else ! member = get_member_type_from_stack( ! ((type_T **)stack->ga_data) + stack->ga_len, count, 2, ! cctx->ctx_type_list); ! type = get_dict_type(member, cctx->ctx_type_list); // drop the key and value types ! stack->ga_len -= 2 * count; // add the dict type to the type stack ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! ((type_T **)stack->ga_data)[stack->ga_len] = type; ! ++stack->ga_len; ! ! return OK; } /* --- 1079,1104 ---- generate_NEWDICT(cctx_T *cctx, int count) { isn_T *isn; ! type_T *member_type; ! type_T *decl_member_type; type_T *type; ! type_T *decl_type; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL) return FAIL; isn->isn_arg.number = count; ! member_type = get_member_type_from_stack(count, 2, ! &decl_member_type, cctx); ! type = get_dict_type(member_type, cctx->ctx_type_list); ! decl_type = get_dict_type(decl_member_type, cctx->ctx_type_list); // drop the key and value types ! cctx->ctx_type_stack.ga_len -= 2 * count; // add the dict type to the type stack ! return push_type_stack2(cctx, type, decl_type); } /* *************** *** 1123,1129 **** generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc) { isn_T *isn; ! garray_T *stack = &cctx->ctx_type_stack; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) --- 1108,1114 ---- generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc) { isn_T *isn; ! type_T *type; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) *************** *** 1139,1151 **** if (ufunc->uf_flags & FC_CLOSURE) cctx->ctx_ufunc->uf_flags |= FC_CLOSURE; ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! ((type_T **)stack->ga_data)[stack->ga_len] = ! ufunc->uf_func_type == NULL ? &t_func_any : ufunc->uf_func_type; ! ++stack->ga_len; ! ! return OK; } /* --- 1124,1131 ---- if (ufunc->uf_flags & FC_CLOSURE) cctx->ctx_ufunc->uf_flags |= FC_CLOSURE; ! type = ufunc->uf_func_type == NULL ? &t_func_any : ufunc->uf_func_type; ! return push_type_stack(cctx, type); } /* *************** *** 1237,1256 **** generate_FOR(cctx_T *cctx, int loop_idx) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FOR)) == NULL) return FAIL; isn->isn_arg.forloop.for_idx = loop_idx; - if (GA_GROW_FAILS(stack, 1)) - return FAIL; // type doesn't matter, will be stored next ! ((type_T **)stack->ga_data)[stack->ga_len] = &t_any; ! ++stack->ga_len; ! ! return OK; } /* * Generate an ISN_TRYCONT instruction. --- 1217,1230 ---- generate_FOR(cctx_T *cctx, int loop_idx) { isn_T *isn; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FOR)) == NULL) return FAIL; isn->isn_arg.forloop.for_idx = loop_idx; // type doesn't matter, will be stored next ! return push_type_stack(cctx, &t_any); } /* * Generate an ISN_TRYCONT instruction. *************** *** 1281,1289 **** isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; int argoff; ! type_T **argtypes = NULL; ! type_T *shuffled_argtypes[MAX_FUNC_ARGS]; ! type_T *maptype = NULL; RETURN_OK_IF_SKIP(cctx); argoff = check_internal_func(func_idx, argcount); --- 1255,1265 ---- isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; int argoff; ! type2_T *typep; ! type2_T *argtypes = NULL; ! type2_T shuffled_argtypes[MAX_FUNC_ARGS]; ! type2_T *maptype = NULL; ! type_T *type; RETURN_OK_IF_SKIP(cctx); argoff = check_internal_func(func_idx, argcount); *************** *** 1301,1322 **** if (argcount > 0) { // Check the types of the arguments. ! argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount; if (method_call && argoff > 1) { int i; for (i = 0; i < argcount; ++i) shuffled_argtypes[i] = (i < argoff - 1) ! ? argtypes[i + 1] ! : (i == argoff - 1) ? argtypes[0] : argtypes[i]; argtypes = shuffled_argtypes; } if (internal_func_check_arg_types(argtypes, func_idx, argcount, cctx) == FAIL) return FAIL; if (internal_func_is_map(func_idx)) ! maptype = *argtypes; } if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL) --- 1277,1306 ---- if (argcount > 0) { // Check the types of the arguments. ! typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount; if (method_call && argoff > 1) { int i; for (i = 0; i < argcount; ++i) shuffled_argtypes[i] = (i < argoff - 1) ! ? typep[i + 1] ! : (i == argoff - 1) ? typep[0] : typep[i]; ! argtypes = shuffled_argtypes; ! } ! else ! { ! int i; ! ! for (i = 0; i < argcount; ++i) ! shuffled_argtypes[i] = typep[i]; argtypes = shuffled_argtypes; } if (internal_func_check_arg_types(argtypes, func_idx, argcount, cctx) == FAIL) return FAIL; if (internal_func_is_map(func_idx)) ! maptype = argtypes; } if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL) *************** *** 1326,1341 **** // Drop the argument types and push the return type. stack->ga_len -= argcount; ! if (GA_GROW_FAILS(stack, 1)) return FAIL; - ((type_T **)stack->ga_data)[stack->ga_len] = - internal_func_ret_type(func_idx, argcount, argtypes); - ++stack->ga_len; ! if (maptype != NULL && maptype->tt_member != NULL ! && maptype->tt_member != &t_any) // Check that map() didn't change the item types. ! generate_TYPECHECK(cctx, maptype, -1, 1); return OK; } --- 1310,1323 ---- // Drop the argument types and push the return type. stack->ga_len -= argcount; ! type = internal_func_ret_type(func_idx, argcount, argtypes); ! if (push_type_stack(cctx, type) == FAIL) return FAIL; ! if (maptype != NULL && maptype[0].type_curr->tt_member != NULL ! && maptype[0].type_curr->tt_member != &t_any) // Check that map() didn't change the item types. ! generate_TYPECHECK(cctx, maptype[0].type_curr, -1, 1); return OK; } *************** *** 1347,1360 **** int generate_LISTAPPEND(cctx_T *cctx) { - garray_T *stack = &cctx->ctx_type_stack; type_T *list_type; type_T *item_type; type_T *expected; // Caller already checked that list_type is a list. ! list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2]; ! item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; expected = list_type->tt_member; if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; --- 1329,1341 ---- int generate_LISTAPPEND(cctx_T *cctx) { type_T *list_type; type_T *item_type; type_T *expected; // Caller already checked that list_type is a list. ! list_type = get_type_on_stack(cctx, 1); ! item_type = get_type_on_stack(cctx, 0); expected = list_type->tt_member; if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; *************** *** 1362,1368 **** if (generate_instr(cctx, ISN_LISTAPPEND) == NULL) return FAIL; ! --stack->ga_len; // drop the argument return OK; } --- 1343,1349 ---- if (generate_instr(cctx, ISN_LISTAPPEND) == NULL) return FAIL; ! --cctx->ctx_type_stack.ga_len; // drop the argument return OK; } *************** *** 1373,1390 **** int generate_BLOBAPPEND(cctx_T *cctx) { - garray_T *stack = &cctx->ctx_type_stack; type_T *item_type; // Caller already checked that blob_type is a blob. ! item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL) return FAIL; ! --stack->ga_len; // drop the argument return OK; } --- 1354,1370 ---- int generate_BLOBAPPEND(cctx_T *cctx) { type_T *item_type; // Caller already checked that blob_type is a blob. ! item_type = get_type_on_stack(cctx, 0); if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL) return FAIL; ! --cctx->ctx_type_stack.ga_len; // drop the argument return OK; } *************** *** 1396,1402 **** generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; int regular_args = ufunc->uf_args.ga_len; int argcount = pushed_argcount; --- 1376,1381 ---- *************** *** 1424,1430 **** type_T *expected; type_T *actual; ! actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i]; if (actual == &t_special && i >= regular_args - ufunc->uf_def_args.ga_len) { --- 1403,1409 ---- type_T *expected; type_T *actual; ! actual = get_type_on_stack(cctx, argcount - i - 1); if (actual == &t_special && i >= regular_args - ufunc->uf_def_args.ga_len) { *************** *** 1479,1492 **** isn->isn_arg.ufunc.cuf_argcount = argcount; } ! stack->ga_len -= argcount; // drop the arguments ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! // add return value ! ((type_T **)stack->ga_data)[stack->ga_len] = ufunc->uf_ret_type; ! ++stack->ga_len; ! return OK; } /* --- 1458,1468 ---- isn->isn_arg.ufunc.cuf_argcount = argcount; } ! // drop the argument types ! cctx->ctx_type_stack.ga_len -= argcount; ! // add return type ! return push_type_stack(cctx, ufunc->uf_ret_type); } /* *************** *** 1496,1502 **** generate_UCALL(cctx_T *cctx, char_u *name, int argcount) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_UCALL)) == NULL) --- 1472,1477 ---- *************** *** 1504,1517 **** isn->isn_arg.ufunc.cuf_name = vim_strsave(name); isn->isn_arg.ufunc.cuf_argcount = argcount; ! stack->ga_len -= argcount; // drop the arguments ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! // add return value ! ((type_T **)stack->ga_data)[stack->ga_len] = &t_any; ! ++stack->ga_len; ! return OK; } /* --- 1479,1489 ---- isn->isn_arg.ufunc.cuf_name = vim_strsave(name); isn->isn_arg.ufunc.cuf_argcount = argcount; ! // drop the argument types ! cctx->ctx_type_stack.ga_len -= argcount; ! // add return value ! return push_type_stack(cctx, &t_any); } /* *************** *** 1527,1533 **** int at_top) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; type_T *ret_type; RETURN_OK_IF_SKIP(cctx); --- 1499,1504 ---- *************** *** 1557,1564 **** for (i = 0; i < argcount; ++i) { int offset = -argcount + i - (at_top ? 0 : 1); ! type_T *actual = ((type_T **)stack->ga_data)[ ! stack->ga_len + offset]; type_T *expected; if (varargs && i >= type->tt_argcount - 1) --- 1528,1534 ---- for (i = 0; i < argcount; ++i) { int offset = -argcount + i - (at_top ? 0 : 1); ! type_T *actual = get_type_on_stack(cctx, -1 - offset); type_T *expected; if (varargs && i >= type->tt_argcount - 1) *************** *** 1594,1603 **** isn->isn_arg.pfunc.cpf_top = at_top; isn->isn_arg.pfunc.cpf_argcount = argcount; ! stack->ga_len -= argcount; // drop the arguments ! // drop the funcref/partial, get back the return value ! ((type_T **)stack->ga_data)[stack->ga_len - 1] = ret_type; // If partial is above the arguments it must be cleared and replaced with // the return value. --- 1564,1574 ---- isn->isn_arg.pfunc.cpf_top = at_top; isn->isn_arg.pfunc.cpf_argcount = argcount; ! // drop the arguments and the funcref/partial ! cctx->ctx_type_stack.ga_len -= argcount + 1; ! // push the return value ! push_type_stack(cctx, ret_type); // If partial is above the arguments it must be cleared and replaced with // the return value. *************** *** 1614,1620 **** generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; type_T *type; RETURN_OK_IF_SKIP(cctx); --- 1585,1590 ---- *************** *** 1623,1629 **** isn->isn_arg.string = vim_strnsave(name, len); // check for dict type ! type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (type->tt_type != VAR_DICT && type != &t_any && type != &t_unknown) { char *tofree; --- 1593,1599 ---- isn->isn_arg.string = vim_strnsave(name, len); // check for dict type ! type = get_type_on_stack(cctx, 0); if (type->tt_type != VAR_DICT && type != &t_any && type != &t_unknown) { char *tofree; *************** *** 1636,1643 **** // change dict type to dict member type if (type->tt_type == VAR_DICT) { ! ((type_T **)stack->ga_data)[stack->ga_len - 1] = ! type->tt_member == &t_unknown ? &t_any : type->tt_member; } return OK; --- 1606,1614 ---- // change dict type to dict member type if (type->tt_type == VAR_DICT) { ! type_T *ntype = type->tt_member == &t_unknown ! ? &t_any : type->tt_member; ! set_type_on_stack(cctx, ntype, 0); } return OK; *************** *** 1734,1752 **** generate_LEGACY_EVAL(cctx_T *cctx, char_u *line) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_LEGACY_EVAL)) == NULL) return FAIL; isn->isn_arg.string = vim_strsave(line); ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! ((type_T **)stack->ga_data)[stack->ga_len] = &t_any; ! ++stack->ga_len; ! ! return OK; } int --- 1705,1717 ---- generate_LEGACY_EVAL(cctx_T *cctx, char_u *line) { isn_T *isn; RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_LEGACY_EVAL)) == NULL) return FAIL; isn->isn_arg.string = vim_strsave(line); ! return push_type_stack(cctx, &t_any); } int *************** *** 1767,1783 **** generate_RANGE(cctx_T *cctx, char_u *range) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL) return FAIL; isn->isn_arg.string = range; ! if (GA_GROW_FAILS(stack, 1)) ! return FAIL; ! ((type_T **)stack->ga_data)[stack->ga_len] = &t_number; ! ++stack->ga_len; ! return OK; } int --- 1732,1743 ---- generate_RANGE(cctx_T *cctx, char_u *range) { isn_T *isn; if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL) return FAIL; isn->isn_arg.string = range; ! return push_type_stack(cctx, &t_number); } int *** ../vim-8.2.3995/src/proto/vim9instr.pro 2021-12-25 18:23:20.766696178 +0000 --- src/proto/vim9instr.pro 2022-01-04 14:51:01.093638037 +0000 *************** *** 1,6 **** --- 1,7 ---- /* vim9instr.c */ isn_T *generate_instr(cctx_T *cctx, isntype_T isn_type); isn_T *generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop); + isn_T *generate_instr_type2(cctx_T *cctx, isntype_T isn_type, type_T *type, type_T *decl_type); isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type); isn_T *generate_instr_debug(cctx_T *cctx); int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx); *** ../vim-8.2.3995/src/vim9compile.c 2022-01-03 12:27:59.355039941 +0000 --- src/vim9compile.c 2022-01-04 11:19:33.943480350 +0000 *************** *** 1639,1645 **** int c = var_start[varlen]; int lines_len = cctx->ctx_ufunc->uf_lines.ga_len; char_u *p = var_start; - garray_T *stack = &cctx->ctx_type_stack; int res; // Evaluate "ll[expr]" of "ll[expr][idx]". End the line with a NUL and --- 1639,1644 ---- *************** *** 1657,1664 **** return FAIL; } ! lhs->lhs_type = stack->ga_len == 0 ? &t_void ! : ((type_T **)stack->ga_data)[stack->ga_len - 1]; // now we can properly check the type if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL && rhs_type != &t_void --- 1656,1663 ---- return FAIL; } ! lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void ! : get_type_on_stack(cctx, 0); // now we can properly check the type if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL && rhs_type != &t_void *************** *** 1717,1723 **** cctx_T *cctx) { vartype_T dest_type; - garray_T *stack = &cctx->ctx_type_stack; int range = FALSE; if (compile_assign_index(var_start, lhs, &range, cctx) == FAIL) --- 1716,1721 ---- *************** *** 1753,1764 **** if (range) { ! type = ((type_T **)stack->ga_data)[stack->ga_len - 2]; if (need_type(type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; } ! type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if ((dest_type != VAR_BLOB && type != &t_special) && need_type(type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) --- 1751,1762 ---- if (range) { ! type = get_type_on_stack(cctx, 1); if (need_type(type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; } ! type = get_type_on_stack(cctx, 0); if ((dest_type != VAR_BLOB && type != &t_special) && need_type(type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) *************** *** 1837,1843 **** int semicolon = 0; int did_generate_slice = FALSE; garray_T *instr = &cctx->ctx_instr; - garray_T *stack = &cctx->ctx_type_stack; char_u *op; int oplen = 0; int heredoc = FALSE; --- 1835,1840 ---- *************** *** 1929,1936 **** int needed_list_len; int did_check = FALSE; ! stacktype = stack->ga_len == 0 ? &t_void ! : ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (stacktype->tt_type == VAR_VOID) { emsg(_(e_cannot_use_void_value)); --- 1926,1933 ---- int needed_list_len; int did_check = FALSE; ! stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void ! : get_type_on_stack(cctx, 0); if (stacktype->tt_type == VAR_VOID) { emsg(_(e_cannot_use_void_value)); *************** *** 2073,2080 **** goto theend; } ! rhs_type = stack->ga_len == 0 ? &t_void ! : ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (lhs.lhs_lvar != NULL && (is_decl || !lhs.lhs_has_type)) { if ((rhs_type->tt_type == VAR_FUNC --- 2070,2077 ---- goto theend; } ! rhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void ! : get_type_on_stack(cctx, 0); if (lhs.lhs_lvar != NULL && (is_decl || !lhs.lhs_has_type)) { if ((rhs_type->tt_type == VAR_FUNC *************** *** 2230,2236 **** else { expected = lhs.lhs_member_type; ! stacktype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if ( #ifdef FEAT_FLOAT // If variable is float operation with number is OK. --- 2227,2233 ---- else { expected = lhs.lhs_member_type; ! stacktype = get_type_on_stack(cctx, 0); if ( #ifdef FEAT_FLOAT // If variable is float operation with number is OK. *************** *** 2527,2533 **** cctx.ctx_lnum = -1; cctx.ctx_outer = outer_cctx; ga_init2(&cctx.ctx_locals, sizeof(lvar_T), 10); ! ga_init2(&cctx.ctx_type_stack, sizeof(type_T *), 50); ga_init2(&cctx.ctx_imports, sizeof(imported_T), 10); cctx.ctx_type_list = &ufunc->uf_type_list; ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50); --- 2524,2531 ---- cctx.ctx_lnum = -1; cctx.ctx_outer = outer_cctx; ga_init2(&cctx.ctx_locals, sizeof(lvar_T), 10); ! // Each entry on the type stack consists of two type pointers. ! ga_init2(&cctx.ctx_type_stack, sizeof(type2_T), 50); ga_init2(&cctx.ctx_imports, sizeof(imported_T), 10); cctx.ctx_type_list = &ufunc->uf_type_list; ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50); *************** *** 2564,2570 **** SOURCING_LNUM = 0; // line number unknown for (i = 0; i < count; ++i) { - garray_T *stack = &cctx.ctx_type_stack; type_T *val_type; int arg_idx = first_def_arg + i; where_T where = WHERE_INIT; --- 2562,2567 ---- *************** *** 2588,2594 **** // If no type specified use the type of the default value. // Otherwise check that the default value type matches the // specified type. ! val_type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; where.wt_index = arg_idx + 1; if (ufunc->uf_arg_types[arg_idx] == &t_unknown) { --- 2585,2591 ---- // If no type specified use the type of the default value. // Otherwise check that the default value type matches the // specified type. ! val_type = get_type_on_stack(&cctx, 0); where.wt_index = arg_idx + 1; if (ufunc->uf_arg_types[arg_idx] == &t_unknown) { *** ../vim-8.2.3995/src/evalfunc.c 2022-01-01 19:42:11.108600753 +0000 --- src/evalfunc.c 2022-01-04 14:23:55.771581543 +0000 *************** *** 195,201 **** // Context passed to an arg_ function. typedef struct { int arg_count; // actual argument count ! type_T **arg_types; // list of argument types int arg_idx; // current argument index (first arg is zero) cctx_T *arg_cctx; } argcontext_T; --- 195,201 ---- // Context passed to an arg_ function. typedef struct { int arg_count; // actual argument count ! type2_T *arg_types; // list of argument types int arg_idx; // current argument index (first arg is zero) cctx_T *arg_cctx; } argcontext_T; *************** *** 203,209 **** // A function to check one argument type. The first argument is the type to // check. If needed, other argument types can be obtained with the context. // E.g. if "arg_idx" is 1, then (type - 1) is the first argument type. ! typedef int (*argcheck_T)(type_T *, argcontext_T *); /* * Call need_type() to check an argument type. --- 203,209 ---- // A function to check one argument type. The first argument is the type to // check. If needed, other argument types can be obtained with the context. // E.g. if "arg_idx" is 1, then (type - 1) is the first argument type. ! typedef int (*argcheck_T)(type_T *, type_T *, argcontext_T *); /* * Call need_type() to check an argument type. *************** *** 225,231 **** * Check "type" is a float or a number. */ static int ! arg_float_or_nr(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 225,231 ---- * Check "type" is a float or a number. */ static int ! arg_float_or_nr(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 240,246 **** * Check "type" is a number. */ static int ! arg_number(type_T *type, argcontext_T *context) { return check_arg_type(&t_number, type, context); } --- 240,246 ---- * Check "type" is a number. */ static int ! arg_number(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_number, type, context); } *************** *** 249,255 **** * Check "type" is a dict of 'any'. */ static int ! arg_dict_any(type_T *type, argcontext_T *context) { return check_arg_type(&t_dict_any, type, context); } --- 249,255 ---- * Check "type" is a dict of 'any'. */ static int ! arg_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_dict_any, type, context); } *************** *** 258,264 **** * Check "type" is a list of 'any'. */ static int ! arg_list_any(type_T *type, argcontext_T *context) { return check_arg_type(&t_list_any, type, context); } --- 258,264 ---- * Check "type" is a list of 'any'. */ static int ! arg_list_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_list_any, type, context); } *************** *** 267,273 **** * Check "type" is a list of numbers. */ static int ! arg_list_number(type_T *type, argcontext_T *context) { return check_arg_type(&t_list_number, type, context); } --- 267,273 ---- * Check "type" is a list of numbers. */ static int ! arg_list_number(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_list_number, type, context); } *************** *** 276,282 **** * Check "type" is a list of strings. */ static int ! arg_list_string(type_T *type, argcontext_T *context) { return check_arg_type(&t_list_string, type, context); } --- 276,282 ---- * Check "type" is a list of strings. */ static int ! arg_list_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_list_string, type, context); } *************** *** 285,291 **** * Check "type" is a string. */ static int ! arg_string(type_T *type, argcontext_T *context) { return check_arg_type(&t_string, type, context); } --- 285,291 ---- * Check "type" is a string. */ static int ! arg_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_string, type, context); } *************** *** 294,300 **** * Check "type" is a blob */ static int ! arg_blob(type_T *type, argcontext_T *context) { return check_arg_type(&t_blob, type, context); } --- 294,300 ---- * Check "type" is a blob */ static int ! arg_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_blob, type, context); } *************** *** 303,309 **** * Check "type" is a bool or number 0 or 1. */ static int ! arg_bool(type_T *type, argcontext_T *context) { return check_arg_type(&t_bool, type, context); } --- 303,309 ---- * Check "type" is a bool or number 0 or 1. */ static int ! arg_bool(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_bool, type, context); } *************** *** 312,318 **** * Check "type" is a list of 'any' or a blob. */ static int ! arg_list_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 312,318 ---- * Check "type" is a list of 'any' or a blob. */ static int ! arg_list_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 327,333 **** * Check "type" is a string or a number */ static int ! arg_string_or_nr(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 327,333 ---- * Check "type" is a string or a number */ static int ! arg_string_or_nr(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 342,348 **** * Check "type" is a buffer (string or a number) */ static int ! arg_buffer(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 342,348 ---- * Check "type" is a buffer (string or a number) */ static int ! arg_buffer(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 357,363 **** * Check "type" is a buffer or a dict of any */ static int ! arg_buffer_or_dict_any(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 357,363 ---- * Check "type" is a buffer or a dict of any */ static int ! arg_buffer_or_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 373,379 **** * Check "type" is a line (string or a number) */ static int ! arg_lnum(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 373,379 ---- * Check "type" is a line (string or a number) */ static int ! arg_lnum(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 388,394 **** * Check "type" is a string or a list of strings. */ static int ! arg_string_or_list_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 388,394 ---- * Check "type" is a string or a list of strings. */ static int ! arg_string_or_list_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 411,417 **** * Check "type" is a string or a list of 'any' */ static int ! arg_string_or_list_any(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 411,417 ---- * Check "type" is a string or a list of 'any' */ static int ! arg_string_or_list_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 426,432 **** * Check "type" is a string or a blob */ static int ! arg_string_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 426,432 ---- * Check "type" is a string or a blob */ static int ! arg_string_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 441,447 **** * Check "type" is a list of 'any' or a dict of 'any'. */ static int ! arg_list_or_dict(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 441,447 ---- * Check "type" is a list of 'any' or a dict of 'any'. */ static int ! arg_list_or_dict(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 456,462 **** * Check "type" is a list of 'any' or a dict of 'any' or a blob. */ static int ! arg_list_or_dict_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 456,462 ---- * Check "type" is a list of 'any' or a dict of 'any' or a blob. */ static int ! arg_list_or_dict_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 472,478 **** * Check "type" is a list of 'any' or a dict of 'any' or a blob or a string. */ static int ! arg_list_or_dict_or_blob_or_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 472,478 ---- * Check "type" is a list of 'any' or a dict of 'any' or a blob or a string. */ static int ! arg_list_or_dict_or_blob_or_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 489,495 **** * Check second argument of filter(): func must return a bool. */ static int ! arg_filter_func(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_FUNC && !(type->tt_member->tt_type == VAR_BOOL --- 489,495 ---- * Check second argument of filter(): func must return a bool. */ static int ! arg_filter_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_FUNC && !(type->tt_member->tt_type == VAR_BOOL *************** *** 507,513 **** * Check second argument of map(). */ static int ! arg_map_func(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_FUNC && type->tt_member != &t_any --- 507,513 ---- * Check second argument of map(). */ static int ! arg_map_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_FUNC && type->tt_member != &t_any *************** *** 515,526 **** { type_T *expected = NULL; ! if (context->arg_types[0]->tt_type == VAR_LIST ! || context->arg_types[0]->tt_type == VAR_DICT) ! expected = context->arg_types[0]->tt_member; ! else if (context->arg_types[0]->tt_type == VAR_STRING) expected = &t_string; ! else if (context->arg_types[0]->tt_type == VAR_BLOB) expected = &t_number; if (expected != NULL) { --- 515,526 ---- { type_T *expected = NULL; ! if (context->arg_types[0].type_curr->tt_type == VAR_LIST ! || context->arg_types[0].type_curr->tt_type == VAR_DICT) ! expected = context->arg_types[0].type_curr->tt_member; ! else if (context->arg_types[0].type_curr->tt_type == VAR_STRING) expected = &t_string; ! else if (context->arg_types[0].type_curr->tt_type == VAR_BLOB) expected = &t_number; if (expected != NULL) { *************** *** 539,545 **** * Also accept a number, one and zero are accepted. */ static int ! arg_string_or_func(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 539,545 ---- * Also accept a number, one and zero are accepted. */ static int ! arg_string_or_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 557,563 **** * Check "type" is a list of 'any' or a blob or a string. */ static int ! arg_string_list_or_blob(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 557,563 ---- * Check "type" is a list of 'any' or a blob or a string. */ static int ! arg_string_list_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 573,579 **** * Check "type" is a job. */ static int ! arg_job(type_T *type, argcontext_T *context) { return check_arg_type(&t_job, type, context); } --- 573,579 ---- * Check "type" is a job. */ static int ! arg_job(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { return check_arg_type(&t_job, type, context); } *************** *** 582,588 **** * Check "type" is a channel or a job. */ static int ! arg_chan_or_job(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 582,588 ---- * Check "type" is a channel or a job. */ static int ! arg_chan_or_job(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 594,606 **** } /* ! * Check "type" is the same type as the previous argument. * Must not be used for the first argcheck_T entry. */ static int ! arg_same_as_prev(type_T *type, argcontext_T *context) { ! type_T *prev_type = context->arg_types[context->arg_idx - 1]; return check_arg_type(prev_type, type, context); } --- 594,606 ---- } /* ! * Check "type" can be used as the type_decl of the previous argument. * Must not be used for the first argcheck_T entry. */ static int ! arg_same_as_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { ! type_T *prev_type = context->arg_types[context->arg_idx - 1].type_decl; return check_arg_type(prev_type, type, context); } *************** *** 611,621 **** * Must not be used for the first argcheck_T entry. */ static int ! arg_same_struct_as_prev(type_T *type, argcontext_T *context) { ! type_T *prev_type = context->arg_types[context->arg_idx - 1]; ! if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type) return check_arg_type(prev_type, type, context); return OK; } --- 611,621 ---- * Must not be used for the first argcheck_T entry. */ static int ! arg_same_struct_as_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { ! type_T *prev_type = context->arg_types[context->arg_idx - 1].type_curr; ! if (prev_type->tt_type != context->arg_types[context->arg_idx].type_curr->tt_type) return check_arg_type(prev_type, type, context); return OK; } *************** *** 625,633 **** * Must not be used for the first argcheck_T entry. */ static int ! arg_item_of_prev(type_T *type, argcontext_T *context) { ! type_T *prev_type = context->arg_types[context->arg_idx - 1]; type_T *expected; if (prev_type->tt_type == VAR_LIST) --- 625,633 ---- * Must not be used for the first argcheck_T entry. */ static int ! arg_item_of_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { ! type_T *prev_type = context->arg_types[context->arg_idx - 1].type_curr; type_T *expected; if (prev_type->tt_type == VAR_LIST) *************** *** 645,651 **** * Check "type" is a string or a number or a list */ static int ! arg_str_or_nr_or_list(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 645,651 ---- * Check "type" is a string or a number or a list */ static int ! arg_str_or_nr_or_list(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 661,667 **** * Check "type" is a dict of 'any' or a string */ static int ! arg_dict_any_or_string(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 661,667 ---- * Check "type" is a dict of 'any' or a string */ static int ! arg_dict_any_or_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 677,690 **** * any) */ static int ! arg_extend3(type_T *type, argcontext_T *context) { ! type_T *first_type = context->arg_types[context->arg_idx - 2]; if (first_type->tt_type == VAR_LIST) ! return arg_number(type, context); if (first_type->tt_type == VAR_DICT) ! return arg_string(type, context); return OK; } --- 677,690 ---- * any) */ static int ! arg_extend3(type_T *type, type_T *decl_type, argcontext_T *context) { ! type_T *first_type = context->arg_types[context->arg_idx - 2].type_curr; if (first_type->tt_type == VAR_LIST) ! return arg_number(type, decl_type, context); if (first_type->tt_type == VAR_DICT) ! return arg_string(type, decl_type, context); return OK; } *************** *** 693,699 **** * funcref) */ static int ! arg_get1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 693,699 ---- * funcref) */ static int ! arg_get1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 713,719 **** * blob or list or dict) */ static int ! arg_len1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 713,719 ---- * blob or list or dict) */ static int ! arg_len1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 733,746 **** * any) */ static int ! arg_remove2(type_T *type, argcontext_T *context) { ! type_T *first_type = context->arg_types[context->arg_idx - 1]; if (first_type->tt_type == VAR_LIST || first_type->tt_type == VAR_BLOB) ! return arg_number(type, context); if (first_type->tt_type == VAR_DICT) ! return arg_string_or_nr(type, context); return OK; } --- 733,746 ---- * any) */ static int ! arg_remove2(type_T *type, type_T *decl_type, argcontext_T *context) { ! type_T *first_type = context->arg_types[context->arg_idx - 1].type_curr; if (first_type->tt_type == VAR_LIST || first_type->tt_type == VAR_BLOB) ! return arg_number(type, decl_type, context); if (first_type->tt_type == VAR_DICT) ! return arg_string_or_nr(type, decl_type, context); return OK; } *************** *** 749,755 **** * list or any) */ static int ! arg_repeat1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 749,755 ---- * list or any) */ static int ! arg_repeat1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 767,773 **** * or any) */ static int ! arg_slice1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 767,773 ---- * or any) */ static int ! arg_slice1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 785,791 **** * or any) */ static int ! arg_count1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 785,791 ---- * or any) */ static int ! arg_count1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 803,809 **** * list or any) */ static int ! arg_cursor1(type_T *type, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN --- 803,809 ---- * list or any) */ static int ! arg_cursor1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) { if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN *************** *** 960,1111 **** * Note that "argtypes" is NULL if "argcount" is zero. */ static type_T * ! ret_void(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_void; } static type_T * ! ret_any(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_any; } static type_T * ! ret_bool(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_bool; } static type_T * ! ret_number_bool(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_number_bool; } static type_T * ! ret_number(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_number; } static type_T * ! ret_float(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_float; } static type_T * ! ret_string(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_string; } static type_T * ! ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_list_any; } static type_T * ! ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_list_number; } static type_T * ! ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_list_string; } static type_T * ! ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_list_dict_any; } static type_T * ! ret_list_items(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_list_list_any; } static type_T * ! ret_list_string_items(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_list_list_string; } static type_T * ! ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_dict_any; } static type_T * ! ret_job_info(int argcount, type_T **argtypes UNUSED) { if (argcount == 0) return &t_list_job; return &t_dict_any; } static type_T * ! ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_dict_number; } static type_T * ! ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_dict_string; } static type_T * ! ret_blob(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_blob; } static type_T * ! ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_func_any; } static type_T * ! ret_func_unknown(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_func_unknown; } static type_T * ! ret_channel(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_channel; } static type_T * ! ret_job(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_job; } static type_T * ! ret_first_arg(int argcount, type_T **argtypes) { if (argcount > 0) ! return argtypes[0]; return &t_void; } static type_T * ! ret_repeat(int argcount, type_T **argtypes) { if (argcount == 0) return &t_any; ! if (argtypes[0] == &t_number) return &t_string; ! return argtypes[0]; } // for map(): returns first argument but item type may differ static type_T * ! ret_first_cont(int argcount, type_T **argtypes) { if (argcount > 0) { ! if (argtypes[0]->tt_type == VAR_LIST) return &t_list_any; ! if (argtypes[0]->tt_type == VAR_DICT) return &t_dict_any; ! if (argtypes[0]->tt_type == VAR_BLOB) ! return argtypes[0]; } return &t_any; } // for finddir() static type_T * ! ret_finddir(int argcount, type_T **argtypes UNUSED) { if (argcount < 3) return &t_string; --- 960,1117 ---- * Note that "argtypes" is NULL if "argcount" is zero. */ static type_T * ! ret_void(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_void; } static type_T * ! ret_any(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_any; } static type_T * ! ret_bool(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_bool; } static type_T * ! ret_number_bool(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_number_bool; } static type_T * ! ret_number(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_number; } static type_T * ! ret_float(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_float; } static type_T * ! ret_string(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_string; } static type_T * ! ret_list_any(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_list_any; } static type_T * ! ret_list_number(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_list_number; } static type_T * ! ret_list_string(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_list_string; } static type_T * ! ret_list_dict_any(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_list_dict_any; } static type_T * ! ret_list_items(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_list_list_any; } static type_T * ! ret_list_string_items(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_list_list_string; } static type_T * ! ret_dict_any(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_dict_any; } static type_T * ! ret_job_info(int argcount, type2_T *argtypes UNUSED) { if (argcount == 0) return &t_list_job; return &t_dict_any; } static type_T * ! ret_dict_number(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_dict_number; } static type_T * ! ret_dict_string(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_dict_string; } static type_T * ! ret_blob(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_blob; } static type_T * ! ret_func_any(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_func_any; } static type_T * ! ret_func_unknown(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_func_unknown; } static type_T * ! ret_channel(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_channel; } static type_T * ! ret_job(int argcount UNUSED, type2_T *argtypes UNUSED) { return &t_job; } static type_T * ! ret_first_arg(int argcount, type2_T *argtypes) { if (argcount > 0) ! return argtypes[0].type_curr; return &t_void; } static type_T * ! ret_repeat(int argcount, type2_T *argtypes) { if (argcount == 0) return &t_any; ! if (argtypes[0].type_curr == &t_number) return &t_string; ! return argtypes[0].type_curr; } // for map(): returns first argument but item type may differ static type_T * ! ret_first_cont(int argcount, type2_T *argtypes) { if (argcount > 0) { ! if (argtypes[0].type_curr->tt_type == VAR_LIST) return &t_list_any; ! if (argtypes[0].type_curr->tt_type == VAR_DICT) return &t_dict_any; ! if (argtypes[0].type_curr->tt_type == VAR_BLOB) ! return argtypes[0].type_curr; } return &t_any; } + // for getline() + static type_T * + ret_getline(int argcount, type2_T *argtypes UNUSED) + { + return argcount == 1 ? &t_string : &t_list_string; + } // for finddir() static type_T * ! ret_finddir(int argcount, type2_T *argtypes UNUSED) { if (argcount < 3) return &t_string; *************** *** 1118,1124 **** * one. */ static type_T * ! ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED) { if (argcount > 0) return &t_dict_any; --- 1124,1130 ---- * one. */ static type_T * ! ret_list_or_dict_0(int argcount, type2_T *argtypes UNUSED) { if (argcount > 0) return &t_dict_any; *************** *** 1130,1136 **** * are two. */ static type_T * ! ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED) { if (argcount > 1) return &t_dict_any; --- 1136,1142 ---- * are two. */ static type_T * ! ret_list_or_dict_1(int argcount, type2_T *argtypes UNUSED) { if (argcount > 1) return &t_dict_any; *************** *** 1138,1144 **** } static type_T * ! ret_argv(int argcount, type_T **argtypes UNUSED) { // argv() returns list of strings if (argcount == 0) --- 1144,1150 ---- } static type_T * ! ret_argv(int argcount, type2_T *argtypes UNUSED) { // argv() returns list of strings if (argcount == 0) *************** *** 1149,1169 **** } static type_T * ! ret_remove(int argcount, type_T **argtypes) { if (argcount > 0) { ! if (argtypes[0]->tt_type == VAR_LIST ! || argtypes[0]->tt_type == VAR_DICT) ! return argtypes[0]->tt_member; ! if (argtypes[0]->tt_type == VAR_BLOB) return &t_number; } return &t_any; } static type_T * ! ret_getreg(int argcount, type_T **argtypes UNUSED) { // Assume that if the third argument is passed it's non-zero if (argcount == 3) --- 1155,1175 ---- } static type_T * ! ret_remove(int argcount, type2_T *argtypes) { if (argcount > 0) { ! if (argtypes[0].type_curr->tt_type == VAR_LIST ! || argtypes[0].type_curr->tt_type == VAR_DICT) ! return argtypes[0].type_curr->tt_member; ! if (argtypes[0].type_curr->tt_type == VAR_BLOB) return &t_number; } return &t_any; } static type_T * ! ret_getreg(int argcount, type2_T *argtypes UNUSED) { // Assume that if the third argument is passed it's non-zero if (argcount == 3) *************** *** 1172,1178 **** } static type_T * ! ret_maparg(int argcount, type_T **argtypes UNUSED) { // Assume that if the fourth argument is passed it's non-zero if (argcount == 4) --- 1178,1184 ---- } static type_T * ! ret_maparg(int argcount, type2_T *argtypes UNUSED) { // Assume that if the fourth argument is passed it's non-zero if (argcount == 4) *************** *** 1191,1197 **** char f_max_argc; // maximal number of arguments char f_argtype; // for method: FEARG_ values argcheck_T *f_argcheck; // list of functions to check argument types ! type_T *(*f_retfunc)(int argcount, type_T **argtypes); // return type function void (*f_func)(typval_T *args, typval_T *rvar); // implementation of function --- 1197,1203 ---- char f_max_argc; // maximal number of arguments char f_argtype; // for method: FEARG_ values argcheck_T *f_argcheck; // list of functions to check argument types ! type_T *(*f_retfunc)(int argcount, type2_T *argtypes); // return type function void (*f_func)(typval_T *args, typval_T *rvar); // implementation of function *************** *** 1599,1605 **** {"getjumplist", 0, 2, FEARG_1, arg2_number, ret_list_any, f_getjumplist}, {"getline", 1, 2, FEARG_1, arg2_lnum, ! ret_f_getline, f_getline}, {"getloclist", 1, 2, 0, arg2_number_dict_any, ret_list_or_dict_1, f_getloclist}, {"getmarklist", 0, 1, FEARG_1, arg1_buffer, --- 1605,1611 ---- {"getjumplist", 0, 2, FEARG_1, arg2_number, ret_list_any, f_getjumplist}, {"getline", 1, 2, FEARG_1, arg2_lnum, ! ret_getline, f_getline}, {"getloclist", 1, 2, 0, arg2_number_dict_any, ret_list_or_dict_1, f_getloclist}, {"getmarklist", 0, 1, FEARG_1, arg1_buffer, *************** *** 2576,2582 **** */ int internal_func_check_arg_types( ! type_T **types, int idx, int argcount, cctx_T *cctx) --- 2582,2588 ---- */ int internal_func_check_arg_types( ! type2_T *types, int idx, int argcount, cctx_T *cctx) *************** *** 2595,2601 **** if (argchecks[i] != NULL) { context.arg_idx = i; ! if (argchecks[i](types[i], &context) == FAIL) return FAIL; } } --- 2601,2608 ---- if (argchecks[i] != NULL) { context.arg_idx = i; ! if (argchecks[i](types[i].type_curr, types[i].type_decl, ! &context) == FAIL) return FAIL; } } *************** *** 2621,2627 **** * "argcount" may be less than the actual count when only getting the type. */ type_T * ! internal_func_ret_type(int idx, int argcount, type_T **argtypes) { return global_functions[idx].f_retfunc(argcount, argtypes); } --- 2628,2634 ---- * "argcount" may be less than the actual count when only getting the type. */ type_T * ! internal_func_ret_type(int idx, int argcount, type2_T *argtypes) { return global_functions[idx].f_retfunc(argcount, argtypes); } *** ../vim-8.2.3995/src/proto/evalfunc.pro 2021-08-06 20:34:34.626972208 +0100 --- src/proto/evalfunc.pro 2022-01-04 14:12:59.504679799 +0000 *************** *** 5,13 **** int find_internal_func(char_u *name); int has_internal_func(char_u *name); char *internal_func_name(int idx); ! int internal_func_check_arg_types(type_T **types, int idx, int argcount, cctx_T *cctx); void internal_func_get_argcount(int idx, int *argcount, int *min_argcount); ! type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes); int internal_func_is_map(int idx); int check_internal_func(int idx, int argcount); int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv); --- 5,13 ---- int find_internal_func(char_u *name); int has_internal_func(char_u *name); char *internal_func_name(int idx); ! int internal_func_check_arg_types(type2_T *types, int idx, int argcount, cctx_T *cctx); void internal_func_get_argcount(int idx, int *argcount, int *min_argcount); ! type_T *internal_func_ret_type(int idx, int argcount, type2_T *argtypes); int internal_func_is_map(int idx); int check_internal_func(int idx, int argcount); int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv); *** ../vim-8.2.3995/src/evalbuffer.c 2021-12-28 11:24:44.636994380 +0000 --- src/evalbuffer.c 2022-01-04 14:16:54.944217860 +0000 *************** *** 807,818 **** get_buffer_lines(buf, lnum, end, TRUE, rettv); } - type_T * - ret_f_getline(int argcount, type_T **argtypes UNUSED) - { - return argcount == 1 ? &t_string : &t_list_string; - } - /* * "getline(lnum, [end])" function */ --- 807,812 ---- *** ../vim-8.2.3995/src/proto/evalbuffer.pro 2020-03-01 13:04:42.224689018 +0000 --- src/proto/evalbuffer.pro 2022-01-04 14:18:10.860067084 +0000 *************** *** 16,22 **** void f_deletebufline(typval_T *argvars, typval_T *rettv); void f_getbufinfo(typval_T *argvars, typval_T *rettv); void f_getbufline(typval_T *argvars, typval_T *rettv); - type_T *ret_f_getline(int argcount, type_T **argtypes); void f_getline(typval_T *argvars, typval_T *rettv); void f_setbufline(typval_T *argvars, typval_T *rettv); void f_setline(typval_T *argvars, typval_T *rettv); --- 16,21 ---- *** ../vim-8.2.3995/src/vim9expr.c 2022-01-01 16:20:56.900401501 +0000 --- src/vim9expr.c 2022-01-04 13:21:15.462750309 +0000 *************** *** 77,83 **** int compile_member(int is_slice, int *keeping_dict, cctx_T *cctx) { ! type_T **typep; garray_T *stack = &cctx->ctx_type_stack; vartype_T vartype; type_T *idxtype; --- 77,83 ---- int compile_member(int is_slice, int *keeping_dict, cctx_T *cctx) { ! type2_T *typep; garray_T *stack = &cctx->ctx_type_stack; vartype_T vartype; type_T *idxtype; *************** *** 85,96 **** // We can index a list, dict and blob. If we don't know the type // we can use the index value type. If we still don't know use an "ANY" // instruction. ! typep = ((type_T **)stack->ga_data) + stack->ga_len ! - (is_slice ? 3 : 2); ! vartype = (*typep)->tt_type; ! idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; // If the index is a string, the variable must be a Dict. ! if ((*typep == &t_any || *typep == &t_unknown) && idxtype == &t_string) vartype = VAR_DICT; if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB) { --- 85,97 ---- // We can index a list, dict and blob. If we don't know the type // we can use the index value type. If we still don't know use an "ANY" // instruction. ! // TODO: what about the decl type? ! typep = (((type2_T *)stack->ga_data) + stack->ga_len - (is_slice ? 3 : 2)); ! vartype = typep->type_curr->tt_type; ! idxtype = (((type2_T *)stack->ga_data) + stack->ga_len - 1)->type_curr; // If the index is a string, the variable must be a Dict. ! if ((typep->type_curr == &t_any || typep->type_curr == &t_unknown) ! && idxtype == &t_string) vartype = VAR_DICT; if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB) { *************** *** 98,104 **** return FAIL; if (is_slice) { ! idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 2]; if (need_type(idxtype, &t_number, -2, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; --- 99,105 ---- return FAIL; if (is_slice) { ! idxtype = get_type_on_stack(cctx, 1); if (need_type(idxtype, &t_number, -2, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; *************** *** 112,130 **** emsg(_(e_cannot_slice_dictionary)); return FAIL; } ! if ((*typep)->tt_type == VAR_DICT) { ! *typep = (*typep)->tt_member; ! if (*typep == &t_unknown) // empty dict was used ! *typep = &t_any; } else { ! if (need_type(*typep, &t_dict_any, -2, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; ! *typep = &t_any; } if (may_generate_2STRING(-1, FALSE, cctx) == FAIL) return FAIL; --- 113,141 ---- emsg(_(e_cannot_slice_dictionary)); return FAIL; } ! if (typep->type_curr->tt_type == VAR_DICT) { ! typep->type_curr = typep->type_curr->tt_member; ! if (typep->type_curr == &t_unknown) // empty dict was used ! typep->type_curr = &t_any; ! if (typep->type_decl->tt_type == VAR_DICT) ! { ! typep->type_decl = typep->type_decl->tt_member; ! if (typep->type_decl == &t_unknown) ! // empty dict was used ! typep->type_decl = &t_any; ! } ! else ! typep->type_decl = typep->type_curr; } else { ! if (need_type(typep->type_curr, &t_dict_any, -2, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; ! typep->type_curr = &t_any; ! typep->type_decl = &t_any; } if (may_generate_2STRING(-1, FALSE, cctx) == FAIL) return FAIL; *************** *** 135,141 **** } else if (vartype == VAR_STRING) { ! *typep = &t_string; if ((is_slice ? generate_instr_drop(cctx, ISN_STRSLICE, 2) : generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL) --- 146,153 ---- } else if (vartype == VAR_STRING) { ! typep->type_curr = &t_string; ! typep->type_decl = &t_string; if ((is_slice ? generate_instr_drop(cctx, ISN_STRSLICE, 2) : generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL) *************** *** 145,162 **** { if (is_slice) { ! *typep = &t_blob; if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL) return FAIL; } else { ! *typep = &t_number; if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL) return FAIL; } } ! else if (vartype == VAR_LIST || *typep == &t_any || *typep == &t_unknown) { if (is_slice) { --- 157,177 ---- { if (is_slice) { ! typep->type_curr = &t_blob; ! typep->type_decl = &t_blob; if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL) return FAIL; } else { ! typep->type_curr = &t_number; ! typep->type_decl = &t_number; if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL) return FAIL; } } ! else if (vartype == VAR_LIST || typep->type_curr == &t_any ! || typep->type_curr == &t_unknown) { if (is_slice) { *************** *** 167,178 **** } else { ! if ((*typep)->tt_type == VAR_LIST) { ! *typep = (*typep)->tt_member; ! if (*typep == &t_unknown) // empty list was used ! *typep = &t_any; } if (generate_instr_drop(cctx, vartype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1) --- 182,202 ---- } else { ! if (typep->type_curr->tt_type == VAR_LIST) { ! typep->type_curr = typep->type_curr->tt_member; ! if (typep->type_curr == &t_unknown) // empty list was used ! typep->type_curr = &t_any; ! if (typep->type_decl->tt_type == VAR_LIST) ! { ! typep->type_decl = typep->type_decl->tt_member; ! if (typep->type_decl == &t_unknown) ! // empty list was used ! typep->type_decl = &t_any; ! } ! else ! typep->type_decl = typep->type_curr; } if (generate_instr_drop(cctx, vartype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1) *************** *** 709,717 **** if (STRCMP(name, "add") == 0 && argcount == 2) { ! garray_T *stack = &cctx->ctx_type_stack; ! type_T *type = ((type_T **)stack->ga_data)[ ! stack->ga_len - 2]; // add() can be compiled to instructions if we know the type if (type->tt_type == VAR_LIST) --- 733,739 ---- if (STRCMP(name, "add") == 0 && argcount == 2) { ! type_T *type = get_type_on_stack(cctx, 1); // add() can be compiled to instructions if we know the type if (type->tt_type == VAR_LIST) *************** *** 758,765 **** if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK) { ! garray_T *stack = &cctx->ctx_type_stack; ! type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; res = generate_PCALL(cctx, argcount, namebuf, type, FALSE); goto theend; --- 780,786 ---- if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK) { ! type_T *type = get_type_on_stack(cctx, 0); res = generate_PCALL(cctx, argcount, namebuf, type, FALSE); goto theend; *************** *** 1421,1430 **** int bool_on_stack(cctx_T *cctx) { - garray_T *stack = &cctx->ctx_type_stack; type_T *type; ! type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (type == &t_bool) return OK; --- 1442,1450 ---- int bool_on_stack(cctx_T *cctx) { type_T *type; ! type = get_type_on_stack(cctx, 0); if (type == &t_bool) return OK; *************** *** 1470,1479 **** { int negate = *p == '-'; isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; type_T *type; ! type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (type != &t_float && need_type(type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; --- 1490,1498 ---- { int negate = *p == '-'; isn_T *isn; type_T *type; ! type = get_type_on_stack(cctx, 0); if (type != &t_float && need_type(type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; *************** *** 1594,1600 **** // is not a function call. if (**arg == '(') { - garray_T *stack = &cctx->ctx_type_stack; type_T *type; int argcount = 0; --- 1613,1618 ---- *************** *** 1603,1609 **** ppconst->pp_is_const = FALSE; // funcref(arg) ! type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; *arg = skipwhite(p + 1); if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL) --- 1621,1627 ---- ppconst->pp_is_const = FALSE; // funcref(arg) ! type = get_type_on_stack(cctx, 0); *arg = skipwhite(p + 1); if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL) *************** *** 1672,1683 **** // instructions of the expression and move the type of the // expression after the argument types. This is what ISN_PCALL // expects. - stack = &cctx->ctx_type_stack; arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end; if (arg_isn_count > 0) { int expr_isn_count = expr_isn_end - expr_isn_start; isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count); if (isn == NULL) return FAIL; --- 1690,1702 ---- // instructions of the expression and move the type of the // expression after the argument types. This is what ISN_PCALL // expects. arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end; if (arg_isn_count > 0) { int expr_isn_count = expr_isn_end - expr_isn_start; isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count); + type_T *decl_type; + type2_T *typep; if (isn == NULL) return FAIL; *************** *** 1693,1707 **** isn, sizeof(isn_T) * expr_isn_count); vim_free(isn); ! type = ((type_T **)stack->ga_data)[type_idx_start]; ! mch_memmove(((type_T **)stack->ga_data) + type_idx_start, ! ((type_T **)stack->ga_data) + type_idx_start + 1, ! sizeof(type_T *) * (stack->ga_len - type_idx_start - 1)); ! ((type_T **)stack->ga_data)[stack->ga_len - 1] = type; } ! type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL) return FAIL; } --- 1712,1730 ---- isn, sizeof(isn_T) * expr_isn_count); vim_free(isn); ! typep = ((type2_T *)stack->ga_data) + type_idx_start; ! type = typep->type_curr; ! decl_type = typep->type_decl; ! mch_memmove(((type2_T *)stack->ga_data) + type_idx_start, ! ((type2_T *)stack->ga_data) + type_idx_start + 1, ! sizeof(type2_T) * (stack->ga_len - type_idx_start - 1)); ! typep = ((type2_T *)stack->ga_data) + stack->ga_len - 1; ! typep->type_curr = type; ! typep->type_decl = decl_type; } ! type = get_type_on_stack(cctx, 0); if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL) return FAIL; } *************** *** 2152,2163 **** if (want_type != NULL) { - garray_T *stack = &cctx->ctx_type_stack; type_T *actual; where_T where = WHERE_INIT; generate_ppconst(cctx, ppconst); ! actual = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (check_type_maybe(want_type, actual, FALSE, where) != OK) { if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) --- 2175,2185 ---- if (want_type != NULL) { type_T *actual; where_T where = WHERE_INIT; generate_ppconst(cctx, ppconst); ! actual = get_type_on_stack(cctx, 0); if (check_type_maybe(want_type, actual, FALSE, where) != OK) { if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) *************** *** 2781,2787 **** generate_JUMP(cctx, op_falsy ? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0); if (op_falsy) ! type1 = ((type_T **)stack->ga_data)[stack->ga_len]; } // evaluate the second expression; any type is accepted --- 2803,2809 ---- generate_JUMP(cctx, op_falsy ? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0); if (op_falsy) ! type1 = get_type_on_stack(cctx, -1); } // evaluate the second expression; any type is accepted *************** *** 2797,2804 **** if (!op_falsy) { // remember the type and drop it --stack->ga_len; - type1 = ((type_T **)stack->ga_data)[stack->ga_len]; end_idx = instr->ga_len; generate_JUMP(cctx, JUMP_ALWAYS, 0); --- 2819,2826 ---- if (!op_falsy) { // remember the type and drop it + type1 = get_type_on_stack(cctx, 0); --stack->ga_len; end_idx = instr->ga_len; generate_JUMP(cctx, JUMP_ALWAYS, 0); *************** *** 2849,2855 **** ppconst->pp_is_const = FALSE; // If the types differ, the result has a more generic type. ! typep = ((type_T **)stack->ga_data) + stack->ga_len - 1; common_type(type1, *typep, typep, cctx->ctx_type_list); // jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE --- 2871,2878 ---- ppconst->pp_is_const = FALSE; // If the types differ, the result has a more generic type. ! typep = &((((type2_T *)stack->ga_data) ! + stack->ga_len - 1)->type_curr); common_type(type1, *typep, typep, cctx->ctx_type_list); // jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE *** ../vim-8.2.3995/src/vim9cmds.c 2022-01-02 14:08:15.154169689 +0000 --- src/vim9cmds.c 2022-01-04 10:40:39.281160362 +0000 *************** *** 769,775 **** int var_list = FALSE; int semicolon = FALSE; size_t varlen; - garray_T *stack = &cctx->ctx_type_stack; garray_T *instr = &cctx->ctx_instr; scope_T *scope; lvar_T *loop_lvar; // loop iteration variable --- 769,774 ---- *************** *** 841,847 **** { // If we know the type of "var" and it is not a supported type we can // give an error now. ! vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING && vartype->tt_type != VAR_BLOB --- 840,846 ---- { // If we know the type of "var" and it is not a supported type we can // give an error now. ! vartype = get_type_on_stack(cctx, 0); if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING && vartype->tt_type != VAR_BLOB *************** *** 898,915 **** generate_UNPACK(cctx, var_count, semicolon); arg = skipwhite(arg + 1); // skip white after '[' ! // the list item is replaced by a number of items ! if (GA_GROW_FAILS(stack, var_count - 1)) ! { ! drop_scope(cctx); ! return NULL; ! } ! --stack->ga_len; for (idx = 0; idx < var_count; ++idx) { ! ((type_T **)stack->ga_data)[stack->ga_len] = ! (semicolon && idx == 0) ? vartype : item_type; ! ++stack->ga_len; } } --- 897,915 ---- generate_UNPACK(cctx, var_count, semicolon); arg = skipwhite(arg + 1); // skip white after '[' ! // drop the list item ! --cctx->ctx_type_stack.ga_len; ! ! // add type of the items for (idx = 0; idx < var_count; ++idx) { ! type_T *type = (semicolon && idx == 0) ? vartype : item_type; ! ! if (push_type_stack(cctx, type) == FAIL) ! { ! drop_scope(cctx); ! return NULL; ! } } } *************** *** 1647,1653 **** char_u *expr_start; int count = 0; int start_ctx_lnum = cctx->ctx_lnum; - garray_T *stack = &cctx->ctx_type_stack; type_T *type; for (;;) --- 1647,1652 ---- *************** *** 1661,1667 **** if (cctx->ctx_skip != SKIP_YES) { // check for non-void type ! type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (type->tt_type == VAR_VOID) { semsg(_(e_expression_does_not_result_in_value_str), expr_start); --- 1660,1666 ---- if (cctx->ctx_skip != SKIP_YES) { // check for non-void type ! type = get_type_on_stack(cctx, 0); if (type->tt_type == VAR_VOID) { semsg(_(e_expression_does_not_result_in_value_str), expr_start); *************** *** 2182,2188 **** compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx) { char_u *p = arg; - garray_T *stack = &cctx->ctx_type_stack; type_T *stack_type; if (*p != NUL && *p != '|' && *p != '\n') --- 2181,2186 ---- *************** *** 2211,2217 **** // "check_return_type" with uf_ret_type set to &t_unknown is used // for an inline function without a specified return type. Set the // return type here. ! stack_type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL || cctx->ctx_ufunc->uf_ret_type == &t_unknown || cctx->ctx_ufunc->uf_ret_type == &t_any)) --- 2209,2215 ---- // "check_return_type" with uf_ret_type set to &t_unknown is used // for an inline function without a specified return type. Set the // return type here. ! stack_type = get_type_on_stack(cctx, 0); if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL || cctx->ctx_ufunc->uf_ret_type == &t_unknown || cctx->ctx_ufunc->uf_ret_type == &t_any)) *** ../vim-8.2.3995/src/testdir/test_vim9_assign.vim 2022-01-03 12:27:59.359039951 +0000 --- src/testdir/test_vim9_assign.vim 2022-01-04 15:14:59.208032865 +0000 *************** *** 639,644 **** --- 639,661 ---- extend(test_null_list(), ['x']) END CheckScriptFailure(lines, 'E1134:', 2) + + # using global var has no declared type + g:myList = [] + g:myList->extend([1]) + g:myList->extend(['x']) + assert_equal([1, 'x'], g:myList) + unlet g:myList + + # using declared list gives an error + lines =<< trim END + var l: list + g:myList = l + g:myList->extend([1]) + g:myList->extend(['x']) + END + CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list but got list', 4) + unlet g:myList enddef def Test_extend_dict() *************** *** 963,968 **** --- 980,1002 ---- var anyDict: dict = {a: 0} assert_equal({a: 0, b: 'x'}, extend(anyDict, {b: 'x'})) + # using global var, which has no declared type + g:myDict = {} + g:myDict->extend({a: 1}) + g:myDict->extend({b: 'x'}) + assert_equal({a: 1, b: 'x'}, g:myDict) + unlet g:myDict + + # using list with declared type gives an error + lines =<< trim END + var d: dict + g:myDict = d + g:myDict->extend({a: 1}) + g:myDict->extend({b: 'x'}) + END + CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict but got dict', 4) + unlet g:myDict + # assignment to script-local dict lines =<< trim END vim9script *** ../vim-8.2.3995/src/testdir/test_vim9_builtin.vim 2022-01-03 16:52:24.616533342 +0000 --- src/testdir/test_vim9_builtin.vim 2022-01-04 14:56:01.857123573 +0000 *************** *** 982,1007 **** END CheckDefAndScriptSuccess(lines) - # FIXME: this should not fail when compiled lines =<< trim END - vim9script assert_equal([1, 2, "x"], extend([1, 2], ["x"])) assert_equal([1, "b", 1], extend([1], ["b", 1])) END ! CheckScriptSuccess(lines) CheckDefAndScriptFailure(['extend("a", 1)'], ['E1013: Argument 1: type mismatch, expected list but got string', 'E712: Argument of extend() must be a List or Dictionary']) ! CheckDefAndScriptFailure(['extend([1, 2], 3)'], ['E1013: Argument 2: type mismatch, expected list but got number', 'E712: Argument of extend() must be a List or Dictionary']) CheckDefAndScriptFailure(['var ll = [1, 2]', 'extend(ll, ["x"])'], ['E1013: Argument 2: type mismatch, expected list but got list', 'E1013: Argument 2: type mismatch, expected list but got list']) CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string') ! CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict but got number') ! CheckDefFailure(['extend({a: 1}, {b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict but got dict') CheckDefFailure(['extend({a: 1}, {b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number') - CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list but got list') - CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list') - CheckScriptFailure(['vim9script', 'var l = [1]', 'extend(l, ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list in extend()') enddef --- 982,1003 ---- END CheckDefAndScriptSuccess(lines) lines =<< trim END assert_equal([1, 2, "x"], extend([1, 2], ["x"])) assert_equal([1, "b", 1], extend([1], ["b", 1])) + + assert_equal({a: 1, b: "x"}, extend({a: 1}, {b: "x"})) END ! CheckDefAndScriptSuccess(lines) CheckDefAndScriptFailure(['extend("a", 1)'], ['E1013: Argument 1: type mismatch, expected list but got string', 'E712: Argument of extend() must be a List or Dictionary']) ! CheckDefAndScriptFailure(['extend([1, 2], 3)'], ['E1013: Argument 2: type mismatch, expected list but got number', 'E712: Argument of extend() must be a List or Dictionary']) CheckDefAndScriptFailure(['var ll = [1, 2]', 'extend(ll, ["x"])'], ['E1013: Argument 2: type mismatch, expected list but got list', 'E1013: Argument 2: type mismatch, expected list but got list']) CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string') ! CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict but got number') CheckDefFailure(['extend({a: 1}, {b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number') CheckScriptFailure(['vim9script', 'var l = [1]', 'extend(l, ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list in extend()') enddef *** ../vim-8.2.3995/src/version.c 2022-01-03 17:32:42.687980478 +0000 --- src/version.c 2022-01-03 21:49:40.701052514 +0000 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 3996, /**/ -- hundred-and-one symptoms of being an internet addict: 214. Your MCI "Circle of Friends" are all Hayes-compatible. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///