From fdadab40c61a6f70a65472cc95ccd5ba52c01772 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 4 Feb 2016 02:11:50 -0700 Subject: [PATCH] implement constant values for enums with payload --- src/all_types.hpp | 1 + src/analyze.cpp | 4 ++++ src/codegen.cpp | 15 ++++++++++++++- test/self_hosted.zig | 28 ++++++++++++++++++++++++---- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 6613b6e68..6cf27163b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -859,6 +859,7 @@ struct TypeTableEntryEnum { TypeEnumField *fields; bool is_invalid; // true if any fields are invalid TypeTableEntry *tag_type; + TypeTableEntry *union_type; // reminder: hash tables must be initialized before use HashMap fn_table; diff --git a/src/analyze.cpp b/src/analyze.cpp index c0fc33ba0..5aad26cf3 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -973,6 +973,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt if (!enum_type->data.enumeration.is_invalid) { enum_type->data.enumeration.gen_field_count = gen_field_index; + enum_type->data.enumeration.union_type = biggest_union_member; TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count); enum_type->data.enumeration.tag_type = tag_type_entry; @@ -2034,6 +2035,9 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp codegen->type_entry = enum_type; codegen->source_node = field_access_node; context->struct_val_expr_alloca_list.append(codegen); + + Expr *expr = get_resolved_expr(field_access_node); + expr->const_val.ok = false; } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) { add_node_error(g, field_access_node, buf_sprintf("enum value '%s.%s' requires parameter of type '%s'", diff --git a/src/codegen.cpp b/src/codegen.cpp index a96fe9ba0..7dd91b6a6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2567,7 +2567,20 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE if (type_entry->data.enumeration.gen_field_count == 0) { return tag_value; } else { - zig_panic("TODO"); + TypeTableEntry *union_type = type_entry->data.enumeration.union_type; + TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag]; + assert(enum_field->value == const_val->data.x_enum.tag); + LLVMValueRef union_value; + if (type_has_bits(enum_field->type_entry)) { + union_value = gen_const_val(g, union_type, const_val->data.x_enum.payload); + } else { + union_value = LLVMGetUndef(union_type->type_ref); + } + LLVMValueRef fields[] = { + tag_value, + union_value, + }; + return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); } } case TypeTableEntryIdFn: diff --git a/test/self_hosted.zig b/test/self_hosted.zig index e6f9d8920..763689286 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -38,11 +38,31 @@ fn call_struct_field(foo: Foo) -> i32 { -error AnError; -error AnError; -error SecondError; - #attribute("test") fn redefinition_of_error_values_allowed() { if (error.AnError == error.SecondError) unreachable{} } +error AnError; +error AnError; +error SecondError; + + + + +#attribute("test") +fn constant_enum_with_payload() { + should_be_empty(AnEnumWithPayload.Empty); + should_be_13(AnEnumWithPayload.Full(13)); +} + +fn should_be_empty(x: AnEnumWithPayload) { + if (x != AnEnumWithPayload.Empty) unreachable{} +} + +fn should_be_13(x: AnEnumWithPayload) { +} + +enum AnEnumWithPayload { + Empty, + Full: i32, +}