authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-19 17:15:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-19 17:15:55-07:00
log4e37fb2fa244e350b4e248332848d40594eee820
tree02de8b32d21a4b673484d69a1f7e223b48bdd523
parent9658c05fd406a13cade56b9c6e26d96764b965cc

implement constant initialization of enum values

see #5

3 files changed, 83 insertions(+), 9 deletions(-)

src/analyze.cpp+26-8
...@@ -2110,7 +2110,8 @@ static TypeEnumField *get_enum_field(TypeTableEntry *enum_type, Buf *name) {...@@ -2110,7 +2110,8 @@ static TypeEnumField *get_enum_field(TypeTableEntry *enum_type, Buf *name) {
2110}2110}
21112111
2112static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,2112static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2113 AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name)2113 AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name,
2114 AstNode *out_node)
2114{2115{
2115 assert(field_access_node->type == NodeTypeFieldAccessExpr);2116 assert(field_access_node->type == NodeTypeFieldAccessExpr);
21162117
...@@ -2119,15 +2120,32 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp...@@ -2119,15 +2120,32 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp
21192120
2120 if (type_enum_field) {2121 if (type_enum_field) {
2121 if (value_node) {2122 if (value_node) {
2122 analyze_expression(g, import, context, type_enum_field->type_entry, value_node);2123 AstNode **value_node_ptr = value_node->parent_field;
2124 TypeTableEntry *value_type = analyze_expression(g, import, context,
2125 type_enum_field->type_entry, value_node);
2126
2127 if (value_type->id == TypeTableEntryIdInvalid) {
2128 return g->builtin_types.entry_invalid;
2129 }
21232130
2124 StructValExprCodeGen *codegen = &field_access_node->data.field_access_expr.resolved_struct_val_expr;2131 StructValExprCodeGen *codegen = &field_access_node->data.field_access_expr.resolved_struct_val_expr;
2125 codegen->type_entry = enum_type;2132 codegen->type_entry = enum_type;
2126 codegen->source_node = field_access_node;2133 codegen->source_node = field_access_node;
2127 context->fn_entry->struct_val_expr_alloca_list.append(codegen);
21282134
2129 Expr *expr = get_resolved_expr(field_access_node);2135 ConstExprValue *value_const_val = &get_resolved_expr(*value_node_ptr)->const_val;
2130 expr->const_val.ok = false;2136 if (value_const_val->ok) {
2137 ConstExprValue *const_val = &get_resolved_expr(out_node)->const_val;
2138 const_val->ok = true;
2139 const_val->data.x_enum.tag = type_enum_field->value;
2140 const_val->data.x_enum.payload = value_const_val;
2141 } else {
2142 if (context->fn_entry) {
2143 context->fn_entry->struct_val_expr_alloca_list.append(codegen);
2144 } else {
2145 add_node_error(g, *value_node_ptr, buf_sprintf("unable to evaluate constant expression"));
2146 return g->builtin_types.entry_invalid;
2147 }
2148 }
2131 } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) {2149 } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) {
2132 add_node_error(g, field_access_node,2150 add_node_error(g, field_access_node,
2133 buf_sprintf("enum value '%s.%s' requires parameter of type '%s'",2151 buf_sprintf("enum value '%s.%s' requires parameter of type '%s'",
...@@ -2135,7 +2153,7 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp...@@ -2135,7 +2153,7 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp
2135 buf_ptr(field_name),2153 buf_ptr(field_name),
2136 buf_ptr(&type_enum_field->type_entry->name)));2154 buf_ptr(&type_enum_field->type_entry->name)));
2137 } else {2155 } else {
2138 Expr *expr = get_resolved_expr(field_access_node);2156 Expr *expr = get_resolved_expr(out_node);
2139 expr->const_val.ok = true;2157 expr->const_val.ok = true;
2140 expr->const_val.data.x_enum.tag = type_enum_field->value;2158 expr->const_val.data.x_enum.tag = type_enum_field->value;
2141 expr->const_val.data.x_enum.payload = nullptr;2159 expr->const_val.data.x_enum.payload = nullptr;
...@@ -2396,7 +2414,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i...@@ -2396,7 +2414,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
2396 } else if (wrapped_in_fn_call) {2414 } else if (wrapped_in_fn_call) {
2397 return resolve_expr_const_val_as_type(g, node, child_type);2415 return resolve_expr_const_val_as_type(g, node, child_type);
2398 } else if (child_type->id == TypeTableEntryIdEnum) {2416 } else if (child_type->id == TypeTableEntryIdEnum) {
2399 return analyze_enum_value_expr(g, import, context, node, nullptr, child_type, field_name);2417 return analyze_enum_value_expr(g, import, context, node, nullptr, child_type, field_name, node);
2400 } else if (child_type->id == TypeTableEntryIdStruct) {2418 } else if (child_type->id == TypeTableEntryIdStruct) {
2401 BlockContext *container_block_context = get_container_block_context(child_type);2419 BlockContext *container_block_context = get_container_block_context(child_type);
2402 auto entry = container_block_context->decl_table.maybe_get(field_name);2420 auto entry = container_block_context->decl_table.maybe_get(field_name);
...@@ -4725,7 +4743,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import...@@ -4725,7 +4743,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
4725 node->data.fn_call_expr.enum_type = child_type;4743 node->data.fn_call_expr.enum_type = child_type;
47264744
4727 return analyze_enum_value_expr(g, import, context, fn_ref_expr, value_node,4745 return analyze_enum_value_expr(g, import, context, fn_ref_expr, value_node,
4728 child_type, field_name);4746 child_type, field_name, node);
4729 }4747 }
4730 } else if (child_type->id == TypeTableEntryIdStruct) {4748 } else if (child_type->id == TypeTableEntryIdStruct) {
4731 Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name;4749 Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name;
src/codegen.cpp+17-1
...@@ -2937,7 +2937,23 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE...@@ -2937,7 +2937,23 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
2937 assert(enum_field->value == const_val->data.x_enum.tag);2937 assert(enum_field->value == const_val->data.x_enum.tag);
2938 LLVMValueRef union_value;2938 LLVMValueRef union_value;
2939 if (type_has_bits(enum_field->type_entry)) {2939 if (type_has_bits(enum_field->type_entry)) {
2940 union_value = gen_const_val(g, union_type, const_val->data.x_enum.payload);2940 uint64_t union_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
2941 union_type->type_ref);
2942 uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
2943 enum_field->type_entry->type_ref);
2944 uint64_t pad_bytes = union_type_bytes - field_type_bytes;
2945
2946 LLVMValueRef correctly_typed_value = gen_const_val(g, enum_field->type_entry,
2947 const_val->data.x_enum.payload);
2948 if (pad_bytes == 0) {
2949 union_value = correctly_typed_value;
2950 } else {
2951 LLVMValueRef fields[] = {
2952 correctly_typed_value,
2953 LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_bytes)),
2954 };
2955 union_value = LLVMConstStruct(fields, 2, false);
2956 }
2941 } else {2957 } else {
2942 union_value = LLVMGetUndef(union_type->type_ref);2958 union_value = LLVMGetUndef(union_type->type_ref);
2943 }2959 }
test/self_hosted.zig+40
...@@ -1204,3 +1204,43 @@ fn const_expression_eval_handling_of_variables() {...@@ -1204,3 +1204,43 @@ fn const_expression_eval_handling_of_variables() {
1204 x = false;1204 x = false;
1205 }1205 }
1206}1206}
1207
1208
1209
1210#attribute("test")
1211fn constant_enum_initialization_with_differing_sizes() {
1212 test3_1(test3_foo);
1213 test3_2(test3_bar);
1214}
1215enum Test3Foo {
1216 One,
1217 Two: f32,
1218 Three: Test3Point,
1219}
1220struct Test3Point {
1221 x: i32,
1222 y: i32,
1223}
1224const test3_foo = Test3Foo.Three(Test3Point {.x = 3, .y = 4});
1225const test3_bar = Test3Foo.Two(13);
1226#static_eval_enable(false)
1227fn test3_1(f: Test3Foo) {
1228 switch (f) {
1229 Three => |pt| {
1230 assert(pt.x == 3);
1231 assert(pt.y == 4);
1232 },
1233 else => unreachable{},
1234 }
1235}
1236#static_eval_enable(false)
1237fn test3_2(f: Test3Foo) {
1238 switch (f) {
1239 Two => |x| {
1240 assert(x == 13);
1241 },
1242 else => unreachable{},
1243 }
1244}
1245
1246