| 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 | 33 | |
| 34 | 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 | 38 | Block = "{" list(option(Statement), ";") "}" |
| 39 | 39 |
src/all_types.hpp+11| ... | ... | @@ -122,6 +122,11 @@ struct ConstBoundFnValue { |
| 122 | 122 | IrInstruction *first_arg; |
| 123 | 123 | }; |
| 124 | 124 | |
| 125 | struct ConstArgTuple { | |
| 126 | size_t start_index; | |
| 127 | size_t end_index; | |
| 128 | }; | |
| 129 | ||
| 125 | 130 | enum ConstValSpecial { |
| 126 | 131 | ConstValSpecialRuntime, |
| 127 | 132 | ConstValSpecialStatic, |
| ... | ... | @@ -163,6 +168,7 @@ struct ConstExprValue { |
| 163 | 168 | ConstPtrValue x_ptr; |
| 164 | 169 | ImportTableEntry *x_import; |
| 165 | 170 | Scope *x_block; |
| 171 | ConstArgTuple x_arg_tuple; | |
| 166 | 172 | |
| 167 | 173 | // populated if special == ConstValSpecialRuntime |
| 168 | 174 | RuntimeHintErrorUnion rh_error_union; |
| ... | ... | @@ -325,6 +331,7 @@ struct AstNodeParamDecl { |
| 325 | 331 | AstNode *type; |
| 326 | 332 | bool is_noalias; |
| 327 | 333 | bool is_inline; |
| 334 | bool is_var_args; | |
| 328 | 335 | }; |
| 329 | 336 | |
| 330 | 337 | struct AstNodeBlock { |
| ... | ... | @@ -936,6 +943,7 @@ enum TypeTableEntryId { |
| 936 | 943 | TypeTableEntryIdNamespace, |
| 937 | 944 | TypeTableEntryIdBlock, |
| 938 | 945 | TypeTableEntryIdBoundFn, |
| 946 | TypeTableEntryIdArgTuple, | |
| 939 | 947 | }; |
| 940 | 948 | |
| 941 | 949 | struct TypeTableEntry { |
| ... | ... | @@ -1034,6 +1042,8 @@ struct FnTableEntry { |
| 1034 | 1042 | |
| 1035 | 1043 | ZigList<IrInstruction *> alloca_list; |
| 1036 | 1044 | ZigList<VariableTableEntry *> variable_list; |
| 1045 | ||
| 1046 | VariableTableEntry *var_args_var; | |
| 1037 | 1047 | }; |
| 1038 | 1048 | |
| 1039 | 1049 | uint32_t fn_table_entry_hash(FnTableEntry*); |
| ... | ... | @@ -1155,6 +1165,7 @@ struct CodeGen { |
| 1155 | 1165 | TypeTableEntry *entry_environ_enum; |
| 1156 | 1166 | TypeTableEntry *entry_oformat_enum; |
| 1157 | 1167 | TypeTableEntry *entry_atomic_order_enum; |
| 1168 | TypeTableEntry *entry_arg_tuple; | |
| 1158 | 1169 | } builtin_types; |
| 1159 | 1170 | |
| 1160 | 1171 | ZigTarget zig_target; |
src/analyze.cpp+52-10| ... | ... | @@ -208,6 +208,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { |
| 208 | 208 | case TypeTableEntryIdBlock: |
| 209 | 209 | case TypeTableEntryIdBoundFn: |
| 210 | 210 | case TypeTableEntryIdEnumTag: |
| 211 | case TypeTableEntryIdArgTuple: | |
| 211 | 212 | return true; |
| 212 | 213 | } |
| 213 | 214 | zig_unreachable(); |
| ... | ... | @@ -245,6 +246,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) { |
| 245 | 246 | case TypeTableEntryIdBlock: |
| 246 | 247 | case TypeTableEntryIdBoundFn: |
| 247 | 248 | case TypeTableEntryIdEnumTag: |
| 249 | case TypeTableEntryIdArgTuple: | |
| 248 | 250 | return true; |
| 249 | 251 | } |
| 250 | 252 | zig_unreachable(); |
| ... | ... | @@ -921,6 +923,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 921 | 923 | assert(param_node->type == NodeTypeParamDecl); |
| 922 | 924 | |
| 923 | 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 | 928 | if (param_is_inline) { |
| 926 | 929 | if (fn_type_id.is_extern) { |
| ... | ... | @@ -929,6 +932,13 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 929 | 932 | return g->builtin_types.entry_invalid; |
| 930 | 933 | } |
| 931 | 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 | 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 | 949 | case TypeTableEntryIdUnreachable: |
| 940 | 950 | case TypeTableEntryIdUndefLit: |
| 941 | 951 | case TypeTableEntryIdNullLit: |
| 952 | case TypeTableEntryIdArgTuple: | |
| 942 | 953 | add_node_error(g, param_node->data.param_decl.type, |
| 943 | 954 | buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name))); |
| 944 | 955 | return g->builtin_types.entry_invalid; |
| ... | ... | @@ -989,6 +1000,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 989 | 1000 | |
| 990 | 1001 | case TypeTableEntryIdUndefLit: |
| 991 | 1002 | case TypeTableEntryIdNullLit: |
| 1003 | case TypeTableEntryIdArgTuple: | |
| 992 | 1004 | add_node_error(g, fn_proto->return_type, |
| 993 | 1005 | buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name))); |
| 994 | 1006 | return g->builtin_types.entry_invalid; |
| ... | ... | @@ -1558,13 +1570,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 1558 | 1570 | |
| 1559 | 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 | 1573 | FnTableEntry *fn_table_entry = create_fn(tld_fn->base.source_node); |
| 1569 | 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 | 1804 | case TypeTableEntryIdUndefLit: |
| 1800 | 1805 | case TypeTableEntryIdNullLit: |
| 1801 | 1806 | case TypeTableEntryIdBlock: |
| 1807 | case TypeTableEntryIdArgTuple: | |
| 1802 | 1808 | add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed", |
| 1803 | 1809 | buf_ptr(&underlying_type->name))); |
| 1804 | 1810 | return g->builtin_types.entry_invalid; |
| ... | ... | @@ -2210,6 +2216,7 @@ static bool is_container(TypeTableEntry *type_entry) { |
| 2210 | 2216 | case TypeTableEntryIdBlock: |
| 2211 | 2217 | case TypeTableEntryIdBoundFn: |
| 2212 | 2218 | case TypeTableEntryIdEnumTag: |
| 2219 | case TypeTableEntryIdArgTuple: | |
| 2213 | 2220 | return false; |
| 2214 | 2221 | } |
| 2215 | 2222 | zig_unreachable(); |
| ... | ... | @@ -2260,6 +2267,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 2260 | 2267 | case TypeTableEntryIdInvalid: |
| 2261 | 2268 | case TypeTableEntryIdVar: |
| 2262 | 2269 | case TypeTableEntryIdEnumTag: |
| 2270 | case TypeTableEntryIdArgTuple: | |
| 2263 | 2271 | zig_unreachable(); |
| 2264 | 2272 | } |
| 2265 | 2273 | } |
| ... | ... | @@ -2290,7 +2298,13 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari |
| 2290 | 2298 | for (size_t i = 0; i < fn_type_id->param_count; i += 1) { |
| 2291 | 2299 | FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; |
| 2292 | 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 | 2309 | TypeTableEntry *param_type = param_info->type; |
| 2296 | 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 | 2322 | param_name, true, create_const_runtime(param_type)); |
| 2309 | 2323 | var->src_arg_index = i; |
| 2310 | 2324 | fn_table_entry->child_scope = var->child_scope; |
| 2325 | var->shadowable = var->shadowable || is_var_args; | |
| 2311 | 2326 | |
| 2312 | 2327 | if (type_has_bits(param_type)) { |
| 2313 | 2328 | fn_table_entry->variable_list.append(var); |
| ... | ... | @@ -2627,6 +2642,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 2627 | 2642 | case TypeTableEntryIdBlock: |
| 2628 | 2643 | case TypeTableEntryIdBoundFn: |
| 2629 | 2644 | case TypeTableEntryIdVar: |
| 2645 | case TypeTableEntryIdArgTuple: | |
| 2630 | 2646 | zig_unreachable(); |
| 2631 | 2647 | case TypeTableEntryIdUnreachable: |
| 2632 | 2648 | case TypeTableEntryIdVoid: |
| ... | ... | @@ -2742,6 +2758,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 2742 | 2758 | case TypeTableEntryIdFloat: |
| 2743 | 2759 | case TypeTableEntryIdNumLitFloat: |
| 2744 | 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 | 2764 | case TypeTableEntryIdPointer: |
| 2746 | 2765 | return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index); |
| 2747 | 2766 | case TypeTableEntryIdUndefLit: |
| ... | ... | @@ -2805,7 +2824,7 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { |
| 2805 | 2824 | bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { |
| 2806 | 2825 | assert(a->fn_entry); |
| 2807 | 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 | 2828 | for (size_t i = 0; i < a->param_count; i += 1) { |
| 2810 | 2829 | ConstExprValue *a_val = &a->params[i]; |
| 2811 | 2830 | ConstExprValue *b_val = &b->params[i]; |
| ... | ... | @@ -2904,6 +2923,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) |
| 2904 | 2923 | case TypeTableEntryIdBlock: |
| 2905 | 2924 | case TypeTableEntryIdBoundFn: |
| 2906 | 2925 | case TypeTableEntryIdVar: |
| 2926 | case TypeTableEntryIdArgTuple: | |
| 2907 | 2927 | zig_unreachable(); |
| 2908 | 2928 | case TypeTableEntryIdArray: |
| 2909 | 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 | 2966 | case TypeTableEntryIdNamespace: |
| 2947 | 2967 | case TypeTableEntryIdBlock: |
| 2948 | 2968 | case TypeTableEntryIdBoundFn: |
| 2969 | case TypeTableEntryIdArgTuple: | |
| 2949 | 2970 | return true; |
| 2950 | 2971 | case TypeTableEntryIdArray: |
| 2951 | 2972 | case TypeTableEntryIdStruct: |
| ... | ... | @@ -3155,6 +3176,20 @@ ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t in |
| 3155 | 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 | 3193 | void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 3159 | 3194 | if (type_entry->id == TypeTableEntryIdStruct) { |
| 3160 | 3195 | if (!type_entry->data.structure.complete) |
| ... | ... | @@ -3245,6 +3280,9 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 3245 | 3280 | return a->data.x_import == b->data.x_import; |
| 3246 | 3281 | case TypeTableEntryIdBlock: |
| 3247 | 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 | 3286 | case TypeTableEntryIdBoundFn: |
| 3249 | 3287 | case TypeTableEntryIdInvalid: |
| 3250 | 3288 | case TypeTableEntryIdUnreachable: |
| ... | ... | @@ -3506,7 +3544,11 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { |
| 3506 | 3544 | buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name)); |
| 3507 | 3545 | return; |
| 3508 | 3546 | } |
| 3547 | case TypeTableEntryIdArgTuple: | |
| 3548 | { | |
| 3549 | buf_appendf(buf, "(args value)"); | |
| 3550 | return; | |
| 3551 | } | |
| 3509 | 3552 | } |
| 3510 | 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 | 133 | size_t start, size_t len, bool is_const); |
| 134 | 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 | 139 | #endif |
src/ast_render.cpp+6-6| ... | ... | @@ -393,7 +393,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 393 | 393 | print_symbol(ar, node->data.fn_proto.name); |
| 394 | 394 | fprintf(ar->f, "("); |
| 395 | 395 | int arg_count = node->data.fn_proto.params.length; |
| 396 | bool is_var_args = node->data.fn_proto.is_var_args; | |
| 397 | 396 | for (int arg_i = 0; arg_i < arg_count; arg_i += 1) { |
| 398 | 397 | AstNode *param_decl = node->data.fn_proto.params.at(arg_i); |
| 399 | 398 | assert(param_decl->type == NodeTypeParamDecl); |
| ... | ... | @@ -404,15 +403,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 404 | 403 | print_symbol(ar, param_decl->data.param_decl.name); |
| 405 | 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 | 413 | fprintf(ar->f, ", "); |
| 411 | 414 | } |
| 412 | 415 | } |
| 413 | if (is_var_args) { | |
| 414 | fprintf(ar->f, "..."); | |
| 415 | } | |
| 416 | 416 | fprintf(ar->f, ")"); |
| 417 | 417 | |
| 418 | 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 | 2636 | case TypeTableEntryIdBlock: |
| 2637 | 2637 | case TypeTableEntryIdBoundFn: |
| 2638 | 2638 | case TypeTableEntryIdVar: |
| 2639 | case TypeTableEntryIdArgTuple: | |
| 2639 | 2640 | zig_unreachable(); |
| 2640 | 2641 | |
| 2641 | 2642 | } |
| ... | ... | @@ -3179,6 +3180,12 @@ static void define_builtin_types(CodeGen *g) { |
| 3179 | 3180 | buf_init_from_str(&entry->name, "(var)"); |
| 3180 | 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 | 3190 | for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) { |
| 3184 | 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 | 3954 | case TypeTableEntryIdUndefLit: |
| 3948 | 3955 | case TypeTableEntryIdNullLit: |
| 3949 | 3956 | case TypeTableEntryIdVar: |
| 3957 | case TypeTableEntryIdArgTuple: | |
| 3950 | 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 | 4347 | |
| 4348 | 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); | |
| 4351 | IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_type); | |
| 4350 | IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val); | |
| 4352 | 4351 | IrInstruction *elem_var_type; |
| 4353 | 4352 | if (node->data.for_expr.elem_is_ptr) { |
| 4354 | 4353 | elem_var_type = pointer_type; |
| ... | ... | @@ -6887,6 +6886,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 6887 | 6886 | case TypeTableEntryIdNamespace: |
| 6888 | 6887 | case TypeTableEntryIdBlock: |
| 6889 | 6888 | case TypeTableEntryIdBoundFn: |
| 6889 | case TypeTableEntryIdArgTuple: | |
| 6890 | 6890 | if (!is_equality_cmp) { |
| 6891 | 6891 | ir_add_error_node(ira, source_node, |
| 6892 | 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 | 7449 | case TypeTableEntryIdFn: |
| 7450 | 7450 | case TypeTableEntryIdBoundFn: |
| 7451 | 7451 | case TypeTableEntryIdEnumTag: |
| 7452 | case TypeTableEntryIdArgTuple: | |
| 7452 | 7453 | // OK |
| 7453 | 7454 | break; |
| 7454 | 7455 | } |
| ... | ... | @@ -7520,21 +7521,35 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod |
| 7520 | 7521 | { |
| 7521 | 7522 | AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i); |
| 7522 | 7523 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 7523 | AstNode *param_type_node = param_decl_node->data.param_decl.type; | |
| 7524 | TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node); | |
| 7525 | if (param_type->id == TypeTableEntryIdInvalid) | |
| 7526 | return false; | |
| 7524 | bool is_var_args = param_decl_node->data.param_decl.is_var_args; | |
| 7525 | bool arg_part_of_generic_id = false; | |
| 7526 | IrInstruction *casted_arg; | |
| 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); | |
| 7529 | if (casted_arg->value.type->id == TypeTableEntryIdInvalid) | |
| 7530 | return false; | |
| 7536 | bool is_var_type = (param_type->id == TypeTableEntryIdVar); | |
| 7537 | if (is_var_type) { | |
| 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; | |
| 7533 | bool is_var_type = (param_type->id == TypeTableEntryIdVar); | |
| 7547 | bool comptime_arg = param_decl_node->data.param_decl.is_inline; | |
| 7534 | 7548 | |
| 7535 | 7549 | ConstExprValue *arg_val; |
| 7536 | 7550 | |
| 7537 | if (inline_arg) { | |
| 7551 | if (comptime_arg) { | |
| 7552 | arg_part_of_generic_id = true; | |
| 7538 | 7553 | arg_val = ir_resolve_const(ira, casted_arg, UndefBad); |
| 7539 | 7554 | if (!arg_val) |
| 7540 | 7555 | return false; |
| ... | ... | @@ -7544,26 +7559,41 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod |
| 7544 | 7559 | } else { |
| 7545 | 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 | 7567 | Buf *param_name = param_decl_node->data.param_decl.name; |
| 7549 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, | |
| 7550 | *child_scope, param_name, true, arg_val); | |
| 7551 | var->value.depends_on_compile_var = true; | |
| 7552 | *child_scope = var->child_scope; | |
| 7568 | if (is_var_args) { | |
| 7569 | if (!impl_fn->var_args_var) { | |
| 7570 | ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen, | |
| 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) { | |
| 7555 | generic_id->params[generic_id->param_count] = *arg_val; | |
| 7556 | generic_id->param_count += 1; | |
| 7580 | } else { | |
| 7581 | VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, | |
| 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) { | |
| 7559 | if (type_requires_comptime(var->value.type)) { | |
| 7560 | ir_add_error(ira, arg, | |
| 7561 | buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&var->value.type->name))); | |
| 7589 | ||
| 7590 | if (!comptime_arg) { | |
| 7591 | if (type_requires_comptime(casted_arg->value.type)) { | |
| 7592 | ir_add_error(ira, casted_arg, | |
| 7593 | buf_sprintf("parameter of type '%s' requires comptime", buf_ptr(&casted_arg->value.type->name))); | |
| 7562 | 7594 | return false; |
| 7563 | 7595 | } |
| 7564 | 7596 | |
| 7565 | var->shadowable = true; | |
| 7566 | ||
| 7567 | 7597 | casted_args[fn_type_id->param_count] = casted_arg; |
| 7568 | 7598 | FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count]; |
| 7569 | 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 | 7601 | impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node; |
| 7572 | 7602 | fn_type_id->param_count += 1; |
| 7573 | 7603 | } |
| 7574 | *next_proto_i += 1; | |
| 7604 | ||
| 7575 | 7605 | return true; |
| 7576 | 7606 | } |
| 7577 | 7607 | |
| ... | ... | @@ -7682,6 +7712,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 7682 | 7712 | FnTypeId inst_fn_type_id = {0}; |
| 7683 | 7713 | init_fn_type_id(&inst_fn_type_id, fn_proto_node); |
| 7684 | 7714 | inst_fn_type_id.param_count = 0; |
| 7715 | inst_fn_type_id.is_var_args = false; | |
| 7685 | 7716 | |
| 7686 | 7717 | // TODO maybe GenericFnTypeId can be replaced with using the child_scope directly |
| 7687 | 7718 | // as the key in generic_table |
| ... | ... | @@ -7918,6 +7949,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct |
| 7918 | 7949 | case TypeTableEntryIdBlock: |
| 7919 | 7950 | case TypeTableEntryIdUnreachable: |
| 7920 | 7951 | case TypeTableEntryIdVar: |
| 7952 | case TypeTableEntryIdArgTuple: | |
| 7921 | 7953 | ir_add_error_node(ira, un_op_instruction->base.source_node, |
| 7922 | 7954 | buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name))); |
| 7923 | 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 | 8022 | case TypeTableEntryIdBlock: |
| 7991 | 8023 | case TypeTableEntryIdBoundFn: |
| 7992 | 8024 | case TypeTableEntryIdEnumTag: |
| 8025 | case TypeTableEntryIdArgTuple: | |
| 7993 | 8026 | { |
| 7994 | 8027 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, |
| 7995 | 8028 | value->value.depends_on_compile_var); |
| ... | ... | @@ -8327,6 +8360,30 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 8327 | 8360 | return_type = array_type; |
| 8328 | 8361 | } else if (is_slice(array_type)) { |
| 8329 | 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 | 8387 | } else { |
| 8331 | 8388 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| 8332 | 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 | 8629 | ConstExprValue *len_val = allocate<ConstExprValue>(1); |
| 8573 | 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 | 8655 | TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; |
| 8576 | 8656 | bool ptr_is_const = true; |
| 8577 | 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 | 8910 | case TypeTableEntryIdFn: |
| 8831 | 8911 | case TypeTableEntryIdTypeDecl: |
| 8832 | 8912 | case TypeTableEntryIdEnumTag: |
| 8913 | case TypeTableEntryIdArgTuple: | |
| 8833 | 8914 | { |
| 8834 | 8915 | ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false); |
| 8835 | 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 | 8928 | static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, |
| 8848 | 8929 | IrInstructionToPtrType *to_ptr_type_instruction) |
| 8849 | 8930 | { |
| 8850 | IrInstruction *type_value = to_ptr_type_instruction->value->other; | |
| 8851 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); | |
| 8931 | IrInstruction *value = to_ptr_type_instruction->value->other; | |
| 8932 | TypeTableEntry *type_entry = value->value.type; | |
| 8852 | 8933 | if (type_entry->id == TypeTableEntryIdInvalid) |
| 8853 | 8934 | return type_entry; |
| 8854 | 8935 | |
| ... | ... | @@ -8857,6 +8938,11 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, |
| 8857 | 8938 | ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false); |
| 8858 | 8939 | } else if (is_slice(type_entry)) { |
| 8859 | 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 | 8946 | } else { |
| 8861 | 8947 | ir_add_error_node(ira, to_ptr_type_instruction->base.source_node, |
| 8862 | 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 | 8950 | } |
| 8865 | 8951 | |
| 8866 | 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 | 8954 | out_val->data.x_type = ptr_type; |
| 8869 | 8955 | return ira->codegen->builtin_types.entry_type; |
| 8870 | 8956 | } |
| ... | ... | @@ -9027,6 +9113,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 9027 | 9113 | case TypeTableEntryIdUndefLit: |
| 9028 | 9114 | case TypeTableEntryIdNullLit: |
| 9029 | 9115 | case TypeTableEntryIdBlock: |
| 9116 | case TypeTableEntryIdArgTuple: | |
| 9030 | 9117 | ir_add_error_node(ira, slice_type_instruction->base.source_node, |
| 9031 | 9118 | buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name))); |
| 9032 | 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 | 9205 | case TypeTableEntryIdUndefLit: |
| 9119 | 9206 | case TypeTableEntryIdNullLit: |
| 9120 | 9207 | case TypeTableEntryIdBlock: |
| 9208 | case TypeTableEntryIdArgTuple: | |
| 9121 | 9209 | ir_add_error_node(ira, array_type_instruction->base.source_node, |
| 9122 | 9210 | buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name))); |
| 9123 | 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 | 9302 | case TypeTableEntryIdMetaType: |
| 9215 | 9303 | case TypeTableEntryIdFn: |
| 9216 | 9304 | case TypeTableEntryIdNamespace: |
| 9305 | case TypeTableEntryIdArgTuple: | |
| 9217 | 9306 | ir_add_error_node(ira, size_of_instruction->base.source_node, |
| 9218 | 9307 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); |
| 9219 | 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 | 9648 | case TypeTableEntryIdUnion: |
| 9560 | 9649 | case TypeTableEntryIdBlock: |
| 9561 | 9650 | case TypeTableEntryIdBoundFn: |
| 9651 | case TypeTableEntryIdArgTuple: | |
| 9562 | 9652 | ir_add_error(ira, &switch_target_instruction->base, |
| 9563 | 9653 | buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); |
| 9564 | 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 | 10165 | case TypeTableEntryIdNamespace: |
| 10076 | 10166 | case TypeTableEntryIdBlock: |
| 10077 | 10167 | case TypeTableEntryIdBoundFn: |
| 10168 | case TypeTableEntryIdArgTuple: | |
| 10078 | 10169 | { |
| 10079 | 10170 | const char *err_format = is_max ? |
| 10080 | 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 | 250 | } |
| 251 | 251 | |
| 252 | 252 | /* |
| 253 | ParamDecl = option("noalias" | "comptime") option(Symbol ":") TypeExpr | "..." | |
| 253 | ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...") | |
| 254 | 254 | */ |
| 255 | 255 | static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) { |
| 256 | 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 | 258 | AstNode *node = ast_create_node(pc, NodeTypeParamDecl, token); |
| 264 | 259 | |
| 265 | 260 | if (token->id == TokenIdKeywordNoAlias) { |
| ... | ... | @@ -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 | 288 | return node; |
| 288 | 289 | } |
| ... | ... | @@ -304,12 +305,10 @@ static void ast_parse_param_decl_list(ParseContext *pc, size_t *token_index, |
| 304 | 305 | for (;;) { |
| 305 | 306 | AstNode *param_decl_node = ast_parse_param_decl(pc, token_index); |
| 306 | 307 | bool expect_end = false; |
| 307 | if (param_decl_node) { | |
| 308 | params->append(param_decl_node); | |
| 309 | } else { | |
| 310 | *is_var_args = true; | |
| 311 | expect_end = true; | |
| 312 | } | |
| 308 | assert(param_decl_node); | |
| 309 | params->append(param_decl_node); | |
| 310 | expect_end = param_decl_node->data.param_decl.is_var_args; | |
| 311 | *is_var_args = expect_end; | |
| 313 | 312 | |
| 314 | 313 | Token *token = &pc->tokens->at(*token_index); |
| 315 | 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 | 832 | )SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'", |
| 833 | 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 | 835 | add_compile_fail_case("write to const global variable", R"SOURCE( |
| 840 | 836 | const x : i32 = 99; |
| 841 | 837 | fn f() { |
| ... | ... | @@ -1633,6 +1629,33 @@ pub fn maybeInt() -> ?i32 { |
| 1633 | 1629 | return 0; |
| 1634 | 1630 | } |
| 1635 | 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 | 28 | const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig"); |
| 29 | 29 | const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig"); |
| 30 | 30 | const test_this = @import("cases/this.zig"); |
| 31 | const test_var_args = @import("cases/var_args.zig"); | |
| 31 | 32 | const test_while = @import("cases/while.zig"); |