Commit 1f6dacbb2f

Andrew Kelley <superjoe30@gmail.com>
2016-12-20 07:50:32
IR: enum init support
1 parent c10ae86
src/all_types.hpp
@@ -848,6 +848,11 @@ struct TypeTableEntryEnum {
     bool complete;
 };
 
+struct TypeTableEntryEnumTag {
+    TypeTableEntry *enum_type;
+    TypeTableEntry *int_type;
+};
+
 struct TypeTableEntryUnion {
     AstNode *decl_node;
     bool is_extern;
@@ -914,6 +919,7 @@ enum TypeTableEntryId {
     TypeTableEntryIdErrorUnion,
     TypeTableEntryIdPureError,
     TypeTableEntryIdEnum,
+    TypeTableEntryIdEnumTag,
     TypeTableEntryIdUnion,
     TypeTableEntryIdFn,
     TypeTableEntryIdTypeDecl,
@@ -940,6 +946,7 @@ struct TypeTableEntry {
         TypeTableEntryMaybe maybe;
         TypeTableEntryError error;
         TypeTableEntryEnum enumeration;
+        TypeTableEntryEnumTag enum_tag;
         TypeTableEntryUnion unionation;
         TypeTableEntryFn fn;
         TypeTableEntryTypeDecl type_decl;
@@ -1452,6 +1459,7 @@ enum IrInstructionId {
     IrInstructionIdErrWrapPayload,
     IrInstructionIdFnProto,
     IrInstructionIdTestComptime,
+    IrInstructionIdInitEnum,
 };
 
 struct IrInstruction {
@@ -2078,6 +2086,15 @@ struct IrInstructionTestComptime {
     IrInstruction *value;
 };
 
+struct IrInstructionInitEnum {
+    IrInstruction base;
+
+    TypeTableEntry *enum_type;
+    TypeEnumField *field;
+    IrInstruction *init_value;
+    LLVMValueRef tmp_ptr;
+};
+
 enum LValPurpose {
     LValPurposeNone,
     LValPurposeAssign,
src/analyze.cpp
@@ -9,7 +9,6 @@
 #include "ast_render.hpp"
 #include "config.h"
 #include "error.hpp"
-#include "eval.hpp"
 #include "ir.hpp"
 #include "ir_print.hpp"
 #include "os.hpp"
@@ -252,6 +251,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
         case TypeTableEntryIdNamespace:
         case TypeTableEntryIdBlock:
         case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdEnumTag:
             return true;
     }
     zig_unreachable();
@@ -677,14 +677,8 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
     entry->type_ref = child_type->type_ref;
     entry->di_type = child_type->di_type;
     entry->zero_bits = child_type->zero_bits;
-
     entry->data.type_decl.child_type = child_type;
-
-    if (child_type->id == TypeTableEntryIdTypeDecl) {
-        entry->data.type_decl.canonical_type = child_type->data.type_decl.canonical_type;
-    } else {
-        entry->data.type_decl.canonical_type = child_type;
-    }
+    entry->data.type_decl.canonical_type = get_underlying_type(child_type);
 
     return entry;
 }
@@ -985,6 +979,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
             case TypeTableEntryIdUnion:
             case TypeTableEntryIdFn:
             case TypeTableEntryIdTypeDecl:
+            case TypeTableEntryIdEnumTag:
                 break;
         }
         FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
@@ -1033,12 +1028,28 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
         case TypeTableEntryIdUnion:
         case TypeTableEntryIdFn:
         case TypeTableEntryIdTypeDecl:
+        case TypeTableEntryIdEnumTag:
             break;
     }
 
     return get_fn_type(g, &fn_type_id);
 }
 
+static TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type) {
+    TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnumTag);
+
+    buf_resize(&entry->name, 0);
+    buf_appendf(&entry->name, "@enumTagType(%s)", buf_ptr(&enum_type->name));
+
+    entry->data.enum_tag.enum_type = enum_type;
+    entry->data.enum_tag.int_type = int_type;
+    entry->type_ref = int_type->type_ref;
+    entry->di_type = int_type->di_type;
+    entry->zero_bits = int_type->zero_bits;
+
+    return entry;
+}
+
 static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
     // if you change this logic you likely must also change similar logic in parseh.cpp
     assert(enum_type->id == TypeTableEntryIdEnum);
@@ -1134,7 +1145,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
         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);
+        TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
+        TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
         enum_type->data.enumeration.tag_type = tag_type_entry;
 
         if (biggest_union_member) {
@@ -1686,6 +1698,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
         case TypeTableEntryIdUnion:
         case TypeTableEntryIdFn:
         case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdEnumTag:
             return type_entry;
     }
     zig_unreachable();
@@ -1890,6 +1903,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
         case TypeTableEntryIdEnum:
         case TypeTableEntryIdUnion:
         case TypeTableEntryIdFn:
+        case TypeTableEntryIdEnumTag:
             return true;
 
         case TypeTableEntryIdTypeDecl:
@@ -2110,6 +2124,7 @@ static bool is_container(TypeTableEntry *type_entry) {
         case TypeTableEntryIdNamespace:
         case TypeTableEntryIdBlock:
         case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdEnumTag:
             return false;
     }
     zig_unreachable();
@@ -2159,6 +2174,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
         case TypeTableEntryIdBoundFn:
         case TypeTableEntryIdInvalid:
         case TypeTableEntryIdVar:
+        case TypeTableEntryIdEnumTag:
             zig_unreachable();
     }
 }
@@ -2509,6 +2525,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
         case TypeTableEntryIdPointer:
         case TypeTableEntryIdPureError:
         case TypeTableEntryIdFn:
+        case TypeTableEntryIdEnumTag:
              return false;
         case TypeTableEntryIdArray:
         case TypeTableEntryIdStruct:
@@ -2650,6 +2667,8 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
             return hash_ptr(const_val->data.x_import);
         case TypeTableEntryIdBlock:
             return hash_ptr(const_val->data.x_block);
+        case TypeTableEntryIdEnumTag:
+            return 983996406 + hash_const_val(type->data.enum_tag.int_type, const_val);
         case TypeTableEntryIdBoundFn:
         case TypeTableEntryIdInvalid:
         case TypeTableEntryIdUnreachable:
@@ -2794,16 +2813,18 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
         case TypeTableEntryIdInt:
         case TypeTableEntryIdFloat:
         case TypeTableEntryIdPointer:
+        case TypeTableEntryIdEnumTag:
             return type_entry;
     }
     zig_unreachable();
 }
 
 bool type_requires_comptime(TypeTableEntry *type_entry) {
-    switch (type_entry->id) {
+    switch (get_underlying_type(type_entry)->id) {
         case TypeTableEntryIdInvalid:
         case TypeTableEntryIdUnreachable:
         case TypeTableEntryIdVar:
+        case TypeTableEntryIdTypeDecl:
             zig_unreachable();
         case TypeTableEntryIdNumLitFloat:
         case TypeTableEntryIdNumLitInt:
@@ -2820,7 +2841,6 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
         case TypeTableEntryIdUnion:
         case TypeTableEntryIdMaybe:
         case TypeTableEntryIdErrorUnion:
-        case TypeTableEntryIdTypeDecl:
         case TypeTableEntryIdEnum:
         case TypeTableEntryIdPureError:
         case TypeTableEntryIdFn:
@@ -2828,6 +2848,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
         case TypeTableEntryIdInt:
         case TypeTableEntryIdFloat:
         case TypeTableEntryIdPointer:
+        case TypeTableEntryIdEnumTag:
             return false;
     }
     zig_unreachable();
@@ -2933,3 +2954,154 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) {
     return var->is_comptime->static_value.data.x_bool;
 }
 
+bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) {
+    switch (type_entry->id) {
+        case TypeTableEntryIdEnum:
+            {
+                ConstEnumValue *enum1 = &a->data.x_enum;
+                ConstEnumValue *enum2 = &b->data.x_enum;
+                if (enum1->tag == enum2->tag) {
+                    TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag];
+                    if (type_has_bits(enum_field->type_entry)) {
+                        zig_panic("TODO const expr analyze enum special value for equality");
+                    } else {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        case TypeTableEntryIdMetaType:
+            return a->data.x_type == b->data.x_type;
+        case TypeTableEntryIdVoid:
+            return true;
+        case TypeTableEntryIdPureError:
+            return a->data.x_pure_err == b->data.x_pure_err;
+        case TypeTableEntryIdFn:
+            return a->data.x_fn == b->data.x_fn;
+        case TypeTableEntryIdBool:
+            return a->data.x_bool == b->data.x_bool;
+        case TypeTableEntryIdInt:
+        case TypeTableEntryIdFloat:
+        case TypeTableEntryIdNumLitFloat:
+        case TypeTableEntryIdNumLitInt:
+            return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
+        case TypeTableEntryIdEnumTag:
+            return const_values_equal(a, b, type_entry->data.enum_tag.int_type);
+        case TypeTableEntryIdPointer:
+            zig_panic("TODO");
+        case TypeTableEntryIdArray:
+            zig_panic("TODO");
+        case TypeTableEntryIdStruct:
+            zig_panic("TODO");
+        case TypeTableEntryIdUnion:
+            zig_panic("TODO");
+        case TypeTableEntryIdUndefLit:
+            zig_panic("TODO");
+        case TypeTableEntryIdNullLit:
+            zig_panic("TODO");
+        case TypeTableEntryIdMaybe:
+            zig_panic("TODO");
+        case TypeTableEntryIdErrorUnion:
+            zig_panic("TODO");
+        case TypeTableEntryIdTypeDecl:
+            zig_panic("TODO");
+        case TypeTableEntryIdNamespace:
+            zig_panic("TODO");
+        case TypeTableEntryIdBlock:
+            zig_panic("TODO");
+        case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdInvalid:
+        case TypeTableEntryIdUnreachable:
+        case TypeTableEntryIdVar:
+            zig_unreachable();
+    }
+    zig_unreachable();
+}
+
+static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
+    assert(int_type->id == TypeTableEntryIdInt);
+
+    for (size_t i = 0; i < CIntTypeCount; i += 1) {
+        if (int_type == g->builtin_types.entry_c_int[i]) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
+    assert(type_entry->id == TypeTableEntryIdInt);
+    if (type_entry->data.integral.bit_count == 64) {
+        return UINT64_MAX;
+    } else if (type_entry->data.integral.bit_count == 32) {
+        return UINT32_MAX;
+    } else if (type_entry->data.integral.bit_count == 16) {
+        return UINT16_MAX;
+    } else if (type_entry->data.integral.bit_count == 8) {
+        return UINT8_MAX;
+    } else {
+        zig_unreachable();
+    }
+}
+
+static int64_t max_signed_val(TypeTableEntry *type_entry) {
+    assert(type_entry->id == TypeTableEntryIdInt);
+    if (type_entry->data.integral.bit_count == 64) {
+        return INT64_MAX;
+    } else if (type_entry->data.integral.bit_count == 32) {
+        return INT32_MAX;
+    } else if (type_entry->data.integral.bit_count == 16) {
+        return INT16_MAX;
+    } else if (type_entry->data.integral.bit_count == 8) {
+        return INT8_MAX;
+    } else {
+        zig_unreachable();
+    }
+}
+
+static int64_t min_signed_val(TypeTableEntry *type_entry) {
+    assert(type_entry->id == TypeTableEntryIdInt);
+    if (type_entry->data.integral.bit_count == 64) {
+        return INT64_MIN;
+    } else if (type_entry->data.integral.bit_count == 32) {
+        return INT32_MIN;
+    } else if (type_entry->data.integral.bit_count == 16) {
+        return INT16_MIN;
+    } else if (type_entry->data.integral.bit_count == 8) {
+        return INT8_MIN;
+    } else {
+        zig_unreachable();
+    }
+}
+
+void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) {
+    if (type_entry->id == TypeTableEntryIdInt) {
+        const_val->special = ConstValSpecialStatic;
+        const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
+        if (is_max) {
+            if (type_entry->data.integral.is_signed) {
+                int64_t val = max_signed_val(type_entry);
+                bignum_init_signed(&const_val->data.x_bignum, val);
+            } else {
+                uint64_t val = max_unsigned_val(type_entry);
+                bignum_init_unsigned(&const_val->data.x_bignum, val);
+            }
+        } else {
+            if (type_entry->data.integral.is_signed) {
+                int64_t val = min_signed_val(type_entry);
+                bignum_init_signed(&const_val->data.x_bignum, val);
+            } else {
+                bignum_init_unsigned(&const_val->data.x_bignum, 0);
+            }
+        }
+    } else if (type_entry->id == TypeTableEntryIdFloat) {
+        zig_panic("TODO analyze_min_max_value float");
+    } else if (type_entry->id == TypeTableEntryIdBool) {
+        const_val->special = ConstValSpecialStatic;
+        const_val->data.x_bool = is_max;
+    } else if (type_entry->id == TypeTableEntryIdVoid) {
+        // nothing to do
+    } else {
+        zig_unreachable();
+    }
+}
src/analyze.hpp
@@ -77,6 +77,8 @@ bool type_requires_comptime(TypeTableEntry *type_entry);
 void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry);
 void complete_enum(CodeGen *g, TypeTableEntry *enum_type);
 bool ir_get_var_is_comptime(VariableTableEntry *var);
+bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry);
+void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
 
 ScopeBlock *create_block_scope(AstNode *node, Scope *parent);
 ScopeDefer *create_defer_scope(AstNode *node, Scope *parent);
src/codegen.cpp
@@ -2144,6 +2144,10 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI
     return get_handle_value(g, tag_field_ptr, tag_type);
 }
 
+static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {
+    zig_panic("TODO ir_render_init_enum");
+}
+
 static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
     AstNode *source_node = instruction->source_node;
     Scope *scope = instruction->scope;
@@ -2278,6 +2282,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
         case IrInstructionIdEnumTag:
             return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction);
+        case IrInstructionIdInitEnum:
+            return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
         case IrInstructionIdSwitchVar:
             zig_panic("TODO render switch var instruction to LLVM");
         case IrInstructionIdContainerInitList:
@@ -2497,6 +2503,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
             }
         case TypeTableEntryIdVoid:
             return nullptr;
+        case TypeTableEntryIdEnumTag:
+            return gen_const_val(g, type_entry->data.enum_tag.int_type, const_val);
         case TypeTableEntryIdInvalid:
         case TypeTableEntryIdMetaType:
         case TypeTableEntryIdUnreachable:
@@ -2876,6 +2884,9 @@ static void do_code_gen(CodeGen *g) {
             } else if (instruction->id == IrInstructionIdErrWrapCode) {
                 IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
                 slot = &err_wrap_code_instruction->tmp_ptr;
+            } else if (instruction->id == IrInstructionIdInitEnum) {
+                IrInstructionInitEnum *init_enum_instruction = (IrInstructionInitEnum *)instruction;
+                slot = &init_enum_instruction->tmp_ptr;
             } else {
                 zig_unreachable();
             }
@@ -3793,7 +3804,8 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
         case TypeTableEntryIdUnion:
         case TypeTableEntryIdFn:
         case TypeTableEntryIdTypeDecl:
-            zig_panic("TODO");
+        case TypeTableEntryIdEnumTag:
+            zig_panic("TODO implement get_c_type for more types");
         case TypeTableEntryIdInvalid:
         case TypeTableEntryIdMetaType:
         case TypeTableEntryIdBoundFn:
src/eval.cpp
@@ -1,429 +0,0 @@
-/*
- * Copyright (c) 2016 Andrew Kelley
- *
- * This file is part of zig, which is MIT licensed.
- * See http://opensource.org/licenses/MIT
- */
-
-#include "eval.hpp"
-#include "analyze.hpp"
-#include "error.hpp"
-
-bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) {
-    switch (type_entry->id) {
-        case TypeTableEntryIdEnum:
-            {
-                ConstEnumValue *enum1 = &a->data.x_enum;
-                ConstEnumValue *enum2 = &b->data.x_enum;
-                if (enum1->tag == enum2->tag) {
-                    TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag];
-                    if (type_has_bits(enum_field->type_entry)) {
-                        zig_panic("TODO const expr analyze enum special value for equality");
-                    } else {
-                        return true;
-                    }
-                }
-                return false;
-            }
-        case TypeTableEntryIdMetaType:
-            return a->data.x_type == b->data.x_type;
-        case TypeTableEntryIdVoid:
-            return true;
-        case TypeTableEntryIdPureError:
-            return a->data.x_pure_err == b->data.x_pure_err;
-        case TypeTableEntryIdFn:
-            return a->data.x_fn == b->data.x_fn;
-        case TypeTableEntryIdBool:
-            return a->data.x_bool == b->data.x_bool;
-        case TypeTableEntryIdInt:
-        case TypeTableEntryIdFloat:
-        case TypeTableEntryIdNumLitFloat:
-        case TypeTableEntryIdNumLitInt:
-            return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
-        case TypeTableEntryIdPointer:
-            zig_panic("TODO");
-        case TypeTableEntryIdArray:
-            zig_panic("TODO");
-        case TypeTableEntryIdStruct:
-            zig_panic("TODO");
-        case TypeTableEntryIdUnion:
-            zig_panic("TODO");
-        case TypeTableEntryIdUndefLit:
-            zig_panic("TODO");
-        case TypeTableEntryIdNullLit:
-            zig_panic("TODO");
-        case TypeTableEntryIdMaybe:
-            zig_panic("TODO");
-        case TypeTableEntryIdErrorUnion:
-            zig_panic("TODO");
-        case TypeTableEntryIdTypeDecl:
-            zig_panic("TODO");
-        case TypeTableEntryIdNamespace:
-            zig_panic("TODO");
-        case TypeTableEntryIdBlock:
-            zig_panic("TODO");
-        case TypeTableEntryIdBoundFn:
-        case TypeTableEntryIdInvalid:
-        case TypeTableEntryIdUnreachable:
-        case TypeTableEntryIdVar:
-            zig_unreachable();
-    }
-    zig_unreachable();
-}
-
-
-static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
-    if (bin_op == BinOpTypeBoolOr || bin_op == BinOpTypeAssignBoolOr) {
-        return a || b;
-    } else if (bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeAssignBoolAnd) {
-        return a && b;
-    } else {
-        zig_unreachable();
-    }
-}
-
-static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
-    assert(type_entry->id == TypeTableEntryIdInt);
-    if (type_entry->data.integral.bit_count == 64) {
-        return UINT64_MAX;
-    } else if (type_entry->data.integral.bit_count == 32) {
-        return UINT32_MAX;
-    } else if (type_entry->data.integral.bit_count == 16) {
-        return UINT16_MAX;
-    } else if (type_entry->data.integral.bit_count == 8) {
-        return UINT8_MAX;
-    } else {
-        zig_unreachable();
-    }
-}
-
-static int64_t max_signed_val(TypeTableEntry *type_entry) {
-    assert(type_entry->id == TypeTableEntryIdInt);
-    if (type_entry->data.integral.bit_count == 64) {
-        return INT64_MAX;
-    } else if (type_entry->data.integral.bit_count == 32) {
-        return INT32_MAX;
-    } else if (type_entry->data.integral.bit_count == 16) {
-        return INT16_MAX;
-    } else if (type_entry->data.integral.bit_count == 8) {
-        return INT8_MAX;
-    } else {
-        zig_unreachable();
-    }
-}
-
-static int64_t min_signed_val(TypeTableEntry *type_entry) {
-    assert(type_entry->id == TypeTableEntryIdInt);
-    if (type_entry->data.integral.bit_count == 64) {
-        return INT64_MIN;
-    } else if (type_entry->data.integral.bit_count == 32) {
-        return INT32_MIN;
-    } else if (type_entry->data.integral.bit_count == 16) {
-        return INT16_MIN;
-    } else if (type_entry->data.integral.bit_count == 8) {
-        return INT8_MIN;
-    } else {
-        zig_unreachable();
-    }
-}
-
-static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
-        ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *),
-        TypeTableEntry *type, bool wrapping_op)
-{
-    bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
-    if (overflow) {
-        return ErrorOverflow;
-    }
-
-    if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum,
-                type->data.integral.bit_count, type->data.integral.is_signed))
-    {
-        if (wrapping_op) {
-            if (type->data.integral.is_signed) {
-                out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
-                out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative;
-            } else if (out_val->data.x_bignum.is_negative) {
-                out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
-                out_val->data.x_bignum.is_negative = false;
-            } else {
-                bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count);
-            }
-        } else {
-            return ErrorOverflow;
-        }
-    }
-
-    out_val->special = ConstValSpecialStatic;
-    out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
-    return 0;
-}
-
-int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
-        BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)
-{
-    assert(op1_val->special != ConstValSpecialRuntime);
-    assert(op2_val->special != ConstValSpecialRuntime);
-    assert(op1_type->id != TypeTableEntryIdInvalid);
-    assert(op2_type->id != TypeTableEntryIdInvalid);
-
-    switch (bin_op) {
-        case BinOpTypeAssign:
-            *out_val = *op2_val;
-            return 0;
-        case BinOpTypeBoolOr:
-        case BinOpTypeBoolAnd:
-        case BinOpTypeAssignBoolAnd:
-        case BinOpTypeAssignBoolOr:
-            assert(op1_type->id == TypeTableEntryIdBool);
-            assert(op2_type->id == TypeTableEntryIdBool);
-            out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool);
-            out_val->special = ConstValSpecialStatic;
-            out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
-            return 0;
-        case BinOpTypeCmpEq:
-        case BinOpTypeCmpNotEq:
-        case BinOpTypeCmpLessThan:
-        case BinOpTypeCmpGreaterThan:
-        case BinOpTypeCmpLessOrEq:
-        case BinOpTypeCmpGreaterOrEq:
-            {
-                bool type_can_gt_lt_cmp = (op1_type->id == TypeTableEntryIdNumLitFloat ||
-                        op1_type->id == TypeTableEntryIdNumLitInt ||
-                        op1_type->id == TypeTableEntryIdFloat ||
-                        op1_type->id == TypeTableEntryIdInt);
-                bool answer;
-                if (type_can_gt_lt_cmp) {
-                    bool (*bignum_cmp)(BigNum *, BigNum *);
-                    if (bin_op == BinOpTypeCmpEq) {
-                        bignum_cmp = bignum_cmp_eq;
-                    } else if (bin_op == BinOpTypeCmpNotEq) {
-                        bignum_cmp = bignum_cmp_neq;
-                    } else if (bin_op == BinOpTypeCmpLessThan) {
-                        bignum_cmp = bignum_cmp_lt;
-                    } else if (bin_op == BinOpTypeCmpGreaterThan) {
-                        bignum_cmp = bignum_cmp_gt;
-                    } else if (bin_op == BinOpTypeCmpLessOrEq) {
-                        bignum_cmp = bignum_cmp_lte;
-                    } else if (bin_op == BinOpTypeCmpGreaterOrEq) {
-                        bignum_cmp = bignum_cmp_gte;
-                    } else {
-                        zig_unreachable();
-                    }
-
-                    answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum);
-                } else {
-                    bool are_equal = const_values_equal(op1_val, op2_val, op1_type);
-                    if (bin_op == BinOpTypeCmpEq) {
-                        answer = are_equal;
-                    } else if (bin_op == BinOpTypeCmpNotEq) {
-                        answer = !are_equal;
-                    } else {
-                        zig_unreachable();
-                    }
-                }
-
-                out_val->depends_on_compile_var =
-                    op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
-                out_val->data.x_bool = answer;
-                out_val->special = ConstValSpecialStatic;
-                return 0;
-            }
-        case BinOpTypeAdd:
-        case BinOpTypeAssignPlus:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false);
-        case BinOpTypeAddWrap:
-        case BinOpTypeAssignPlusWrap:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true);
-        case BinOpTypeBinOr:
-        case BinOpTypeAssignBitOr:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false);
-        case BinOpTypeBinXor:
-        case BinOpTypeAssignBitXor:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false);
-        case BinOpTypeBinAnd:
-        case BinOpTypeAssignBitAnd:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false);
-        case BinOpTypeBitShiftLeft:
-        case BinOpTypeAssignBitShiftLeft:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false);
-        case BinOpTypeBitShiftLeftWrap:
-        case BinOpTypeAssignBitShiftLeftWrap:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true);
-        case BinOpTypeBitShiftRight:
-        case BinOpTypeAssignBitShiftRight:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false);
-        case BinOpTypeSub:
-        case BinOpTypeAssignMinus:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false);
-        case BinOpTypeSubWrap:
-        case BinOpTypeAssignMinusWrap:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true);
-        case BinOpTypeMult:
-        case BinOpTypeAssignTimes:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false);
-        case BinOpTypeMultWrap:
-        case BinOpTypeAssignTimesWrap:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true);
-        case BinOpTypeDiv:
-        case BinOpTypeAssignDiv:
-            {
-                bool is_int = false;
-                bool is_float = false;
-                if (op1_type->id == TypeTableEntryIdInt ||
-                    op1_type->id == TypeTableEntryIdNumLitInt)
-                {
-                    is_int = true;
-                } else if (op1_type->id == TypeTableEntryIdFloat ||
-                           op1_type->id == TypeTableEntryIdNumLitFloat)
-                {
-                    is_float = true;
-                }
-                if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) ||
-                    (is_float && op2_val->data.x_bignum.data.x_float == 0.0))
-                {
-                    return ErrorDivByZero;
-                } else {
-                    return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false);
-                }
-            }
-        case BinOpTypeMod:
-        case BinOpTypeAssignMod:
-            return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false);
-        case BinOpTypeUnwrapMaybe:
-            zig_panic("TODO");
-        case BinOpTypeArrayCat:
-        case BinOpTypeArrayMult:
-        case BinOpTypeInvalid:
-            zig_unreachable();
-    }
-    zig_unreachable();
-}
-
-void eval_const_expr_implicit_cast(CastOp cast_op,
-        ConstExprValue *other_val, TypeTableEntry *other_type,
-        ConstExprValue *const_val, TypeTableEntry *new_type)
-{
-    const_val->depends_on_compile_var = other_val->depends_on_compile_var;
-    const_val->special = other_val->special;
-
-    assert(other_val != const_val);
-    switch (cast_op) {
-        case CastOpNoCast:
-            zig_unreachable();
-        case CastOpNoop:
-        case CastOpWidenOrShorten:
-            *const_val = *other_val;
-            break;
-        case CastOpPointerReinterpret:
-            zig_panic("TODO compile time pointer reinterpret");
-            break;
-        case CastOpPtrToInt:
-        case CastOpIntToPtr:
-        case CastOpResizeSlice:
-        case CastOpBytesToSlice:
-            // can't do it
-            break;
-        case CastOpToUnknownSizeArray:
-            {
-                assert(other_type->id == TypeTableEntryIdArray);
-                assert(other_val->data.x_array.size == other_type->data.array.len);
-
-                const_val->data.x_struct.fields = allocate<ConstExprValue>(2);
-                ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index];
-                ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index];
-
-                ptr_field->special = ConstValSpecialStatic;
-                ptr_field->data.x_ptr.base_ptr = other_val;
-
-                len_field->special = ConstValSpecialStatic;
-                bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len);
-
-                const_val->special = ConstValSpecialStatic;
-                break;
-            }
-        case CastOpErrToInt:
-            {
-                uint64_t value;
-                if (other_type->id == TypeTableEntryIdErrorUnion) {
-                    value = other_val->data.x_err_union.err ? other_val->data.x_err_union.err->value : 0;
-                } else if (other_type->id == TypeTableEntryIdPureError) {
-                    value = other_val->data.x_pure_err->value;
-                } else {
-                    zig_unreachable();
-                }
-                bignum_init_unsigned(&const_val->data.x_bignum, value);
-                const_val->special = ConstValSpecialStatic;
-                break;
-            }
-        case CastOpIntToFloat:
-            bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum);
-            const_val->special = ConstValSpecialStatic;
-            break;
-        case CastOpFloatToInt:
-            bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum);
-            const_val->special = ConstValSpecialStatic;
-            break;
-        case CastOpBoolToInt:
-            bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0);
-            const_val->special = ConstValSpecialStatic;
-            break;
-        case CastOpIntToEnum:
-            {
-                uint64_t value = other_val->data.x_bignum.data.x_uint;
-                assert(new_type->id == TypeTableEntryIdEnum);
-                assert(value < new_type->data.enumeration.src_field_count);
-                const_val->data.x_enum.tag = value;
-                const_val->data.x_enum.payload = NULL;
-                const_val->special = ConstValSpecialStatic;
-                break;
-            }
-        case CastOpEnumToInt:
-            bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag);
-            const_val->special = ConstValSpecialStatic;
-            break;
-    }
-}
-
-static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
-    assert(int_type->id == TypeTableEntryIdInt);
-
-    for (size_t i = 0; i < CIntTypeCount; i += 1) {
-        if (int_type == g->builtin_types.entry_c_int[i]) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) {
-    if (type_entry->id == TypeTableEntryIdInt) {
-        const_val->special = ConstValSpecialStatic;
-        const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
-        if (is_max) {
-            if (type_entry->data.integral.is_signed) {
-                int64_t val = max_signed_val(type_entry);
-                bignum_init_signed(&const_val->data.x_bignum, val);
-            } else {
-                uint64_t val = max_unsigned_val(type_entry);
-                bignum_init_unsigned(&const_val->data.x_bignum, val);
-            }
-        } else {
-            if (type_entry->data.integral.is_signed) {
-                int64_t val = min_signed_val(type_entry);
-                bignum_init_signed(&const_val->data.x_bignum, val);
-            } else {
-                bignum_init_unsigned(&const_val->data.x_bignum, 0);
-            }
-        }
-    } else if (type_entry->id == TypeTableEntryIdFloat) {
-        zig_panic("TODO analyze_min_max_value float");
-    } else if (type_entry->id == TypeTableEntryIdBool) {
-        const_val->special = ConstValSpecialStatic;
-        const_val->data.x_bool = is_max;
-    } else if (type_entry->id == TypeTableEntryIdVoid) {
-        // nothing to do
-    } else {
-        zig_unreachable();
-    }
-}
src/eval.hpp
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2016 Andrew Kelley
- *
- * This file is part of zig, which is MIT licensed.
- * See http://opensource.org/licenses/MIT
- */
-
-#ifndef ZIG_EVAL_HPP
-#define ZIG_EVAL_HPP
-
-#include "all_types.hpp"
-
-bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry);
-int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
-        BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val);
-
-void eval_const_expr_implicit_cast(CastOp cast_op,
-        ConstExprValue *other_val, TypeTableEntry *other_type,
-        ConstExprValue *const_val, TypeTableEntry *new_type);
-
-void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
-
-#endif
src/ir.cpp
@@ -8,7 +8,6 @@
 #include "analyze.hpp"
 #include "ast_render.hpp"
 #include "error.hpp"
-#include "eval.hpp"
 #include "ir.hpp"
 #include "ir_print.hpp"
 #include "os.hpp"
@@ -447,6 +446,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *)
     return IrInstructionIdTestComptime;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) {
+    return IrInstructionIdInitEnum;
+}
+
 template<typename T>
 static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(1);
@@ -1861,6 +1864,28 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo
     return &instruction->base;
 }
 
+static IrInstruction *ir_build_init_enum(IrBuilder *irb, Scope *scope, AstNode *source_node,
+        TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value)
+{
+    IrInstructionInitEnum *instruction = ir_build_instruction<IrInstructionInitEnum>(irb, scope, source_node);
+    instruction->enum_type = enum_type;
+    instruction->field = field;
+    instruction->init_value = init_value;
+
+    ir_ref_instruction(init_value);
+
+    return &instruction->base;
+}
+
+static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old_instruction,
+    TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value)
+{
+    IrInstruction *new_instruction = ir_build_init_enum(irb, old_instruction->scope, old_instruction->source_node,
+            enum_type, field, init_value);
+    ir_link_new_instruction(new_instruction, old_instruction);
+    return new_instruction;
+}
+
 static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
     results[ReturnKindUnconditional] = 0;
     results[ReturnKindError] = 0;
@@ -4596,6 +4621,90 @@ static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableE
     }
 }
 
+static void eval_const_expr_implicit_cast(CastOp cast_op,
+        ConstExprValue *other_val, TypeTableEntry *other_type,
+        ConstExprValue *const_val, TypeTableEntry *new_type)
+{
+    const_val->depends_on_compile_var = other_val->depends_on_compile_var;
+    const_val->special = other_val->special;
+
+    assert(other_val != const_val);
+    switch (cast_op) {
+        case CastOpNoCast:
+            zig_unreachable();
+        case CastOpNoop:
+        case CastOpWidenOrShorten:
+            *const_val = *other_val;
+            break;
+        case CastOpPointerReinterpret:
+            zig_panic("TODO compile time pointer reinterpret");
+            break;
+        case CastOpPtrToInt:
+        case CastOpIntToPtr:
+        case CastOpResizeSlice:
+        case CastOpBytesToSlice:
+            // can't do it
+            break;
+        case CastOpToUnknownSizeArray:
+            {
+                assert(other_type->id == TypeTableEntryIdArray);
+                assert(other_val->data.x_array.size == other_type->data.array.len);
+
+                const_val->data.x_struct.fields = allocate<ConstExprValue>(2);
+                ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index];
+                ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index];
+
+                ptr_field->special = ConstValSpecialStatic;
+                ptr_field->data.x_ptr.base_ptr = other_val;
+
+                len_field->special = ConstValSpecialStatic;
+                bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len);
+
+                const_val->special = ConstValSpecialStatic;
+                break;
+            }
+        case CastOpErrToInt:
+            {
+                uint64_t value;
+                if (other_type->id == TypeTableEntryIdErrorUnion) {
+                    value = other_val->data.x_err_union.err ? other_val->data.x_err_union.err->value : 0;
+                } else if (other_type->id == TypeTableEntryIdPureError) {
+                    value = other_val->data.x_pure_err->value;
+                } else {
+                    zig_unreachable();
+                }
+                bignum_init_unsigned(&const_val->data.x_bignum, value);
+                const_val->special = ConstValSpecialStatic;
+                break;
+            }
+        case CastOpIntToFloat:
+            bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum);
+            const_val->special = ConstValSpecialStatic;
+            break;
+        case CastOpFloatToInt:
+            bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum);
+            const_val->special = ConstValSpecialStatic;
+            break;
+        case CastOpBoolToInt:
+            bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0);
+            const_val->special = ConstValSpecialStatic;
+            break;
+        case CastOpIntToEnum:
+            {
+                uint64_t value = other_val->data.x_bignum.data.x_uint;
+                assert(new_type->id == TypeTableEntryIdEnum);
+                assert(value < new_type->data.enumeration.src_field_count);
+                const_val->data.x_enum.tag = value;
+                const_val->data.x_enum.payload = NULL;
+                const_val->special = ConstValSpecialStatic;
+                break;
+            }
+        case CastOpEnumToInt:
+            bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag);
+            const_val->special = ConstValSpecialStatic;
+            break;
+    }
+}
 static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
         TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)
 {
@@ -5562,6 +5671,9 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
                 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
             return ira->codegen->builtin_types.entry_invalid;
 
+        case TypeTableEntryIdEnumTag:
+            zig_panic("TODO implement comparison for enum tag type");
+
         case TypeTableEntryIdVar:
             zig_unreachable();
     }
@@ -6074,6 +6186,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
         case TypeTableEntryIdUnion:
         case TypeTableEntryIdFn:
         case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdEnumTag:
             // OK
             break;
     }
@@ -6517,6 +6630,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
         case TypeTableEntryIdUnion:
         case TypeTableEntryIdFn:
         case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdEnumTag:
             {
                 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
                         value->static_value.depends_on_compile_var);
@@ -6603,6 +6717,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
         case TypeTableEntryIdNamespace:
         case TypeTableEntryIdBlock:
         case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdEnumTag:
             {
                 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
                         value->static_value.depends_on_compile_var);
@@ -7175,7 +7290,11 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
                                 create_const_enum_tag(field->value), child_type, depends_on_compile_var,
                                 ConstPtrSpecialNone, ptr_is_const);
                     } else {
-                        zig_panic("TODO enum tag type");
+                        bool ptr_is_const = true;
+                        return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+                                create_const_unsigned_negative(field->value, false),
+                                child_type->data.enumeration.tag_type, depends_on_compile_var,
+                                ConstPtrSpecialNone, ptr_is_const);
                     }
                 }
             }
@@ -7377,6 +7496,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
         case TypeTableEntryIdUnion:
         case TypeTableEntryIdFn:
         case TypeTableEntryIdTypeDecl:
+        case TypeTableEntryIdEnumTag:
             {
                 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false);
                 // TODO depends_on_compile_var should be set based on whether the type of the expression
@@ -7596,6 +7716,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
         case TypeTableEntryIdFn:
         case TypeTableEntryIdNamespace:
         case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdEnumTag:
             {
                 TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const);
                 ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base,
@@ -7685,6 +7806,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
         case TypeTableEntryIdFn:
         case TypeTableEntryIdNamespace:
         case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdEnumTag:
             {
                 TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size);
                 bool depends_on_compile_var = child_type_value->static_value.depends_on_compile_var ||
@@ -7774,6 +7896,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
         case TypeTableEntryIdPureError:
         case TypeTableEntryIdEnum:
         case TypeTableEntryIdUnion:
+        case TypeTableEntryIdEnumTag:
             {
                 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
                 bool depends_on_compile_var = false; // TODO types should be able to depend on compile var
@@ -8089,6 +8212,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
         case TypeTableEntryIdErrorUnion:
             // see https://github.com/andrewrk/zig/issues/83
             zig_panic("TODO switch on error union");
+        case TypeTableEntryIdEnumTag:
+            zig_panic("TODO switch on enum tag type");
         case TypeTableEntryIdUnreachable:
         case TypeTableEntryIdArray:
         case TypeTableEntryIdStruct:
@@ -8347,86 +8472,133 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
 
 static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) {
     IrInstruction *container_type_value = instruction->container_type->other;
-    TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
-    if (container_type->id == TypeTableEntryIdInvalid)
+    if (container_type_value->type_entry->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     size_t elem_count = instruction->item_count;
-    bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;
+    if (container_type_value->type_entry->id == TypeTableEntryIdMetaType) {
+        TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
+        if (container_type->id == TypeTableEntryIdInvalid)
+            return ira->codegen->builtin_types.entry_invalid;
 
-    if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) {
-        return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var);
-    } else if (is_slice(container_type)) {
-        TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
-        assert(pointer_type->id == TypeTableEntryIdPointer);
-        TypeTableEntry *child_type = pointer_type->data.pointer.child_type;
+        bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;
 
-        ConstExprValue const_val = {};
-        const_val.special = ConstValSpecialStatic;
-        const_val.depends_on_compile_var = depends_on_compile_var;
-        const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count);
-        const_val.data.x_array.size = elem_count;
+        if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) {
+            return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var);
+        } else if (is_slice(container_type)) {
+            TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
+            assert(pointer_type->id == TypeTableEntryIdPointer);
+            TypeTableEntry *child_type = pointer_type->data.pointer.child_type;
 
-        FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
-        bool outside_fn = (fn_entry == nullptr);
+            ConstExprValue const_val = {};
+            const_val.special = ConstValSpecialStatic;
+            const_val.depends_on_compile_var = depends_on_compile_var;
+            const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count);
+            const_val.data.x_array.size = elem_count;
 
-        IrInstruction **new_items = allocate<IrInstruction *>(elem_count);
+            FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
+            bool outside_fn = (fn_entry == nullptr);
 
-        IrInstruction *first_non_const_instruction = nullptr;
+            IrInstruction **new_items = allocate<IrInstruction *>(elem_count);
 
-        for (size_t i = 0; i < elem_count; i += 1) {
-            IrInstruction *arg_value = instruction->items[i]->other;
-            if (arg_value->type_entry->id == TypeTableEntryIdInvalid)
-                return ira->codegen->builtin_types.entry_invalid;
+            IrInstruction *first_non_const_instruction = nullptr;
 
-            new_items[i] = arg_value;
+            for (size_t i = 0; i < elem_count; i += 1) {
+                IrInstruction *arg_value = instruction->items[i]->other;
+                if (arg_value->type_entry->id == TypeTableEntryIdInvalid)
+                    return ira->codegen->builtin_types.entry_invalid;
 
-            if (const_val.special == ConstValSpecialStatic) {
-                if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) {
-                    ConstExprValue *elem_val = ir_resolve_const(ira, arg_value, UndefBad);
-                    if (!elem_val)
-                        return ira->codegen->builtin_types.entry_invalid;
+                new_items[i] = arg_value;
 
-                    const_val.data.x_array.elements[i] = *elem_val;
-                    const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var;
-                } else {
-                    first_non_const_instruction = arg_value;
-                    const_val.special = ConstValSpecialRuntime;
+                if (const_val.special == ConstValSpecialStatic) {
+                    if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) {
+                        ConstExprValue *elem_val = ir_resolve_const(ira, arg_value, UndefBad);
+                        if (!elem_val)
+                            return ira->codegen->builtin_types.entry_invalid;
+
+                        const_val.data.x_array.elements[i] = *elem_val;
+                        const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var;
+                    } else {
+                        first_non_const_instruction = arg_value;
+                        const_val.special = ConstValSpecialRuntime;
+                    }
                 }
             }
-        }
 
-        TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
-        if (const_val.special == ConstValSpecialStatic) {
-            ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var);
-            *out_val = const_val;
+            TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
+            if (const_val.special == ConstValSpecialStatic) {
+                ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var);
+                *out_val = const_val;
+                return fixed_size_array_type;
+            }
+
+            if (outside_fn) {
+                ir_add_error_node(ira, first_non_const_instruction->source_node,
+                    buf_sprintf("unable to evaluate constant expression"));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
+
+            IrInstruction *new_instruction = ir_build_container_init_list_from(&ira->new_irb, &instruction->base,
+                container_type_value, elem_count, new_items);
+            ir_add_alloca(ira, new_instruction, fixed_size_array_type);
             return fixed_size_array_type;
+        } else if (container_type->id == TypeTableEntryIdArray) {
+            // same as slice init but we make a compile error if the length is wrong
+            zig_panic("TODO array container init");
+        } else if (container_type->id == TypeTableEntryIdVoid) {
+            if (elem_count != 0) {
+                ir_add_error_node(ira, instruction->base.source_node,
+                    buf_sprintf("void expression expects no arguments"));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
+            return ir_analyze_void(ira, &instruction->base);
+        } else {
+            ir_add_error_node(ira, instruction->base.source_node,
+                buf_sprintf("type '%s' does not support array initialization",
+                    buf_ptr(&container_type->name)));
+            return ira->codegen->builtin_types.entry_invalid;
         }
-
-        if (outside_fn) {
-            ir_add_error_node(ira, first_non_const_instruction->source_node,
-                buf_sprintf("unable to evaluate constant expression"));
+    } else if (container_type_value->type_entry->id == TypeTableEntryIdEnumTag) {
+        // TODO I wrote this commit message when I had some sake
+        // might be worth re-examining sober
+        if (elem_count != 1) {
+            ir_add_error(ira, &instruction->base, buf_sprintf("expected 1 elment"));
             return ira->codegen->builtin_types.entry_invalid;
         }
+        ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad);
+        if (!tag_value)
+            return ira->codegen->builtin_types.entry_invalid;
 
-        IrInstruction *new_instruction = ir_build_container_init_list_from(&ira->new_irb, &instruction->base,
-            container_type_value, elem_count, new_items);
-        ir_add_alloca(ira, new_instruction, fixed_size_array_type);
-        return fixed_size_array_type;
-    } else if (container_type->id == TypeTableEntryIdArray) {
-        // same as slice init but we make a compile error if the length is wrong
-        zig_panic("TODO array container init");
-    } else if (container_type->id == TypeTableEntryIdVoid) {
-        if (elem_count != 0) {
-            ir_add_error_node(ira, instruction->base.source_node,
-                buf_sprintf("void expression expects no arguments"));
+        TypeTableEntry *enum_type = container_type_value->type_entry->data.enum_tag.enum_type;
+
+        uint64_t tag_uint = tag_value->data.x_bignum.data.x_uint;
+        TypeEnumField *field = &enum_type->data.enumeration.fields[tag_uint];
+        TypeTableEntry *this_field_type = field->type_entry;
+
+        IrInstruction *init_value = instruction->items[0]->other;
+
+        IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type);
+        if (casted_init_value == ira->codegen->invalid_instruction)
             return ira->codegen->builtin_types.entry_invalid;
+
+        if (instr_is_comptime(casted_init_value)) {
+            ConstExprValue *init_val = ir_resolve_const(ira, casted_init_value, UndefOk);
+            if (!init_val)
+                return ira->codegen->builtin_types.entry_invalid;
+            ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
+                    casted_init_value->static_value.depends_on_compile_var);
+            out_val->data.x_enum.tag = tag_uint;
+            out_val->data.x_enum.payload = init_val;
+            return enum_type;
         }
-        return ir_analyze_void(ira, &instruction->base);
+
+        IrInstruction *new_instruction = ir_build_init_enum_from(&ira->new_irb, &instruction->base,
+                enum_type, field, casted_init_value);
+        ir_add_alloca(ira, new_instruction, enum_type);
+        return enum_type;
     } else {
-        ir_add_error_node(ira, instruction->base.source_node,
-            buf_sprintf("type '%s' does not support array initialization",
-                buf_ptr(&container_type->name)));
+        ir_add_error(ira, container_type_value,
+            buf_sprintf("expected type, found '%s'", buf_ptr(&container_type_value->type_entry->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
 }
@@ -8471,6 +8643,8 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
                 eval_min_max_value(ira->codegen, canon_type, out_val, is_max);
                 return target_type;
             }
+        case TypeTableEntryIdEnumTag:
+            zig_panic("TODO min/max value for enum tag type");
         case TypeTableEntryIdVar:
         case TypeTableEntryIdMetaType:
         case TypeTableEntryIdUnreachable:
@@ -8984,55 +9158,17 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *child_type = ir_resolve_type(ira, type_value);
-    TypeTableEntry *canon_type = get_underlying_type(child_type);
 
-    if (count_value->static_value.special == ConstValSpecialStatic) {
-        // this should be the same as an array declaration
-
-        uint64_t count;
-        if (!ir_resolve_usize(ira, count_value, &count))
-            return ira->codegen->builtin_types.entry_invalid;
-
-        zig_panic("TODO alloca with compile time known count");
-    }
-
-    switch (canon_type->id) {
-        case TypeTableEntryIdInvalid:
-        case TypeTableEntryIdTypeDecl:
-            zig_unreachable();
-        case TypeTableEntryIdBool:
-        case TypeTableEntryIdVoid:
-        case TypeTableEntryIdInt:
-        case TypeTableEntryIdFloat:
-        case TypeTableEntryIdPointer:
-        case TypeTableEntryIdArray:
-        case TypeTableEntryIdStruct:
-        case TypeTableEntryIdMaybe:
-        case TypeTableEntryIdErrorUnion:
-        case TypeTableEntryIdPureError:
-        case TypeTableEntryIdEnum:
-        case TypeTableEntryIdUnion:
-        case TypeTableEntryIdFn:
-            {
-                TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false);
-                IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value);
-                ir_add_alloca(ira, new_instruction, slice_type);
-                return slice_type;
-            }
-        case TypeTableEntryIdVar:
-        case TypeTableEntryIdMetaType:
-        case TypeTableEntryIdUnreachable:
-        case TypeTableEntryIdNumLitFloat:
-        case TypeTableEntryIdNumLitInt:
-        case TypeTableEntryIdUndefLit:
-        case TypeTableEntryIdNullLit:
-        case TypeTableEntryIdNamespace:
-        case TypeTableEntryIdBlock:
-        case TypeTableEntryIdBoundFn:
-            ir_add_error(ira, type_value,
-                buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name)));
-            // TODO if this is a typedecl, add error note showing the declaration of the type decl
-            return ira->codegen->builtin_types.entry_invalid;
+    if (type_requires_comptime(child_type)) {
+        ir_add_error(ira, type_value,
+            buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name)));
+        // TODO if this is a typedecl, add error note showing the declaration of the type decl
+        return ira->codegen->builtin_types.entry_invalid;
+    } else {
+        TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false);
+        IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value);
+        ir_add_alloca(ira, new_instruction, slice_type);
+        return slice_type;
     }
     zig_unreachable();
 }
@@ -9804,6 +9940,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
         case IrInstructionIdStructFieldPtr:
         case IrInstructionIdEnumFieldPtr:
         case IrInstructionIdStructInit:
+        case IrInstructionIdInitEnum:
             zig_panic("TODO analyze more instructions");
     }
     zig_unreachable();
@@ -9959,6 +10096,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdErrWrapPayload:
         case IrInstructionIdFnProto:
         case IrInstructionIdTestComptime:
+        case IrInstructionIdInitEnum:
             return false;
         case IrInstructionIdAsm:
             {
src/ir_print.cpp
@@ -183,6 +183,13 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
                 fprintf(irp->f, "(pure error constant)");
                 return;
             }
+        case TypeTableEntryIdEnumTag:
+            {
+                TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type;
+                TypeEnumField *field = &enum_type->data.enumeration.fields[const_val->data.x_bignum.data.x_uint];
+                fprintf(irp->f, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
+                return;
+            }
     }
     zig_unreachable();
 }
@@ -911,6 +918,12 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
     fprintf(irp->f, ")");
 }
 
+static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) {
+    fprintf(irp->f, "%s.%s { ", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name));
+    ir_print_other_instruction(irp, instruction->init_value);
+    fprintf(irp->f, "{");
+}
+
 static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
     ir_print_prefix(irp, instruction);
     switch (instruction->id) {
@@ -1147,6 +1160,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdTestComptime:
             ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
             break;
+        case IrInstructionIdInitEnum:
+            ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction);
+            break;
     }
     fprintf(irp->f, "\n");
 }
test/cases3/enum.zig
@@ -0,0 +1,37 @@
+fn enumType() {
+    @setFnTest(this);
+
+    const foo1 = Foo.One {13};
+    const foo2 = Foo.Two { Point { .x = 1234, .y = 5678, }};
+    const bar = Bar.B;
+
+    assert(bar == Bar.B);
+    assert(@memberCount(Foo) == 3);
+    assert(@memberCount(Bar) == 4);
+    const expected_foo_size = 16 + @sizeOf(usize);
+    assert(@sizeOf(Foo) == expected_foo_size);
+    assert(@sizeOf(Bar) == 1);
+}
+const Point = struct {
+    x: u64,
+    y: u64,
+};
+const Foo = enum {
+    One: i32,
+    Two: Point,
+    Three: void,
+};
+const Bar = enum {
+    A,
+    B,
+    C,
+    D,
+};
+
+fn assert(ok: bool) {
+    if (!ok)
+        @unreachable();
+}
+
+
+
test/self_hosted.zig
@@ -333,41 +333,6 @@ fn maybeType() {
 }
 
 
-fn enumType() {
-    @setFnTest(this, true);
-
-    const foo1 = EnumTypeFoo.One {13};
-    const foo2 = EnumTypeFoo.Two {EnumType { .x = 1234, .y = 5678, }};
-    const bar = EnumTypeBar.B;
-
-    assert(bar == EnumTypeBar.B);
-    assert(@memberCount(EnumTypeFoo) == 3);
-    assert(@memberCount(EnumTypeBar) == 4);
-    const expected_foo_size = switch (@compileVar("arch")) {
-        i386 => 20,
-        x86_64 => 24,
-        else => @unreachable(),
-    };
-    assert(@sizeOf(EnumTypeFoo) == expected_foo_size);
-    assert(@sizeOf(EnumTypeBar) == 1);
-}
-struct EnumType {
-    x: u64,
-    y: u64,
-}
-enum EnumTypeFoo {
-    One: i32,
-    Two: EnumType,
-    Three: void,
-}
-enum EnumTypeBar {
-    A,
-    B,
-    C,
-    D,
-}
-
-
 fn arrayLiteral() {
     @setFnTest(this, true);
 
test/self_hosted3.zig
@@ -8,3 +8,4 @@ const test_for = @import("cases3/for.zig");
 const test_math = @import("cases3/math.zig");
 const test_generics = @import("cases3/generics.zig");
 const test_defer = @import("cases3/defer.zig");
+const test_enum = @import("cases3/enum.zig");
CMakeLists.txt
@@ -46,7 +46,6 @@ set(ZIG_SOURCES
     "${CMAKE_SOURCE_DIR}/src/codegen.cpp"
     "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
     "${CMAKE_SOURCE_DIR}/src/error.cpp"
-    "${CMAKE_SOURCE_DIR}/src/eval.cpp"
     "${CMAKE_SOURCE_DIR}/src/ir.cpp"
     "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
     "${CMAKE_SOURCE_DIR}/src/link.cpp"