| author | |
| committer | |
| log | 17cb85dfb837949cd3a559fe8e99dee1f72463a4 |
| tree | a35d23e26938586ba0fb706964e2b7c2b4b894f7 |
| parent | 1826a961608037405237f12df5aec94f8f5f3a10 |
See #7711 files changed, 257 insertions(+), 63 deletions(-)
doc/langref.md+1-1| ... | @@ -33,7 +33,7 @@ FnDef = option("inline" | "extern") FnProto Block | ... | @@ -33,7 +33,7 @@ FnDef = option("inline" | "extern") FnProto Block |
| 33 | 33 | ||
| 34 | ParamDeclList = "(" list(ParamDecl, ",") ")" | 34 | ParamDeclList = "(" list(ParamDecl, ",") ")" |
| 35 | 35 | ||
| 36 | ParamDecl = option("noalias" | "comptime") option(Symbol ":") TypeExpr | "..." | 36 | ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...") |
| 37 | 37 | ||
| 38 | Block = "{" list(option(Statement), ";") "}" | 38 | Block = "{" list(option(Statement), ";") "}" |
| 39 | 39 |
src/all_types.hpp+11| ... | @@ -122,6 +122,11 @@ struct ConstBoundFnValue { | ... | @@ -122,6 +122,11 @@ struct ConstBoundFnValue { |
| 122 | IrInstruction *first_arg; | 122 | IrInstruction *first_arg; |
| 123 | }; | 123 | }; |
| 124 | 124 | ||
| 125 | struct ConstArgTuple { | ||
| 126 | size_t start_index; | ||
| 127 | size_t end_index; | ||
| 128 | }; | ||
| 129 | |||
| 125 | enum ConstValSpecial { | 130 | enum ConstValSpecial { |
| 126 | ConstValSpecialRuntime, | 131 | ConstValSpecialRuntime, |
| 127 | ConstValSpecialStatic, | 132 | ConstValSpecialStatic, |
| ... | @@ -163,6 +168,7 @@ struct ConstExprValue { | ... | @@ -163,6 +168,7 @@ struct ConstExprValue { |
| 163 | ConstPtrValue x_ptr; | 168 | ConstPtrValue x_ptr; |
| 164 | ImportTableEntry *x_import; | 169 | ImportTableEntry *x_import; |
| 165 | Scope *x_block; | 170 | Scope *x_block; |
| 171 | ConstArgTuple x_arg_tuple; | ||
| 166 | 172 | ||
| 167 | // populated if special == ConstValSpecialRuntime | 173 | // populated if special == ConstValSpecialRuntime |
| 168 | RuntimeHintErrorUnion rh_error_union; | 174 | RuntimeHintErrorUnion rh_error_union; |
| ... | @@ -325,6 +331,7 @@ struct AstNodeParamDecl { | ... | @@ -325,6 +331,7 @@ struct AstNodeParamDecl { |
| 325 | AstNode *type; | 331 | AstNode *type; |
| 326 | bool is_noalias; | 332 | bool is_noalias; |
| 327 | bool is_inline; | 333 | bool is_inline; |
| 334 | bool is_var_args; | ||
| 328 | }; | 335 | }; |
| 329 | 336 | ||
| 330 | struct AstNodeBlock { | 337 | struct AstNodeBlock { |
| ... | @@ -936,6 +943,7 @@ enum TypeTableEntryId { | ... | @@ -936,6 +943,7 @@ enum TypeTableEntryId { |
| 936 | TypeTableEntryIdNamespace, | 943 | TypeTableEntryIdNamespace, |
| 937 | TypeTableEntryIdBlock, | 944 | TypeTableEntryIdBlock, |
| 938 | TypeTableEntryIdBoundFn, | 945 | TypeTableEntryIdBoundFn, |
| 946 | TypeTableEntryIdArgTuple, | ||
| 939 | }; | 947 | }; |
| 940 | 948 | ||
| 941 | struct TypeTableEntry { | 949 | struct TypeTableEntry { |
| ... | @@ -1034,6 +1042,8 @@ struct FnTableEntry { | ... | @@ -1034,6 +1042,8 @@ struct FnTableEntry { |
| 1034 | 1042 | ||
| 1035 | ZigList<IrInstruction *> alloca_list; | 1043 | ZigList<IrInstruction *> alloca_list; |
| 1036 | ZigList<VariableTableEntry *> variable_list; | 1044 | ZigList<VariableTableEntry *> variable_list; |
| 1045 | |||
| 1046 | VariableTableEntry *var_args_var; | ||
| 1037 | }; | 1047 | }; |
| 1038 | 1048 | ||
| 1039 | uint32_t fn_table_entry_hash(FnTableEntry*); | 1049 | uint32_t fn_table_entry_hash(FnTableEntry*); |
| ... | @@ -1155,6 +1165,7 @@ struct CodeGen { | ... | @@ -1155,6 +1165,7 @@ struct CodeGen { |
| 1155 | TypeTableEntry *entry_environ_enum; | 1165 | TypeTableEntry *entry_environ_enum; |
| 1156 | TypeTableEntry *entry_oformat_enum; | 1166 | TypeTableEntry *entry_oformat_enum; |
| 1157 | TypeTableEntry *entry_atomic_order_enum; | 1167 | TypeTableEntry *entry_atomic_order_enum; |
| 1168 | TypeTableEntry *entry_arg_tuple; | ||
| 1158 | } builtin_types; | 1169 | } builtin_types; |
| 1159 | 1170 | ||
| 1160 | ZigTarget zig_target; | 1171 | ZigTarget zig_target; |
src/analyze.cpp+52-10| ... | @@ -208,6 +208,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { | ... | @@ -208,6 +208,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { |
| 208 | case TypeTableEntryIdBlock: | 208 | case TypeTableEntryIdBlock: |
| 209 | case TypeTableEntryIdBoundFn: | 209 | case TypeTableEntryIdBoundFn: |
| 210 | case TypeTableEntryIdEnumTag: | 210 | case TypeTableEntryIdEnumTag: |
| 211 | case TypeTableEntryIdArgTuple: | ||
| 211 | return true; | 212 | return true; |
| 212 | } | 213 | } |
| 213 | zig_unreachable(); | 214 | zig_unreachable(); |
| ... | @@ -245,6 +246,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) { | ... | @@ -245,6 +246,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) { |
| 245 | case TypeTableEntryIdBlock: | 246 | case TypeTableEntryIdBlock: |
| 246 | case TypeTableEntryIdBoundFn: | 247 | case TypeTableEntryIdBoundFn: |
| 247 | case TypeTableEntryIdEnumTag: | 248 | case TypeTableEntryIdEnumTag: |
| 249 | case TypeTableEntryIdArgTuple: | ||
| 248 | return true; | 250 | return true; |
| 249 | } | 251 | } |
| 250 | zig_unreachable(); | 252 | zig_unreachable(); |
| ... | @@ -921,6 +923,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -921,6 +923,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 921 | assert(param_node->type == NodeTypeParamDecl); | 923 | assert(param_node->type == NodeTypeParamDecl); |
| 922 | 924 | ||
| 923 | bool param_is_inline = param_node->data.param_decl.is_inline; | 925 | bool param_is_inline = param_node->data.param_decl.is_inline; |
| 926 | bool param_is_var_args = param_node->data.param_decl.is_var_args; | ||
| 924 | 927 | ||
| 925 | if (param_is_inline) { | 928 | if (param_is_inline) { |
| 926 | if (fn_type_id.is_extern) { | 929 | if (fn_type_id.is_extern) { |
| ... | @@ -929,6 +932,13 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -929,6 +932,13 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 929 | return g->builtin_types.entry_invalid; | 932 | return g->builtin_types.entry_invalid; |
| 930 | } | 933 | } |
| 931 | return get_generic_fn_type(g, &fn_type_id); | 934 | return get_generic_fn_type(g, &fn_type_id); |
| 935 | } else if (param_is_var_args) { | ||
| 936 | if (fn_type_id.is_extern) { | ||
| 937 | fn_type_id.param_count = fn_type_id.next_param_index; | ||
| 938 | continue; | ||
| 939 | } else { | ||
| 940 | return get_generic_fn_type(g, &fn_type_id); | ||
| 941 | } | ||
| 932 | } | 942 | } |
| 933 | 943 | ||
| 934 | TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); | 944 | TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); |
| ... | @@ -939,6 +949,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -939,6 +949,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 939 | case TypeTableEntryIdUnreachable: | 949 | case TypeTableEntryIdUnreachable: |
| 940 | case TypeTableEntryIdUndefLit: | 950 | case TypeTableEntryIdUndefLit: |
| 941 | case TypeTableEntryIdNullLit: | 951 | case TypeTableEntryIdNullLit: |
| 952 | case TypeTableEntryIdArgTuple: | ||
| 942 | add_node_error(g, param_node->data.param_decl.type, | 953 | add_node_error(g, param_node->data.param_decl.type, |
| 943 | buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name))); | 954 | buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name))); |
| 944 | return g->builtin_types.entry_invalid; | 955 | return g->builtin_types.entry_invalid; |
| ... | @@ -989,6 +1000,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -989,6 +1000,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 989 | 1000 | ||
| 990 | case TypeTableEntryIdUndefLit: | 1001 | case TypeTableEntryIdUndefLit: |
| 991 | case TypeTableEntryIdNullLit: | 1002 | case TypeTableEntryIdNullLit: |
| 1003 | case TypeTableEntryIdArgTuple: | ||
| 992 | add_node_error(g, fn_proto->return_type, | 1004 | add_node_error(g, fn_proto->return_type, |
| 993 | buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name))); | 1005 | buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name))); |
| 994 | return g->builtin_types.entry_invalid; | 1006 | return g->builtin_types.entry_invalid; |
| ... | @@ -1558,13 +1570,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -1558,13 +1570,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 1558 | 1570 | ||
| 1559 | AstNode *fn_def_node = fn_proto->fn_def_node; | 1571 | AstNode *fn_def_node = fn_proto->fn_def_node; |
| 1560 | 1572 | ||
| 1561 | if (fn_def_node && fn_proto->is_var_args) { | ||
| 1562 | add_node_error(g, proto_node, | ||
| 1563 | buf_sprintf("variadic arguments only allowed in extern function declarations")); | ||
| 1564 | tld_fn->base.resolution = TldResolutionInvalid; | ||
| 1565 | return; | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | FnTableEntry *fn_table_entry = create_fn(tld_fn->base.source_node); | 1573 | FnTableEntry *fn_table_entry = create_fn(tld_fn->base.source_node); |
| 1569 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); | 1574 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); |
| 1570 | 1575 | ||
| ... | @@ -1799,6 +1804,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt | ... | @@ -1799,6 +1804,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt |
| 1799 | case TypeTableEntryIdUndefLit: | 1804 | case TypeTableEntryIdUndefLit: |
| 1800 | case TypeTableEntryIdNullLit: | 1805 | case TypeTableEntryIdNullLit: |
| 1801 | case TypeTableEntryIdBlock: | 1806 | case TypeTableEntryIdBlock: |
| 1807 | case TypeTableEntryIdArgTuple: | ||
| 1802 | add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed", | 1808 | add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed", |
| 1803 | buf_ptr(&underlying_type->name))); | 1809 | buf_ptr(&underlying_type->name))); |
| 1804 | return g->builtin_types.entry_invalid; | 1810 | return g->builtin_types.entry_invalid; |
| ... | @@ -2210,6 +2216,7 @@ static bool is_container(TypeTableEntry *type_entry) { | ... | @@ -2210,6 +2216,7 @@ static bool is_container(TypeTableEntry *type_entry) { |
| 2210 | case TypeTableEntryIdBlock: | 2216 | case TypeTableEntryIdBlock: |
| 2211 | case TypeTableEntryIdBoundFn: | 2217 | case TypeTableEntryIdBoundFn: |
| 2212 | case TypeTableEntryIdEnumTag: | 2218 | case TypeTableEntryIdEnumTag: |
| 2219 | case TypeTableEntryIdArgTuple: | ||
| 2213 | return false; | 2220 | return false; |
| 2214 | } | 2221 | } |
| 2215 | zig_unreachable(); | 2222 | zig_unreachable(); |
| ... | @@ -2260,6 +2267,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -2260,6 +2267,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 2260 | case TypeTableEntryIdInvalid: | 2267 | case TypeTableEntryIdInvalid: |
| 2261 | case TypeTableEntryIdVar: | 2268 | case TypeTableEntryIdVar: |
| 2262 | case TypeTableEntryIdEnumTag: | 2269 | case TypeTableEntryIdEnumTag: |
| 2270 | case TypeTableEntryIdArgTuple: | ||
| 2263 | zig_unreachable(); | 2271 | zig_unreachable(); |
| 2264 | } | 2272 | } |
| 2265 | } | 2273 | } |
| ... | @@ -2290,7 +2298,13 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari | ... | @@ -2290,7 +2298,13 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari |
| 2290 | for (size_t i = 0; i < fn_type_id->param_count; i += 1) { | 2298 | for (size_t i = 0; i < fn_type_id->param_count; i += 1) { |
| 2291 | FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; | 2299 | FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; |
| 2292 | AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i); | 2300 | AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i); |
| 2293 | Buf *param_name = param_decl_node ? param_decl_node->data.param_decl.name : buf_sprintf("arg%zu", i); | 2301 | Buf *param_name; |
| 2302 | bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args; | ||
| 2303 | if (param_decl_node && !is_var_args) { | ||
| 2304 | param_name = param_decl_node->data.param_decl.name; | ||
| 2305 | } else { | ||
| 2306 | param_name = buf_sprintf("arg%zu", i); | ||
| 2307 | } | ||
| 2294 | 2308 | ||
| 2295 | TypeTableEntry *param_type = param_info->type; | 2309 | TypeTableEntry *param_type = param_info->type; |
| 2296 | bool is_noalias = param_info->is_noalias; | 2310 | bool is_noalias = param_info->is_noalias; |
| ... | @@ -2308,6 +2322,7 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari | ... | @@ -2308,6 +2322,7 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari |
| 2308 | param_name, true, create_const_runtime(param_type)); | 2322 | param_name, true, create_const_runtime(param_type)); |
| 2309 | var->src_arg_index = i; | 2323 | var->src_arg_index = i; |
| 2310 | fn_table_entry->child_scope = var->child_scope; | 2324 | fn_table_entry->child_scope = var->child_scope; |
| 2325 | var->shadowable = var->shadowable || is_var_args; | ||
| 2311 | 2326 | ||
| 2312 | if (type_has_bits(param_type)) { | 2327 | if (type_has_bits(param_type)) { |
| 2313 | fn_table_entry->variable_list.append(var); | 2328 | fn_table_entry->variable_list.append(var); |
| ... | @@ -2627,6 +2642,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -2627,6 +2642,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 2627 | case TypeTableEntryIdBlock: | 2642 | case TypeTableEntryIdBlock: |
| 2628 | case TypeTableEntryIdBoundFn: | 2643 | case TypeTableEntryIdBoundFn: |
| 2629 | case TypeTableEntryIdVar: | 2644 | case TypeTableEntryIdVar: |
| 2645 | case TypeTableEntryIdArgTuple: | ||
| 2630 | zig_unreachable(); | 2646 | zig_unreachable(); |
| 2631 | case TypeTableEntryIdUnreachable: | 2647 | case TypeTableEntryIdUnreachable: |
| 2632 | case TypeTableEntryIdVoid: | 2648 | case TypeTableEntryIdVoid: |
| ... | @@ -2742,6 +2758,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { | ... | @@ -2742,6 +2758,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 2742 | case TypeTableEntryIdFloat: | 2758 | case TypeTableEntryIdFloat: |
| 2743 | case TypeTableEntryIdNumLitFloat: | 2759 | case TypeTableEntryIdNumLitFloat: |
| 2744 | return const_val->data.x_bignum.data.x_float * UINT32_MAX; | 2760 | return const_val->data.x_bignum.data.x_float * UINT32_MAX; |
| 2761 | case TypeTableEntryIdArgTuple: | ||
| 2762 | return const_val->data.x_arg_tuple.start_index * 281907309 + | ||
| 2763 | const_val->data.x_arg_tuple.end_index * 2290442768; | ||
| 2745 | case TypeTableEntryIdPointer: | 2764 | case TypeTableEntryIdPointer: |
| 2746 | return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index); | 2765 | return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index); |
| 2747 | case TypeTableEntryIdUndefLit: | 2766 | case TypeTableEntryIdUndefLit: |
| ... | @@ -2805,7 +2824,7 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { | ... | @@ -2805,7 +2824,7 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { |
| 2805 | bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { | 2824 | bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { |
| 2806 | assert(a->fn_entry); | 2825 | assert(a->fn_entry); |
| 2807 | if (a->fn_entry != b->fn_entry) return false; | 2826 | if (a->fn_entry != b->fn_entry) return false; |
| 2808 | assert(a->param_count == b->param_count); | 2827 | if (a->param_count != b->param_count) return false; |
| 2809 | for (size_t i = 0; i < a->param_count; i += 1) { | 2828 | for (size_t i = 0; i < a->param_count; i += 1) { |
| 2810 | ConstExprValue *a_val = &a->params[i]; | 2829 | ConstExprValue *a_val = &a->params[i]; |
| 2811 | ConstExprValue *b_val = &b->params[i]; | 2830 | ConstExprValue *b_val = &b->params[i]; |
| ... | @@ -2904,6 +2923,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) | ... | @@ -2904,6 +2923,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) |
| 2904 | case TypeTableEntryIdBlock: | 2923 | case TypeTableEntryIdBlock: |
| 2905 | case TypeTableEntryIdBoundFn: | 2924 | case TypeTableEntryIdBoundFn: |
| 2906 | case TypeTableEntryIdVar: | 2925 | case TypeTableEntryIdVar: |
| 2926 | case TypeTableEntryIdArgTuple: | ||
| 2907 | zig_unreachable(); | 2927 | zig_unreachable(); |
| 2908 | case TypeTableEntryIdArray: | 2928 | case TypeTableEntryIdArray: |
| 2909 | return type_of_first_thing_in_memory(type_entry->data.array.child_type); | 2929 | return type_of_first_thing_in_memory(type_entry->data.array.child_type); |
| ... | @@ -2946,6 +2966,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { | ... | @@ -2946,6 +2966,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 2946 | case TypeTableEntryIdNamespace: | 2966 | case TypeTableEntryIdNamespace: |
| 2947 | case TypeTableEntryIdBlock: | 2967 | case TypeTableEntryIdBlock: |
| 2948 | case TypeTableEntryIdBoundFn: | 2968 | case TypeTableEntryIdBoundFn: |
| 2969 | case TypeTableEntryIdArgTuple: | ||
| 2949 | return true; | 2970 | return true; |
| 2950 | case TypeTableEntryIdArray: | 2971 | case TypeTableEntryIdArray: |
| 2951 | case TypeTableEntryIdStruct: | 2972 | case TypeTableEntryIdStruct: |
| ... | @@ -3155,6 +3176,20 @@ ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t in | ... | @@ -3155,6 +3176,20 @@ ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t in |
| 3155 | return const_val; | 3176 | return const_val; |
| 3156 | } | 3177 | } |
| 3157 | 3178 | ||
| 3179 | void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end) { | ||
| 3180 | const_val->special = ConstValSpecialStatic; | ||
| 3181 | const_val->type = g->builtin_types.entry_arg_tuple; | ||
| 3182 | const_val->data.x_arg_tuple.start_index = arg_index_start; | ||
| 3183 | const_val->data.x_arg_tuple.end_index = arg_index_end; | ||
| 3184 | } | ||
| 3185 | |||
| 3186 | ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end) { | ||
| 3187 | ConstExprValue *const_val = allocate<ConstExprValue>(1); | ||
| 3188 | init_const_arg_tuple(g, const_val, arg_index_start, arg_index_end); | ||
| 3189 | return const_val; | ||
| 3190 | } | ||
| 3191 | |||
| 3192 | |||
| 3158 | void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) { | 3193 | void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 3159 | if (type_entry->id == TypeTableEntryIdStruct) { | 3194 | if (type_entry->id == TypeTableEntryIdStruct) { |
| 3160 | if (!type_entry->data.structure.complete) | 3195 | if (!type_entry->data.structure.complete) |
| ... | @@ -3245,6 +3280,9 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { | ... | @@ -3245,6 +3280,9 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 3245 | return a->data.x_import == b->data.x_import; | 3280 | return a->data.x_import == b->data.x_import; |
| 3246 | case TypeTableEntryIdBlock: | 3281 | case TypeTableEntryIdBlock: |
| 3247 | return a->data.x_block == b->data.x_block; | 3282 | return a->data.x_block == b->data.x_block; |
| 3283 | case TypeTableEntryIdArgTuple: | ||
| 3284 | return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index && | ||
| 3285 | a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index; | ||
| 3248 | case TypeTableEntryIdBoundFn: | 3286 | case TypeTableEntryIdBoundFn: |
| 3249 | case TypeTableEntryIdInvalid: | 3287 | case TypeTableEntryIdInvalid: |
| 3250 | case TypeTableEntryIdUnreachable: | 3288 | case TypeTableEntryIdUnreachable: |
| ... | @@ -3506,7 +3544,11 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { | ... | @@ -3506,7 +3544,11 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { |
| 3506 | buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name)); | 3544 | buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name)); |
| 3507 | return; | 3545 | return; |
| 3508 | } | 3546 | } |
| 3547 | case TypeTableEntryIdArgTuple: | ||
| 3548 | { | ||
| 3549 | buf_appendf(buf, "(args value)"); | ||
| 3550 | return; | ||
| 3551 | } | ||
| 3509 | } | 3552 | } |
| 3510 | zig_unreachable(); | 3553 | zig_unreachable(); |
| 3511 | } | 3554 | } |
| 3512 |
src/analyze.hpp+3| ... | @@ -133,4 +133,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr | ... | @@ -133,4 +133,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr |
| 133 | size_t start, size_t len, bool is_const); | 133 | size_t start, size_t len, bool is_const); |
| 134 | ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const); | 134 | ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const); |
| 135 | 135 | ||
| 136 | void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end); | ||
| 137 | ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end); | ||
| 138 | |||
| 136 | #endif | 139 | #endif |
src/ast_render.cpp+6-6| ... | @@ -393,7 +393,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -393,7 +393,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 393 | print_symbol(ar, node->data.fn_proto.name); | 393 | print_symbol(ar, node->data.fn_proto.name); |
| 394 | fprintf(ar->f, "("); | 394 | fprintf(ar->f, "("); |
| 395 | int arg_count = node->data.fn_proto.params.length; | 395 | int arg_count = node->data.fn_proto.params.length; |
| 396 | bool is_var_args = node->data.fn_proto.is_var_args; | ||
| 397 | for (int arg_i = 0; arg_i < arg_count; arg_i += 1) { | 396 | for (int arg_i = 0; arg_i < arg_count; arg_i += 1) { |
| 398 | AstNode *param_decl = node->data.fn_proto.params.at(arg_i); | 397 | AstNode *param_decl = node->data.fn_proto.params.at(arg_i); |
| 399 | assert(param_decl->type == NodeTypeParamDecl); | 398 | assert(param_decl->type == NodeTypeParamDecl); |
| ... | @@ -404,15 +403,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -404,15 +403,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 404 | print_symbol(ar, param_decl->data.param_decl.name); | 403 | print_symbol(ar, param_decl->data.param_decl.name); |
| 405 | fprintf(ar->f, ": "); | 404 | fprintf(ar->f, ": "); |
| 406 | } | 405 | } |
| 407 | render_node_grouped(ar, param_decl->data.param_decl.type); | 406 | if (param_decl->data.param_decl.is_var_args) { |
| 407 | fprintf(ar->f, "..."); | ||
| 408 | } else { | ||
| 409 | render_node_grouped(ar, param_decl->data.param_decl.type); | ||
| 410 | } | ||
| 408 | 411 | ||
| 409 | if (arg_i + 1 < arg_count || is_var_args) { | 412 | if (arg_i + 1 < arg_count) { |
| 410 | fprintf(ar->f, ", "); | 413 | fprintf(ar->f, ", "); |
| 411 | } | 414 | } |
| 412 | } | 415 | } |
| 413 | if (is_var_args) { | ||
| 414 | fprintf(ar->f, "..."); | ||
| 415 | } | ||
| 416 | fprintf(ar->f, ")"); | 416 | fprintf(ar->f, ")"); |
| 417 | 417 | ||
| 418 | AstNode *return_type_node = node->data.fn_proto.return_type; | 418 | AstNode *return_type_node = node->data.fn_proto.return_type; |
src/codegen.cpp+8| ... | @@ -2636,6 +2636,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -2636,6 +2636,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 2636 | case TypeTableEntryIdBlock: | 2636 | case TypeTableEntryIdBlock: |
| 2637 | case TypeTableEntryIdBoundFn: | 2637 | case TypeTableEntryIdBoundFn: |
| 2638 | case TypeTableEntryIdVar: | 2638 | case TypeTableEntryIdVar: |
| 2639 | case TypeTableEntryIdArgTuple: | ||
| 2639 | zig_unreachable(); | 2640 | zig_unreachable(); |
| 2640 | 2641 | ||
| 2641 | } | 2642 | } |
| ... | @@ -3179,6 +3180,12 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3179,6 +3180,12 @@ static void define_builtin_types(CodeGen *g) { |
| 3179 | buf_init_from_str(&entry->name, "(var)"); | 3180 | buf_init_from_str(&entry->name, "(var)"); |
| 3180 | g->builtin_types.entry_var = entry; | 3181 | g->builtin_types.entry_var = entry; |
| 3181 | } | 3182 | } |
| 3183 | { | ||
| 3184 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArgTuple); | ||
| 3185 | buf_init_from_str(&entry->name, "(args)"); | ||
| 3186 | entry->zero_bits = true; | ||
| 3187 | g->builtin_types.entry_arg_tuple = entry; | ||
| 3188 | } | ||
| 3182 | 3189 | ||
| 3183 | for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) { | 3190 | for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) { |
| 3184 | size_t size_in_bits = int_sizes_in_bits[int_size_i]; | 3191 | size_t size_in_bits = int_sizes_in_bits[int_size_i]; |
| ... | @@ -3947,6 +3954,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { | ... | @@ -3947,6 +3954,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { |
| 3947 | case TypeTableEntryIdUndefLit: | 3954 | case TypeTableEntryIdUndefLit: |
| 3948 | case TypeTableEntryIdNullLit: | 3955 | case TypeTableEntryIdNullLit: |
| 3949 | case TypeTableEntryIdVar: | 3956 | case TypeTableEntryIdVar: |
| 3957 | case TypeTableEntryIdArgTuple: | ||
| 3950 | zig_unreachable(); | 3958 | zig_unreachable(); |
| 3951 | } | 3959 | } |
| 3952 | } | 3960 | } |
src/ir.cpp+120-29| ... | @@ -4347,8 +4347,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -4347,8 +4347,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4347 | 4347 | ||
| 4348 | IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr); | 4348 | IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr); |
| 4349 | 4349 | ||
| 4350 | IrInstruction *array_type = ir_build_typeof(irb, parent_scope, array_node, array_val); | 4350 | IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val); |
| 4351 | IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_type); | ||
| 4352 | IrInstruction *elem_var_type; | 4351 | IrInstruction *elem_var_type; |
| 4353 | if (node->data.for_expr.elem_is_ptr) { | 4352 | if (node->data.for_expr.elem_is_ptr) { |
| 4354 | elem_var_type = pointer_type; | 4353 | elem_var_type = pointer_type; |
| ... | @@ -6887,6 +6886,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -6887,6 +6886,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 6887 | case TypeTableEntryIdNamespace: | 6886 | case TypeTableEntryIdNamespace: |
| 6888 | case TypeTableEntryIdBlock: | 6887 | case TypeTableEntryIdBlock: |
| 6889 | case TypeTableEntryIdBoundFn: | 6888 | case TypeTableEntryIdBoundFn: |
| 6889 | case TypeTableEntryIdArgTuple: | ||
| 6890 | if (!is_equality_cmp) { | 6890 | if (!is_equality_cmp) { |
| 6891 | ir_add_error_node(ira, source_node, | 6891 | ir_add_error_node(ira, source_node, |
| 6892 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); | 6892 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); |
| ... | @@ -7449,6 +7449,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc | ... | @@ -7449,6 +7449,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc |
| 7449 | case TypeTableEntryIdFn: | 7449 | case TypeTableEntryIdFn: |
| 7450 | case TypeTableEntryIdBoundFn: | 7450 | case TypeTableEntryIdBoundFn: |
| 7451 | case TypeTableEntryIdEnumTag: | 7451 | case TypeTableEntryIdEnumTag: |
| 7452 | case TypeTableEntryIdArgTuple: | ||
| 7452 | // OK | 7453 | // OK |
| 7453 | break; | 7454 | break; |
| 7454 | } | 7455 | } |
| ... | @@ -7520,21 +7521,35 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod | ... | @@ -7520,21 +7521,35 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod |
| 7520 | { | 7521 | { |
| 7521 | AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); | 7522 | AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); |
| 7522 | assert(param_decl_node->type == NodeTypeParamDecl); | 7523 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 7523 | AstNode *param_type_node = param_decl_node->data.param_decl.type; | 7524 | bool is_var_args = param_decl_node->data.param_decl.is_var_args; |
| 7524 | TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node); | 7525 | bool arg_part_of_generic_id = false; |
| 7525 | if (param_type->id == TypeTableEntryIdInvalid) | 7526 | IrInstruction *casted_arg; |
| 7526 | return false; | 7527 | if (is_var_args) { |
| 7528 | arg_part_of_generic_id = true; | ||
| 7529 | casted_arg = arg; | ||
| 7530 | } else { | ||
| 7531 | AstNode *param_type_node = param_decl_node->data.param_decl.type; | ||
| 7532 | TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node); | ||
| 7533 | if (param_type->id == TypeTableEntryIdInvalid) | ||
| 7534 | return false; | ||
| 7527 | 7535 | ||
| 7528 | IrInstruction *casted_arg = ir_implicit_cast(ira, arg, param_type); | 7536 | bool is_var_type = (param_type->id == TypeTableEntryIdVar); |
| 7529 | if (casted_arg->value.type->id == TypeTableEntryIdInvalid) | 7537 | if (is_var_type) { |
| 7530 | return false; | 7538 | arg_part_of_generic_id = true; |
| 7539 | casted_arg = arg; | ||
| 7540 | } else { | ||
| 7541 | casted_arg = ir_implicit_cast(ira, arg, param_type); | ||
| 7542 | if (casted_arg->value.type->id == TypeTableEntryIdInvalid) | ||
| 7543 | return false; | ||
| 7544 | } | ||
| 7545 | } | ||
| 7531 | 7546 | ||
| 7532 | bool inline_arg = param_decl_node->data.param_decl.is_inline; | 7547 | bool comptime_arg = param_decl_node->data.param_decl.is_inline; |
| 7533 | bool is_var_type = (param_type->id == TypeTableEntryIdVar); | ||
| 7534 | 7548 | ||
| 7535 | ConstExprValue *arg_val; | 7549 | ConstExprValue *arg_val; |
| 7536 | 7550 | ||
| 7537 | if (inline_arg) { | 7551 | if (comptime_arg) { |
| 7552 | arg_part_of_generic_id = true; | ||
| 7538 | arg_val = ir_resolve_const(ira, casted_arg, UndefBad); | 7553 | arg_val = ir_resolve_const(ira, casted_arg, UndefBad); |
| 7539 | if (!arg_val) | 7554 | if (!arg_val) |
| 7540 | return false; | 7555 | return false; |
| ... | @@ -7544,26 +7559,41 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod | ... | @@ -7544,26 +7559,41 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod |
| 7544 | } else { | 7559 | } else { |
| 7545 | arg_val = create_const_runtime(casted_arg->value.type); | 7560 | arg_val = create_const_runtime(casted_arg->value.type); |
| 7546 | } | 7561 | } |
| 7562 | if (arg_part_of_generic_id) { | ||
| 7563 | generic_id->params[generic_id->param_count] = *arg_val; | ||
| 7564 | generic_id->param_count += 1; | ||
| 7565 | } | ||
| 7547 | 7566 | ||
| 7548 | Buf *param_name = param_decl_node->data.param_decl.name; | 7567 | Buf *param_name = param_decl_node->data.param_decl.name; |
| 7549 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, | 7568 | if (is_var_args) { |
| 7550 | *child_scope, param_name, true, arg_val); | 7569 | if (!impl_fn->var_args_var) { |
| 7551 | var->value.depends_on_compile_var = true; | 7570 | ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen, |
| 7552 | *child_scope = var->child_scope; | 7571 | fn_type_id->param_count, fn_type_id->param_count + 1); |
| 7572 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, | ||
| 7573 | *child_scope, param_name, true, var_args_val); | ||
| 7574 | var->value.depends_on_compile_var = true; | ||
| 7575 | *child_scope = var->child_scope; | ||
| 7576 | impl_fn->var_args_var = var; | ||
| 7577 | } | ||
| 7578 | impl_fn->var_args_var->value.data.x_arg_tuple.end_index = fn_type_id->param_count + 1; | ||
| 7553 | 7579 | ||
| 7554 | if (inline_arg || is_var_type) { | 7580 | } else { |
| 7555 | generic_id->params[generic_id->param_count] = *arg_val; | 7581 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, |
| 7556 | generic_id->param_count += 1; | 7582 | *child_scope, param_name, true, arg_val); |
| 7583 | var->value.depends_on_compile_var = true; | ||
| 7584 | *child_scope = var->child_scope; | ||
| 7585 | var->shadowable = !comptime_arg; | ||
| 7586 | |||
| 7587 | *next_proto_i += 1; | ||
| 7557 | } | 7588 | } |
| 7558 | if (!inline_arg) { | 7589 | |
| 7559 | if (type_requires_comptime(var->value.type)) { | 7590 | if (!comptime_arg) { |
| 7560 | ir_add_error(ira, arg, | 7591 | if (type_requires_comptime(casted_arg->value.type)) { |
| 7561 | buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&var->value.type->name))); | 7592 | ir_add_error(ira, casted_arg, |
| 7593 | buf_sprintf("parameter of type '%s' requires comptime", buf_ptr(&casted_arg->value.type->name))); | ||
| 7562 | return false; | 7594 | return false; |
| 7563 | } | 7595 | } |
| 7564 | 7596 | ||
| 7565 | var->shadowable = true; | ||
| 7566 | |||
| 7567 | casted_args[fn_type_id->param_count] = casted_arg; | 7597 | casted_args[fn_type_id->param_count] = casted_arg; |
| 7568 | FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count]; | 7598 | FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count]; |
| 7569 | param_info->type = casted_arg->value.type; | 7599 | param_info->type = casted_arg->value.type; |
| ... | @@ -7571,7 +7601,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod | ... | @@ -7571,7 +7601,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod |
| 7571 | impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node; | 7601 | impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node; |
| 7572 | fn_type_id->param_count += 1; | 7602 | fn_type_id->param_count += 1; |
| 7573 | } | 7603 | } |
| 7574 | *next_proto_i += 1; | 7604 | |
| 7575 | return true; | 7605 | return true; |
| 7576 | } | 7606 | } |
| 7577 | 7607 | ||
| ... | @@ -7682,6 +7712,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -7682,6 +7712,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 7682 | FnTypeId inst_fn_type_id = {0}; | 7712 | FnTypeId inst_fn_type_id = {0}; |
| 7683 | init_fn_type_id(&inst_fn_type_id, fn_proto_node); | 7713 | init_fn_type_id(&inst_fn_type_id, fn_proto_node); |
| 7684 | inst_fn_type_id.param_count = 0; | 7714 | inst_fn_type_id.param_count = 0; |
| 7715 | inst_fn_type_id.is_var_args = false; | ||
| 7685 | 7716 | ||
| 7686 | // TODO maybe GenericFnTypeId can be replaced with using the child_scope directly | 7717 | // TODO maybe GenericFnTypeId can be replaced with using the child_scope directly |
| 7687 | // as the key in generic_table | 7718 | // as the key in generic_table |
| ... | @@ -7918,6 +7949,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct | ... | @@ -7918,6 +7949,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct |
| 7918 | case TypeTableEntryIdBlock: | 7949 | case TypeTableEntryIdBlock: |
| 7919 | case TypeTableEntryIdUnreachable: | 7950 | case TypeTableEntryIdUnreachable: |
| 7920 | case TypeTableEntryIdVar: | 7951 | case TypeTableEntryIdVar: |
| 7952 | case TypeTableEntryIdArgTuple: | ||
| 7921 | ir_add_error_node(ira, un_op_instruction->base.source_node, | 7953 | ir_add_error_node(ira, un_op_instruction->base.source_node, |
| 7922 | buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name))); | 7954 | buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name))); |
| 7923 | // TODO if meta_type is type decl, add note pointing to type decl declaration | 7955 | // TODO if meta_type is type decl, add note pointing to type decl declaration |
| ... | @@ -7990,6 +8022,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op | ... | @@ -7990,6 +8022,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op |
| 7990 | case TypeTableEntryIdBlock: | 8022 | case TypeTableEntryIdBlock: |
| 7991 | case TypeTableEntryIdBoundFn: | 8023 | case TypeTableEntryIdBoundFn: |
| 7992 | case TypeTableEntryIdEnumTag: | 8024 | case TypeTableEntryIdEnumTag: |
| 8025 | case TypeTableEntryIdArgTuple: | ||
| 7993 | { | 8026 | { |
| 7994 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, | 8027 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, |
| 7995 | value->value.depends_on_compile_var); | 8028 | value->value.depends_on_compile_var); |
| ... | @@ -8327,6 +8360,30 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc | ... | @@ -8327,6 +8360,30 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 8327 | return_type = array_type; | 8360 | return_type = array_type; |
| 8328 | } else if (is_slice(array_type)) { | 8361 | } else if (is_slice(array_type)) { |
| 8329 | return_type = array_type->data.structure.fields[0].type_entry; | 8362 | return_type = array_type->data.structure.fields[0].type_entry; |
| 8363 | } else if (array_type->id == TypeTableEntryIdArgTuple) { | ||
| 8364 | ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad); | ||
| 8365 | if (!ptr_val) | ||
| 8366 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8367 | ConstExprValue *args_val = const_ptr_pointee(ptr_val); | ||
| 8368 | size_t start = args_val->data.x_arg_tuple.start_index; | ||
| 8369 | size_t end = args_val->data.x_arg_tuple.end_index; | ||
| 8370 | ConstExprValue *elem_index_val = ir_resolve_const(ira, elem_index, UndefBad); | ||
| 8371 | if (!elem_index_val) | ||
| 8372 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8373 | size_t index = bignum_to_twos_complement(&elem_index_val->data.x_bignum); | ||
| 8374 | size_t len = end - start; | ||
| 8375 | if (index >= len) { | ||
| 8376 | ir_add_error(ira, &elem_ptr_instruction->base, | ||
| 8377 | buf_sprintf("index %zu outside argument list of size %zu", index, len)); | ||
| 8378 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8379 | } | ||
| 8380 | size_t abs_index = start + index; | ||
| 8381 | FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); | ||
| 8382 | assert(fn_entry); | ||
| 8383 | VariableTableEntry *var = fn_entry->variable_list.at(abs_index); | ||
| 8384 | bool depends_on_compile_var = array_ptr->value.depends_on_compile_var || | ||
| 8385 | elem_index->value.depends_on_compile_var; | ||
| 8386 | return ir_analyze_var_ptr(ira, &elem_ptr_instruction->base, var, true, depends_on_compile_var); | ||
| 8330 | } else { | 8387 | } else { |
| 8331 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, | 8388 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| 8332 | buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); | 8389 | buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); |
| ... | @@ -8572,6 +8629,29 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru | ... | @@ -8572,6 +8629,29 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 8572 | ConstExprValue *len_val = allocate<ConstExprValue>(1); | 8629 | ConstExprValue *len_val = allocate<ConstExprValue>(1); |
| 8573 | init_const_usize(ira->codegen, len_val, container_type->data.array.len); | 8630 | init_const_usize(ira->codegen, len_val, container_type->data.array.len); |
| 8574 | 8631 | ||
| 8632 | TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; | ||
| 8633 | bool ptr_is_const = true; | ||
| 8634 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, | ||
| 8635 | usize, false, ConstPtrSpecialNone, ptr_is_const); | ||
| 8636 | } else { | ||
| 8637 | ir_add_error_node(ira, source_node, | ||
| 8638 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), | ||
| 8639 | buf_ptr(&container_type->name))); | ||
| 8640 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8641 | } | ||
| 8642 | } else if (container_type->id == TypeTableEntryIdArgTuple) { | ||
| 8643 | ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); | ||
| 8644 | if (!container_ptr_val) | ||
| 8645 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8646 | |||
| 8647 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); | ||
| 8648 | ConstExprValue *child_val = const_ptr_pointee(container_ptr_val); | ||
| 8649 | |||
| 8650 | if (buf_eql_str(field_name, "len")) { | ||
| 8651 | ConstExprValue *len_val = allocate<ConstExprValue>(1); | ||
| 8652 | size_t len = child_val->data.x_arg_tuple.end_index - child_val->data.x_arg_tuple.start_index; | ||
| 8653 | init_const_usize(ira->codegen, len_val, len); | ||
| 8654 | |||
| 8575 | TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; | 8655 | TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; |
| 8576 | bool ptr_is_const = true; | 8656 | bool ptr_is_const = true; |
| 8577 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, | 8657 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, |
| ... | @@ -8830,6 +8910,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi | ... | @@ -8830,6 +8910,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi |
| 8830 | case TypeTableEntryIdFn: | 8910 | case TypeTableEntryIdFn: |
| 8831 | case TypeTableEntryIdTypeDecl: | 8911 | case TypeTableEntryIdTypeDecl: |
| 8832 | case TypeTableEntryIdEnumTag: | 8912 | case TypeTableEntryIdEnumTag: |
| 8913 | case TypeTableEntryIdArgTuple: | ||
| 8833 | { | 8914 | { |
| 8834 | ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false); | 8915 | ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false); |
| 8835 | // TODO depends_on_compile_var should be set based on whether the type of the expression | 8916 | // TODO depends_on_compile_var should be set based on whether the type of the expression |
| ... | @@ -8847,8 +8928,8 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi | ... | @@ -8847,8 +8928,8 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi |
| 8847 | static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, | 8928 | static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, |
| 8848 | IrInstructionToPtrType *to_ptr_type_instruction) | 8929 | IrInstructionToPtrType *to_ptr_type_instruction) |
| 8849 | { | 8930 | { |
| 8850 | IrInstruction *type_value = to_ptr_type_instruction->value->other; | 8931 | IrInstruction *value = to_ptr_type_instruction->value->other; |
| 8851 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); | 8932 | TypeTableEntry *type_entry = value->value.type; |
| 8852 | if (type_entry->id == TypeTableEntryIdInvalid) | 8933 | if (type_entry->id == TypeTableEntryIdInvalid) |
| 8853 | return type_entry; | 8934 | return type_entry; |
| 8854 | 8935 | ||
| ... | @@ -8857,6 +8938,11 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, | ... | @@ -8857,6 +8938,11 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, |
| 8857 | ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false); | 8938 | ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false); |
| 8858 | } else if (is_slice(type_entry)) { | 8939 | } else if (is_slice(type_entry)) { |
| 8859 | ptr_type = type_entry->data.structure.fields[0].type_entry; | 8940 | ptr_type = type_entry->data.structure.fields[0].type_entry; |
| 8941 | } else if (type_entry->id == TypeTableEntryIdArgTuple) { | ||
| 8942 | ConstExprValue *arg_tuple_val = ir_resolve_const(ira, value, UndefBad); | ||
| 8943 | if (!arg_tuple_val) | ||
| 8944 | return ira->codegen->builtin_types.entry_invalid; | ||
| 8945 | zig_panic("TODO for loop on var args"); | ||
| 8860 | } else { | 8946 | } else { |
| 8861 | ir_add_error_node(ira, to_ptr_type_instruction->base.source_node, | 8947 | ir_add_error_node(ira, to_ptr_type_instruction->base.source_node, |
| 8862 | buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name))); | 8948 | buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name))); |
| ... | @@ -8864,7 +8950,7 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, | ... | @@ -8864,7 +8950,7 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, |
| 8864 | } | 8950 | } |
| 8865 | 8951 | ||
| 8866 | ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base, | 8952 | ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base, |
| 8867 | type_value->value.depends_on_compile_var); | 8953 | value->value.depends_on_compile_var); |
| 8868 | out_val->data.x_type = ptr_type; | 8954 | out_val->data.x_type = ptr_type; |
| 8869 | return ira->codegen->builtin_types.entry_type; | 8955 | return ira->codegen->builtin_types.entry_type; |
| 8870 | } | 8956 | } |
| ... | @@ -9027,6 +9113,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, | ... | @@ -9027,6 +9113,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 9027 | case TypeTableEntryIdUndefLit: | 9113 | case TypeTableEntryIdUndefLit: |
| 9028 | case TypeTableEntryIdNullLit: | 9114 | case TypeTableEntryIdNullLit: |
| 9029 | case TypeTableEntryIdBlock: | 9115 | case TypeTableEntryIdBlock: |
| 9116 | case TypeTableEntryIdArgTuple: | ||
| 9030 | ir_add_error_node(ira, slice_type_instruction->base.source_node, | 9117 | ir_add_error_node(ira, slice_type_instruction->base.source_node, |
| 9031 | buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name))); | 9118 | buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name))); |
| 9032 | // TODO if this is a typedecl, add error note showing the declaration of the type decl | 9119 | // TODO if this is a typedecl, add error note showing the declaration of the type decl |
| ... | @@ -9118,6 +9205,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, | ... | @@ -9118,6 +9205,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 9118 | case TypeTableEntryIdUndefLit: | 9205 | case TypeTableEntryIdUndefLit: |
| 9119 | case TypeTableEntryIdNullLit: | 9206 | case TypeTableEntryIdNullLit: |
| 9120 | case TypeTableEntryIdBlock: | 9207 | case TypeTableEntryIdBlock: |
| 9208 | case TypeTableEntryIdArgTuple: | ||
| 9121 | ir_add_error_node(ira, array_type_instruction->base.source_node, | 9209 | ir_add_error_node(ira, array_type_instruction->base.source_node, |
| 9122 | buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name))); | 9210 | buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name))); |
| 9123 | // TODO if this is a typedecl, add error note showing the declaration of the type decl | 9211 | // TODO if this is a typedecl, add error note showing the declaration of the type decl |
| ... | @@ -9214,6 +9302,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, | ... | @@ -9214,6 +9302,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 9214 | case TypeTableEntryIdMetaType: | 9302 | case TypeTableEntryIdMetaType: |
| 9215 | case TypeTableEntryIdFn: | 9303 | case TypeTableEntryIdFn: |
| 9216 | case TypeTableEntryIdNamespace: | 9304 | case TypeTableEntryIdNamespace: |
| 9305 | case TypeTableEntryIdArgTuple: | ||
| 9217 | ir_add_error_node(ira, size_of_instruction->base.source_node, | 9306 | ir_add_error_node(ira, size_of_instruction->base.source_node, |
| 9218 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); | 9307 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); |
| 9219 | // TODO if this is a typedecl, add error note showing the declaration of the type decl | 9308 | // TODO if this is a typedecl, add error note showing the declaration of the type decl |
| ... | @@ -9559,6 +9648,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -9559,6 +9648,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 9559 | case TypeTableEntryIdUnion: | 9648 | case TypeTableEntryIdUnion: |
| 9560 | case TypeTableEntryIdBlock: | 9649 | case TypeTableEntryIdBlock: |
| 9561 | case TypeTableEntryIdBoundFn: | 9650 | case TypeTableEntryIdBoundFn: |
| 9651 | case TypeTableEntryIdArgTuple: | ||
| 9562 | ir_add_error(ira, &switch_target_instruction->base, | 9652 | ir_add_error(ira, &switch_target_instruction->base, |
| 9563 | buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); | 9653 | buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); |
| 9564 | // TODO if this is a typedecl, add error note showing the declaration of the type decl | 9654 | // TODO if this is a typedecl, add error note showing the declaration of the type decl |
| ... | @@ -10075,6 +10165,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -10075,6 +10165,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 10075 | case TypeTableEntryIdNamespace: | 10165 | case TypeTableEntryIdNamespace: |
| 10076 | case TypeTableEntryIdBlock: | 10166 | case TypeTableEntryIdBlock: |
| 10077 | case TypeTableEntryIdBoundFn: | 10167 | case TypeTableEntryIdBoundFn: |
| 10168 | case TypeTableEntryIdArgTuple: | ||
| 10078 | { | 10169 | { |
| 10079 | const char *err_format = is_max ? | 10170 | const char *err_format = is_max ? |
| 10080 | "no max value available for type '%s'" : | 10171 | "no max value available for type '%s'" : |
src/parser.cpp+12-13| ... | @@ -250,16 +250,11 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool | ... | @@ -250,16 +250,11 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | /* | 252 | /* |
| 253 | ParamDecl = option("noalias" | "comptime") option(Symbol ":") TypeExpr | "..." | 253 | ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...") |
| 254 | */ | 254 | */ |
| 255 | static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) { | 255 | static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) { |
| 256 | Token *token = &pc->tokens->at(*token_index); | 256 | Token *token = &pc->tokens->at(*token_index); |
| 257 | 257 | ||
| 258 | if (token->id == TokenIdEllipsis) { | ||
| 259 | *token_index += 1; | ||
| 260 | return nullptr; | ||
| 261 | } | ||
| 262 | |||
| 263 | AstNode *node = ast_create_node(pc, NodeTypeParamDecl, token); | 258 | AstNode *node = ast_create_node(pc, NodeTypeParamDecl, token); |
| 264 | 259 | ||
| 265 | if (token->id == TokenIdKeywordNoAlias) { | 260 | if (token->id == TokenIdKeywordNoAlias) { |
| ... | @@ -282,7 +277,13 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) { | ... | @@ -282,7 +277,13 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) { |
| 282 | } | 277 | } |
| 283 | } | 278 | } |
| 284 | 279 | ||
| 285 | node->data.param_decl.type = ast_parse_type_expr(pc, token_index, true); | 280 | Token *ellipsis_tok = &pc->tokens->at(*token_index); |
| 281 | if (ellipsis_tok->id == TokenIdEllipsis) { | ||
| 282 | *token_index += 1; | ||
| 283 | node->data.param_decl.is_var_args = true; | ||
| 284 | } else { | ||
| 285 | node->data.param_decl.type = ast_parse_type_expr(pc, token_index, true); | ||
| 286 | } | ||
| 286 | 287 | ||
| 287 | return node; | 288 | return node; |
| 288 | } | 289 | } |
| ... | @@ -304,12 +305,10 @@ static void ast_parse_param_decl_list(ParseContext *pc, size_t *token_index, | ... | @@ -304,12 +305,10 @@ static void ast_parse_param_decl_list(ParseContext *pc, size_t *token_index, |
| 304 | for (;;) { | 305 | for (;;) { |
| 305 | AstNode *param_decl_node = ast_parse_param_decl(pc, token_index); | 306 | AstNode *param_decl_node = ast_parse_param_decl(pc, token_index); |
| 306 | bool expect_end = false; | 307 | bool expect_end = false; |
| 307 | if (param_decl_node) { | 308 | assert(param_decl_node); |
| 308 | params->append(param_decl_node); | 309 | params->append(param_decl_node); |
| 309 | } else { | 310 | expect_end = param_decl_node->data.param_decl.is_var_args; |
| 310 | *is_var_args = true; | 311 | *is_var_args = expect_end; |
| 311 | expect_end = true; | ||
| 312 | } | ||
| 313 | 312 | ||
| 314 | Token *token = &pc->tokens->at(*token_index); | 313 | Token *token = &pc->tokens->at(*token_index); |
| 315 | *token_index += 1; | 314 | *token_index += 1; |
test/cases/var_args.zig created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | fn add(args: ...) -> i32 { | ||
| 4 | var sum = i32(0); | ||
| 5 | {comptime var i: usize = 0; inline while (i < args.len; i += 1) { | ||
| 6 | sum += args[i]; | ||
| 7 | }} | ||
| 8 | return sum; | ||
| 9 | } | ||
| 10 | |||
| 11 | fn testAddArbitraryArgs() { | ||
| 12 | @setFnTest(this); | ||
| 13 | |||
| 14 | assert(add(i32(1), i32(2), i32(3), i32(4)) == 10); | ||
| 15 | assert(add(i32(1234)) == 1234); | ||
| 16 | } | ||
test/run_tests.cpp+27-4| ... | @@ -832,10 +832,6 @@ fn f() { | ... | @@ -832,10 +832,6 @@ fn f() { |
| 832 | )SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'", | 832 | )SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'", |
| 833 | ".tmp_source.zig:5:24: error: expected type 'usize', found 'bool'"); | 833 | ".tmp_source.zig:5:24: error: expected type 'usize', found 'bool'"); |
| 834 | 834 | ||
| 835 | add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE( | ||
| 836 | fn f(...) {} | ||
| 837 | )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern function declarations"); | ||
| 838 | |||
| 839 | add_compile_fail_case("write to const global variable", R"SOURCE( | 835 | add_compile_fail_case("write to const global variable", R"SOURCE( |
| 840 | const x : i32 = 99; | 836 | const x : i32 = 99; |
| 841 | fn f() { | 837 | fn f() { |
| ... | @@ -1633,6 +1629,33 @@ pub fn maybeInt() -> ?i32 { | ... | @@ -1633,6 +1629,33 @@ pub fn maybeInt() -> ?i32 { |
| 1633 | return 0; | 1629 | return 0; |
| 1634 | } | 1630 | } |
| 1635 | )SOURCE", 1, ".tmp_source.zig:5:11: error: cannot return from defer expression"); | 1631 | )SOURCE", 1, ".tmp_source.zig:5:11: error: cannot return from defer expression"); |
| 1632 | |||
| 1633 | add_compile_fail_case("attempt to access var args out of bounds", R"SOURCE( | ||
| 1634 | fn add(args: ...) -> i32 { | ||
| 1635 | args[0] + args[1] | ||
| 1636 | } | ||
| 1637 | |||
| 1638 | fn foo() -> i32 { | ||
| 1639 | add(i32(1234)) | ||
| 1640 | } | ||
| 1641 | )SOURCE", 2, | ||
| 1642 | ".tmp_source.zig:3:19: error: index 1 outside argument list of size 1", | ||
| 1643 | ".tmp_source.zig:7:8: note: called from here"); | ||
| 1644 | |||
| 1645 | add_compile_fail_case("pass integer literal to var args", R"SOURCE( | ||
| 1646 | fn add(args: ...) -> i32 { | ||
| 1647 | var sum = i32(0); | ||
| 1648 | {comptime var i: usize = 0; inline while (i < args.len; i += 1) { | ||
| 1649 | sum += args[i]; | ||
| 1650 | }} | ||
| 1651 | return sum; | ||
| 1652 | } | ||
| 1653 | |||
| 1654 | fn bar() -> i32 { | ||
| 1655 | add(1, 2, 3, 4) | ||
| 1656 | } | ||
| 1657 | )SOURCE", 1, ".tmp_source.zig:11:9: error: parameter of type '(integer literal)' requires comptime"); | ||
| 1658 | |||
| 1636 | } | 1659 | } |
| 1637 | 1660 | ||
| 1638 | ////////////////////////////////////////////////////////////////////////////// | 1661 | ////////////////////////////////////////////////////////////////////////////// |
test/self_hosted.zig+1| ... | @@ -28,4 +28,5 @@ const test_switch = @import("cases/switch.zig"); | ... | @@ -28,4 +28,5 @@ const test_switch = @import("cases/switch.zig"); |
| 28 | const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig"); | 28 | const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig"); |
| 29 | const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig"); | 29 | const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig"); |
| 30 | const test_this = @import("cases/this.zig"); | 30 | const test_this = @import("cases/this.zig"); |
| 31 | const test_var_args = @import("cases/var_args.zig"); | ||
| 31 | const test_while = @import("cases/while.zig"); | 32 | const test_while = @import("cases/while.zig"); |