| author | |
| committer | |
| log | a4cba900e53154abd5595bacf709fe8fdcc86b27 |
| tree | 906b7b238f5f5d3797d04180c137f9829ca43944 |
| parent | 5490f907fe4b5c8323eaf917b1ead8760c9eca34 |
See #435 files changed, 59 insertions(+), 51 deletions(-)
src/all_types.hpp+1| ... | ... | @@ -673,6 +673,7 @@ struct AstNodeSymbolExpr { |
| 673 | 673 | FnTableEntry *fn_entry; |
| 674 | 674 | // set this to instead of analyzing the node, pretend it's a type entry and it's this one. |
| 675 | 675 | TypeTableEntry *override_type_entry; |
| 676 | TypeEnumField *enum_field; | |
| 676 | 677 | }; |
| 677 | 678 | |
| 678 | 679 | struct AstNodeBoolLiteral { |
src/analyze.cpp+24-4| ... | ... | @@ -4508,10 +4508,30 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, |
| 4508 | 4508 | if (item_node->type == NodeTypeSwitchRange) { |
| 4509 | 4509 | zig_panic("TODO range in switch statement"); |
| 4510 | 4510 | } |
| 4511 | analyze_expression(g, import, context, expr_type, item_node); | |
| 4512 | ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val; | |
| 4513 | if (!const_val->ok) { | |
| 4514 | add_node_error(g, item_node, buf_sprintf("unable to resolve constant expression")); | |
| 4511 | ||
| 4512 | if (expr_type->id == TypeTableEntryIdEnum) { | |
| 4513 | if (item_node->type == NodeTypeSymbol) { | |
| 4514 | Buf *field_name = &item_node->data.symbol_expr.symbol; | |
| 4515 | TypeEnumField *type_enum_field = get_enum_field(expr_type, field_name); | |
| 4516 | if (type_enum_field) { | |
| 4517 | item_node->data.symbol_expr.enum_field = type_enum_field; | |
| 4518 | } else { | |
| 4519 | add_node_error(g, item_node, | |
| 4520 | buf_sprintf("enum '%s' has no field '%s'", | |
| 4521 | buf_ptr(&expr_type->name), buf_ptr(field_name))); | |
| 4522 | } | |
| 4523 | } else { | |
| 4524 | add_node_error(g, item_node, buf_sprintf("expected enum tag name")); | |
| 4525 | } | |
| 4526 | } else { | |
| 4527 | TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node); | |
| 4528 | if (item_type->id != TypeTableEntryIdInvalid) { | |
| 4529 | ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val; | |
| 4530 | if (!const_val->ok) { | |
| 4531 | add_node_error(g, item_node, | |
| 4532 | buf_sprintf("unable to resolve constant expression")); | |
| 4533 | } | |
| 4534 | } | |
| 4515 | 4535 | } |
| 4516 | 4536 | } |
| 4517 | 4537 | var_type = expr_type; |
src/codegen.cpp+8-13| ... | ... | @@ -2357,21 +2357,16 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 2357 | 2357 | for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) { |
| 2358 | 2358 | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); |
| 2359 | 2359 | assert(item_node->type != NodeTypeSwitchRange); |
| 2360 | assert(get_resolved_expr(item_node)->const_val.ok); | |
| 2361 | LLVMValueRef val_handle = gen_expr(g, item_node); | |
| 2362 | 2360 | LLVMValueRef val; |
| 2363 | if (handle_is_ptr(target_type)) { | |
| 2364 | if (target_type->id == TypeTableEntryIdEnum) { | |
| 2365 | ConstExprValue *item_const_val = &get_resolved_expr(item_node)->const_val; | |
| 2366 | assert(item_const_val->ok); | |
| 2367 | assert(get_expr_type(item_node)->id == TypeTableEntryIdEnum); | |
| 2368 | val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref, | |
| 2369 | item_const_val->data.x_enum.tag, false); | |
| 2370 | } else { | |
| 2371 | zig_unreachable(); | |
| 2372 | } | |
| 2361 | if (target_type->id == TypeTableEntryIdEnum) { | |
| 2362 | assert(item_node->type == NodeTypeSymbol); | |
| 2363 | TypeEnumField *enum_field = item_node->data.symbol_expr.enum_field; | |
| 2364 | assert(enum_field); | |
| 2365 | val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref, | |
| 2366 | enum_field->value, false); | |
| 2373 | 2367 | } else { |
| 2374 | val = val_handle; | |
| 2368 | assert(get_resolved_expr(item_node)->const_val.ok); | |
| 2369 | val = gen_expr(g, item_node); | |
| 2375 | 2370 | } |
| 2376 | 2371 | LLVMAddCase(switch_instr, val, prong_block); |
| 2377 | 2372 | } |
test/run_tests.cpp-26| ... | ... | @@ -1157,32 +1157,6 @@ fn fn3() -> u32 {7} |
| 1157 | 1157 | fn fn4() -> u32 {8} |
| 1158 | 1158 | )SOURCE", "5\n6\n7\n8\n"); |
| 1159 | 1159 | |
| 1160 | add_simple_case("switch statement", R"SOURCE( | |
| 1161 | import "std.zig"; | |
| 1162 | ||
| 1163 | enum Foo { | |
| 1164 | A, | |
| 1165 | B, | |
| 1166 | C, | |
| 1167 | D, | |
| 1168 | } | |
| 1169 | ||
| 1170 | pub fn main(args: [][]u8) -> %void { | |
| 1171 | const foo = Foo.C; | |
| 1172 | const val: i32 = switch (foo) { | |
| 1173 | Foo.A => 1, | |
| 1174 | Foo.B => 2, | |
| 1175 | Foo.C => 3, | |
| 1176 | Foo.D => 4, | |
| 1177 | }; | |
| 1178 | if (val != 3) { | |
| 1179 | %%stdout.printf("BAD\n"); | |
| 1180 | } | |
| 1181 | ||
| 1182 | %%stdout.printf("OK\n"); | |
| 1183 | } | |
| 1184 | )SOURCE", "OK\n"); | |
| 1185 | ||
| 1186 | 1160 | add_simple_case("const number literal", R"SOURCE( |
| 1187 | 1161 | import "std.zig"; |
| 1188 | 1162 |
test/self_hosted.zig+26-8| ... | ... | @@ -59,14 +59,14 @@ fn constant_enum_with_payload() { |
| 59 | 59 | |
| 60 | 60 | fn should_be_empty(x: AnEnumWithPayload) { |
| 61 | 61 | switch (x) { |
| 62 | AnEnumWithPayload.Empty => {}, | |
| 62 | Empty => {}, | |
| 63 | 63 | else => unreachable{}, |
| 64 | 64 | } |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | fn should_be_not_empty(x: AnEnumWithPayload) { |
| 68 | 68 | switch (x) { |
| 69 | AnEnumWithPayload.Empty => unreachable{}, | |
| 69 | Empty => unreachable{}, | |
| 70 | 70 | else => {}, |
| 71 | 71 | } |
| 72 | 72 | } |
| ... | ... | @@ -111,9 +111,9 @@ fn non_const_cast_bool_to_int(t: bool, f: bool) { |
| 111 | 111 | fn switch_on_enum() { |
| 112 | 112 | const fruit = Fruit.Orange; |
| 113 | 113 | switch (fruit) { |
| 114 | Fruit.Apple => unreachable{}, | |
| 115 | Fruit.Orange => {}, | |
| 116 | Fruit.Banana => unreachable{}, | |
| 114 | Apple => unreachable{}, | |
| 115 | Orange => {}, | |
| 116 | Banana => unreachable{}, | |
| 117 | 117 | } |
| 118 | 118 | non_const_switch_on_enum(fruit); |
| 119 | 119 | } |
| ... | ... | @@ -124,8 +124,26 @@ enum Fruit { |
| 124 | 124 | } |
| 125 | 125 | fn non_const_switch_on_enum(fruit: Fruit) { |
| 126 | 126 | switch (fruit) { |
| 127 | Fruit.Apple => unreachable{}, | |
| 128 | Fruit.Orange => {}, | |
| 129 | Fruit.Banana => unreachable{}, | |
| 127 | Apple => unreachable{}, | |
| 128 | Orange => {}, | |
| 129 | Banana => unreachable{}, | |
| 130 | 130 | } |
| 131 | 131 | } |
| 132 | ||
| 133 | #attribute("test") | |
| 134 | fn switch_statement() { | |
| 135 | const foo = SwitchStatmentFoo.C; | |
| 136 | const val: i32 = switch (foo) { | |
| 137 | A => 1, | |
| 138 | B => 2, | |
| 139 | C => 3, | |
| 140 | D => 4, | |
| 141 | }; | |
| 142 | if (val != 3) unreachable{}; | |
| 143 | } | |
| 144 | enum SwitchStatmentFoo { | |
| 145 | A, | |
| 146 | B, | |
| 147 | C, | |
| 148 | D, | |
| 149 | } |