authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-09 18:50:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-09 18:53:28-07:00
logd8f6388b63b3c4abe235a5fe0a49e9b18f6fb2f5
tree4ed6e6ba5a173ca66f5137af175d170966838e54
parentf45c374664b38dcbf8c65c938863ed10d0dda25a

if statements can be const expr evaluated

also introduce error for unnecessary if statement but if the condition depends on a compile variable, then the if statement is OK

7 files changed, 385 insertions(+), 377 deletions(-)

example/cat/main.zig+3-3
...@@ -13,7 +13,7 @@ pub fn main(args: [][]u8) -> %void {...@@ -13,7 +13,7 @@ pub fn main(args: [][]u8) -> %void {
13 for (arg, args[1...]) {13 for (arg, args[1...]) {
14 if (arg == "-") {14 if (arg == "-") {
15 catted_anything = true;15 catted_anything = true;
16 %return cat_stream(stdin);16 cat_stream(stdin) %% |err| return err;
17 } else if (arg[0] == '-') {17 } else if (arg[0] == '-') {
18 return usage(exe);18 return usage(exe);
19 } else {19 } else {
...@@ -24,11 +24,11 @@ pub fn main(args: [][]u8) -> %void {...@@ -24,11 +24,11 @@ pub fn main(args: [][]u8) -> %void {
24 defer is.close();24 defer is.close();
2525
26 catted_anything = true;26 catted_anything = true;
27 %return cat_stream(is);27 cat_stream(is) %% |err| return err;
28 }28 }
29 }29 }
30 if (!catted_anything) {30 if (!catted_anything) {
31 %return cat_stream(stdin)31 cat_stream(stdin) %% |err| return err;
32 }32 }
33}33}
3434
src/all_types.hpp+14-11
...@@ -1049,6 +1049,19 @@ struct BuiltinFnEntry {...@@ -1049,6 +1049,19 @@ struct BuiltinFnEntry {
1049 LLVMValueRef fn_val;1049 LLVMValueRef fn_val;
1050};1050};
10511051
1052enum CIntType {
1053 CIntTypeShort,
1054 CIntTypeUShort,
1055 CIntTypeInt,
1056 CIntTypeUInt,
1057 CIntTypeLong,
1058 CIntTypeULong,
1059 CIntTypeLongLong,
1060 CIntTypeULongLong,
1061
1062 CIntTypeCount,
1063};
1064
1052struct CodeGen {1065struct CodeGen {
1053 LLVMModuleRef module;1066 LLVMModuleRef module;
1054 ZigList<ErrorMsg*> errors;1067 ZigList<ErrorMsg*> errors;
...@@ -1072,7 +1085,7 @@ struct CodeGen {...@@ -1072,7 +1085,7 @@ struct CodeGen {
1072 struct {1085 struct {
1073 TypeTableEntry *entry_bool;1086 TypeTableEntry *entry_bool;
1074 TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64]1087 TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64]
1075 TypeTableEntry *entry_c_int[8];1088 TypeTableEntry *entry_c_int[CIntTypeCount];
1076 TypeTableEntry *entry_c_long_double;1089 TypeTableEntry *entry_c_long_double;
1077 TypeTableEntry *entry_u8;1090 TypeTableEntry *entry_u8;
1078 TypeTableEntry *entry_u16;1091 TypeTableEntry *entry_u16;
...@@ -1196,16 +1209,6 @@ struct BlockContext {...@@ -1196,16 +1209,6 @@ struct BlockContext {
1196 Buf *c_import_buf;1209 Buf *c_import_buf;
1197};1210};
11981211
1199enum CIntType {
1200 CIntTypeShort,
1201 CIntTypeUShort,
1202 CIntTypeInt,
1203 CIntTypeUInt,
1204 CIntTypeLong,
1205 CIntTypeULong,
1206 CIntTypeLongLong,
1207 CIntTypeULongLong,
1208};
12091212
12101213
1211#endif1214#endif
src/analyze.cpp+105-31
...@@ -2159,6 +2159,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry...@@ -2159,6 +2159,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
2159 &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val;2159 &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val;
2160 if (field_val->ok) {2160 if (field_val->ok) {
2161 const_val->data.x_struct.fields[field_index] = field_val;2161 const_val->data.x_struct.fields[field_index] = field_val;
2162 const_val->depends_on_compile_var = const_val->depends_on_compile_var || field_val->depends_on_compile_var;
2162 } else {2163 } else {
2163 const_val->ok = false;2164 const_val->ok = false;
2164 }2165 }
...@@ -2197,6 +2198,8 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry...@@ -2197,6 +2198,8 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
2197 ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val;2198 ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val;
2198 if (elem_const_val->ok) {2199 if (elem_const_val->ok) {
2199 const_val->data.x_array.fields[i] = elem_const_val;2200 const_val->data.x_array.fields[i] = elem_const_val;
2201 const_val->depends_on_compile_var = const_val->depends_on_compile_var ||
2202 elem_const_val->depends_on_compile_var;
2200 } else {2203 } else {
2201 const_val->ok = false;2204 const_val->ok = false;
2202 }2205 }
...@@ -2431,9 +2434,12 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node,...@@ -2431,9 +2434,12 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node,
2431 return g->builtin_types.entry_pure_error;2434 return g->builtin_types.entry_pure_error;
2432}2435}
24332436
2434static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value) {2437static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value,
2438 bool depends_on_compile_var)
2439{
2435 Expr *expr = get_resolved_expr(node);2440 Expr *expr = get_resolved_expr(node);
2436 expr->const_val.ok = true;2441 expr->const_val.ok = true;
2442 expr->const_val.depends_on_compile_var = depends_on_compile_var;
2437 expr->const_val.data.x_bool = value;2443 expr->const_val.data.x_bool = value;
2438 return g->builtin_types.entry_bool;2444 return g->builtin_types.entry_bool;
2439}2445}
...@@ -2817,7 +2823,8 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im...@@ -2817,7 +2823,8 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
2817 zig_unreachable();2823 zig_unreachable();
2818 }2824 }
28192825
2820 return resolve_expr_const_val_as_bool(g, node, answer);2826 bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
2827 return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var);
2821}2828}
28222829
2823static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,2830static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
...@@ -2844,7 +2851,8 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i...@@ -2844,7 +2851,8 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i
2844 }2851 }
28452852
2846 bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool);2853 bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool);
2847 return resolve_expr_const_val_as_bool(g, node, answer);2854 bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
2855 return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var);
2848}2856}
28492857
2850static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,2858static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
...@@ -3001,6 +3009,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,...@@ -3001,6 +3009,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
3001 }3009 }
3002 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;3010 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
3003 const_val->ok = true;3011 const_val->ok = true;
3012 const_val->depends_on_compile_var = op1_val->depends_on_compile_var ||
3013 op2_val->depends_on_compile_var;
30043014
3005 ConstExprValue *all_fields = allocate<ConstExprValue>(2);3015 ConstExprValue *all_fields = allocate<ConstExprValue>(2);
3006 ConstExprValue *ptr_field = &all_fields[0];3016 ConstExprValue *ptr_field = &all_fields[0];
...@@ -3444,51 +3454,111 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor...@@ -3444,51 +3454,111 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor
3444 return g->builtin_types.entry_unreachable;3454 return g->builtin_types.entry_unreachable;
3445}3455}
34463456
3447static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import, BlockContext *context,3457static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3448 TypeTableEntry *expected_type, AstNode *then_block, AstNode *else_node, AstNode *parent_node)3458 TypeTableEntry *expected_type, AstNode *node,
3459 AstNode **then_node, AstNode **else_node, bool cond_is_const, bool cond_bool_val)
3449{3460{
3450 TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type, then_block);3461 if (!*else_node) {
34513462 *else_node = create_ast_void_node(g, import, node);
3452 TypeTableEntry *else_type;3463 normalize_parent_ptrs(node);
3453 if (else_node) {
3454 else_type = analyze_expression(g, import, context, expected_type, else_node);
3455 } else {
3456 else_type = resolve_type_compatibility(g, import, context, parent_node, expected_type,
3457 g->builtin_types.entry_void);
3458 }3464 }
34593465
3466 TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type, *then_node);
3467 TypeTableEntry *else_type = analyze_expression(g, import, context, expected_type, *else_node);
34603468
3469 if (then_type->id == TypeTableEntryIdInvalid || else_type->id == TypeTableEntryIdInvalid) {
3470 return g->builtin_types.entry_invalid;
3471 }
3472
3473 TypeTableEntry *result_type;
3461 if (expected_type) {3474 if (expected_type) {
3462 return (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;3475 result_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
3463 } else {3476 } else {
3464 AstNode *op_nodes[] = {then_block, else_node};3477 AstNode *op_nodes[] = {*then_node, *else_node};
3465 TypeTableEntry *op_types[] = {then_type, else_type};3478 TypeTableEntry *op_types[] = {then_type, else_type};
3466 return resolve_peer_type_compatibility(g, import, context, parent_node, op_nodes, op_types, 2);3479 result_type = resolve_peer_type_compatibility(g, import, context, node, op_nodes, op_types, 2);
3480 }
3481
3482 if (!cond_is_const) {
3483 return result_type;
3467 }3484 }
3485
3486 ConstExprValue *other_const_val;
3487 if (cond_bool_val) {
3488 other_const_val = &get_resolved_expr(*then_node)->const_val;
3489 } else {
3490 other_const_val = &get_resolved_expr(*else_node)->const_val;
3491 }
3492 if (!other_const_val->ok) {
3493 return result_type;
3494 }
3495
3496 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
3497 *const_val = *other_const_val;
3498 return result_type;
3468}3499}
34693500
3470static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,3501static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3471 TypeTableEntry *expected_type, AstNode *node)3502 TypeTableEntry *expected_type, AstNode *node)
3472{3503{
3473 analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.if_bool_expr.condition);3504 AstNode **cond = &node->data.if_bool_expr.condition;
3505 TypeTableEntry *cond_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, *cond);
3506
3507 if (cond_type->id == TypeTableEntryIdInvalid) {
3508 return cond_type;
3509 }
34743510
3475 return analyze_if_then_else(g, import, context, expected_type,3511 ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val;
3476 node->data.if_bool_expr.then_block,3512 if (cond_val->ok && !cond_val->depends_on_compile_var) {
3477 node->data.if_bool_expr.else_node,3513 const char *str_val = cond_val->data.x_bool ? "true" : "false";
3478 node);3514 add_node_error(g, first_executing_node(*cond),
3515 buf_sprintf("condition is always %s; unnecessary if statement", str_val));
3516 }
3517
3518 bool cond_is_const = cond_val->ok;
3519 bool cond_bool_val = cond_val->data.x_bool;
3520
3521 AstNode **then_node = &node->data.if_bool_expr.then_block;
3522 AstNode **else_node = &node->data.if_bool_expr.else_node;
3523
3524 return analyze_if(g, import, context, expected_type, node,
3525 then_node, else_node, cond_is_const, cond_bool_val);
3479}3526}
34803527
3481static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,3528static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
3482 TypeTableEntry *expected_type, AstNode *node)3529 TypeTableEntry *expected_type, AstNode *node)
3483{3530{
3484 assert(node->type == NodeTypeIfVarExpr);3531 assert(node->type == NodeTypeIfVarExpr);
34853532
3486 BlockContext *child_context = new_block_context(node, context);3533 BlockContext *child_context = new_block_context(node, parent_context);
34873534
3488 analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true);3535 analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true);
3536 VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;
3537 if (var->type->id == TypeTableEntryIdInvalid) {
3538 return g->builtin_types.entry_invalid;
3539 }
3540 AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr;
3541 ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val;
3542 bool cond_is_const = var_const_val->ok;
3543 bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false;
3544
3545
3546 AstNode **then_node = &node->data.if_var_expr.then_block;
3547 AstNode **else_node = &node->data.if_var_expr.else_node;
34893548
3490 return analyze_if_then_else(g, import, child_context, expected_type,3549 return analyze_if(g, import, child_context, expected_type,
3491 node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node);3550 node, then_node, else_node, cond_is_const, cond_bool_val);
3551}
3552
3553static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
3554 assert(int_type->id == TypeTableEntryIdInt);
3555
3556 for (int i = 0; i < CIntTypeCount; i += 1) {
3557 if (int_type == g->builtin_types.entry_c_int[i]) {
3558 return true;
3559 }
3560 }
3561 return false;
3492}3562}
34933563
3494static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,3564static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
...@@ -3504,6 +3574,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor...@@ -3504,6 +3574,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
3504 } else if (type_entry->id == TypeTableEntryIdInt) {3574 } else if (type_entry->id == TypeTableEntryIdInt) {
3505 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;3575 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
3506 const_val->ok = true;3576 const_val->ok = true;
3577 const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
3507 if (is_max) {3578 if (is_max) {
3508 if (type_entry->data.integral.is_signed) {3579 if (type_entry->data.integral.is_signed) {
3509 int64_t val;3580 int64_t val;
...@@ -3558,7 +3629,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor...@@ -3558,7 +3629,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
3558 zig_panic("TODO analyze_min_max_value float");3629 zig_panic("TODO analyze_min_max_value float");
3559 return type_entry;3630 return type_entry;
3560 } else if (type_entry->id == TypeTableEntryIdBool) {3631 } else if (type_entry->id == TypeTableEntryIdBool) {
3561 return resolve_expr_const_val_as_bool(g, node, is_max);3632 return resolve_expr_const_val_as_bool(g, node, is_max, false);
3562 } else {3633 } else {
3563 add_node_error(g, node,3634 add_node_error(g, node,
3564 buf_sprintf(err_format, buf_ptr(&type_entry->name)));3635 buf_sprintf(err_format, buf_ptr(&type_entry->name)));
...@@ -3573,6 +3644,8 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex...@@ -3573,6 +3644,8 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
3573 if (!other_val->ok) {3644 if (!other_val->ok) {
3574 return;3645 return;
3575 }3646 }
3647 const_val->depends_on_compile_var = other_val->depends_on_compile_var;
3648
3576 assert(other_val != const_val);3649 assert(other_val != const_val);
3577 switch (node->data.fn_call_expr.cast_op) {3650 switch (node->data.fn_call_expr.cast_op) {
3578 case CastOpNoCast:3651 case CastOpNoCast:
...@@ -4132,11 +4205,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -4132,11 +4205,11 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
4132 const_val->depends_on_compile_var = true;4205 const_val->depends_on_compile_var = true;
41334206
4134 if (buf_eql_str(&var_name, "is_big_endian")) {4207 if (buf_eql_str(&var_name, "is_big_endian")) {
4135 return resolve_expr_const_val_as_bool(g, node, g->is_big_endian);4208 return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
4136 } else if (buf_eql_str(&var_name, "is_release")) {4209 } else if (buf_eql_str(&var_name, "is_release")) {
4137 return resolve_expr_const_val_as_bool(g, node, g->is_release_build);4210 return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
4138 } else if (buf_eql_str(&var_name, "is_test")) {4211 } else if (buf_eql_str(&var_name, "is_test")) {
4139 return resolve_expr_const_val_as_bool(g, node, g->is_test_build);4212 return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
4140 } else {4213 } else {
4141 add_node_error(g, *str_node,4214 add_node_error(g, *str_node,
4142 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));4215 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));
...@@ -4353,7 +4426,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo...@@ -4353,7 +4426,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
4353 }4426 }
43544427
4355 bool answer = !target_const_val->data.x_bool;4428 bool answer = !target_const_val->data.x_bool;
4356 return resolve_expr_const_val_as_bool(g, node, answer);4429 return resolve_expr_const_val_as_bool(g, node, answer, target_const_val->depends_on_compile_var);
4357 }4430 }
4358 case PrefixOpBinNot:4431 case PrefixOpBinNot:
4359 {4432 {
...@@ -4390,6 +4463,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo...@@ -4390,6 +4463,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
4390 }4463 }
4391 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;4464 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
4392 const_val->ok = true;4465 const_val->ok = true;
4466 const_val->depends_on_compile_var = target_const_val->depends_on_compile_var;
4393 bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum);4467 bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum);
4394 return expr_type;4468 return expr_type;
4395 } else {4469 } else {
...@@ -4880,7 +4954,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -4880,7 +4954,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
4880 node->data.char_literal.value);4954 node->data.char_literal.value);
4881 break;4955 break;
4882 case NodeTypeBoolLiteral:4956 case NodeTypeBoolLiteral:
4883 return_type = resolve_expr_const_val_as_bool(g, node, node->data.bool_literal.value);4957 return_type = resolve_expr_const_val_as_bool(g, node, node->data.bool_literal.value, false);
4884 break;4958 break;
4885 case NodeTypeNullLiteral:4959 case NodeTypeNullLiteral:
4886 return_type = analyze_null_literal_expr(g, import, context, expected_type, node);4960 return_type = analyze_null_literal_expr(g, import, context, expected_type, node);
src/codegen.cpp+45-70
...@@ -1737,81 +1737,60 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {...@@ -1737,81 +1737,60 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
1737 zig_unreachable();1737 zig_unreachable();
1738}1738}
17391739
1740static LLVMValueRef gen_defer(CodeGen *g, AstNode *node) {
1741 assert(node->type == NodeTypeDefer);
1742
1743
1744 return nullptr;
1745}
1746
1747static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value,1740static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value,
1748 AstNode *then_node, AstNode *else_node)1741 AstNode *then_node, AstNode *else_node)
1749{1742{
1750 TypeTableEntry *then_type = get_expr_type(then_node);1743 assert(then_node);
1751 bool use_expr_value = (then_type->id != TypeTableEntryIdUnreachable &&1744 assert(else_node);
1752 then_type->id != TypeTableEntryIdVoid);
1753
1754 if (else_node) {
1755 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
1756 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
1757
1758 LLVMBasicBlockRef endif_block;
1759 bool then_endif_reachable = get_expr_type(then_node)->id != TypeTableEntryIdUnreachable;
1760 bool else_endif_reachable = get_expr_type(else_node)->id != TypeTableEntryIdUnreachable;
1761 if (then_endif_reachable || else_endif_reachable) {
1762 endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
1763 }
17641745
1765 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);1746 TypeTableEntry *then_type = get_expr_type(then_node);
17661747 TypeTableEntry *else_type = get_expr_type(else_node);
1767 LLVMPositionBuilderAtEnd(g->builder, then_block);
1768 LLVMValueRef then_expr_result = gen_expr(g, then_node);
1769 if (then_endif_reachable) {
1770 LLVMBuildBr(g->builder, endif_block);
1771 }
1772 LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
1773
1774 LLVMPositionBuilderAtEnd(g->builder, else_block);
1775 LLVMValueRef else_expr_result = gen_expr(g, else_node);
1776 if (else_endif_reachable) {
1777 LLVMBuildBr(g->builder, endif_block);
1778 }
1779 LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
17801748
1781 if (then_endif_reachable || else_endif_reachable) {1749 bool use_then_value = type_has_bits(then_type);
1782 LLVMPositionBuilderAtEnd(g->builder, endif_block);1750 bool use_else_value = type_has_bits(else_type);
1783 if (use_expr_value) {
1784 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
1785 LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
1786 LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
1787 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
17881751
1789 return phi;1752 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
1790 }1753 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
1791 }
17921754
1793 return nullptr;1755 LLVMBasicBlockRef endif_block;
1756 bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable;
1757 bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable;
1758 if (then_endif_reachable || else_endif_reachable) {
1759 endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
1794 }1760 }
17951761
1796 assert(!use_expr_value || then_type->id == TypeTableEntryIdErrorUnion);1762 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
1797
1798 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
1799 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
1800
1801 LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);
18021763
1803 LLVMPositionBuilderAtEnd(g->builder, then_block);1764 LLVMPositionBuilderAtEnd(g->builder, then_block);
1804 gen_expr(g, then_node);1765 LLVMValueRef then_expr_result = gen_expr(g, then_node);
1805 if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)1766 if (then_endif_reachable) {
1806 LLVMBuildBr(g->builder, endif_block);1767 LLVMBuildBr(g->builder, endif_block);
1768 }
1769 LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
18071770
1808 LLVMPositionBuilderAtEnd(g->builder, endif_block);1771 LLVMPositionBuilderAtEnd(g->builder, else_block);
18091772 LLVMValueRef else_expr_result = gen_expr(g, else_node);
1810 if (use_expr_value) {1773 if (else_endif_reachable) {
1811 return LLVMConstNull(g->err_tag_type->type_ref);1774 LLVMBuildBr(g->builder, endif_block);
1812 } else {
1813 return nullptr;
1814 }1775 }
1776 LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
1777
1778 if (then_endif_reachable || else_endif_reachable) {
1779 LLVMPositionBuilderAtEnd(g->builder, endif_block);
1780 if (use_then_value && use_else_value) {
1781 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
1782 LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
1783 LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
1784 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
1785 return phi;
1786 } else if (use_then_value) {
1787 return then_expr_result;
1788 } else if (use_else_value) {
1789 return else_expr_result;
1790 }
1791 }
1792
1793 return nullptr;
1815}1794}
18161795
1817static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {1796static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
...@@ -1866,14 +1845,6 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {...@@ -1866,14 +1845,6 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
1866 return return_value;1845 return return_value;
1867}1846}
18681847
1869//static int block_exit_path_count(BlockContext *block_context) {
1870// int sum = 0;
1871// for (int i = 0; i < BlockExitPathCount; i += 1) {
1872// sum += block_context->block_exit_paths[i] ? 1 : 0;
1873// }
1874// return sum;
1875//}
1876
1877static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {1848static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
1878 assert(block_node->type == NodeTypeBlock);1849 assert(block_node->type == NodeTypeBlock);
18791850
...@@ -2553,7 +2524,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -2553,7 +2524,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
2553 case NodeTypeReturnExpr:2524 case NodeTypeReturnExpr:
2554 return gen_return_expr(g, node);2525 return gen_return_expr(g, node);
2555 case NodeTypeDefer:2526 case NodeTypeDefer:
2556 return gen_defer(g, node);2527 // nothing to do
2528 return nullptr;
2557 case NodeTypeVariableDeclaration:2529 case NodeTypeVariableDeclaration:
2558 return gen_var_decl_expr(g, node);2530 return gen_var_decl_expr(g, node);
2559 case NodeTypePrefixOpExpr:2531 case NodeTypePrefixOpExpr:
...@@ -3191,6 +3163,7 @@ static const CIntTypeInfo c_int_type_infos[] = {...@@ -3191,6 +3163,7 @@ static const CIntTypeInfo c_int_type_infos[] = {
31913163
3192static int get_c_type_size_in_bits(CodeGen *g, CIntType id) {3164static int get_c_type_size_in_bits(CodeGen *g, CIntType id) {
3193 // TODO other architectures besides x86_643165 // TODO other architectures besides x86_64
3166 // other operating systems besides linux
3194 switch (id) {3167 switch (id) {
3195 case CIntTypeShort:3168 case CIntTypeShort:
3196 case CIntTypeUShort:3169 case CIntTypeUShort:
...@@ -3203,6 +3176,8 @@ static int get_c_type_size_in_bits(CodeGen *g, CIntType id) {...@@ -3203,6 +3176,8 @@ static int get_c_type_size_in_bits(CodeGen *g, CIntType id) {
3203 case CIntTypeLongLong:3176 case CIntTypeLongLong:
3204 case CIntTypeULongLong:3177 case CIntTypeULongLong:
3205 return 64;3178 return 64;
3179 case CIntTypeCount:
3180 zig_unreachable();
3206 }3181 }
3207 zig_unreachable();3182 zig_unreachable();
3208}3183}
std/test_runner.zig+1
...@@ -16,6 +16,7 @@ pub fn run_tests() -> %void {...@@ -16,6 +16,7 @@ pub fn run_tests() -> %void {
16 %%stderr.print_str(" ");16 %%stderr.print_str(" ");
17 %%stderr.print_str(test_fn.name);17 %%stderr.print_str(test_fn.name);
18 %%stderr.print_str("...");18 %%stderr.print_str("...");
19 %%stderr.flush();
1920
20 test_fn.func();21 test_fn.func();
2122
test/run_tests.cpp+7-255
...@@ -225,26 +225,6 @@ pub fn foo_function() -> bool {...@@ -225,26 +225,6 @@ pub fn foo_function() -> bool {
225 )SOURCE");225 )SOURCE");
226 }226 }
227227
228 add_simple_case("if statements", R"SOURCE(
229import "std.zig";
230
231pub fn main(args: [][]u8) -> %void {
232 if (1 != 0) {
233 %%stdout.printf("1 is true\n");
234 } else {
235 %%stdout.printf("1 is false\n");
236 }
237 if (0 != 0) {
238 %%stdout.printf("0 is true\n");
239 } else if (1 - 1 != 0) {
240 %%stdout.printf("1 - 1 is true\n");
241 }
242 if (!(0 != 0)) {
243 %%stdout.printf("!0 is true\n");
244 }
245}
246 )SOURCE", "1 is true\n!0 is true\n");
247
248 add_simple_case("params", R"SOURCE(228 add_simple_case("params", R"SOURCE(
249import "std.zig";229import "std.zig";
250230
...@@ -259,46 +239,6 @@ pub fn main(args: [][]u8) -> %void {...@@ -259,46 +239,6 @@ pub fn main(args: [][]u8) -> %void {
259}239}
260 )SOURCE", "pass\n");240 )SOURCE", "pass\n");
261241
262 add_simple_case("local variables", R"SOURCE(
263import "std.zig";
264
265pub fn main(args: [][]u8) -> %void {
266 const a : i32 = 1;
267 const b = i32(2);
268 if (a + b == 3) {
269 %%stdout.printf("OK\n");
270 }
271}
272 )SOURCE", "OK\n");
273
274 add_simple_case("bool literals", R"SOURCE(
275import "std.zig";
276
277pub fn main(args: [][]u8) -> %void {
278 if (true) { %%stdout.printf("OK 1\n"); }
279 if (false) { %%stdout.printf("BAD 1\n"); }
280 if (!true) { %%stdout.printf("BAD 2\n"); }
281 if (!false) { %%stdout.printf("OK 2\n"); }
282}
283 )SOURCE", "OK 1\nOK 2\n");
284
285 add_simple_case("separate block scopes", R"SOURCE(
286import "std.zig";
287
288pub fn main(args: [][]u8) -> %void {
289 if (true) {
290 const no_conflict : i32 = 5;
291 if (no_conflict == 5) { %%stdout.printf("OK 1\n"); }
292 }
293
294 const c = {
295 const no_conflict = i32(10);
296 no_conflict
297 };
298 if (c == 10) { %%stdout.printf("OK 2\n"); }
299}
300 )SOURCE", "OK 1\nOK 2\n");
301
302 add_simple_case("void parameters", R"SOURCE(242 add_simple_case("void parameters", R"SOURCE(
303import "std.zig";243import "std.zig";
304244
...@@ -314,48 +254,6 @@ fn void_fun(a : i32, b : void, c : i32) {...@@ -314,48 +254,6 @@ fn void_fun(a : i32, b : void, c : i32) {
314}254}
315 )SOURCE", "OK\n");255 )SOURCE", "OK\n");
316256
317 add_simple_case("void struct fields", R"SOURCE(
318import "std.zig";
319struct Foo {
320 a : void,
321 b : i32,
322 c : void,
323}
324pub fn main(args: [][]u8) -> %void {
325 const foo = Foo {
326 .a = void{},
327 .b = 1,
328 .c = void{},
329 };
330 if (foo.b != 1) {
331 %%stdout.printf("BAD\n");
332 }
333 if (@sizeof(Foo) != 4) {
334 %%stdout.printf("BAD\n");
335 }
336 %%stdout.printf("OK\n");
337}
338
339 )SOURCE", "OK\n");
340
341 add_simple_case("void arrays", R"SOURCE(
342import "std.zig";
343
344pub fn main(args: [][]u8) -> %void {
345 var array: [4]void = undefined;
346 array[0] = void{};
347 array[1] = array[2];
348 if (@sizeof(@typeof(array)) != 0) {
349 %%stdout.printf("BAD sizeof\n");
350 }
351 if (array.len != 4) {
352 %%stdout.printf("BAD len\n");
353 }
354 %%stdout.printf("OK\n");
355}
356 )SOURCE", "OK\n");
357
358
359 add_simple_case("mutable local variables", R"SOURCE(257 add_simple_case("mutable local variables", R"SOURCE(
360import "std.zig";258import "std.zig";
361259
...@@ -414,27 +312,6 @@ pub fn main(args: [][]u8) -> %void {...@@ -414,27 +312,6 @@ pub fn main(args: [][]u8) -> %void {
414 )SOURCE", "Hello, world!\n");312 )SOURCE", "Hello, world!\n");
415313
416314
417 add_simple_case("a + b + c", R"SOURCE(
418import "std.zig";
419
420pub fn main(args: [][]u8) -> %void {
421 if (false || false || false) { %%stdout.printf("BAD 1\n"); }
422 if (true && true && false) { %%stdout.printf("BAD 2\n"); }
423 if (1 | 2 | 4 != 7) { %%stdout.printf("BAD 3\n"); }
424 if (3 ^ 6 ^ 8 != 13) { %%stdout.printf("BAD 4\n"); }
425 if (7 & 14 & 28 != 4) { %%stdout.printf("BAD 5\n"); }
426 if (9 << 1 << 2 != 9 << 3) { %%stdout.printf("BAD 6\n"); }
427 if (90 >> 1 >> 2 != 90 >> 3) { %%stdout.printf("BAD 7\n"); }
428 if (100 - 1 + 1000 != 1099) { %%stdout.printf("BAD 8\n"); }
429 if (5 * 4 / 2 % 3 != 1) { %%stdout.printf("BAD 9\n"); }
430 if (i32(i32(5)) != 5) { %%stdout.printf("BAD 10\n"); }
431 if (!!false) { %%stdout.printf("BAD 11\n"); }
432 if (i32(7) != --(i32(7))) { %%stdout.printf("BAD 12\n"); }
433
434 %%stdout.printf("OK\n");
435}
436 )SOURCE", "OK\n");
437
438 add_simple_case("short circuit", R"SOURCE(315 add_simple_case("short circuit", R"SOURCE(
439import "std.zig";316import "std.zig";
440317
...@@ -729,39 +606,6 @@ pub fn main(args: [][]u8) -> %void {...@@ -729,39 +606,6 @@ pub fn main(args: [][]u8) -> %void {
729}606}
730 )SOURCE", "loop\nloop\nloop\nloop\n");607 )SOURCE", "loop\nloop\nloop\nloop\n");
731608
732 add_simple_case("maybe type", R"SOURCE(
733import "std.zig";
734pub fn main(args: [][]u8) -> %void {
735 const x : ?bool = true;
736
737 if (const y ?= x) {
738 if (y) {
739 %%stdout.printf("x is true\n");
740 } else {
741 %%stdout.printf("x is false\n");
742 }
743 } else {
744 %%stdout.printf("x is none\n");
745 }
746
747 const next_x : ?i32 = null;
748
749 const z = next_x ?? 1234;
750
751 if (z != 1234) {
752 %%stdout.printf("BAD\n");
753 }
754
755 const final_x : ?i32 = 13;
756
757 const num = final_x ?? unreachable{};
758
759 if (num != 13) {
760 %%stdout.printf("BAD\n");
761 }
762}
763 )SOURCE", "x is true\n");
764
765 add_simple_case("implicit cast after unreachable", R"SOURCE(609 add_simple_case("implicit cast after unreachable", R"SOURCE(
766import "std.zig";610import "std.zig";
767pub fn main(args: [][]u8) -> %void {611pub fn main(args: [][]u8) -> %void {
...@@ -971,73 +815,6 @@ fn print_ok(val: @typeof(x)) -> @typeof(foo) {...@@ -971,73 +815,6 @@ fn print_ok(val: @typeof(x)) -> @typeof(foo) {
971const foo : i32 = 0;815const foo : i32 = 0;
972 )SOURCE", "OK\n");816 )SOURCE", "OK\n");
973817
974 add_simple_case("enum type", R"SOURCE(
975import "std.zig";
976
977struct Point {
978 x: u64,
979 y: u64,
980}
981
982enum Foo {
983 One: i32,
984 Two: Point,
985 Three: void,
986}
987
988enum Bar {
989 A,
990 B,
991 C,
992 D,
993}
994
995pub fn main(args: [][]u8) -> %void {
996 const foo1 = Foo.One(13);
997 const foo2 = Foo.Two(Point { .x = 1234, .y = 5678, });
998 const bar = Bar.B;
999
1000 if (bar != Bar.B) {
1001 %%stdout.printf("BAD 1\n");
1002 }
1003
1004 if (@member_count(Foo) != 3) {
1005 %%stdout.printf("BAD 2\n");
1006 }
1007
1008 if (@member_count(Bar) != 4) {
1009 %%stdout.printf("BAD 3\n");
1010 }
1011
1012 if (@sizeof(Foo) != 24) {
1013 %%stdout.printf("BAD 4\n");
1014 }
1015 if (@sizeof(Bar) != 1) {
1016 %%stdout.printf("BAD 5\n");
1017 }
1018
1019 %%stdout.printf("OK\n");
1020}
1021 )SOURCE", "OK\n");
1022
1023 add_simple_case("array literal", R"SOURCE(
1024import "std.zig";
1025
1026pub fn main(args: [][]u8) -> %void {
1027 const HEX_MULT = []u16{4096, 256, 16, 1};
1028
1029 if (HEX_MULT.len != 4) {
1030 %%stdout.printf("BAD\n");
1031 }
1032
1033 if (HEX_MULT[1] != 256) {
1034 %%stdout.printf("BAD\n");
1035 }
1036
1037 %%stdout.printf("OK\n");
1038}
1039 )SOURCE", "OK\n");
1040
1041 add_simple_case("nested arrays", R"SOURCE(818 add_simple_case("nested arrays", R"SOURCE(
1042import "std.zig";819import "std.zig";
1043820
...@@ -1092,23 +869,6 @@ fn fn3() -> u32 {7}...@@ -1092,23 +869,6 @@ fn fn3() -> u32 {7}
1092fn fn4() -> u32 {8}869fn fn4() -> u32 {8}
1093 )SOURCE", "5\n6\n7\n8\n");870 )SOURCE", "5\n6\n7\n8\n");
1094871
1095 add_simple_case("const number literal", R"SOURCE(
1096import "std.zig";
1097
1098const ten = 10;
1099
1100pub fn main(args: [][]u8) -> %void {
1101 const one = 1;
1102 const eleven = ten + one;
1103
1104 if (eleven != 11) {
1105 %%stdout.printf("BAD\n");
1106 }
1107
1108 %%stdout.printf("OK\n");
1109}
1110 )SOURCE", "OK\n");
1111
1112 add_simple_case("statically initialized struct", R"SOURCE(872 add_simple_case("statically initialized struct", R"SOURCE(
1113import "std.zig";873import "std.zig";
1114struct Foo {874struct Foo {
...@@ -1139,21 +899,6 @@ pub fn main(args: [][]u8) -> %void {...@@ -1139,21 +899,6 @@ pub fn main(args: [][]u8) -> %void {
1139}899}
1140 )SOURCE", "OK\n");900 )SOURCE", "OK\n");
1141901
1142 add_simple_case("error values", R"SOURCE(
1143import "std.zig";
1144error err1;
1145error err2;
1146pub fn main(args: [][]u8) -> %void {
1147 const a = i32(error.err1);
1148 const b = i32(error.err2);
1149 if (a == b) {
1150 %%stdout.printf("BAD\n");
1151 }
1152
1153 %%stdout.printf("OK\n");
1154}
1155 )SOURCE", "OK\n");
1156
1157 add_simple_case("return with implicit cast from while loop", R"SOURCE(902 add_simple_case("return with implicit cast from while loop", R"SOURCE(
1158import "std.zig";903import "std.zig";
1159pub fn main(args: [][]u8) -> %void {904pub fn main(args: [][]u8) -> %void {
...@@ -1988,6 +1733,13 @@ struct Foo {...@@ -1988,6 +1733,13 @@ struct Foo {
1988}1733}
1989fn get() -> isize { 1 }1734fn get() -> isize { 1 }
1990 )SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression");1735 )SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression");
1736
1737
1738 add_compile_fail_case("unnecessary if statement", R"SOURCE(
1739fn f() {
1740 if (true) { }
1741}
1742 )SOURCE", 1, ".tmp_source.zig:3:9: error: condition is always true; unnecessary if statement");
1991}1743}
19921744
1993//////////////////////////////////////////////////////////////////////////////1745//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig+210-7
...@@ -5,7 +5,6 @@ fn empty_function() {}...@@ -5,7 +5,6 @@ fn empty_function() {}
55
66
77
8
9/**8/**
10 * multi line doc comment9 * multi line doc comment
11 */10 */
...@@ -19,6 +18,200 @@ fn comments() {...@@ -19,6 +18,200 @@ fn comments() {
19fn comments_f1(s: []u8) {}18fn comments_f1(s: []u8) {}
2019
2120
21#attribute("test")
22fn if_statements() {
23 should_be_equal(1, 1);
24 first_eql_third(2, 1, 2);
25}
26fn should_be_equal(a: i32, b: i32) {
27 if (a != b) {
28 unreachable{};
29 } else {
30 return;
31 }
32}
33fn first_eql_third(a: i32, b: i32, c: i32) {
34 if (a == b) {
35 unreachable{};
36 } else if (b == c) {
37 unreachable{};
38 } else if (a == c) {
39 return;
40 } else {
41 unreachable{};
42 }
43}
44
45
46#attribute("test")
47fn local_variables() {
48 test_loc_vars(2);
49}
50fn test_loc_vars(b: i32) {
51 const a: i32 = 1;
52 if (a + b != 3) unreachable{};
53}
54
55#attribute("test")
56fn bool_literals() {
57 should_be_true(true);
58 should_be_false(false);
59}
60fn should_be_true(b: bool) {
61 if (!b) unreachable{};
62}
63fn should_be_false(b: bool) {
64 if (b) unreachable{};
65}
66
67
68#attribute("test")
69fn separate_block_scopes() {
70 {
71 const no_conflict : i32 = 5;
72 assert(no_conflict == 5);
73 }
74
75 const c = {
76 const no_conflict = i32(10);
77 no_conflict
78 };
79 assert(c == 10);
80}
81
82
83#attribute("test")
84fn void_struct_fields() {
85 const foo = VoidStructFieldsFoo {
86 .a = void{},
87 .b = 1,
88 .c = void{},
89 };
90 assert(foo.b == 1);
91 assert(@sizeof(VoidStructFieldsFoo) == 4);
92}
93struct VoidStructFieldsFoo {
94 a : void,
95 b : i32,
96 c : void,
97}
98
99
100#attribute("test")
101fn void_arrays() {
102 var array: [4]void = undefined;
103 array[0] = void{};
104 array[1] = array[2];
105 assert(@sizeof(@typeof(array)) == 0);
106 assert(array.len == 4);
107}
108
109
110#attribute("test")
111fn three_expr_in_a_row() {
112 assert_false(false || false || false);
113 assert_false(true && true && false);
114 assert_false(1 | 2 | 4 != 7);
115 assert_false(3 ^ 6 ^ 8 != 13);
116 assert_false(7 & 14 & 28 != 4);
117 assert_false(9 << 1 << 2 != 9 << 3);
118 assert_false(90 >> 1 >> 2 != 90 >> 3);
119 assert_false(100 - 1 + 1000 != 1099);
120 assert_false(5 * 4 / 2 % 3 != 1);
121 assert_false(i32(i32(5)) != 5);
122 assert_false(!!false);
123 assert_false(i32(7) != --(i32(7)));
124}
125fn assert_false(b: bool) {
126 assert(!b);
127}
128
129
130#attribute("test")
131fn maybe_type() {
132 const x : ?bool = true;
133
134 if (const y ?= x) {
135 if (y) {
136 // OK
137 } else {
138 unreachable{};
139 }
140 } else {
141 unreachable{};
142 }
143
144 const next_x : ?i32 = null;
145
146 const z = next_x ?? 1234;
147
148 assert(z == 1234);
149
150 const final_x : ?i32 = 13;
151
152 const num = final_x ?? unreachable{};
153
154 assert(num == 13);
155}
156
157
158#attribute("test")
159fn enum_type() {
160 const foo1 = EnumTypeFoo.One(13);
161 const foo2 = EnumTypeFoo.Two(EnumType { .x = 1234, .y = 5678, });
162 const bar = EnumTypeBar.B;
163
164 assert(bar == EnumTypeBar.B);
165 assert(@member_count(EnumTypeFoo) == 3);
166 assert(@member_count(EnumTypeBar) == 4);
167 assert(@sizeof(EnumTypeFoo) == 24);
168 assert(@sizeof(EnumTypeBar) == 1);
169}
170struct EnumType {
171 x: u64,
172 y: u64,
173}
174enum EnumTypeFoo {
175 One: i32,
176 Two: EnumType,
177 Three: void,
178}
179enum EnumTypeBar {
180 A,
181 B,
182 C,
183 D,
184}
185
186
187#attribute("test")
188fn array_literal() {
189 const HEX_MULT = []u16{4096, 256, 16, 1};
190
191 assert(HEX_MULT.len == 4);
192 assert(HEX_MULT[1] == 256);
193}
194
195
196#attribute("test")
197fn const_number_literal() {
198 const one = 1;
199 const eleven = ten + one;
200
201 assert(eleven == 11);
202}
203const ten = 10;
204
205
206#attribute("test")
207fn error_values() {
208 const a = i32(error.err1);
209 const b = i32(error.err2);
210 assert(a != b);
211}
212error err1;
213error err2;
214
22215
23216
24#attribute("test")217#attribute("test")
...@@ -42,11 +235,14 @@ fn call_struct_field(foo: Foo) -> i32 {...@@ -42,11 +235,14 @@ fn call_struct_field(foo: Foo) -> i32 {
42235
43#attribute("test")236#attribute("test")
44fn redefinition_of_error_values_allowed() {237fn redefinition_of_error_values_allowed() {
45 if (error.AnError == error.SecondError) unreachable{}238 should_be_not_equal(error.AnError, error.SecondError);
46}239}
47error AnError;240error AnError;
48error AnError;241error AnError;
49error SecondError;242error SecondError;
243fn should_be_not_equal(a: error, b: error) {
244 if (a == b) unreachable{}
245}
50246
51247
52248
...@@ -98,14 +294,14 @@ fn continue_in_for_loop() {...@@ -98,14 +294,14 @@ fn continue_in_for_loop() {
98fn cast_bool_to_int() {294fn cast_bool_to_int() {
99 const t = true;295 const t = true;
100 const f = false;296 const f = false;
101 if (i32(t) != i32(1)) unreachable{}297 assert(i32(t) == i32(1));
102 if (i32(f) != i32(0)) unreachable{}298 assert(i32(f) == i32(0));
103 non_const_cast_bool_to_int(t, f);299 non_const_cast_bool_to_int(t, f);
104}300}
105301
106fn non_const_cast_bool_to_int(t: bool, f: bool) {302fn non_const_cast_bool_to_int(t: bool, f: bool) {
107 if (i32(t) != i32(1)) unreachable{}303 assert(i32(t) == i32(1));
108 if (i32(f) != i32(0)) unreachable{}304 assert(i32(f) == i32(0));
109}305}
110306
111307
...@@ -240,7 +436,7 @@ fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 {...@@ -240,7 +436,7 @@ fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 {
240#attribute("test")436#attribute("test")
241fn builtin_const_eval() {437fn builtin_const_eval() {
242 const x : i32 = @const_eval(1 + 2 + 3);438 const x : i32 = @const_eval(1 + 2 + 3);
243 if (x != @const_eval(6)) unreachable{};439 assert(x == @const_eval(6));
244}440}
245441
246#attribute("test")442#attribute("test")
...@@ -279,3 +475,10 @@ struct ArrayDotLenConstExpr {...@@ -279,3 +475,10 @@ struct ArrayDotLenConstExpr {
279 y: [@const_eval(some_array.len)]u8,475 y: [@const_eval(some_array.len)]u8,
280}476}
281const some_array = []u8 {0, 1, 2, 3};477const some_array = []u8 {0, 1, 2, 3};
478
479
480
481
482fn assert(b: bool) {
483 if (!b) unreachable{}
484}