Mercurial > vim
comparison src/vim9expr.c @ 26935:ccb9be1cdd71 v8.2.3996
patch 8.2.3996: Vim9: type checking lacks information about declared type
Commit: https://github.com/vim/vim/commit/078a46161e8b1b30bf306d6c1f4f0af7c616a989
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Jan 4 15:17:03 2022 +0000
patch 8.2.3996: Vim9: type checking lacks information about declared type
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.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 04 Jan 2022 16:30:06 +0100 |
parents | 612339679616 |
children | 8796f1384750 |
comparison
equal
deleted
inserted
replaced
26934:2d3dd8065e25 | 26935:ccb9be1cdd71 |
---|---|
75 * "keeping_dict" is used for dict[func](arg) to pass dict to func. | 75 * "keeping_dict" is used for dict[func](arg) to pass dict to func. |
76 */ | 76 */ |
77 int | 77 int |
78 compile_member(int is_slice, int *keeping_dict, cctx_T *cctx) | 78 compile_member(int is_slice, int *keeping_dict, cctx_T *cctx) |
79 { | 79 { |
80 type_T **typep; | 80 type2_T *typep; |
81 garray_T *stack = &cctx->ctx_type_stack; | 81 garray_T *stack = &cctx->ctx_type_stack; |
82 vartype_T vartype; | 82 vartype_T vartype; |
83 type_T *idxtype; | 83 type_T *idxtype; |
84 | 84 |
85 // We can index a list, dict and blob. If we don't know the type | 85 // We can index a list, dict and blob. If we don't know the type |
86 // we can use the index value type. If we still don't know use an "ANY" | 86 // we can use the index value type. If we still don't know use an "ANY" |
87 // instruction. | 87 // instruction. |
88 typep = ((type_T **)stack->ga_data) + stack->ga_len | 88 // TODO: what about the decl type? |
89 - (is_slice ? 3 : 2); | 89 typep = (((type2_T *)stack->ga_data) + stack->ga_len - (is_slice ? 3 : 2)); |
90 vartype = (*typep)->tt_type; | 90 vartype = typep->type_curr->tt_type; |
91 idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | 91 idxtype = (((type2_T *)stack->ga_data) + stack->ga_len - 1)->type_curr; |
92 // If the index is a string, the variable must be a Dict. | 92 // If the index is a string, the variable must be a Dict. |
93 if ((*typep == &t_any || *typep == &t_unknown) && idxtype == &t_string) | 93 if ((typep->type_curr == &t_any || typep->type_curr == &t_unknown) |
94 && idxtype == &t_string) | |
94 vartype = VAR_DICT; | 95 vartype = VAR_DICT; |
95 if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB) | 96 if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB) |
96 { | 97 { |
97 if (need_type(idxtype, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) | 98 if (need_type(idxtype, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) |
98 return FAIL; | 99 return FAIL; |
99 if (is_slice) | 100 if (is_slice) |
100 { | 101 { |
101 idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 2]; | 102 idxtype = get_type_on_stack(cctx, 1); |
102 if (need_type(idxtype, &t_number, -2, 0, cctx, | 103 if (need_type(idxtype, &t_number, -2, 0, cctx, |
103 FALSE, FALSE) == FAIL) | 104 FALSE, FALSE) == FAIL) |
104 return FAIL; | 105 return FAIL; |
105 } | 106 } |
106 } | 107 } |
110 if (is_slice) | 111 if (is_slice) |
111 { | 112 { |
112 emsg(_(e_cannot_slice_dictionary)); | 113 emsg(_(e_cannot_slice_dictionary)); |
113 return FAIL; | 114 return FAIL; |
114 } | 115 } |
115 if ((*typep)->tt_type == VAR_DICT) | 116 if (typep->type_curr->tt_type == VAR_DICT) |
116 { | 117 { |
117 *typep = (*typep)->tt_member; | 118 typep->type_curr = typep->type_curr->tt_member; |
118 if (*typep == &t_unknown) | 119 if (typep->type_curr == &t_unknown) |
119 // empty dict was used | 120 // empty dict was used |
120 *typep = &t_any; | 121 typep->type_curr = &t_any; |
122 if (typep->type_decl->tt_type == VAR_DICT) | |
123 { | |
124 typep->type_decl = typep->type_decl->tt_member; | |
125 if (typep->type_decl == &t_unknown) | |
126 // empty dict was used | |
127 typep->type_decl = &t_any; | |
128 } | |
129 else | |
130 typep->type_decl = typep->type_curr; | |
121 } | 131 } |
122 else | 132 else |
123 { | 133 { |
124 if (need_type(*typep, &t_dict_any, -2, 0, cctx, | 134 if (need_type(typep->type_curr, &t_dict_any, -2, 0, cctx, |
125 FALSE, FALSE) == FAIL) | 135 FALSE, FALSE) == FAIL) |
126 return FAIL; | 136 return FAIL; |
127 *typep = &t_any; | 137 typep->type_curr = &t_any; |
138 typep->type_decl = &t_any; | |
128 } | 139 } |
129 if (may_generate_2STRING(-1, FALSE, cctx) == FAIL) | 140 if (may_generate_2STRING(-1, FALSE, cctx) == FAIL) |
130 return FAIL; | 141 return FAIL; |
131 if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL) | 142 if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL) |
132 return FAIL; | 143 return FAIL; |
133 if (keeping_dict != NULL) | 144 if (keeping_dict != NULL) |
134 *keeping_dict = TRUE; | 145 *keeping_dict = TRUE; |
135 } | 146 } |
136 else if (vartype == VAR_STRING) | 147 else if (vartype == VAR_STRING) |
137 { | 148 { |
138 *typep = &t_string; | 149 typep->type_curr = &t_string; |
150 typep->type_decl = &t_string; | |
139 if ((is_slice | 151 if ((is_slice |
140 ? generate_instr_drop(cctx, ISN_STRSLICE, 2) | 152 ? generate_instr_drop(cctx, ISN_STRSLICE, 2) |
141 : generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL) | 153 : generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL) |
142 return FAIL; | 154 return FAIL; |
143 } | 155 } |
144 else if (vartype == VAR_BLOB) | 156 else if (vartype == VAR_BLOB) |
145 { | 157 { |
146 if (is_slice) | 158 if (is_slice) |
147 { | 159 { |
148 *typep = &t_blob; | 160 typep->type_curr = &t_blob; |
161 typep->type_decl = &t_blob; | |
149 if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL) | 162 if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL) |
150 return FAIL; | 163 return FAIL; |
151 } | 164 } |
152 else | 165 else |
153 { | 166 { |
154 *typep = &t_number; | 167 typep->type_curr = &t_number; |
168 typep->type_decl = &t_number; | |
155 if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL) | 169 if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL) |
156 return FAIL; | 170 return FAIL; |
157 } | 171 } |
158 } | 172 } |
159 else if (vartype == VAR_LIST || *typep == &t_any || *typep == &t_unknown) | 173 else if (vartype == VAR_LIST || typep->type_curr == &t_any |
174 || typep->type_curr == &t_unknown) | |
160 { | 175 { |
161 if (is_slice) | 176 if (is_slice) |
162 { | 177 { |
163 if (generate_instr_drop(cctx, | 178 if (generate_instr_drop(cctx, |
164 vartype == VAR_LIST ? ISN_LISTSLICE : ISN_ANYSLICE, | 179 vartype == VAR_LIST ? ISN_LISTSLICE : ISN_ANYSLICE, |
165 2) == FAIL) | 180 2) == FAIL) |
166 return FAIL; | 181 return FAIL; |
167 } | 182 } |
168 else | 183 else |
169 { | 184 { |
170 if ((*typep)->tt_type == VAR_LIST) | 185 if (typep->type_curr->tt_type == VAR_LIST) |
171 { | 186 { |
172 *typep = (*typep)->tt_member; | 187 typep->type_curr = typep->type_curr->tt_member; |
173 if (*typep == &t_unknown) | 188 if (typep->type_curr == &t_unknown) |
174 // empty list was used | 189 // empty list was used |
175 *typep = &t_any; | 190 typep->type_curr = &t_any; |
191 if (typep->type_decl->tt_type == VAR_LIST) | |
192 { | |
193 typep->type_decl = typep->type_decl->tt_member; | |
194 if (typep->type_decl == &t_unknown) | |
195 // empty list was used | |
196 typep->type_decl = &t_any; | |
197 } | |
198 else | |
199 typep->type_decl = typep->type_curr; | |
176 } | 200 } |
177 if (generate_instr_drop(cctx, | 201 if (generate_instr_drop(cctx, |
178 vartype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1) | 202 vartype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1) |
179 == FAIL) | 203 == FAIL) |
180 return FAIL; | 204 return FAIL; |
707 goto theend; | 731 goto theend; |
708 } | 732 } |
709 | 733 |
710 if (STRCMP(name, "add") == 0 && argcount == 2) | 734 if (STRCMP(name, "add") == 0 && argcount == 2) |
711 { | 735 { |
712 garray_T *stack = &cctx->ctx_type_stack; | 736 type_T *type = get_type_on_stack(cctx, 1); |
713 type_T *type = ((type_T **)stack->ga_data)[ | |
714 stack->ga_len - 2]; | |
715 | 737 |
716 // add() can be compiled to instructions if we know the type | 738 // add() can be compiled to instructions if we know the type |
717 if (type->tt_type == VAR_LIST) | 739 if (type->tt_type == VAR_LIST) |
718 { | 740 { |
719 // inline "add(list, item)" so that the type can be checked | 741 // inline "add(list, item)" so that the type can be checked |
756 // Not for eome#Func(), it will be loaded later. | 778 // Not for eome#Func(), it will be loaded later. |
757 p = namebuf; | 779 p = namebuf; |
758 if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload | 780 if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload |
759 && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK) | 781 && compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK) |
760 { | 782 { |
761 garray_T *stack = &cctx->ctx_type_stack; | 783 type_T *type = get_type_on_stack(cctx, 0); |
762 type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | |
763 | 784 |
764 res = generate_PCALL(cctx, argcount, namebuf, type, FALSE); | 785 res = generate_PCALL(cctx, argcount, namebuf, type, FALSE); |
765 goto theend; | 786 goto theend; |
766 } | 787 } |
767 | 788 |
1419 * condition. Give an error and return FAIL if not. | 1440 * condition. Give an error and return FAIL if not. |
1420 */ | 1441 */ |
1421 int | 1442 int |
1422 bool_on_stack(cctx_T *cctx) | 1443 bool_on_stack(cctx_T *cctx) |
1423 { | 1444 { |
1424 garray_T *stack = &cctx->ctx_type_stack; | |
1425 type_T *type; | 1445 type_T *type; |
1426 | 1446 |
1427 type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | 1447 type = get_type_on_stack(cctx, 0); |
1428 if (type == &t_bool) | 1448 if (type == &t_bool) |
1429 return OK; | 1449 return OK; |
1430 | 1450 |
1431 if (type == &t_any | 1451 if (type == &t_any |
1432 || type == &t_unknown | 1452 || type == &t_unknown |
1468 --p; | 1488 --p; |
1469 if (*p == '-' || *p == '+') | 1489 if (*p == '-' || *p == '+') |
1470 { | 1490 { |
1471 int negate = *p == '-'; | 1491 int negate = *p == '-'; |
1472 isn_T *isn; | 1492 isn_T *isn; |
1473 garray_T *stack = &cctx->ctx_type_stack; | |
1474 type_T *type; | 1493 type_T *type; |
1475 | 1494 |
1476 type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | 1495 type = get_type_on_stack(cctx, 0); |
1477 if (type != &t_float && need_type(type, &t_number, | 1496 if (type != &t_float && need_type(type, &t_number, |
1478 -1, 0, cctx, FALSE, FALSE) == FAIL) | 1497 -1, 0, cctx, FALSE, FALSE) == FAIL) |
1479 return FAIL; | 1498 return FAIL; |
1480 | 1499 |
1481 while (p > start && (p[-1] == '-' || p[-1] == '+')) | 1500 while (p > start && (p[-1] == '-' || p[-1] == '+')) |
1592 | 1611 |
1593 // Do not skip over white space to find the "(", "execute 'x' (expr)" | 1612 // Do not skip over white space to find the "(", "execute 'x' (expr)" |
1594 // is not a function call. | 1613 // is not a function call. |
1595 if (**arg == '(') | 1614 if (**arg == '(') |
1596 { | 1615 { |
1597 garray_T *stack = &cctx->ctx_type_stack; | |
1598 type_T *type; | 1616 type_T *type; |
1599 int argcount = 0; | 1617 int argcount = 0; |
1600 | 1618 |
1601 if (generate_ppconst(cctx, ppconst) == FAIL) | 1619 if (generate_ppconst(cctx, ppconst) == FAIL) |
1602 return FAIL; | 1620 return FAIL; |
1603 ppconst->pp_is_const = FALSE; | 1621 ppconst->pp_is_const = FALSE; |
1604 | 1622 |
1605 // funcref(arg) | 1623 // funcref(arg) |
1606 type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | 1624 type = get_type_on_stack(cctx, 0); |
1607 | 1625 |
1608 *arg = skipwhite(p + 1); | 1626 *arg = skipwhite(p + 1); |
1609 if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL) | 1627 if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL) |
1610 return FAIL; | 1628 return FAIL; |
1611 if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL) | 1629 if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL) |
1670 | 1688 |
1671 // Move the instructions for the arguments to before the | 1689 // Move the instructions for the arguments to before the |
1672 // instructions of the expression and move the type of the | 1690 // instructions of the expression and move the type of the |
1673 // expression after the argument types. This is what ISN_PCALL | 1691 // expression after the argument types. This is what ISN_PCALL |
1674 // expects. | 1692 // expects. |
1675 stack = &cctx->ctx_type_stack; | |
1676 arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end; | 1693 arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end; |
1677 if (arg_isn_count > 0) | 1694 if (arg_isn_count > 0) |
1678 { | 1695 { |
1679 int expr_isn_count = expr_isn_end - expr_isn_start; | 1696 int expr_isn_count = expr_isn_end - expr_isn_start; |
1680 isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count); | 1697 isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count); |
1698 type_T *decl_type; | |
1699 type2_T *typep; | |
1681 | 1700 |
1682 if (isn == NULL) | 1701 if (isn == NULL) |
1683 return FAIL; | 1702 return FAIL; |
1684 mch_memmove(isn, ((isn_T *)cctx->ctx_instr.ga_data) | 1703 mch_memmove(isn, ((isn_T *)cctx->ctx_instr.ga_data) |
1685 + expr_isn_start, | 1704 + expr_isn_start, |
1691 mch_memmove(((isn_T *)cctx->ctx_instr.ga_data) | 1710 mch_memmove(((isn_T *)cctx->ctx_instr.ga_data) |
1692 + expr_isn_start + arg_isn_count, | 1711 + expr_isn_start + arg_isn_count, |
1693 isn, sizeof(isn_T) * expr_isn_count); | 1712 isn, sizeof(isn_T) * expr_isn_count); |
1694 vim_free(isn); | 1713 vim_free(isn); |
1695 | 1714 |
1696 type = ((type_T **)stack->ga_data)[type_idx_start]; | 1715 typep = ((type2_T *)stack->ga_data) + type_idx_start; |
1697 mch_memmove(((type_T **)stack->ga_data) + type_idx_start, | 1716 type = typep->type_curr; |
1698 ((type_T **)stack->ga_data) + type_idx_start + 1, | 1717 decl_type = typep->type_decl; |
1699 sizeof(type_T *) | 1718 mch_memmove(((type2_T *)stack->ga_data) + type_idx_start, |
1719 ((type2_T *)stack->ga_data) + type_idx_start + 1, | |
1720 sizeof(type2_T) | |
1700 * (stack->ga_len - type_idx_start - 1)); | 1721 * (stack->ga_len - type_idx_start - 1)); |
1701 ((type_T **)stack->ga_data)[stack->ga_len - 1] = type; | 1722 typep = ((type2_T *)stack->ga_data) + stack->ga_len - 1; |
1723 typep->type_curr = type; | |
1724 typep->type_decl = decl_type; | |
1702 } | 1725 } |
1703 | 1726 |
1704 type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | 1727 type = get_type_on_stack(cctx, 0); |
1705 if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL) | 1728 if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL) |
1706 return FAIL; | 1729 return FAIL; |
1707 } | 1730 } |
1708 else | 1731 else |
1709 { | 1732 { |
2150 if (compile_expr8(arg, cctx, ppconst) == FAIL) | 2173 if (compile_expr8(arg, cctx, ppconst) == FAIL) |
2151 return FAIL; | 2174 return FAIL; |
2152 | 2175 |
2153 if (want_type != NULL) | 2176 if (want_type != NULL) |
2154 { | 2177 { |
2155 garray_T *stack = &cctx->ctx_type_stack; | |
2156 type_T *actual; | 2178 type_T *actual; |
2157 where_T where = WHERE_INIT; | 2179 where_T where = WHERE_INIT; |
2158 | 2180 |
2159 generate_ppconst(cctx, ppconst); | 2181 generate_ppconst(cctx, ppconst); |
2160 actual = ((type_T **)stack->ga_data)[stack->ga_len - 1]; | 2182 actual = get_type_on_stack(cctx, 0); |
2161 if (check_type_maybe(want_type, actual, FALSE, where) != OK) | 2183 if (check_type_maybe(want_type, actual, FALSE, where) != OK) |
2162 { | 2184 { |
2163 if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) | 2185 if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) |
2164 == FAIL) | 2186 == FAIL) |
2165 return FAIL; | 2187 return FAIL; |
2779 if (op_falsy) | 2801 if (op_falsy) |
2780 end_idx = instr->ga_len; | 2802 end_idx = instr->ga_len; |
2781 generate_JUMP(cctx, op_falsy | 2803 generate_JUMP(cctx, op_falsy |
2782 ? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0); | 2804 ? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0); |
2783 if (op_falsy) | 2805 if (op_falsy) |
2784 type1 = ((type_T **)stack->ga_data)[stack->ga_len]; | 2806 type1 = get_type_on_stack(cctx, -1); |
2785 } | 2807 } |
2786 | 2808 |
2787 // evaluate the second expression; any type is accepted | 2809 // evaluate the second expression; any type is accepted |
2788 if (may_get_next_line_error(p + 1 + op_falsy, arg, cctx) == FAIL) | 2810 if (may_get_next_line_error(p + 1 + op_falsy, arg, cctx) == FAIL) |
2789 return FAIL; | 2811 return FAIL; |
2795 generate_ppconst(cctx, ppconst); | 2817 generate_ppconst(cctx, ppconst); |
2796 | 2818 |
2797 if (!op_falsy) | 2819 if (!op_falsy) |
2798 { | 2820 { |
2799 // remember the type and drop it | 2821 // remember the type and drop it |
2822 type1 = get_type_on_stack(cctx, 0); | |
2800 --stack->ga_len; | 2823 --stack->ga_len; |
2801 type1 = ((type_T **)stack->ga_data)[stack->ga_len]; | |
2802 | 2824 |
2803 end_idx = instr->ga_len; | 2825 end_idx = instr->ga_len; |
2804 generate_JUMP(cctx, JUMP_ALWAYS, 0); | 2826 generate_JUMP(cctx, JUMP_ALWAYS, 0); |
2805 | 2827 |
2806 // jump here from JUMP_IF_FALSE | 2828 // jump here from JUMP_IF_FALSE |
2847 | 2869 |
2848 generate_ppconst(cctx, ppconst); | 2870 generate_ppconst(cctx, ppconst); |
2849 ppconst->pp_is_const = FALSE; | 2871 ppconst->pp_is_const = FALSE; |
2850 | 2872 |
2851 // If the types differ, the result has a more generic type. | 2873 // If the types differ, the result has a more generic type. |
2852 typep = ((type_T **)stack->ga_data) + stack->ga_len - 1; | 2874 typep = &((((type2_T *)stack->ga_data) |
2875 + stack->ga_len - 1)->type_curr); | |
2853 common_type(type1, *typep, typep, cctx->ctx_type_list); | 2876 common_type(type1, *typep, typep, cctx->ctx_type_list); |
2854 | 2877 |
2855 // jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE | 2878 // jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE |
2856 isn = ((isn_T *)instr->ga_data) + end_idx; | 2879 isn = ((isn_T *)instr->ga_data) + end_idx; |
2857 isn->isn_arg.jump.jump_where = instr->ga_len; | 2880 isn->isn_arg.jump.jump_where = instr->ga_len; |