| author | |
| committer | |
| log | d8f6388b63b3c4abe235a5fe0a49e9b18f6fb2f5 |
| tree | 4ed6e6ba5a173ca66f5137af175d170966838e54 |
| parent | f45c374664b38dcbf8c65c938863ed10d0dda25a |
also introduce error for unnecessary if statement
but if the condition depends on a compile variable, then
the if statement is OK7 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(); |
| 25 | 25 | ||
| 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 | } |
| 34 | 34 |
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 | }; |
| 1051 | 1051 | ||
| 1052 | enum CIntType { | ||
| 1053 | CIntTypeShort, | ||
| 1054 | CIntTypeUShort, | ||
| 1055 | CIntTypeInt, | ||
| 1056 | CIntTypeUInt, | ||
| 1057 | CIntTypeLong, | ||
| 1058 | CIntTypeULong, | ||
| 1059 | CIntTypeLongLong, | ||
| 1060 | CIntTypeULongLong, | ||
| 1061 | |||
| 1062 | CIntTypeCount, | ||
| 1063 | }; | ||
| 1064 | |||
| 1052 | struct CodeGen { | 1065 | struct 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 | }; |
| 1198 | 1211 | ||
| 1199 | enum CIntType { | ||
| 1200 | CIntTypeShort, | ||
| 1201 | CIntTypeUShort, | ||
| 1202 | CIntTypeInt, | ||
| 1203 | CIntTypeUInt, | ||
| 1204 | CIntTypeLong, | ||
| 1205 | CIntTypeULong, | ||
| 1206 | CIntTypeLongLong, | ||
| 1207 | CIntTypeULongLong, | ||
| 1208 | }; | ||
| 1209 | 1212 | ||
| 1210 | 1213 | ||
| 1211 | #endif | 1214 | #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 | } |
| 2433 | 2436 | ||
| 2434 | static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value) { | 2437 | static 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 | } |
| 2819 | 2825 | ||
| 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 | } |
| 2822 | 2829 | ||
| 2823 | static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2830 | static 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 | } |
| 2845 | 2852 | ||
| 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 | } |
| 2849 | 2857 | ||
| 2850 | static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2858 | static 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; | ||
| 3004 | 3014 | ||
| 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 | } |
| 3446 | 3456 | ||
| 3447 | static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 3457 | static 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) { |
| 3451 | 3462 | *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 | } |
| 3459 | 3465 | ||
| 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); | ||
| 3460 | 3468 | ||
| 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 | } |
| 3469 | 3500 | ||
| 3470 | static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 3501 | static 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 | } | ||
| 3474 | 3510 | ||
| 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 | } |
| 3480 | 3527 | ||
| 3481 | static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 3528 | static 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); |
| 3485 | 3532 | ||
| 3486 | BlockContext *child_context = new_block_context(node, context); | 3533 | BlockContext *child_context = new_block_context(node, parent_context); |
| 3487 | 3534 | ||
| 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; | ||
| 3489 | 3548 | ||
| 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 | |||
| 3553 | static 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 | } |
| 3493 | 3563 | ||
| 3494 | static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 3564 | static 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; |
| 4133 | 4206 | ||
| 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 | } |
| 4354 | 4427 | ||
| 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 | } |
| 1739 | 1739 | ||
| 1740 | static LLVMValueRef gen_defer(CodeGen *g, AstNode *node) { | ||
| 1741 | assert(node->type == NodeTypeDefer); | ||
| 1742 | |||
| 1743 | |||
| 1744 | return nullptr; | ||
| 1745 | } | ||
| 1746 | |||
| 1747 | static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value, | 1740 | static 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 | } | ||
| 1764 | 1745 | ||
| 1765 | LLVMBuildCondBr(g->builder, cond_value, then_block, else_block); | 1746 | TypeTableEntry *then_type = get_expr_type(then_node); |
| 1766 | 1747 | 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); | ||
| 1780 | 1748 | ||
| 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); | ||
| 1788 | 1751 | ||
| 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 | } | ||
| 1792 | 1754 | ||
| 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 | } |
| 1795 | 1761 | ||
| 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); | ||
| 1802 | 1763 | ||
| 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); | ||
| 1807 | 1770 | ||
| 1808 | LLVMPositionBuilderAtEnd(g->builder, endif_block); | 1771 | LLVMPositionBuilderAtEnd(g->builder, else_block); |
| 1809 | 1772 | 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 | } |
| 1816 | 1795 | ||
| 1817 | static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) { | 1796 | static 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 | } |
| 1868 | 1847 | ||
| 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 | |||
| 1877 | static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { | 1848 | static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { |
| 1878 | assert(block_node->type == NodeTypeBlock); | 1849 | assert(block_node->type == NodeTypeBlock); |
| 1879 | 1850 | ||
| ... | @@ -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[] = { |
| 3191 | 3163 | ||
| 3192 | static int get_c_type_size_in_bits(CodeGen *g, CIntType id) { | 3164 | static int get_c_type_size_in_bits(CodeGen *g, CIntType id) { |
| 3193 | // TODO other architectures besides x86_64 | 3165 | // 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(); | ||
| 19 | 20 | ||
| 20 | test_fn.func(); | 21 | test_fn.func(); |
| 21 | 22 |
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 | } |
| 227 | 227 | ||
| 228 | add_simple_case("if statements", R"SOURCE( | ||
| 229 | import "std.zig"; | ||
| 230 | |||
| 231 | pub 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( |
| 249 | import "std.zig"; | 229 | import "std.zig"; |
| 250 | 230 | ||
| ... | @@ -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"); |
| 261 | 241 | ||
| 262 | add_simple_case("local variables", R"SOURCE( | ||
| 263 | import "std.zig"; | ||
| 264 | |||
| 265 | pub 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( | ||
| 275 | import "std.zig"; | ||
| 276 | |||
| 277 | pub 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( | ||
| 286 | import "std.zig"; | ||
| 287 | |||
| 288 | pub 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( |
| 303 | import "std.zig"; | 243 | import "std.zig"; |
| 304 | 244 | ||
| ... | @@ -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"); |
| 316 | 256 | ||
| 317 | add_simple_case("void struct fields", R"SOURCE( | ||
| 318 | import "std.zig"; | ||
| 319 | struct Foo { | ||
| 320 | a : void, | ||
| 321 | b : i32, | ||
| 322 | c : void, | ||
| 323 | } | ||
| 324 | pub 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( | ||
| 342 | import "std.zig"; | ||
| 343 | |||
| 344 | pub 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( |
| 360 | import "std.zig"; | 258 | import "std.zig"; |
| 361 | 259 | ||
| ... | @@ -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"); |
| 415 | 313 | ||
| 416 | 314 | ||
| 417 | add_simple_case("a + b + c", R"SOURCE( | ||
| 418 | import "std.zig"; | ||
| 419 | |||
| 420 | pub 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( |
| 439 | import "std.zig"; | 316 | import "std.zig"; |
| 440 | 317 | ||
| ... | @@ -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"); |
| 731 | 608 | ||
| 732 | add_simple_case("maybe type", R"SOURCE( | ||
| 733 | import "std.zig"; | ||
| 734 | pub 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( |
| 766 | import "std.zig"; | 610 | import "std.zig"; |
| 767 | pub fn main(args: [][]u8) -> %void { | 611 | pub 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) { |
| 971 | const foo : i32 = 0; | 815 | const foo : i32 = 0; |
| 972 | )SOURCE", "OK\n"); | 816 | )SOURCE", "OK\n"); |
| 973 | 817 | ||
| 974 | add_simple_case("enum type", R"SOURCE( | ||
| 975 | import "std.zig"; | ||
| 976 | |||
| 977 | struct Point { | ||
| 978 | x: u64, | ||
| 979 | y: u64, | ||
| 980 | } | ||
| 981 | |||
| 982 | enum Foo { | ||
| 983 | One: i32, | ||
| 984 | Two: Point, | ||
| 985 | Three: void, | ||
| 986 | } | ||
| 987 | |||
| 988 | enum Bar { | ||
| 989 | A, | ||
| 990 | B, | ||
| 991 | C, | ||
| 992 | D, | ||
| 993 | } | ||
| 994 | |||
| 995 | pub 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( | ||
| 1024 | import "std.zig"; | ||
| 1025 | |||
| 1026 | pub 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( |
| 1042 | import "std.zig"; | 819 | import "std.zig"; |
| 1043 | 820 | ||
| ... | @@ -1092,23 +869,6 @@ fn fn3() -> u32 {7} | ... | @@ -1092,23 +869,6 @@ fn fn3() -> u32 {7} |
| 1092 | fn fn4() -> u32 {8} | 869 | fn fn4() -> u32 {8} |
| 1093 | )SOURCE", "5\n6\n7\n8\n"); | 870 | )SOURCE", "5\n6\n7\n8\n"); |
| 1094 | 871 | ||
| 1095 | add_simple_case("const number literal", R"SOURCE( | ||
| 1096 | import "std.zig"; | ||
| 1097 | |||
| 1098 | const ten = 10; | ||
| 1099 | |||
| 1100 | pub 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( |
| 1113 | import "std.zig"; | 873 | import "std.zig"; |
| 1114 | struct Foo { | 874 | struct 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"); |
| 1141 | 901 | ||
| 1142 | add_simple_case("error values", R"SOURCE( | ||
| 1143 | import "std.zig"; | ||
| 1144 | error err1; | ||
| 1145 | error err2; | ||
| 1146 | pub 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( |
| 1158 | import "std.zig"; | 903 | import "std.zig"; |
| 1159 | pub fn main(args: [][]u8) -> %void { | 904 | pub fn main(args: [][]u8) -> %void { |
| ... | @@ -1988,6 +1733,13 @@ struct Foo { | ... | @@ -1988,6 +1733,13 @@ struct Foo { |
| 1988 | } | 1733 | } |
| 1989 | fn get() -> isize { 1 } | 1734 | fn 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( | ||
| 1739 | fn f() { | ||
| 1740 | if (true) { } | ||
| 1741 | } | ||
| 1742 | )SOURCE", 1, ".tmp_source.zig:3:9: error: condition is always true; unnecessary if statement"); | ||
| 1991 | } | 1743 | } |
| 1992 | 1744 | ||
| 1993 | ////////////////////////////////////////////////////////////////////////////// | 1745 | ////////////////////////////////////////////////////////////////////////////// |
test/self_hosted.zig+210-7| ... | @@ -5,7 +5,6 @@ fn empty_function() {} | ... | @@ -5,7 +5,6 @@ fn empty_function() {} |
| 5 | 5 | ||
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | |||
| 9 | /** | 8 | /** |
| 10 | * multi line doc comment | 9 | * multi line doc comment |
| 11 | */ | 10 | */ |
| ... | @@ -19,6 +18,200 @@ fn comments() { | ... | @@ -19,6 +18,200 @@ fn comments() { |
| 19 | fn comments_f1(s: []u8) {} | 18 | fn comments_f1(s: []u8) {} |
| 20 | 19 | ||
| 21 | 20 | ||
| 21 | #attribute("test") | ||
| 22 | fn if_statements() { | ||
| 23 | should_be_equal(1, 1); | ||
| 24 | first_eql_third(2, 1, 2); | ||
| 25 | } | ||
| 26 | fn should_be_equal(a: i32, b: i32) { | ||
| 27 | if (a != b) { | ||
| 28 | unreachable{}; | ||
| 29 | } else { | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | fn 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") | ||
| 47 | fn local_variables() { | ||
| 48 | test_loc_vars(2); | ||
| 49 | } | ||
| 50 | fn test_loc_vars(b: i32) { | ||
| 51 | const a: i32 = 1; | ||
| 52 | if (a + b != 3) unreachable{}; | ||
| 53 | } | ||
| 54 | |||
| 55 | #attribute("test") | ||
| 56 | fn bool_literals() { | ||
| 57 | should_be_true(true); | ||
| 58 | should_be_false(false); | ||
| 59 | } | ||
| 60 | fn should_be_true(b: bool) { | ||
| 61 | if (!b) unreachable{}; | ||
| 62 | } | ||
| 63 | fn should_be_false(b: bool) { | ||
| 64 | if (b) unreachable{}; | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | #attribute("test") | ||
| 69 | fn 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") | ||
| 84 | fn 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 | } | ||
| 93 | struct VoidStructFieldsFoo { | ||
| 94 | a : void, | ||
| 95 | b : i32, | ||
| 96 | c : void, | ||
| 97 | } | ||
| 98 | |||
| 99 | |||
| 100 | #attribute("test") | ||
| 101 | fn 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") | ||
| 111 | fn 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 | } | ||
| 125 | fn assert_false(b: bool) { | ||
| 126 | assert(!b); | ||
| 127 | } | ||
| 128 | |||
| 129 | |||
| 130 | #attribute("test") | ||
| 131 | fn 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") | ||
| 159 | fn 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 | } | ||
| 170 | struct EnumType { | ||
| 171 | x: u64, | ||
| 172 | y: u64, | ||
| 173 | } | ||
| 174 | enum EnumTypeFoo { | ||
| 175 | One: i32, | ||
| 176 | Two: EnumType, | ||
| 177 | Three: void, | ||
| 178 | } | ||
| 179 | enum EnumTypeBar { | ||
| 180 | A, | ||
| 181 | B, | ||
| 182 | C, | ||
| 183 | D, | ||
| 184 | } | ||
| 185 | |||
| 186 | |||
| 187 | #attribute("test") | ||
| 188 | fn 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") | ||
| 197 | fn const_number_literal() { | ||
| 198 | const one = 1; | ||
| 199 | const eleven = ten + one; | ||
| 200 | |||
| 201 | assert(eleven == 11); | ||
| 202 | } | ||
| 203 | const ten = 10; | ||
| 204 | |||
| 205 | |||
| 206 | #attribute("test") | ||
| 207 | fn error_values() { | ||
| 208 | const a = i32(error.err1); | ||
| 209 | const b = i32(error.err2); | ||
| 210 | assert(a != b); | ||
| 211 | } | ||
| 212 | error err1; | ||
| 213 | error err2; | ||
| 214 | |||
| 22 | 215 | ||
| 23 | 216 | ||
| 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 { |
| 42 | 235 | ||
| 43 | #attribute("test") | 236 | #attribute("test") |
| 44 | fn redefinition_of_error_values_allowed() { | 237 | fn redefinition_of_error_values_allowed() { |
| 45 | if (error.AnError == error.SecondError) unreachable{} | 238 | should_be_not_equal(error.AnError, error.SecondError); |
| 46 | } | 239 | } |
| 47 | error AnError; | 240 | error AnError; |
| 48 | error AnError; | 241 | error AnError; |
| 49 | error SecondError; | 242 | error SecondError; |
| 243 | fn should_be_not_equal(a: error, b: error) { | ||
| 244 | if (a == b) unreachable{} | ||
| 245 | } | ||
| 50 | 246 | ||
| 51 | 247 | ||
| 52 | 248 | ||
| ... | @@ -98,14 +294,14 @@ fn continue_in_for_loop() { | ... | @@ -98,14 +294,14 @@ fn continue_in_for_loop() { |
| 98 | fn cast_bool_to_int() { | 294 | fn 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 | } |
| 105 | 301 | ||
| 106 | fn non_const_cast_bool_to_int(t: bool, f: bool) { | 302 | fn 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 | } |
| 110 | 306 | ||
| 111 | 307 | ||
| ... | @@ -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") |
| 241 | fn builtin_const_eval() { | 437 | fn 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 | } |
| 245 | 441 | ||
| 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 | } |
| 281 | const some_array = []u8 {0, 1, 2, 3}; | 477 | const some_array = []u8 {0, 1, 2, 3}; |
| 478 | |||
| 479 | |||
| 480 | |||
| 481 | |||
| 482 | fn assert(b: bool) { | ||
| 483 | if (!b) unreachable{} | ||
| 484 | } |