authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-04 16:09:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-04 16:09:06-07:00
loga4cba900e53154abd5595bacf709fe8fdcc86b27
tree906b7b238f5f5d3797d04180c137f9829ca43944
parent5490f907fe4b5c8323eaf917b1ead8760c9eca34

no namespace required when switching on enum

See #43

5 files changed, 59 insertions(+), 51 deletions(-)

src/all_types.hpp+1
...@@ -673,6 +673,7 @@ struct AstNodeSymbolExpr {...@@ -673,6 +673,7 @@ struct AstNodeSymbolExpr {
673 FnTableEntry *fn_entry;673 FnTableEntry *fn_entry;
674 // set this to instead of analyzing the node, pretend it's a type entry and it's this one.674 // set this to instead of analyzing the node, pretend it's a type entry and it's this one.
675 TypeTableEntry *override_type_entry;675 TypeTableEntry *override_type_entry;
676 TypeEnumField *enum_field;
676};677};
677678
678struct AstNodeBoolLiteral {679struct AstNodeBoolLiteral {
src/analyze.cpp+24-4
...@@ -4508,10 +4508,30 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4508,10 +4508,30 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4508 if (item_node->type == NodeTypeSwitchRange) {4508 if (item_node->type == NodeTypeSwitchRange) {
4509 zig_panic("TODO range in switch statement");4509 zig_panic("TODO range in switch statement");
4510 }4510 }
4511 analyze_expression(g, import, context, expr_type, item_node);4511
4512 ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val;4512 if (expr_type->id == TypeTableEntryIdEnum) {
4513 if (!const_val->ok) {4513 if (item_node->type == NodeTypeSymbol) {
4514 add_node_error(g, item_node, buf_sprintf("unable to resolve constant expression"));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 var_type = expr_type;4537 var_type = expr_type;
src/codegen.cpp+8-13
...@@ -2357,21 +2357,16 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {...@@ -2357,21 +2357,16 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
2357 for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {2357 for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
2358 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);2358 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
2359 assert(item_node->type != NodeTypeSwitchRange);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 LLVMValueRef val;2360 LLVMValueRef val;
2363 if (handle_is_ptr(target_type)) {2361 if (target_type->id == TypeTableEntryIdEnum) {
2364 if (target_type->id == TypeTableEntryIdEnum) {2362 assert(item_node->type == NodeTypeSymbol);
2365 ConstExprValue *item_const_val = &get_resolved_expr(item_node)->const_val;2363 TypeEnumField *enum_field = item_node->data.symbol_expr.enum_field;
2366 assert(item_const_val->ok);2364 assert(enum_field);
2367 assert(get_expr_type(item_node)->id == TypeTableEntryIdEnum);2365 val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref,
2368 val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref,2366 enum_field->value, false);
2369 item_const_val->data.x_enum.tag, false);
2370 } else {
2371 zig_unreachable();
2372 }
2373 } else {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 LLVMAddCase(switch_instr, val, prong_block);2371 LLVMAddCase(switch_instr, val, prong_block);
2377 }2372 }
test/run_tests.cpp-26
...@@ -1157,32 +1157,6 @@ fn fn3() -> u32 {7}...@@ -1157,32 +1157,6 @@ fn fn3() -> u32 {7}
1157fn fn4() -> u32 {8}1157fn fn4() -> u32 {8}
1158 )SOURCE", "5\n6\n7\n8\n");1158 )SOURCE", "5\n6\n7\n8\n");
11591159
1160 add_simple_case("switch statement", R"SOURCE(
1161import "std.zig";
1162
1163enum Foo {
1164 A,
1165 B,
1166 C,
1167 D,
1168}
1169
1170pub 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 add_simple_case("const number literal", R"SOURCE(1160 add_simple_case("const number literal", R"SOURCE(
1187import "std.zig";1161import "std.zig";
11881162
test/self_hosted.zig+26-8
...@@ -59,14 +59,14 @@ fn constant_enum_with_payload() {...@@ -59,14 +59,14 @@ fn constant_enum_with_payload() {
5959
60fn should_be_empty(x: AnEnumWithPayload) {60fn should_be_empty(x: AnEnumWithPayload) {
61 switch (x) {61 switch (x) {
62 AnEnumWithPayload.Empty => {},62 Empty => {},
63 else => unreachable{},63 else => unreachable{},
64 }64 }
65}65}
6666
67fn should_be_not_empty(x: AnEnumWithPayload) {67fn should_be_not_empty(x: AnEnumWithPayload) {
68 switch (x) {68 switch (x) {
69 AnEnumWithPayload.Empty => unreachable{},69 Empty => unreachable{},
70 else => {},70 else => {},
71 }71 }
72}72}
...@@ -111,9 +111,9 @@ fn non_const_cast_bool_to_int(t: bool, f: bool) {...@@ -111,9 +111,9 @@ fn non_const_cast_bool_to_int(t: bool, f: bool) {
111fn switch_on_enum() {111fn switch_on_enum() {
112 const fruit = Fruit.Orange;112 const fruit = Fruit.Orange;
113 switch (fruit) {113 switch (fruit) {
114 Fruit.Apple => unreachable{},114 Apple => unreachable{},
115 Fruit.Orange => {},115 Orange => {},
116 Fruit.Banana => unreachable{},116 Banana => unreachable{},
117 }117 }
118 non_const_switch_on_enum(fruit);118 non_const_switch_on_enum(fruit);
119}119}
...@@ -124,8 +124,26 @@ enum Fruit {...@@ -124,8 +124,26 @@ enum Fruit {
124}124}
125fn non_const_switch_on_enum(fruit: Fruit) {125fn non_const_switch_on_enum(fruit: Fruit) {
126 switch (fruit) {126 switch (fruit) {
127 Fruit.Apple => unreachable{},127 Apple => unreachable{},
128 Fruit.Orange => {},128 Orange => {},
129 Fruit.Banana => unreachable{},129 Banana => unreachable{},
130 }130 }
131}131}
132
133#attribute("test")
134fn 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}
144enum SwitchStatmentFoo {
145 A,
146 B,
147 C,
148 D,
149}