Commit 581edd643f

Andrew Kelley <andrew@ziglang.org>
2019-01-30 03:47:26
backport copy elision changes
This commit contains everything from the copy-elision-2 branch that does not have to do with copy elision directly, but is generally useful for master branch. * All const values know their parents, when applicable, not just structs and unions. * Null pointers in const values are represented explicitly, rather than as a HardCodedAddr value of 0. * Rename "maybe" to "optional" in various code locations. * Separate DeclVarSrc and DeclVarGen * Separate PtrCastSrc and PtrCastGen * Separate CmpxchgSrc and CmpxchgGen * Represent optional error set as an integer, using the 0 value. In a const value, it uses nullptr. * Introduce type_has_one_possible_value and use it where applicable. * Fix debug builds not setting memory to 0xaa when storing undefined. * Separate the type of a variable from the const value of a variable. * Use copy_const_val where appropriate. * Rearrange structs to pack data more efficiently. * Move test/cases/* to test/behavior/* * Use `std.debug.assertOrPanic` in behavior tests instead of `std.debug.assert`. * Fix outdated slice syntax in docs.
1 parent 9c328b4
doc/langref.html.in
@@ -4327,7 +4327,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {
       <p>
       For example, if we were to introduce another function to the above snippet:
       </p>
-      {#code_begin|test_err|unable to evaluate constant expression#}
+      {#code_begin|test_err|values of type 'type' must be comptime known#}
 fn max(comptime T: type, a: T, b: T) T {
     return if (a > b) a else b;
 }
@@ -5905,13 +5905,13 @@ fn add(a: i32, b: i32) i32 { return a + b; }
       This function is a low level intrinsic with no safety mechanisms. Most code
       should not use this function, instead using something like this:
       </p>
-      <pre>{#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}</pre>
+      <pre>{#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}</pre>
       <p>
       The optimizer is intelligent enough to turn the above snippet into a memcpy.
       </p>
       <p>There is also a standard library function for this:</p>
       <pre>{#syntax#}const mem = @import("std").mem;
-mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre>
+mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre>
       {#header_close#}
 
       {#header_open|@memset#}
@@ -5923,7 +5923,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre>
       This function is a low level intrinsic with no safety mechanisms. Most
       code should not use this function, instead using something like this:
       </p>
-      <pre>{#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}</pre>
+      <pre>{#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}</pre>
       <p>
       The optimizer is intelligent enough to turn the above snippet into a memset.
       </p>
@@ -6592,9 +6592,10 @@ pub const TypeInfo = union(TypeId) {
       {#header_close#}
 
       {#header_open|@typeName#}
-      <pre>{#syntax#}@typeName(T: type) []u8{#endsyntax#}</pre>
+      <pre>{#syntax#}@typeName(T: type) [N]u8{#endsyntax#}</pre>
       <p>
-      This function returns the string representation of a type.
+      This function returns the string representation of a type, as
+      an array. It is equivalent to a string literal of the type name.
       </p>
 
       {#header_close#}
src/all_types.hpp
@@ -56,9 +56,6 @@ struct IrExecutable {
     size_t next_debug_id;
     size_t *backward_branch_count;
     size_t backward_branch_quota;
-    bool invalid;
-    bool is_inline;
-    bool is_generic_instantiation;
     ZigFn *fn_entry;
     Buf *c_import_buf;
     AstNode *source_node;
@@ -78,6 +75,10 @@ struct IrExecutable {
     IrBasicBlock *coro_suspend_block;
     IrBasicBlock *coro_final_cleanup_block;
     ZigVar *coro_allocator_var;
+
+    bool invalid;
+    bool is_inline;
+    bool is_generic_instantiation;
 };
 
 enum OutType {
@@ -90,6 +91,9 @@ enum OutType {
 enum ConstParentId {
     ConstParentIdNone,
     ConstParentIdStruct,
+    ConstParentIdErrUnionCode,
+    ConstParentIdErrUnionPayload,
+    ConstParentIdOptionalPayload,
     ConstParentIdArray,
     ConstParentIdUnion,
     ConstParentIdScalar,
@@ -107,6 +111,15 @@ struct ConstParent {
             ConstExprValue *struct_val;
             size_t field_index;
         } p_struct;
+        struct {
+            ConstExprValue *err_union_val;
+        } p_err_union_code;
+        struct {
+            ConstExprValue *err_union_val;
+        } p_err_union_payload;
+        struct {
+            ConstExprValue *optional_val;
+        } p_optional_payload;
         struct {
             ConstExprValue *union_val;
         } p_union;
@@ -118,13 +131,11 @@ struct ConstParent {
 
 struct ConstStructValue {
     ConstExprValue *fields;
-    ConstParent parent;
 };
 
 struct ConstUnionValue {
     BigInt tag;
     ConstExprValue *payload;
-    ConstParent parent;
 };
 
 enum ConstArraySpecial {
@@ -138,7 +149,6 @@ struct ConstArrayValue {
     union {
         struct {
             ConstExprValue *elements;
-            ConstParent parent;
         } s_none;
         Buf *s_buf;
     } data;
@@ -153,19 +163,29 @@ enum ConstPtrSpecial {
     ConstPtrSpecialBaseArray,
     // The pointer points to a field in an underlying struct.
     ConstPtrSpecialBaseStruct,
+    // The pointer points to the error set field of an error union
+    ConstPtrSpecialBaseErrorUnionCode,
+    // The pointer points to the payload field of an error union
+    ConstPtrSpecialBaseErrorUnionPayload,
+    // The pointer points to the payload field of an optional
+    ConstPtrSpecialBaseOptionalPayload,
     // This means that we did a compile-time pointer reinterpret and we cannot
     // understand the value of pointee at compile time. However, we will still
     // emit a binary with a compile time known address.
     // In this case index is the numeric address value.
-    // We also use this for null pointer. We need the data layout for ConstCastOnly == true
-    // types to be the same, so all optionals of pointer types use x_ptr
-    // instead of x_optional
     ConstPtrSpecialHardCodedAddr,
     // This means that the pointer represents memory of assigning to _.
     // That is, storing discards the data, and loading is invalid.
     ConstPtrSpecialDiscard,
     // This is actually a function.
     ConstPtrSpecialFunction,
+    // This means the pointer is null. This is only allowed when the type is ?*T.
+    // We use this instead of ConstPtrSpecialHardCodedAddr because often we check
+    // for that value to avoid doing comptime work.
+    // We need the data layout for ConstCastOnly == true
+    // types to be the same, so all optionals of pointer types use x_ptr
+    // instead of x_optional.
+    ConstPtrSpecialNull,
 };
 
 enum ConstPtrMut {
@@ -199,6 +219,15 @@ struct ConstPtrValue {
             ConstExprValue *struct_val;
             size_t field_index;
         } base_struct;
+        struct {
+            ConstExprValue *err_union_val;
+        } base_err_union_code;
+        struct {
+            ConstExprValue *err_union_val;
+        } base_err_union_payload;
+        struct {
+            ConstExprValue *optional_val;
+        } base_optional_payload;
         struct {
             uint64_t addr;
         } hard_coded_addr;
@@ -209,7 +238,7 @@ struct ConstPtrValue {
 };
 
 struct ConstErrValue {
-    ErrorTableEntry *err;
+    ConstExprValue *error_set;
     ConstExprValue *payload;
 };
 
@@ -265,6 +294,7 @@ struct ConstGlobalRefs {
 struct ConstExprValue {
     ZigType *type;
     ConstValSpecial special;
+    ConstParent parent;
     ConstGlobalRefs *global_refs;
 
     union {
@@ -433,7 +463,7 @@ enum NodeType {
     NodeTypeArrayType,
     NodeTypeErrorType,
     NodeTypeIfErrorExpr,
-    NodeTypeTestExpr,
+    NodeTypeIfOptional,
     NodeTypeErrorSetDecl,
     NodeTypeCancel,
     NodeTypeResume,
@@ -677,7 +707,7 @@ struct AstNodeUse {
     AstNode *expr;
 
     TldResolution resolution;
-    IrInstruction *value;
+    ConstExprValue *value;
 };
 
 struct AstNodeIfBoolExpr {
@@ -1610,7 +1640,7 @@ struct CodeGen {
     HashMap<FnTypeId *, ZigType *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
     HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
     HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
-    HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
+    HashMap<Scope *, ConstExprValue *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
     HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
     HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
     HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
@@ -1802,10 +1832,9 @@ enum VarLinkage {
 
 struct ZigVar {
     Buf name;
-    ConstExprValue *value;
+    ConstExprValue *const_value;
+    ZigType *var_type;
     LLVMValueRef value_ref;
-    bool src_is_const;
-    bool gen_is_const;
     IrInstruction *is_comptime;
     // which node is the declaration of the variable
     AstNode *decl_node;
@@ -1815,17 +1844,21 @@ struct ZigVar {
     Scope *parent_scope;
     Scope *child_scope;
     LLVMValueRef param_value_ref;
-    bool shadowable;
     size_t mem_slot_index;
     IrExecutable *owner_exec;
     size_t ref_count;
-    VarLinkage linkage;
-    uint32_t align_bytes;
 
     // In an inline loop, multiple variables may be created,
     // In this case, a reference to a variable should follow
     // this pointer to the redefined variable.
     ZigVar *next_var;
+
+    uint32_t align_bytes;
+    VarLinkage linkage;
+
+    bool shadowable;
+    bool src_is_const;
+    bool gen_is_const;
 };
 
 struct ErrorTableEntry {
@@ -1891,10 +1924,11 @@ struct ScopeBlock {
     ZigList<IrInstruction *> *incoming_values;
     ZigList<IrBasicBlock *> *incoming_blocks;
 
-    bool safety_off;
     AstNode *safety_set_node;
-    bool fast_math_on;
     AstNode *fast_math_set_node;
+
+    bool safety_off;
+    bool fast_math_on;
 };
 
 // This scope is created from every defer expression.
@@ -2030,8 +2064,19 @@ struct IrBasicBlock {
     IrInstruction *must_be_comptime_source_instr;
 };
 
+// These instructions are in transition to having "pass 1" instructions
+// and "pass 2" instructions. The pass 1 instructions are suffixed with Src
+// and pass 2 are suffixed with Gen.
+// Once all instructions are separated in this way, they'll have different
+// base types for better type safety.
+// Src instructions are generated by ir_gen_* functions in ir.cpp from AST.
+// ir_analyze_* functions consume Src instructions and produce Gen instructions.
+// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
+// Src instructions do not have type information; Gen instructions do.
 enum IrInstructionId {
     IrInstructionIdInvalid,
+    IrInstructionIdDeclVarSrc,
+    IrInstructionIdDeclVarGen,
     IrInstructionIdBr,
     IrInstructionIdCondBr,
     IrInstructionIdSwitchBr,
@@ -2040,7 +2085,6 @@ enum IrInstructionId {
     IrInstructionIdPhi,
     IrInstructionIdUnOp,
     IrInstructionIdBinOp,
-    IrInstructionIdDeclVar,
     IrInstructionIdLoadPtr,
     IrInstructionIdStorePtr,
     IrInstructionIdFieldPtr,
@@ -2069,7 +2113,7 @@ enum IrInstructionId {
     IrInstructionIdAsm,
     IrInstructionIdSizeOf,
     IrInstructionIdTestNonNull,
-    IrInstructionIdUnwrapOptional,
+    IrInstructionIdOptionalUnwrapPtr,
     IrInstructionIdOptionalWrap,
     IrInstructionIdUnionTag,
     IrInstructionIdClz,
@@ -2085,7 +2129,8 @@ enum IrInstructionId {
     IrInstructionIdCompileLog,
     IrInstructionIdErrName,
     IrInstructionIdEmbedFile,
-    IrInstructionIdCmpxchg,
+    IrInstructionIdCmpxchgSrc,
+    IrInstructionIdCmpxchgGen,
     IrInstructionIdFence,
     IrInstructionIdTruncate,
     IrInstructionIdIntCast,
@@ -2114,7 +2159,8 @@ enum IrInstructionId {
     IrInstructionIdErrWrapPayload,
     IrInstructionIdFnProto,
     IrInstructionIdTestComptime,
-    IrInstructionIdPtrCast,
+    IrInstructionIdPtrCastSrc,
+    IrInstructionIdPtrCastGen,
     IrInstructionIdBitCast,
     IrInstructionIdWidenOrShorten,
     IrInstructionIdIntToPtr,
@@ -2194,6 +2240,22 @@ struct IrInstruction {
     bool is_gen;
 };
 
+struct IrInstructionDeclVarSrc {
+    IrInstruction base;
+
+    ZigVar *var;
+    IrInstruction *var_type;
+    IrInstruction *align_value;
+    IrInstruction *init_value;
+};
+
+struct IrInstructionDeclVarGen {
+    IrInstruction base;
+
+    ZigVar *var;
+    IrInstruction *init_value;
+};
+
 struct IrInstructionCondBr {
     IrInstruction base;
 
@@ -2302,20 +2364,11 @@ struct IrInstructionBinOp {
     IrInstruction base;
 
     IrInstruction *op1;
-    IrBinOp op_id;
     IrInstruction *op2;
+    IrBinOp op_id;
     bool safety_check_on;
 };
 
-struct IrInstructionDeclVar {
-    IrInstruction base;
-
-    ZigVar *var;
-    IrInstruction *var_type;
-    IrInstruction *align_value;
-    IrInstruction *init_value;
-};
-
 struct IrInstructionLoadPtr {
     IrInstruction base;
 
@@ -2335,7 +2388,6 @@ struct IrInstructionFieldPtr {
     IrInstruction *container_ptr;
     Buf *field_name_buffer;
     IrInstruction *field_name_expr;
-    bool is_const;
 };
 
 struct IrInstructionStructFieldPtr {
@@ -2378,13 +2430,13 @@ struct IrInstructionCall {
     ZigFn *fn_entry;
     size_t arg_count;
     IrInstruction **args;
-    bool is_comptime;
     LLVMValueRef tmp_ptr;
-    FnInline fn_inline;
-    bool is_async;
 
     IrInstruction *async_allocator;
     IrInstruction *new_stack;
+    FnInline fn_inline;
+    bool is_async;
+    bool is_comptime;
 };
 
 struct IrInstructionConst {
@@ -2527,9 +2579,9 @@ struct IrInstructionSliceType {
     IrInstruction base;
 
     IrInstruction *align_value;
+    IrInstruction *child_type;
     bool is_const;
     bool is_volatile;
-    IrInstruction *child_type;
 };
 
 struct IrInstructionAsm {
@@ -2557,10 +2609,12 @@ struct IrInstructionTestNonNull {
     IrInstruction *value;
 };
 
-struct IrInstructionUnwrapOptional {
+// Takes a pointer to an optional value, returns a pointer
+// to the payload.
+struct IrInstructionOptionalUnwrapPtr {
     IrInstruction base;
 
-    IrInstruction *value;
+    IrInstruction *base_ptr;
     bool safety_check_on;
 };
 
@@ -2651,7 +2705,7 @@ struct IrInstructionEmbedFile {
     IrInstruction *name;
 };
 
-struct IrInstructionCmpxchg {
+struct IrInstructionCmpxchgSrc {
     IrInstruction base;
 
     IrInstruction *type_value;
@@ -2661,14 +2715,19 @@ struct IrInstructionCmpxchg {
     IrInstruction *success_order_value;
     IrInstruction *failure_order_value;
 
-    // if this instruction gets to runtime then we know these values:
-    ZigType *type;
-    AtomicOrder success_order;
-    AtomicOrder failure_order;
-
     bool is_weak;
+};
 
+struct IrInstructionCmpxchgGen {
+    IrInstruction base;
+
+    IrInstruction *ptr;
+    IrInstruction *cmp_value;
+    IrInstruction *new_value;
     LLVMValueRef tmp_ptr;
+    AtomicOrder success_order;
+    AtomicOrder failure_order;
+    bool is_weak;
 };
 
 struct IrInstructionFence {
@@ -2851,7 +2910,7 @@ struct IrInstructionTestErr {
 struct IrInstructionUnwrapErrCode {
     IrInstruction base;
 
-    IrInstruction *value;
+    IrInstruction *err_union;
 };
 
 struct IrInstructionUnwrapErrPayload {
@@ -2899,13 +2958,19 @@ struct IrInstructionTestComptime {
     IrInstruction *value;
 };
 
-struct IrInstructionPtrCast {
+struct IrInstructionPtrCastSrc {
     IrInstruction base;
 
     IrInstruction *dest_type;
     IrInstruction *ptr;
 };
 
+struct IrInstructionPtrCastGen {
+    IrInstruction base;
+
+    IrInstruction *ptr;
+};
+
 struct IrInstructionBitCast {
     IrInstruction base;
 
src/analyze.cpp
@@ -570,7 +570,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
         if (child_type->zero_bits) {
             entry->type_ref = LLVMInt1Type();
             entry->di_type = g->builtin_types.entry_bool->di_type;
-        } else if (type_is_codegen_pointer(child_type)) {
+        } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
             assert(child_type->di_type);
             // this is an optimization but also is necessary for calling C
             // functions where all pointers are maybe pointers
@@ -1278,7 +1278,9 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
     return entry;
 }
 
-static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) {
+static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry,
+        Buf *type_name)
+{
     size_t backward_branch_count = 0;
     return ir_eval_const_value(g, scope, node, type_entry,
             &backward_branch_count, default_backward_branch_quota,
@@ -1286,12 +1288,12 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod
 }
 
 ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
-    IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
-    if (result->value.type->id == ZigTypeIdInvalid)
+    ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
+    if (type_is_invalid(result->type))
         return g->builtin_types.entry_invalid;
 
-    assert(result->value.special != ConstValSpecialRuntime);
-    return result->value.data.x_type;
+    assert(result->special != ConstValSpecialRuntime);
+    return result->data.x_type;
 }
 
 ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
@@ -1342,11 +1344,11 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou
 }
 
 static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) {
-    IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
-    if (type_is_invalid(align_result->value.type))
+    ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
+    if (type_is_invalid(align_result->type))
         return false;
 
-    uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint);
+    uint32_t align_bytes = bigint_as_unsigned(&align_result->data.x_bigint);
     if (align_bytes == 0) {
         add_node_error(g, node, buf_sprintf("alignment must be >= 1"));
         return false;
@@ -1364,12 +1366,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
     ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
             PtrLenUnknown, 0, 0, 0);
     ZigType *str_type = get_slice_type(g, ptr_type);
-    IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr);
-    if (type_is_invalid(instr->value.type))
+    ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr);
+    if (type_is_invalid(result_val->type))
         return false;
 
-    ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index];
-    ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index];
+    ConstExprValue *ptr_field = &result_val->data.x_struct.fields[slice_ptr_index];
+    ConstExprValue *len_field = &result_val->data.x_struct.fields[slice_len_index];
 
     assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray);
     ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val;
@@ -2504,20 +2506,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
         // In this first pass we resolve explicit tag values.
         // In a second pass we will fill in the unspecified ones.
         if (tag_value != nullptr) {
-            IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
-            if (result_inst->value.type->id == ZigTypeIdInvalid) {
+            ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+            if (type_is_invalid(result->type)) {
                 enum_type->data.enumeration.is_invalid = true;
                 continue;
             }
-            assert(result_inst->value.special != ConstValSpecialRuntime);
-            assert(result_inst->value.type->id == ZigTypeIdInt ||
-                   result_inst->value.type->id == ZigTypeIdComptimeInt);
-            auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+            assert(result->special != ConstValSpecialRuntime);
+            assert(result->type->id == ZigTypeIdInt ||
+                   result->type->id == ZigTypeIdComptimeInt);
+            auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value);
             if (entry == nullptr) {
-                bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint);
+                bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint);
             } else {
                 Buf *val_buf = buf_alloc();
-                bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+                bigint_append_buf(val_buf, &result->data.x_bigint, 10);
 
                 ErrorMsg *msg = add_node_error(g, tag_value,
                         buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
@@ -2944,19 +2946,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
             // In a second pass we will fill in the unspecified ones.
             if (tag_value != nullptr) {
                 ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type;
-                IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
-                if (result_inst->value.type->id == ZigTypeIdInvalid) {
+                ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+                if (type_is_invalid(result->type)) {
                     union_type->data.unionation.is_invalid = true;
                     continue;
                 }
-                assert(result_inst->value.special != ConstValSpecialRuntime);
-                assert(result_inst->value.type->id == ZigTypeIdInt);
-                auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+                assert(result->special != ConstValSpecialRuntime);
+                assert(result->type->id == ZigTypeIdInt);
+                auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value);
                 if (entry == nullptr) {
-                    bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
+                    bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint);
                 } else {
                     Buf *val_buf = buf_alloc();
-                    bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+                    bigint_append_buf(val_buf, &result->data.x_bigint, 10);
 
                     ErrorMsg *msg = add_node_error(g, tag_value,
                             buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
@@ -3419,7 +3421,8 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
     resolve_top_level_decl(g, tld, false, tld->source_node);
     assert(tld->id == TldIdVar);
     TldVar *tld_var = (TldVar *)tld;
-    tld_var->var->value = value;
+    tld_var->var->const_value = value;
+    tld_var->var->var_type = value->type;
     tld_var->var->align_bytes = get_abi_alignment(g, value->type);
 }
 
@@ -3513,7 +3516,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
         case NodeTypeArrayType:
         case NodeTypeErrorType:
         case NodeTypeIfErrorExpr:
-        case NodeTypeTestExpr:
+        case NodeTypeIfOptional:
         case NodeTypeErrorSetDecl:
         case NodeTypeCancel:
         case NodeTypeResume:
@@ -3582,13 +3585,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
 // Set name to nullptr to make the variable anonymous (not visible to programmer).
 // TODO merge with definition of add_local_var in ir.cpp
 ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
-    bool is_const, ConstExprValue *value, Tld *src_tld)
+    bool is_const, ConstExprValue *const_value, Tld *src_tld, ZigType *var_type)
 {
     Error err;
-    assert(value);
+    assert(const_value != nullptr);
+    assert(var_type != nullptr);
 
     ZigVar *variable_entry = allocate<ZigVar>(1);
-    variable_entry->value = value;
+    variable_entry->const_value = const_value;
+    variable_entry->var_type = var_type;
     variable_entry->parent_scope = parent_scope;
     variable_entry->shadowable = false;
     variable_entry->mem_slot_index = SIZE_MAX;
@@ -3597,23 +3602,23 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
     assert(name);
     buf_init_from_buf(&variable_entry->name, name);
 
-    if ((err = type_resolve(g, value->type, ResolveStatusAlignmentKnown))) {
-        variable_entry->value->type = g->builtin_types.entry_invalid;
+    if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) {
+        variable_entry->var_type = g->builtin_types.entry_invalid;
     } else {
-        variable_entry->align_bytes = get_abi_alignment(g, value->type);
+        variable_entry->align_bytes = get_abi_alignment(g, var_type);
 
         ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr);
         if (existing_var && !existing_var->shadowable) {
             ErrorMsg *msg = add_node_error(g, source_node,
                     buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
             add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
-            variable_entry->value->type = g->builtin_types.entry_invalid;
+            variable_entry->var_type = g->builtin_types.entry_invalid;
         } else {
             ZigType *type;
             if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) {
                 add_node_error(g, source_node,
                         buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
-                variable_entry->value->type = g->builtin_types.entry_invalid;
+                variable_entry->var_type = g->builtin_types.entry_invalid;
             } else {
                 Scope *search_scope = nullptr;
                 if (src_tld == nullptr) {
@@ -3627,7 +3632,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
                         ErrorMsg *msg = add_node_error(g, source_node,
                                 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
                         add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
-                        variable_entry->value->type = g->builtin_types.entry_invalid;
+                        variable_entry->var_type = g->builtin_types.entry_invalid;
                     }
                 }
             }
@@ -3677,7 +3682,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
         linkage = VarLinkageInternal;
     }
 
-    IrInstruction *init_value = nullptr;
+    ConstExprValue *init_value = nullptr;
 
     // TODO more validation for types that can't be used for export/extern variables
     ZigType *implicit_type = nullptr;
@@ -3686,7 +3691,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
     } else if (var_decl->expr) {
         init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol);
         assert(init_value);
-        implicit_type = init_value->value.type;
+        implicit_type = init_value->type;
 
         if (implicit_type->id == ZigTypeIdUnreachable) {
             add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable"));
@@ -3704,7 +3709,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
             add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
             implicit_type = g->builtin_types.entry_invalid;
         }
-        assert(implicit_type->id == ZigTypeIdInvalid || init_value->value.special != ConstValSpecialRuntime);
+        assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime);
     } else if (linkage != VarLinkageExternal) {
         add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
         implicit_type = g->builtin_types.entry_invalid;
@@ -3713,19 +3718,19 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
     ZigType *type = explicit_type ? explicit_type : implicit_type;
     assert(type != nullptr); // should have been caught by the parser
 
-    ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type);
+    ConstExprValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(type);
 
     tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol,
-            is_const, init_val, &tld_var->base);
+            is_const, init_val, &tld_var->base, type);
     tld_var->var->linkage = linkage;
 
     if (implicit_type != nullptr && type_is_invalid(implicit_type)) {
-        tld_var->var->value->type = g->builtin_types.entry_invalid;
+        tld_var->var->var_type = g->builtin_types.entry_invalid;
     }
 
     if (var_decl->align_expr != nullptr) {
         if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) {
-            tld_var->var->value->type = g->builtin_types.entry_invalid;
+            tld_var->var->var_type = g->builtin_types.entry_invalid;
         }
     }
 
@@ -4090,7 +4095,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) {
         }
 
         ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
-                param_name, true, create_const_runtime(param_type), nullptr);
+                param_name, true, create_const_runtime(param_type), nullptr, param_type);
         var->src_arg_index = i;
         fn_table_entry->child_scope = var->child_scope;
         var->shadowable = var->shadowable || is_var_args;
@@ -4228,18 +4233,17 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
         preview_use_decl(g, src_use_node);
     }
 
-    IrInstruction *use_target_value = src_use_node->data.use.value;
-    if (use_target_value->value.type->id == ZigTypeIdInvalid) {
+    ConstExprValue *use_target_value = src_use_node->data.use.value;
+    if (type_is_invalid(use_target_value->type)) {
         dst_use_node->owner->any_imports_failed = true;
         return;
     }
 
     dst_use_node->data.use.resolution = TldResolutionOk;
 
-    ConstExprValue *const_val = &use_target_value->value;
-    assert(const_val->special != ConstValSpecialRuntime);
+    assert(use_target_value->special != ConstValSpecialRuntime);
 
-    ImportTableEntry *target_import = const_val->data.x_import;
+    ImportTableEntry *target_import = use_target_value->data.x_import;
     assert(target_import);
 
     if (target_import->any_imports_failed) {
@@ -4302,10 +4306,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
     }
 
     node->data.use.resolution = TldResolutionResolving;
-    IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,
+    ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base,
         node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
 
-    if (result->value.type->id == ZigTypeIdInvalid)
+    if (type_is_invalid(result->type))
         node->owner->any_imports_failed = true;
 
     node->data.use.value = result;
@@ -4486,7 +4490,8 @@ bool handle_is_ptr(ZigType *type_entry) {
              return type_has_bits(type_entry->data.error_union.payload_type);
         case ZigTypeIdOptional:
              return type_has_bits(type_entry->data.maybe.child_type) &&
-                    !type_is_codegen_pointer(type_entry->data.maybe.child_type);
+                    !type_is_codegen_pointer(type_entry->data.maybe.child_type) &&
+                    type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;
         case ZigTypeIdUnion:
              assert(type_entry->data.unionation.zero_bits_known);
              if (type_entry->data.unionation.gen_field_count == 0)
@@ -4732,6 +4737,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
     return true;
 }
 
+static uint32_t hash_const_val_error_set(ConstExprValue *const_val) {
+    assert(const_val->data.x_err_set != nullptr);
+    return const_val->data.x_err_set->value ^ 2630160122;
+}
+
 static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
     uint32_t hash_val = 0;
     switch (const_val->data.x_ptr.mut) {
@@ -4763,6 +4773,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
             hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
             hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
             return hash_val;
+        case ConstPtrSpecialBaseErrorUnionCode:
+            hash_val += (uint32_t)2994743799;
+            hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val);
+            return hash_val;
+        case ConstPtrSpecialBaseErrorUnionPayload:
+            hash_val += (uint32_t)3456080131;
+            hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_payload.err_union_val);
+            return hash_val;
+        case ConstPtrSpecialBaseOptionalPayload:
+            hash_val += (uint32_t)3163140517;
+            hash_val += hash_ptr(const_val->data.x_ptr.data.base_optional_payload.optional_val);
+            return hash_val;
         case ConstPtrSpecialHardCodedAddr:
             hash_val += (uint32_t)4048518294;
             hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
@@ -4774,6 +4796,9 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
             hash_val += (uint32_t)2590901619;
             hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
             return hash_val;
+        case ConstPtrSpecialNull:
+            hash_val += (uint32_t)1486246455;
+            return hash_val;
     }
     zig_unreachable();
 }
@@ -4872,7 +4897,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
             return 2709806591;
         case ZigTypeIdOptional:
             if (get_codegen_ptr_type(const_val->type) != nullptr) {
-                return hash_const_val(const_val) * 1992916303;
+                return hash_const_val_ptr(const_val) * 1992916303;
+            } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) {
+                return hash_const_val_error_set(const_val) * 3147031929;
             } else {
                 if (const_val->data.x_optional) {
                     return hash_const_val(const_val->data.x_optional) * 1992916303;
@@ -4884,8 +4911,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
             // TODO better hashing algorithm
             return 3415065496;
         case ZigTypeIdErrorSet:
-            assert(const_val->data.x_err_set != nullptr);
-            return const_val->data.x_err_set->value ^ 2630160122;
+            return hash_const_val_error_set(const_val);
         case ZigTypeIdNamespace:
             return hash_ptr(const_val->data.x_import);
         case ZigTypeIdBoundFn:
@@ -4987,7 +5013,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
             return can_mutate_comptime_var_state(value->data.x_optional);
 
         case ZigTypeIdErrorUnion:
-            if (value->data.x_err_union.err != nullptr)
+            if (value->data.x_err_union.error_set->data.x_err_set != nullptr)
                 return false;
             assert(value->data.x_err_union.payload != nullptr);
             return can_mutate_comptime_var_state(value->data.x_err_union.payload);
@@ -5048,9 +5074,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) {
     while (scope) {
         if (scope->id == ScopeIdVarDecl) {
             ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
-            if (type_is_invalid(var_scope->var->value->type))
+            if (type_is_invalid(var_scope->var->var_type))
                 return false;
-            if (can_mutate_comptime_var_state(var_scope->var->value))
+            if (can_mutate_comptime_var_state(var_scope->var->const_value))
                 return false;
         } else if (scope->id == ScopeIdFnDef) {
             return true;
@@ -5068,7 +5094,7 @@ uint32_t fn_eval_hash(Scope* scope) {
     while (scope) {
         if (scope->id == ScopeIdVarDecl) {
             ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
-            result += hash_const_val(var_scope->var->value);
+            result += hash_const_val(var_scope->var->const_value);
         } else if (scope->id == ScopeIdFnDef) {
             ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
             result += hash_ptr(fn_scope->fn_entry);
@@ -5092,10 +5118,16 @@ bool fn_eval_eql(Scope *a, Scope *b) {
         if (a->id == ScopeIdVarDecl) {
             ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a;
             ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b;
-            if (a_var_scope->var->value->type != b_var_scope->var->value->type)
-                return false;
-            if (!const_values_equal(a->codegen, a_var_scope->var->value, b_var_scope->var->value))
+            if (a_var_scope->var->var_type != b_var_scope->var->var_type)
                 return false;
+            if (a_var_scope->var->var_type == a_var_scope->var->const_value->type &&
+                b_var_scope->var->var_type == b_var_scope->var->const_value->type)
+            {
+                if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value))
+                    return false;
+            } else {
+                zig_panic("TODO comptime ptr reinterpret for fn_eval_eql");
+            }
         } else if (a->id == ScopeIdFnDef) {
             ScopeFnDef *a_fn_scope = (ScopeFnDef *)a;
             ScopeFnDef *b_fn_scope = (ScopeFnDef *)b;
@@ -5113,6 +5145,7 @@ bool fn_eval_eql(Scope *a, Scope *b) {
     return false;
 }
 
+// Whether the type has bits at runtime.
 bool type_has_bits(ZigType *type_entry) {
     assert(type_entry);
     assert(!type_is_invalid(type_entry));
@@ -5120,6 +5153,65 @@ bool type_has_bits(ZigType *type_entry) {
     return !type_entry->zero_bits;
 }
 
+// Whether you can infer the value based solely on the type.
+OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
+    assert(type_entry != nullptr);
+    Error err;
+    if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
+        return OnePossibleValueInvalid;
+    switch (type_entry->id) {
+        case ZigTypeIdInvalid:
+            zig_unreachable();
+        case ZigTypeIdOpaque:
+        case ZigTypeIdComptimeFloat:
+        case ZigTypeIdComptimeInt:
+        case ZigTypeIdMetaType:
+        case ZigTypeIdNamespace:
+        case ZigTypeIdBoundFn:
+        case ZigTypeIdArgTuple:
+        case ZigTypeIdOptional:
+        case ZigTypeIdFn:
+        case ZigTypeIdBool:
+        case ZigTypeIdFloat:
+        case ZigTypeIdPromise:
+        case ZigTypeIdErrorUnion:
+            return OnePossibleValueNo;
+        case ZigTypeIdUndefined:
+        case ZigTypeIdNull:
+        case ZigTypeIdVoid:
+        case ZigTypeIdUnreachable:
+            return OnePossibleValueYes;
+        case ZigTypeIdArray:
+            if (type_entry->data.array.len == 0)
+                return OnePossibleValueYes;
+            return type_has_one_possible_value(g, type_entry->data.array.child_type);
+        case ZigTypeIdStruct:
+            for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
+                TypeStructField *field = &type_entry->data.structure.fields[i];
+                switch (type_has_one_possible_value(g, field->type_entry)) {
+                    case OnePossibleValueInvalid:
+                        return OnePossibleValueInvalid;
+                    case OnePossibleValueNo:
+                        return OnePossibleValueNo;
+                    case OnePossibleValueYes:
+                        continue;
+                }
+            }
+            return OnePossibleValueYes;
+        case ZigTypeIdErrorSet:
+        case ZigTypeIdEnum:
+        case ZigTypeIdInt:
+            return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes;
+        case ZigTypeIdPointer:
+            return type_has_one_possible_value(g, type_entry->data.pointer.child_type);
+        case ZigTypeIdUnion:
+            if (type_entry->data.unionation.src_field_count > 1)
+                return OnePossibleValueNo;
+            return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry);
+    }
+    zig_unreachable();
+}
+
 ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
     Error err;
     if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
@@ -5574,6 +5666,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
             if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
                 return false;
             return true;
+        case ConstPtrSpecialBaseErrorUnionCode:
+            if (a->data.x_ptr.data.base_err_union_code.err_union_val !=
+                b->data.x_ptr.data.base_err_union_code.err_union_val &&
+                a->data.x_ptr.data.base_err_union_code.err_union_val->global_refs !=
+                b->data.x_ptr.data.base_err_union_code.err_union_val->global_refs)
+            {
+                return false;
+            }
+            return true;
+        case ConstPtrSpecialBaseErrorUnionPayload:
+            if (a->data.x_ptr.data.base_err_union_payload.err_union_val !=
+                b->data.x_ptr.data.base_err_union_payload.err_union_val &&
+                a->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs !=
+                b->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs)
+            {
+                return false;
+            }
+            return true;
+        case ConstPtrSpecialBaseOptionalPayload:
+            if (a->data.x_ptr.data.base_optional_payload.optional_val !=
+                b->data.x_ptr.data.base_optional_payload.optional_val &&
+                a->data.x_ptr.data.base_optional_payload.optional_val->global_refs !=
+                b->data.x_ptr.data.base_optional_payload.optional_val->global_refs)
+            {
+                return false;
+            }
+            return true;
         case ConstPtrSpecialHardCodedAddr:
             if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
                 return false;
@@ -5582,6 +5701,8 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
             return true;
         case ConstPtrSpecialFunction:
             return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
+        case ConstPtrSpecialNull:
+            return true;
     }
     zig_unreachable();
 }
@@ -5750,7 +5871,7 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v
     }
 }
 
-void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
+static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
     assert(type_entry->id == ZigTypeIdPointer);
 
     if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) {
@@ -5763,6 +5884,9 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy
             zig_unreachable();
         case ConstPtrSpecialRef:
         case ConstPtrSpecialBaseStruct:
+        case ConstPtrSpecialBaseErrorUnionCode:
+        case ConstPtrSpecialBaseErrorUnionPayload:
+        case ConstPtrSpecialBaseOptionalPayload:
             buf_appendf(buf, "*");
             // TODO we need a source node for const_ptr_pointee because it can generate compile errors
             render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
@@ -5790,10 +5914,21 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy
                 buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
                 return;
             }
+        case ConstPtrSpecialNull:
+            buf_append_str(buf, "null");
+            return;
     }
     zig_unreachable();
 }
 
+static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
+    if (const_val->data.x_err_set == nullptr) {
+        buf_append_str(buf, "null");
+    } else {
+        buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name));
+    }
+}
+
 void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
     switch (const_val->special) {
         case ConstValSpecialRuntime:
@@ -5921,6 +6056,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
             {
                 if (get_codegen_ptr_type(const_val->type) != nullptr)
                     return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type);
+                if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet)
+                    return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type);
                 if (const_val->data.x_optional) {
                     render_const_value(g, buf, const_val->data.x_optional);
                 } else {
@@ -5958,11 +6095,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
         case ZigTypeIdErrorUnion:
             {
                 buf_appendf(buf, "%s(", buf_ptr(&type_entry->name));
-                if (const_val->data.x_err_union.err == nullptr) {
+                ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+                if (err_set == nullptr) {
                     render_const_value(g, buf, const_val->data.x_err_union.payload);
                 } else {
                     buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name),
-                            buf_ptr(&const_val->data.x_err_union.err->name));
+                            buf_ptr(&err_set->name));
                 }
                 buf_appendf(buf, ")");
                 return;
@@ -5977,10 +6115,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
                 return;
             }
         case ZigTypeIdErrorSet:
-            {
-                buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name));
-                return;
-            }
+            return render_const_val_err_set(g, buf, const_val, type_entry);
         case ZigTypeIdArgTuple:
             {
                 buf_appendf(buf, "(args value)");
@@ -6172,6 +6307,10 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
 // Canonicalize the array value as ConstArraySpecialNone
 void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
     assert(const_val->type->id == ZigTypeIdArray);
+    if (const_val->special == ConstValSpecialUndef) {
+        const_val->special = ConstValSpecialStatic;
+        const_val->data.x_array.special = ConstArraySpecialUndef;
+    }
     switch (const_val->data.x_array.special) {
         case ConstArraySpecialNone:
             return;
@@ -6215,17 +6354,7 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
 }
 
 ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {
-    assert(value->type);
-    ZigType *type_entry = value->type;
-    if (type_entry->id == ZigTypeIdArray) {
-        expand_undef_array(g, value);
-        return &value->data.x_array.data.s_none.parent;
-    } else if (type_entry->id == ZigTypeIdStruct) {
-        return &value->data.x_struct.parent;
-    } else if (type_entry->id == ZigTypeIdUnion) {
-        return &value->data.x_union.parent;
-    }
-    return nullptr;
+    return &value->parent;
 }
 
 static const ZigTypeId all_type_ids[] = {
@@ -6453,7 +6582,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
     resolve_top_level_decl(codegen, tld, false, nullptr);
     assert(tld->id == TldIdVar);
     TldVar *tld_var = (TldVar *)tld;
-    ConstExprValue *var_value = tld_var->var->value;
+    ConstExprValue *var_value = tld_var->var->const_value;
     assert(var_value != nullptr);
     return var_value;
 }
src/analyze.hpp
@@ -81,7 +81,7 @@ ZigFn *scope_fn_entry(Scope *scope);
 ImportTableEntry *get_scope_import(Scope *scope);
 void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
 ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
-    bool is_const, ConstExprValue *init_value, Tld *src_tld);
+    bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type);
 ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
 ZigFn *create_fn(CodeGen *g, AstNode *proto_node);
 ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value);
@@ -222,6 +222,13 @@ enum ReqCompTime {
 };
 ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry);
 
+enum OnePossibleValue {
+    OnePossibleValueInvalid,
+    OnePossibleValueNo,
+    OnePossibleValueYes,
+};
+OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry);
+
 Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
         ConstExprValue *const_val, ZigType *wanted_type);
 
src/ast_render.cpp
@@ -233,8 +233,8 @@ static const char *node_type_str(NodeType node_type) {
             return "ErrorType";
         case NodeTypeIfErrorExpr:
             return "IfErrorExpr";
-        case NodeTypeTestExpr:
-            return "TestExpr";
+        case NodeTypeIfOptional:
+            return "IfOptional";
         case NodeTypeErrorSetDecl:
             return "ErrorSetDecl";
         case NodeTypeCancel:
@@ -387,7 +387,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
             if (node->data.if_err_expr.else_node)
                 return statement_terminates_without_semicolon(node->data.if_err_expr.else_node);
             return node->data.if_err_expr.then_node->type == NodeTypeBlock;
-        case NodeTypeTestExpr:
+        case NodeTypeIfOptional:
             if (node->data.test_expr.else_node)
                 return statement_terminates_without_semicolon(node->data.test_expr.else_node);
             return node->data.test_expr.then_node->type == NodeTypeBlock;
@@ -974,7 +974,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
                 }
                 break;
             }
-        case NodeTypeTestExpr:
+        case NodeTypeIfOptional:
             {
                 fprintf(ar->f, "if (");
                 render_node_grouped(ar, node->data.test_expr.target_node);
src/codegen.cpp
@@ -313,6 +313,8 @@ static void render_const_val(CodeGen *g, ConstExprValue *const_val, const char *
 static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name);
 static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name);
 static void generate_error_name_table(CodeGen *g);
+static bool value_is_all_undef(ConstExprValue *const_val);
+static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr);
 
 static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) {
     unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
@@ -461,6 +463,21 @@ static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkag
     }
 }
 
+static bool cc_want_sret_attr(CallingConvention cc) {
+    switch (cc) {
+        case CallingConventionNaked:
+            zig_unreachable();
+        case CallingConventionC:
+        case CallingConventionCold:
+        case CallingConventionStdcall:
+            return true;
+        case CallingConventionAsync:
+        case CallingConventionUnspecified:
+            return false;
+    }
+    zig_unreachable();
+}
+
 static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
     if (fn_table_entry->llvm_value)
         return fn_table_entry->llvm_value;
@@ -598,9 +615,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
     } else if (type_is_codegen_pointer(return_type)) {
         addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
     } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
-        addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
         addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
-        if (cc == CallingConventionC) {
+        addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
+        if (cc_want_sret_attr(cc)) {
             addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");
         }
         init_gen_i = 1;
@@ -2200,10 +2217,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
                 assert(variable);
                 assert(variable->value_ref);
 
-                if (!handle_is_ptr(variable->value->type)) {
+                if (!handle_is_ptr(variable->var_type)) {
                     clear_debug_source_node(g);
-                    gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref,
-                            variable->align_bytes, false);
+                    gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index),
+                            variable->value_ref, variable->align_bytes, false);
                 }
 
                 if (variable->decl_node) {
@@ -2961,7 +2978,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
 }
 
 static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
-        IrInstructionPtrCast *instruction)
+        IrInstructionPtrCastGen *instruction)
 {
     ZigType *wanted_type = instruction->base.value.type;
     if (!type_has_bits(wanted_type)) {
@@ -3149,11 +3166,11 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
 }
 
 static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
-        IrInstructionDeclVar *decl_var_instruction)
+        IrInstructionDeclVarGen *decl_var_instruction)
 {
     ZigVar *var = decl_var_instruction->var;
 
-    if (!type_has_bits(var->value->type))
+    if (!type_has_bits(var->var_type))
         return nullptr;
 
     if (var->ref_count == 0 && g->build_mode != BuildModeDebug)
@@ -3161,34 +3178,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
 
     IrInstruction *init_value = decl_var_instruction->init_value;
 
-    bool have_init_expr = false;
-
-    ConstExprValue *const_val = &init_value->value;
-    if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic)
-        have_init_expr = true;
+    bool have_init_expr = !value_is_all_undef(&init_value->value);
 
     if (have_init_expr) {
-        assert(var->value->type == init_value->value.type);
-        ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
+        ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false,
                 PtrLenSingle, var->align_bytes, 0, 0);
         LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
         gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
-    } else {
-        bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
-        if (want_safe) {
-            ZigType *usize = g->builtin_types.entry_usize;
-            uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref);
-            assert(size_bytes > 0);
-
-            assert(var->align_bytes > 0);
-
-            // memset uninitialized memory to 0xa
-            LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
-            LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
-            LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, "");
-            LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
-            ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, var->align_bytes, false);
-        }
+    } else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) {
+        uint32_t align_bytes = (var->align_bytes == 0) ? get_abi_alignment(g, var->var_type) : var->align_bytes;
+        gen_undef_init(g, align_bytes, var->var_type, var->value_ref);
     }
 
     gen_var_debug_decl(g, var);
@@ -3225,21 +3224,75 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
     return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
 }
 
-static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
-    LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
-    LLVMValueRef value = ir_llvm_value(g, instruction->value);
+static bool value_is_all_undef(ConstExprValue *const_val) {
+    switch (const_val->special) {
+        case ConstValSpecialRuntime:
+            return false;
+        case ConstValSpecialUndef:
+            return true;
+        case ConstValSpecialStatic:
+            if (const_val->type->id == ZigTypeIdStruct) {
+                for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) {
+                    if (!value_is_all_undef(&const_val->data.x_struct.fields[i]))
+                        return false;
+                }
+                return true;
+            } else if (const_val->type->id == ZigTypeIdArray) {
+                switch (const_val->data.x_array.special) {
+                    case ConstArraySpecialUndef:
+                        return true;
+                    case ConstArraySpecialBuf:
+                        return false;
+                    case ConstArraySpecialNone:
+                        for (size_t i = 0; i < const_val->type->data.array.len; i += 1) {
+                            if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i]))
+                                return false;
+                        }
+                        return true;
+                }
+                zig_unreachable();
+            } else {
+                return false;
+            }
+    }
+    zig_unreachable();
+}
 
-    assert(instruction->ptr->value.type->id == ZigTypeIdPointer);
-    ZigType *ptr_type = instruction->ptr->value.type;
+static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {
+    assert(type_has_bits(value_type));
+    uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref);
+    assert(size_bytes > 0);
+    assert(ptr_align_bytes > 0);
+    // memset uninitialized memory to 0xaa
+    LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+    LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
+    LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
+    ZigType *usize = g->builtin_types.entry_usize;
+    LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
+    ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);
+}
 
-    gen_assign_raw(g, ptr, ptr_type, value);
+static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
+    ZigType *ptr_type = instruction->ptr->value.type;
+    assert(ptr_type->id == ZigTypeIdPointer);
+    if (!type_has_bits(ptr_type))
+        return nullptr;
 
+    bool have_init_expr = !value_is_all_undef(&instruction->value->value); 
+    if (have_init_expr) {
+        LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
+        LLVMValueRef value = ir_llvm_value(g, instruction->value);
+        gen_assign_raw(g, ptr, ptr_type, value);
+    } else if (ir_want_runtime_safety(g, &instruction->base)) {
+        gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type,
+            ir_llvm_value(g, instruction->ptr)); 
+    }
     return nullptr;
 }
 
 static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
     ZigVar *var = instruction->var;
-    if (type_has_bits(var->value->type)) {
+    if (type_has_bits(var->var_type)) {
         assert(var->value_ref);
         return var->value_ref;
     } else {
@@ -3553,7 +3606,8 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
         LLVMPositionBuilderAtEnd(g->builder, ok_block);
     }
 
-    LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, "");
+    LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr,
+            union_type->data.unionation.gen_union_index, "");
     LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
     return bitcasted_union_field_ptr;
 }
@@ -3715,8 +3769,8 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR
     if (child_type->zero_bits) {
         return maybe_handle;
     } else {
-        bool maybe_is_ptr = type_is_codegen_pointer(child_type);
-        if (maybe_is_ptr) {
+        bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+        if (is_scalar) {
             return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
         } else {
             LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");
@@ -3731,17 +3785,17 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable
     return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value));
 }
 
-static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
-        IrInstructionUnwrapOptional *instruction)
+static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable,
+        IrInstructionOptionalUnwrapPtr *instruction)
 {
-    ZigType *ptr_type = instruction->value->value.type;
+    ZigType *ptr_type = instruction->base_ptr->value.type;
     assert(ptr_type->id == ZigTypeIdPointer);
     ZigType *maybe_type = ptr_type->data.pointer.child_type;
     assert(maybe_type->id == ZigTypeIdOptional);
     ZigType *child_type = maybe_type->data.maybe.child_type;
-    LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
-    LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
+    LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr);
     if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
+        LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
         LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
         LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
         LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
@@ -3755,8 +3809,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
     if (child_type->zero_bits) {
         return nullptr;
     } else {
-        bool maybe_is_ptr = type_is_codegen_pointer(child_type);
-        if (maybe_is_ptr) {
+        bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+        if (is_scalar) {
             return maybe_ptr;
         } else {
             LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
@@ -4174,7 +4228,7 @@ static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed)
     zig_unreachable();
 }
 
-static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) {
+static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchgGen *instruction) {
     LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
     LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
     LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
@@ -4189,18 +4243,18 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
     assert(maybe_type->id == ZigTypeIdOptional);
     ZigType *child_type = maybe_type->data.maybe.child_type;
 
-    if (type_is_codegen_pointer(child_type)) {
+    if (!handle_is_ptr(maybe_type)) {
         LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
         LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
         return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
     }
 
     assert(instruction->tmp_ptr != nullptr);
-    assert(type_has_bits(instruction->type));
+    assert(type_has_bits(child_type));
 
     LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
     LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
-    gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
+    gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val);
 
     LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
     LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
@@ -4351,6 +4405,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
         assert(array_type->data.structure.is_slice);
         assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
         assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
+        assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind);
 
         size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index;
         assert(ptr_index != SIZE_MAX);
@@ -4540,12 +4595,14 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
     return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");
 }
 
-static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) {
-    ZigType *ptr_type = instruction->value->value.type;
+static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable,
+        IrInstructionUnwrapErrCode *instruction)
+{
+    ZigType *ptr_type = instruction->err_union->value.type;
     assert(ptr_type->id == ZigTypeIdPointer);
     ZigType *err_union_type = ptr_type->data.pointer.child_type;
     ZigType *payload_type = err_union_type->data.error_union.payload_type;
-    LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
+    LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union);
     LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
 
     if (type_has_bits(payload_type)) {
@@ -4556,7 +4613,13 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
     }
 }
 
-static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
+static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable,
+        IrInstructionUnwrapErrPayload *instruction)
+{
+    bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on &&
+        g->errors_by_index.length > 1;
+    if (!want_safety && !type_has_bits(instruction->base.value.type))
+        return nullptr;
     ZigType *ptr_type = instruction->value->value.type;
     assert(ptr_type->id == ZigTypeIdPointer);
     ZigType *err_union_type = ptr_type->data.pointer.child_type;
@@ -4568,7 +4631,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
         return err_union_handle;
     }
 
-    if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) {
+    if (want_safety) {
         LLVMValueRef err_val;
         if (type_has_bits(payload_type)) {
             LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
@@ -4607,7 +4670,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
     }
 
     LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
-    if (type_is_codegen_pointer(child_type)) {
+    if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
         return payload_val;
     }
 
@@ -5184,12 +5247,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdToBytes:
         case IrInstructionIdEnumToInt:
         case IrInstructionIdCheckRuntimeScope:
+        case IrInstructionIdDeclVarSrc:
+        case IrInstructionIdPtrCastSrc:
+        case IrInstructionIdCmpxchgSrc:
             zig_unreachable();
 
+        case IrInstructionIdDeclVarGen:
+            return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction);
         case IrInstructionIdReturn:
             return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
-        case IrInstructionIdDeclVar:
-            return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction);
         case IrInstructionIdBinOp:
             return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction);
         case IrInstructionIdCast:
@@ -5220,8 +5286,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
         case IrInstructionIdTestNonNull:
             return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
-        case IrInstructionIdUnwrapOptional:
-            return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction);
+        case IrInstructionIdOptionalUnwrapPtr:
+            return ir_render_optional_unwrap_ptr(g, executable, (IrInstructionOptionalUnwrapPtr *)instruction);
         case IrInstructionIdClz:
             return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
         case IrInstructionIdCtz:
@@ -5236,8 +5302,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_ref(g, executable, (IrInstructionRef *)instruction);
         case IrInstructionIdErrName:
             return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction);
-        case IrInstructionIdCmpxchg:
-            return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);
+        case IrInstructionIdCmpxchgGen:
+            return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchgGen *)instruction);
         case IrInstructionIdFence:
             return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
         case IrInstructionIdTruncate:
@@ -5278,8 +5344,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
         case IrInstructionIdUnionInit:
             return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
-        case IrInstructionIdPtrCast:
-            return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
+        case IrInstructionIdPtrCastGen:
+            return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction);
         case IrInstructionIdBitCast:
             return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction);
         case IrInstructionIdWidenOrShorten:
@@ -5377,6 +5443,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
 static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
 static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
 static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
+static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
+static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
+static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val);
 
 static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
     switch (parent->id) {
@@ -5387,6 +5456,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
         case ConstParentIdStruct:
             return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val,
                     parent->data.p_struct.field_index);
+        case ConstParentIdErrUnionCode:
+            return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val);
+        case ConstParentIdErrUnionPayload:
+            return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val);
+        case ConstParentIdOptionalPayload:
+            return gen_const_ptr_optional_payload_recursive(g, parent->data.p_optional_payload.optional_val);
         case ConstParentIdArray:
             return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,
                     parent->data.p_array.elem_index);
@@ -5402,7 +5477,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
 
 static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) {
     expand_undef_array(g, array_const_val);
-    ConstParent *parent = &array_const_val->data.x_array.data.s_none.parent;
+    ConstParent *parent = &array_const_val->parent;
     LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent);
 
     LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr)));
@@ -5427,7 +5502,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
 }
 
 static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) {
-    ConstParent *parent = &struct_const_val->data.x_struct.parent;
+    ConstParent *parent = &struct_const_val->parent;
     LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent);
 
     ZigType *u32 = g->builtin_types.entry_u32;
@@ -5438,8 +5513,44 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
     return LLVMConstInBoundsGEP(base_ptr, indices, 2);
 }
 
+static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val) {
+    ConstParent *parent = &err_union_const_val->parent;
+    LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent);
+
+    ZigType *u32 = g->builtin_types.entry_u32;
+    LLVMValueRef indices[] = {
+        LLVMConstNull(u32->type_ref),
+        LLVMConstInt(u32->type_ref, err_union_err_index, false),
+    };
+    return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
+static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val) {
+    ConstParent *parent = &err_union_const_val->parent;
+    LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent);
+
+    ZigType *u32 = g->builtin_types.entry_u32;
+    LLVMValueRef indices[] = {
+        LLVMConstNull(u32->type_ref),
+        LLVMConstInt(u32->type_ref, err_union_payload_index, false),
+    };
+    return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
+static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val) {
+    ConstParent *parent = &optional_const_val->parent;
+    LLVMValueRef base_ptr = gen_parent_ptr(g, optional_const_val, parent);
+
+    ZigType *u32 = g->builtin_types.entry_u32;
+    LLVMValueRef indices[] = {
+        LLVMConstNull(u32->type_ref),
+        LLVMConstInt(u32->type_ref, maybe_child_index, false),
+    };
+    return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
 static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) {
-    ConstParent *parent = &union_const_val->data.x_union.parent;
+    ConstParent *parent = &union_const_val->parent;
     LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent);
 
     ZigType *u32 = g->builtin_types.entry_u32;
@@ -5609,6 +5720,63 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
                 render_const_val_global(g, const_val, "");
                 return ptr_val;
             }
+        case ConstPtrSpecialBaseErrorUnionCode:
+            {
+                render_const_val_global(g, const_val, name);
+                ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val;
+                assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
+                if (err_union_const_val->type->zero_bits) {
+                    // make this a null pointer
+                    ZigType *usize = g->builtin_types.entry_usize;
+                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+                            const_val->type->type_ref);
+                    render_const_val_global(g, const_val, "");
+                    return const_val->global_refs->llvm_value;
+                }
+                LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val);
+                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+                const_val->global_refs->llvm_value = ptr_val;
+                render_const_val_global(g, const_val, "");
+                return ptr_val;
+            }
+        case ConstPtrSpecialBaseErrorUnionPayload:
+            {
+                render_const_val_global(g, const_val, name);
+                ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val;
+                assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
+                if (err_union_const_val->type->zero_bits) {
+                    // make this a null pointer
+                    ZigType *usize = g->builtin_types.entry_usize;
+                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+                            const_val->type->type_ref);
+                    render_const_val_global(g, const_val, "");
+                    return const_val->global_refs->llvm_value;
+                }
+                LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val);
+                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+                const_val->global_refs->llvm_value = ptr_val;
+                render_const_val_global(g, const_val, "");
+                return ptr_val;
+            }
+        case ConstPtrSpecialBaseOptionalPayload:
+            {
+                render_const_val_global(g, const_val, name);
+                ConstExprValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val;
+                assert(optional_const_val->type->id == ZigTypeIdOptional);
+                if (optional_const_val->type->zero_bits) {
+                    // make this a null pointer
+                    ZigType *usize = g->builtin_types.entry_usize;
+                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+                            const_val->type->type_ref);
+                    render_const_val_global(g, const_val, "");
+                    return const_val->global_refs->llvm_value;
+                }
+                LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val);
+                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+                const_val->global_refs->llvm_value = ptr_val;
+                render_const_val_global(g, const_val, "");
+                return ptr_val;
+            }
         case ConstPtrSpecialHardCodedAddr:
             {
                 render_const_val_global(g, const_val, name);
@@ -5621,10 +5789,17 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
             }
         case ConstPtrSpecialFunction:
             return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
+        case ConstPtrSpecialNull:
+            return LLVMConstNull(const_val->type->type_ref);
     }
     zig_unreachable();
 }
 
+static LLVMValueRef gen_const_val_err_set(CodeGen *g, ConstExprValue *const_val, const char *name) {
+    uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value;
+    return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, value, false);
+}
+
 static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
     Error err;
 
@@ -5644,9 +5819,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
         case ZigTypeIdInt:
             return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
         case ZigTypeIdErrorSet:
-            assert(const_val->data.x_err_set != nullptr);
-            return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref,
-                    const_val->data.x_err_set->value, false);
+            return gen_const_val_err_set(g, const_val, name);
         case ZigTypeIdFloat:
             switch (type_entry->data.floating.bit_count) {
                 case 16:
@@ -5680,6 +5853,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
                 } else if (type_is_codegen_pointer(child_type)) {
                     return gen_const_val_ptr(g, const_val, name);
+                } else if (child_type->id == ZigTypeIdErrorSet) {
+                    return gen_const_val_err_set(g, const_val, name);
                 } else {
                     LLVMValueRef child_val;
                     LLVMValueRef maybe_val;
@@ -5914,7 +6089,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                 ZigType *err_set_type = type_entry->data.error_union.err_set_type;
                 if (!type_has_bits(payload_type)) {
                     assert(type_has_bits(err_set_type));
-                    uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
+                    ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+                    uint64_t value = (err_set == nullptr) ? 0 : err_set->value;
                     return LLVMConstInt(g->err_tag_type->type_ref, value, false);
                 } else if (!type_has_bits(err_set_type)) {
                     assert(type_has_bits(payload_type));
@@ -5923,8 +6099,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     LLVMValueRef err_tag_value;
                     LLVMValueRef err_payload_value;
                     bool make_unnamed_struct;
-                    if (const_val->data.x_err_union.err) {
-                        err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);
+                    ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+                    if (err_set != nullptr) {
+                        err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false);
                         err_payload_value = LLVMConstNull(payload_type->type_ref);
                         make_unnamed_struct = false;
                     } else {
@@ -6130,10 +6307,13 @@ static void do_code_gen(CodeGen *g) {
         TldVar *tld_var = g->global_vars.at(i);
         ZigVar *var = tld_var->var;
 
-        if (var->value->type->id == ZigTypeIdComptimeFloat) {
+        if (var->var_type->id == ZigTypeIdComptimeFloat) {
             // Generate debug info for it but that's it.
-            ConstExprValue *const_val = var->value;
+            ConstExprValue *const_val = var->const_value;
             assert(const_val->special != ConstValSpecialRuntime);
+            if (const_val->type != var->var_type) {
+                zig_panic("TODO debug info for var with ptr casted value");
+            }
             ZigType *var_type = g->builtin_types.entry_f128;
             ConstExprValue coerced_value;
             coerced_value.special = ConstValSpecialStatic;
@@ -6144,10 +6324,13 @@ static void do_code_gen(CodeGen *g) {
             continue;
         }
 
-        if (var->value->type->id == ZigTypeIdComptimeInt) {
+        if (var->var_type->id == ZigTypeIdComptimeInt) {
             // Generate debug info for it but that's it.
-            ConstExprValue *const_val = var->value;
+            ConstExprValue *const_val = var->const_value;
             assert(const_val->special != ConstValSpecialRuntime);
+            if (const_val->type != var->var_type) {
+                zig_panic("TODO debug info for var with ptr casted value");
+            }
             size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint);
             if (bits_needed < 8) {
                 bits_needed = 8;
@@ -6158,7 +6341,7 @@ static void do_code_gen(CodeGen *g) {
             continue;
         }
 
-        if (!type_has_bits(var->value->type))
+        if (!type_has_bits(var->var_type))
             continue;
 
         assert(var->decl_node);
@@ -6167,9 +6350,9 @@ static void do_code_gen(CodeGen *g) {
         if (var->linkage == VarLinkageExternal) {
             LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name));
             if (existing_llvm_var) {
-                global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->value->type->type_ref, 0));
+                global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->var_type->type_ref, 0));
             } else {
-                global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name));
+                global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name));
                 // TODO debug info for the extern variable
 
                 LLVMSetLinkage(global_value, LLVMExternalLinkage);
@@ -6180,9 +6363,9 @@ static void do_code_gen(CodeGen *g) {
         } else {
             bool exported = (var->linkage == VarLinkageExport);
             const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));
-            render_const_val(g, var->value, mangled_name);
-            render_const_val_global(g, var->value, mangled_name);
-            global_value = var->value->global_refs->llvm_global;
+            render_const_val(g, var->const_value, mangled_name);
+            render_const_val_global(g, var->const_value, mangled_name);
+            global_value = var->const_value->global_refs->llvm_global;
 
             if (exported) {
                 LLVMSetLinkage(global_value, LLVMExternalLinkage);
@@ -6194,8 +6377,10 @@ static void do_code_gen(CodeGen *g) {
             LLVMSetAlignment(global_value, var->align_bytes);
 
             // TODO debug info for function pointers
-            if (var->gen_is_const && var->value->type->id != ZigTypeIdFn) {
-                gen_global_var(g, var, var->value->global_refs->llvm_value, var->value->type);
+            // Here we use const_value->type because that's the type of the llvm global,
+            // which we const ptr cast upon use to whatever it needs to be.
+            if (var->gen_is_const && var->const_value->type->id != ZigTypeIdFn) {
+                gen_global_var(g, var, var->const_value->global_refs->llvm_value, var->const_value->type);
             }
 
             LLVMSetGlobalConstant(global_value, var->gen_is_const);
@@ -6281,8 +6466,8 @@ 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 == IrInstructionIdCmpxchg) {
-                IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction;
+            } else if (instruction->id == IrInstructionIdCmpxchgGen) {
+                IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction;
                 slot = &cmpxchg_instruction->tmp_ptr;
             } else {
                 zig_unreachable();
@@ -6304,12 +6489,12 @@ static void do_code_gen(CodeGen *g) {
         for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
             ZigVar *var = fn_table_entry->variable_list.at(var_i);
 
-            if (!type_has_bits(var->value->type)) {
+            if (!type_has_bits(var->var_type)) {
                 continue;
             }
             if (ir_get_var_is_comptime(var))
                 continue;
-            switch (type_requires_comptime(g, var->value->type)) {
+            switch (type_requires_comptime(g, var->var_type)) {
                 case ReqCompTimeInvalid:
                     zig_unreachable();
                 case ReqCompTimeYes:
@@ -6319,11 +6504,11 @@ static void do_code_gen(CodeGen *g) {
             }
 
             if (var->src_arg_index == SIZE_MAX) {
-                var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
+                var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
 
                 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
                         buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
-                        var->value->type->di_type, !g->strip_debug_symbols, 0);
+                        var->var_type->di_type, !g->strip_debug_symbols, 0);
 
             } else if (is_c_abi) {
                 fn_walk_var.data.vars.var = var;
@@ -6333,16 +6518,16 @@ static void do_code_gen(CodeGen *g) {
                 ZigType *gen_type;
                 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
 
-                if (handle_is_ptr(var->value->type)) {
+                if (handle_is_ptr(var->var_type)) {
                     if (gen_info->is_byval) {
-                        gen_type = var->value->type;
+                        gen_type = var->var_type;
                     } else {
                         gen_type = gen_info->type;
                     }
                     var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index);
                 } else {
-                    gen_type = var->value->type;
-                    var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
+                    gen_type = var->var_type;
+                    var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
                 }
                 if (var->decl_node) {
                     var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
@@ -7458,9 +7643,9 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
         ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i];
         this_val->special = ConstValSpecialStatic;
         this_val->type = struct_type;
-        this_val->data.x_struct.parent.id = ConstParentIdArray;
-        this_val->data.x_struct.parent.data.p_array.array_val = test_fn_array;
-        this_val->data.x_struct.parent.data.p_array.elem_index = i;
+        this_val->parent.id = ConstParentIdArray;
+        this_val->parent.data.p_array.array_val = test_fn_array;
+        this_val->parent.data.p_array.elem_index = i;
         this_val->data.x_struct.fields = create_const_vals(2);
 
         ConstExprValue *name_field = &this_val->data.x_struct.fields[0];
src/ir.cpp
@@ -167,6 +167,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
         ZigType *dest_type, IrInstruction *dest_type_src);
 static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed);
 static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs);
+static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align);
 
 static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
     assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -178,15 +179,28 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
         case ConstPtrSpecialRef:
             result = const_val->data.x_ptr.data.ref.pointee;
             break;
-        case ConstPtrSpecialBaseArray:
-            expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val);
-            result = &const_val->data.x_ptr.data.base_array.array_val->data.x_array.data.s_none.elements[
-                const_val->data.x_ptr.data.base_array.elem_index];
+        case ConstPtrSpecialBaseArray: {
+            ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
+            expand_undef_array(g, array_val);
+            result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];
             break;
+        }
         case ConstPtrSpecialBaseStruct:
             result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[
                 const_val->data.x_ptr.data.base_struct.field_index];
             break;
+        case ConstPtrSpecialBaseErrorUnionCode:
+            result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set;
+            break;
+        case ConstPtrSpecialBaseErrorUnionPayload:
+            result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload;
+            break;
+        case ConstPtrSpecialBaseOptionalPayload:
+            result = const_val->data.x_ptr.data.base_optional_payload.optional_val->data.x_optional;
+            break;
+        case ConstPtrSpecialNull:
+            result = const_val;
+            break;
         case ConstPtrSpecialHardCodedAddr:
             zig_unreachable();
         case ConstPtrSpecialDiscard:
@@ -198,6 +212,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
     return result;
 }
 
+static bool is_opt_err_set(ZigType *ty) {
+    return ty->id == ZigTypeIdErrorSet ||
+        (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet);
+}
+
 static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
     if (a == b)
         return true;
@@ -208,15 +227,10 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
     if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr)
         return true;
 
-    return false;
-}
+    if (is_opt_err_set(a) && is_opt_err_set(b))
+        return true;
 
-ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
-    ConstExprValue *result = const_ptr_pointee_unchecked(g, const_val);
-    if (const_val->type->id == ZigTypeIdPointer) {
-        assert(types_have_same_zig_comptime_repr(const_val->type->data.pointer.child_type, result->type));
-    }
-    return result;
+    return false;
 }
 
 static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
@@ -305,6 +319,14 @@ static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) {
     return new_bb;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarSrc *) {
+    return IrInstructionIdDeclVarSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarGen *) {
+    return IrInstructionIdDeclVarGen;
+}
+
 static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) {
     return IrInstructionIdCondBr;
 }
@@ -337,10 +359,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) {
     return IrInstructionIdBinOp;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) {
-    return IrInstructionIdDeclVar;
-}
-
 static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) {
     return IrInstructionIdExport;
 }
@@ -449,8 +467,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) {
     return IrInstructionIdTestNonNull;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) {
-    return IrInstructionIdUnwrapOptional;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalUnwrapPtr *) {
+    return IrInstructionIdOptionalUnwrapPtr;
 }
 
 static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) {
@@ -517,8 +535,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) {
     return IrInstructionIdEmbedFile;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) {
-    return IrInstructionIdCmpxchg;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgSrc *) {
+    return IrInstructionIdCmpxchgSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgGen *) {
+    return IrInstructionIdCmpxchgGen;
 }
 
 static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {
@@ -649,8 +671,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *)
     return IrInstructionIdTestComptime;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) {
-    return IrInstructionIdPtrCast;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastSrc *) {
+    return IrInstructionIdPtrCastSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) {
+    return IrInstructionIdPtrCastGen;
 }
 
 static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
@@ -915,7 +941,7 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
     ir_ref_instruction(condition, irb->current_basic_block);
     ir_ref_bb(then_block);
     ir_ref_bb(else_block);
-    if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block);
+    if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block);
 
     return &cond_br_instruction->base;
 }
@@ -931,16 +957,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou
     return &return_instruction->base;
 }
 
-static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node,
-    ZigType *type_entry)
-{
-    assert(type_entry);
-    IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.value.type = type_entry;
-    const_instruction->base.value.special = ConstValSpecialStatic;
-    return &const_instruction->base;
-}
-
 static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
     const_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
@@ -1188,14 +1204,11 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
     call_instruction->async_allocator = async_allocator;
     call_instruction->new_stack = new_stack;
 
-    if (fn_ref)
-        ir_ref_instruction(fn_ref, irb->current_basic_block);
+    if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);
     for (size_t i = 0; i < arg_count; i += 1)
         ir_ref_instruction(args[i], irb->current_basic_block);
-    if (async_allocator)
-        ir_ref_instruction(async_allocator, irb->current_basic_block);
-    if (new_stack != nullptr)
-        ir_ref_instruction(new_stack, irb->current_basic_block);
+    if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block);
+    if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
 
     return &call_instruction->base;
 }
@@ -1280,7 +1293,7 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope,
     container_init_list_instruction->item_count = item_count;
     container_init_list_instruction->items = items;
 
-    ir_ref_instruction(container_type, irb->current_basic_block);
+    if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block);
     for (size_t i = 0; i < item_count; i += 1) {
         ir_ref_instruction(items[i], irb->current_basic_block);
     }
@@ -1355,10 +1368,10 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
     return &instruction->base;
 }
 
-static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
         ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value)
 {
-    IrInstructionDeclVar *decl_var_instruction = ir_build_instruction<IrInstructionDeclVar>(irb, scope, source_node);
+    IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction<IrInstructionDeclVarSrc>(irb, scope, source_node);
     decl_var_instruction->base.value.special = ConstValSpecialStatic;
     decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
     decl_var_instruction->var = var;
@@ -1366,13 +1379,28 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s
     decl_var_instruction->align_value = align_value;
     decl_var_instruction->init_value = init_value;
 
-    if (var_type) ir_ref_instruction(var_type, irb->current_basic_block);
-    if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
+    if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block);
+    if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
     ir_ref_instruction(init_value, irb->current_basic_block);
 
     return &decl_var_instruction->base;
 }
 
+static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+        ZigVar *var, IrInstruction *init_value)
+{
+    IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction<IrInstructionDeclVarGen>(&ira->new_irb,
+            source_instruction->scope, source_instruction->source_node);
+    decl_var_instruction->base.value.special = ConstValSpecialStatic;
+    decl_var_instruction->base.value.type = ira->codegen->builtin_types.entry_void;
+    decl_var_instruction->var = var;
+    decl_var_instruction->init_value = init_value;
+
+    ir_ref_instruction(init_value, ira->new_irb.current_basic_block);
+
+    return &decl_var_instruction->base;
+}
+
 static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node,
         IrInstruction *name, IrInstruction *target, IrInstruction *linkage)
 {
@@ -1542,14 +1570,14 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod
     return &instruction->base;
 }
 
-static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value,
-        bool safety_check_on)
+static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
+        IrInstruction *base_ptr, bool safety_check_on)
 {
-    IrInstructionUnwrapOptional *instruction = ir_build_instruction<IrInstructionUnwrapOptional>(irb, scope, source_node);
-    instruction->value = value;
+    IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction<IrInstructionOptionalUnwrapPtr>(irb, scope, source_node);
+    instruction->base_ptr = base_ptr;
     instruction->safety_check_on = safety_check_on;
 
-    ir_ref_instruction(value, irb->current_basic_block);
+    ir_ref_instruction(base_ptr, irb->current_basic_block);
 
     return &instruction->base;
 }
@@ -1765,13 +1793,12 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
     return &instruction->base;
 }
 
-static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value,
-    IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
+static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+    IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
     IrInstruction *success_order_value, IrInstruction *failure_order_value,
-    bool is_weak,
-    ZigType *type, AtomicOrder success_order, AtomicOrder failure_order)
+    bool is_weak)
 {
-    IrInstructionCmpxchg *instruction = ir_build_instruction<IrInstructionCmpxchg>(irb, scope, source_node);
+    IrInstructionCmpxchgSrc *instruction = ir_build_instruction<IrInstructionCmpxchgSrc>(irb, scope, source_node);
     instruction->type_value = type_value;
     instruction->ptr = ptr;
     instruction->cmp_value = cmp_value;
@@ -1779,16 +1806,33 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so
     instruction->success_order_value = success_order_value;
     instruction->failure_order_value = failure_order_value;
     instruction->is_weak = is_weak;
-    instruction->type = type;
-    instruction->success_order = success_order;
-    instruction->failure_order = failure_order;
 
-    if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block);
+    ir_ref_instruction(type_value, irb->current_basic_block);
     ir_ref_instruction(ptr, irb->current_basic_block);
     ir_ref_instruction(cmp_value, irb->current_basic_block);
     ir_ref_instruction(new_value, irb->current_basic_block);
-    if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block);
-    if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block);
+    ir_ref_instruction(success_order_value, irb->current_basic_block);
+    ir_ref_instruction(failure_order_value, irb->current_basic_block);
+
+    return &instruction->base;
+}
+
+static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+    IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
+    AtomicOrder success_order, AtomicOrder failure_order, bool is_weak)
+{
+    IrInstructionCmpxchgGen *instruction = ir_build_instruction<IrInstructionCmpxchgGen>(&ira->new_irb,
+            source_instruction->scope, source_instruction->source_node);
+    instruction->ptr = ptr;
+    instruction->cmp_value = cmp_value;
+    instruction->new_value = new_value;
+    instruction->success_order = success_order;
+    instruction->failure_order = failure_order;
+    instruction->is_weak = is_weak;
+
+    ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
+    ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block);
+    ir_ref_instruction(new_value, ira->new_irb.current_basic_block);
 
     return &instruction->base;
 }
@@ -2060,12 +2104,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s
 }
 
 static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node,
-    IrInstruction *value)
+    IrInstruction *err_union)
 {
     IrInstructionUnwrapErrCode *instruction = ir_build_instruction<IrInstructionUnwrapErrCode>(irb, scope, source_node);
-    instruction->value = value;
+    instruction->err_union = err_union;
 
-    ir_ref_instruction(value, irb->current_basic_block);
+    ir_ref_instruction(err_union, irb->current_basic_block);
 
     return &instruction->base;
 }
@@ -2115,20 +2159,33 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo
     return &instruction->base;
 }
 
-static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
         IrInstruction *dest_type, IrInstruction *ptr)
 {
-    IrInstructionPtrCast *instruction = ir_build_instruction<IrInstructionPtrCast>(
+    IrInstructionPtrCastSrc *instruction = ir_build_instruction<IrInstructionPtrCastSrc>(
             irb, scope, source_node);
     instruction->dest_type = dest_type;
     instruction->ptr = ptr;
 
-    if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
+    ir_ref_instruction(dest_type, irb->current_basic_block);
     ir_ref_instruction(ptr, irb->current_basic_block);
 
     return &instruction->base;
 }
 
+static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+        ZigType *ptr_type, IrInstruction *ptr)
+{
+    IrInstructionPtrCastGen *instruction = ir_build_instruction<IrInstructionPtrCastGen>(
+            &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+    instruction->base.value.type = ptr_type;
+    instruction->ptr = ptr;
+
+    ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
+
+    return &instruction->base;
+}
+
 static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
         IrInstruction *dest_type, IrInstruction *value)
 {
@@ -2807,10 +2864,13 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
                     Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
                     IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
                     if (defer_expr_value != irb->codegen->invalid_instruction) {
-                        if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == ZigTypeIdUnreachable) {
+                        if (defer_expr_value->value.type != nullptr &&
+                                defer_expr_value->value.type->id == ZigTypeIdUnreachable)
+                        {
                             is_noreturn = true;
                         } else {
-                            ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
+                            ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node,
+                                        defer_expr_value));
                         }
                     }
                 }
@@ -3065,7 +3125,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
     variable_entry->mem_slot_index = SIZE_MAX;
     variable_entry->is_comptime = is_comptime;
     variable_entry->src_arg_index = SIZE_MAX;
-    variable_entry->value = create_const_vals(1);
+    variable_entry->const_value = create_const_vals(1);
 
     if (is_comptime != nullptr) {
         is_comptime->ref_count += 1;
@@ -3080,20 +3140,20 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
                 ErrorMsg *msg = add_node_error(codegen, node,
                         buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
                 add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
-                variable_entry->value->type = codegen->builtin_types.entry_invalid;
+                variable_entry->var_type = codegen->builtin_types.entry_invalid;
             } else {
                 ZigType *type;
                 if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) {
                     add_node_error(codegen, node,
                             buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
-                    variable_entry->value->type = codegen->builtin_types.entry_invalid;
+                    variable_entry->var_type = codegen->builtin_types.entry_invalid;
                 } else {
                     Tld *tld = find_decl(codegen, parent_scope, name);
                     if (tld != nullptr) {
                         ErrorMsg *msg = add_node_error(codegen, node,
                                 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
                         add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
-                        variable_entry->value->type = codegen->builtin_types.entry_invalid;
+                        variable_entry->var_type = codegen->builtin_types.entry_invalid;
                     }
                 }
             }
@@ -3156,7 +3216,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
         scope_block->incoming_blocks = &incoming_blocks;
         scope_block->incoming_values = &incoming_values;
         scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd");
-        scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope));
+        scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node,
+                ir_should_inline(irb->exec, parent_scope));
     }
 
     bool is_continuation_unreachable = false;
@@ -3174,9 +3235,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
             // defer starts a new scope
             child_scope = statement_node->data.defer.child_scope;
             assert(child_scope);
-        } else if (statement_value->id == IrInstructionIdDeclVar) {
+        } else if (statement_value->id == IrInstructionIdDeclVarSrc) {
             // variable declarations start a new scope
-            IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
+            IrInstructionDeclVarSrc *decl_var_instruction = (IrInstructionDeclVarSrc *)statement_value;
             child_scope = decl_var_instruction->var->child_scope;
         } else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) {
             // this statement's value must be void
@@ -3331,7 +3392,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
     return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
 }
 
-static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
     assert(node->type == NodeTypeBinOpExpr);
 
     AstNode *op1_node = node->data.bin_op_expr.op1;
@@ -3365,7 +3426,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
         ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime));
 
     ir_set_cursor_at_end_and_append_block(irb, ok_block);
-    IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false);
+    IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false);
     IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
     IrBasicBlock *after_ok_block = irb->current_basic_block;
     ir_build_br(irb, parent_scope, node, end_block, is_comptime);
@@ -3483,7 +3544,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
         case BinOpTypeMergeErrorSets:
             return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
         case BinOpTypeUnwrapOptional:
-            return ir_gen_maybe_ok_or(irb, scope, node);
+            return ir_gen_orelse(irb, scope, node);
         case BinOpTypeErrorUnion:
             return ir_gen_error_union(irb, scope, node);
     }
@@ -3542,6 +3603,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
                     buf_ptr(variable_name)));
             return irb->codegen->invalid_instruction;
         }
+        assert(err == ErrorPrimitiveTypeNotFound);
     } else {
         IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type);
         if (lval == LValPtr) {
@@ -3904,9 +3966,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
                 if (arg5_value == irb->codegen->invalid_instruction)
                     return arg5_value;
 
-                IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
-                    arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
-                    nullptr, AtomicOrderUnordered, AtomicOrderUnordered);
+                IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value,
+                    arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak));
                 return ir_lval_wrap(irb, scope, cmpxchg, lval);
             }
         case BuiltinFnIdFence:
@@ -4346,7 +4407,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
                 if (arg1_value == irb->codegen->invalid_instruction)
                     return arg1_value;
 
-                IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
+                IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value);
                 return ir_lval_wrap(irb, scope, ptr_cast, lval);
             }
         case BuiltinFnIdBitCast:
@@ -4784,7 +4845,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
         }
     }
 
-    IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
+    IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
+            is_async, async_allocator, nullptr);
     return ir_lval_wrap(irb, scope, fn_call, lval);
 }
 
@@ -4793,7 +4855,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
 
     IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope);
     if (condition == irb->codegen->invalid_instruction)
-        return condition;
+        return irb->codegen->invalid_instruction;
 
     IrInstruction *is_comptime;
     if (ir_should_inline(irb->exec, scope)) {
@@ -4816,7 +4878,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
     Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
     IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope);
     if (then_expr_result == irb->codegen->invalid_instruction)
-        return then_expr_result;
+        return irb->codegen->invalid_instruction;
     IrBasicBlock *after_then_block = irb->current_basic_block;
     if (!instr_is_unreachable(then_expr_result))
         ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -4826,7 +4888,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
     if (else_node) {
         else_expr_result = ir_gen_node(irb, else_node, subexpr_scope);
         if (else_expr_result == irb->codegen->invalid_instruction)
-            return else_expr_result;
+            return irb->codegen->invalid_instruction;
     } else {
         else_expr_result = ir_build_const_void(irb, scope, node);
     }
@@ -4927,7 +4989,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
             ptr_len, align_value, bit_offset_start, host_int_bytes);
 }
 
-static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
+static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
         LVal lval)
 {
     IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
@@ -5053,11 +5115,11 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
         ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime);
     ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol,
         is_const, is_const, is_shadowable, is_comptime);
-    // we detect IrInstructionIdDeclVar in gen_block to make sure the next node
+    // we detect IrInstructionIdDeclVarSrc in gen_block to make sure the next node
     // is inside var->child_scope
 
     if (!is_extern && !variable_declaration->expr) {
-        var->value->type = irb->codegen->builtin_types.entry_invalid;
+        var->var_type = irb->codegen->builtin_types.entry_invalid;
         add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized"));
         return irb->codegen->invalid_instruction;
     }
@@ -5084,7 +5146,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
     if (init_value == irb->codegen->invalid_instruction)
         return init_value;
 
-    return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value);
+    return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, init_value);
 }
 
 static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -5140,7 +5202,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
                     err_val_ptr, false);
             IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
                 var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);
-            ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+            ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
         }
 
         ZigList<IrInstruction *> incoming_values = {0};
@@ -5180,7 +5242,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
                 true, false, false, is_comptime);
         Scope *err_scope = err_var->child_scope;
         IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
-        ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
+        ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
 
         IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope);
         if (else_result == irb->codegen->invalid_instruction)
@@ -5220,10 +5282,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
         }
 
         ir_set_cursor_at_end_and_append_block(irb, body_block);
-        IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
+        IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false);
         IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
             var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);
-        ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+        ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
 
         ZigList<IrInstruction *> incoming_values = {0};
         ZigList<IrBasicBlock *> incoming_blocks = {0};
@@ -5380,7 +5442,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
     Scope *child_scope = elem_var->child_scope;
 
     IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node);
-    ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value);
+    ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value);
     IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var);
 
     AstNode *index_var_source_node;
@@ -5398,7 +5460,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
     IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize);
     IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
     IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
-    ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero);
+    ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero);
     IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var);
 
 
@@ -5622,8 +5684,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
     return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile);
 }
 
-static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
-    assert(node->type == NodeTypeTestExpr);
+static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+    assert(node->type == NodeTypeIfOptional);
 
     Buf *var_symbol = node->data.test_expr.var_symbol;
     AstNode *expr_node = node->data.test_expr.target_node;
@@ -5661,9 +5723,9 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
         ZigVar *var = ir_create_var(irb, node, subexpr_scope,
                 var_symbol, is_const, is_const, is_shadowable, is_comptime);
 
-        IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
+        IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false);
         IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
-        ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+        ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
         var_scope = var->child_scope;
     } else {
         var_scope = subexpr_scope;
@@ -5738,7 +5800,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
 
         IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false);
         IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
-        ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+        ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
         var_scope = var->child_scope;
     } else {
         var_scope = subexpr_scope;
@@ -5763,7 +5825,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
                     err_symbol, is_const, is_const, is_shadowable, is_comptime);
 
             IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr);
-            ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+            ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
             err_var_scope = var->child_scope;
         } else {
             err_var_scope = subexpr_scope;
@@ -5818,7 +5880,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
             var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
         }
         IrInstruction *var_type = nullptr; // infer the type
-        ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value);
+        ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_value);
     } else {
         child_scope = scope;
     }
@@ -6228,7 +6290,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)
     return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true);
 }
 
-static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
     assert(node->type == NodeTypeUnwrapErrorExpr);
 
     AstNode *op1_node = node->data.unwrap_err_expr.op1;
@@ -6242,7 +6304,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
             add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name)));
             return irb->codegen->invalid_instruction;
         }
-        return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone);
+        return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, LValNone);
     }
 
 
@@ -6276,7 +6338,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
             is_const, is_const, is_shadowable, is_comptime);
         err_scope = var->child_scope;
         IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
-        ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
+        ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
     } else {
         err_scope = parent_scope;
     }
@@ -6312,7 +6374,8 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
     ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope;
     if (need_comma)
         buf_append_char(name, ',');
-    render_const_value(codegen, name, var_scope->var->value);
+    // TODO: const ptr reinterpret here to make the var type agree with the value?
+    render_const_value(codegen, name, var_scope->var->const_value);
     return true;
 }
 
@@ -6562,7 +6625,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
     IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
 
     // TODO relies on Zig not re-ordering fields
-    IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
+    IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
     IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
     Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
     IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
@@ -6640,7 +6703,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
             get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
 
     // TODO relies on Zig not re-ordering fields
-    IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
+    IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
     IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
     Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
     IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
@@ -6756,7 +6819,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
     IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
     IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
     ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
-    ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value);
+    ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value);
     IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var);
     ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr);
     IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
@@ -7050,7 +7113,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
             if (maybe_ptr == irb->codegen->invalid_instruction)
                 return irb->codegen->invalid_instruction;
 
-            IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
+            IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true);
             if (lval == LValPtr)
                 return unwrapped_ptr;
 
@@ -7074,8 +7137,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
             return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval);
         case NodeTypeIfErrorExpr:
             return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval);
-        case NodeTypeTestExpr:
-            return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval);
+        case NodeTypeIfOptional:
+            return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval);
         case NodeTypeSwitchExpr:
             return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval);
         case NodeTypeCompTime:
@@ -7093,7 +7156,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
         case NodeTypeSliceExpr:
             return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval);
         case NodeTypeUnwrapErrorExpr:
-            return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval);
+            return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval);
         case NodeTypeContainerDecl:
             return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
         case NodeTypeFnProto:
@@ -7152,6 +7215,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
     ir_ref_bb(irb->current_basic_block);
 
     ZigFn *fn_entry = exec_fn_entry(irb->exec);
+
     bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
     IrInstruction *coro_id;
     IrInstruction *u8_ptr_type;
@@ -7172,27 +7236,27 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
         ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
         IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
         // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
-        ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
+        ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
         coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var);
 
         ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
         IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
         IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
                 get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
-        ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
+        ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
         irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
 
         u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
                 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
-        IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
+        IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
         coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
         coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
         IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
-        ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
+        ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
         IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
                 ImplicitAllocatorIdArg);
         irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
-        ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
+        ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
         Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
         IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
         IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
@@ -7208,7 +7272,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
         ir_build_return(irb, coro_scope, node, undef);
 
         ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
-        IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
+        IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
         irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
 
         Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
@@ -7286,8 +7350,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
                     get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
                         false, false, PtrLenUnknown, 0, 0, 0));
             IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
-            IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
-            IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
+            IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
+            IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
                     irb->exec->coro_result_field_ptr);
             IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
                     fn_entry->type_entry->data.fn.fn_type_id.return_type);
@@ -7303,7 +7367,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
         // Before we destroy the coroutine frame, we need to load the target promise into
         // a register or local variable which does not get spilled into the frame,
         // otherwise llvm tries to access memory inside the destroyed frame.
-        IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
+        IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node,
                 irb->exec->await_handle_var_ptr, false);
         IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
         ir_build_br(irb, scope, node, check_free_block, const_bool_false);
@@ -7338,7 +7402,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
         IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
                 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
                     false, false, PtrLenUnknown, 0, 0, 0));
-        IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
+        IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
         IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
         IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
         IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
@@ -7435,7 +7499,7 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
     return val;
 }
 
-static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) {
+static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) {
     IrBasicBlock *bb = exec->basic_block_list.at(0);
     for (size_t i = 0; i < bb->instruction_list.length; i += 1) {
         IrInstruction *instruction = bb->instruction_list.at(i);
@@ -7445,16 +7509,16 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec)
             if (value->value.special == ConstValSpecialRuntime) {
                 exec_add_error_node(codegen, exec, value->source_node,
                         buf_sprintf("unable to evaluate constant expression"));
-                return codegen->invalid_instruction;
+                return &codegen->invalid_instruction->value;
             }
-            return value;
+            return &value->value;
         } else if (ir_has_side_effects(instruction)) {
             exec_add_error_node(codegen, exec, instruction->source_node,
                     buf_sprintf("unable to evaluate constant expression"));
-            return codegen->invalid_instruction;
+            return &codegen->invalid_instruction->value;
         }
     }
-    return codegen->invalid_instruction;
+    return &codegen->invalid_instruction->value;
 }
 
 static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) {
@@ -8768,13 +8832,13 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
     size_t errors_count = 0;
     ZigType *err_set_type = nullptr;
     if (prev_inst->value.type->id == ZigTypeIdErrorSet) {
+        if (!resolve_inferred_error_set(ira->codegen, prev_inst->value.type, prev_inst->source_node)) {
+            return ira->codegen->builtin_types.entry_invalid;
+        }
         if (type_is_global_error_set(prev_inst->value.type)) {
             err_set_type = ira->codegen->builtin_types.entry_global_error_set;
         } else {
             err_set_type = prev_inst->value.type;
-            if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) {
-                return ira->codegen->builtin_types.entry_invalid;
-            }
             update_errors_helper(ira->codegen, &errors, &errors_count);
 
             for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
@@ -8933,6 +8997,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
             if (prev_type->id == ZigTypeIdArray) {
                 convert_to_const_slice = true;
             }
+            if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
+                return ira->codegen->builtin_types.entry_invalid;
+            }
             if (type_is_global_error_set(cur_type)) {
                 err_set_type = ira->codegen->builtin_types.entry_global_error_set;
                 continue;
@@ -8940,9 +9007,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
             if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) {
                 continue;
             }
-            if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
-                return ira->codegen->builtin_types.entry_invalid;
-            }
 
             update_errors_helper(ira->codegen, &errors, &errors_count);
 
@@ -9432,14 +9496,23 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
     }
     return true;
 }
+
+static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) {
+    IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
+            old_instruction->scope, old_instruction->source_node);
+    IrInstruction *new_instruction = &const_instruction->base;
+    new_instruction->value.type = ty;
+    new_instruction->value.special = ConstValSpecialStatic;
+    return new_instruction;
+}
+
 static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
         ZigType *wanted_type, CastOp cast_op, bool need_alloca)
 {
     if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) &&
         cast_op != CastOpResizeSlice)
     {
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type,
             &result->value, wanted_type))
         {
@@ -9476,9 +9549,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
         if (pointee == nullptr)
             return ira->codegen->invalid_instruction;
         if (pointee->special != ConstValSpecialRuntime) {
-            IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                    source_instr->source_node, wanted_type);
-            result->value.type = wanted_type;
+            IrInstruction *result = ir_const(ira, source_instr, wanted_type);
             result->value.data.x_ptr.special = ConstPtrSpecialBaseArray;
             result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
             result->value.data.x_ptr.data.base_array.array_val = pointee;
@@ -9517,8 +9588,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
             assert(is_slice(wanted_type));
             bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
 
-            IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                    source_instr->source_node, wanted_type);
+            IrInstruction *result = ir_const(ira, source_instr, wanted_type);
             init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
             result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut =
                 value->value.data.x_ptr.mut;
@@ -9653,15 +9723,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction)
     return instruction;
 }
 
-static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) {
-    IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
-            old_instruction->scope, old_instruction->source_node);
-    IrInstruction *new_instruction = &const_instruction->base;
-    new_instruction->value.type = ty;
-    new_instruction->value.special = ConstValSpecialStatic;
-    return new_instruction;
-}
-
 static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) {
     IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type);
     result->value.data.x_type = ty;
@@ -9719,13 +9780,13 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un
     zig_unreachable();
 }
 
-IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
+ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
         ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
         ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
         IrExecutable *parent_exec)
 {
     if (expected_type != nullptr && type_is_invalid(expected_type))
-        return codegen->invalid_instruction;
+        return &codegen->invalid_instruction->value;
 
     IrExecutable *ir_executable = allocate<IrExecutable>(1);
     ir_executable->source_node = source_node;
@@ -9738,13 +9799,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
     ir_gen(codegen, node, scope, ir_executable);
 
     if (ir_executable->invalid)
-        return codegen->invalid_instruction;
+        return &codegen->invalid_instruction->value;
 
     if (codegen->verbose_ir) {
         fprintf(stderr, "\nSource: ");
         ast_render(codegen, stderr, node, 4);
         fprintf(stderr, "\n{ // (IR)\n");
-        ir_print(codegen, stderr, ir_executable, 4);
+        ir_print(codegen, stderr, ir_executable, 2);
         fprintf(stderr, "}\n");
     }
     IrExecutable *analyzed_executable = allocate<IrExecutable>(1);
@@ -9760,11 +9821,11 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
     analyzed_executable->begin_scope = scope;
     ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node);
     if (type_is_invalid(result_type))
-        return codegen->invalid_instruction;
+        return &codegen->invalid_instruction->value;
 
     if (codegen->verbose_ir) {
         fprintf(stderr, "{ // (analyzed)\n");
-        ir_print(codegen, stderr, analyzed_executable, 4);
+        ir_print(codegen, stderr, analyzed_executable, 2);
         fprintf(stderr, "}\n");
     }
 
@@ -9838,7 +9899,9 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
     return const_val->data.x_ptr.data.fn.fn_entry;
 }
 
-static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) {
+static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+        ZigType *wanted_type)
+{
     assert(wanted_type->id == ZigTypeIdOptional);
 
     if (instr_is_comptime(value)) {
@@ -9854,7 +9917,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
                 source_instr->scope, source_instr->source_node);
         const_instruction->base.value.special = ConstValSpecialStatic;
-        if (get_codegen_ptr_type(wanted_type) != nullptr) {
+        if (types_have_same_zig_comptime_repr(wanted_type, payload_type)) {
             copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst);
         } else {
             const_instruction->base.value.data.x_optional = val;
@@ -9885,11 +9948,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
         if (!val)
             return ira->codegen->invalid_instruction;
 
+        ConstExprValue *err_set_val = create_const_vals(1);
+        err_set_val->type = wanted_type->data.error_union.err_set_type;
+        err_set_val->special = ConstValSpecialStatic;
+        err_set_val->data.x_err_set = nullptr;
+
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
                 source_instr->scope, source_instr->source_node);
         const_instruction->base.value.type = wanted_type;
         const_instruction->base.value.special = ConstValSpecialStatic;
-        const_instruction->base.value.data.x_err_union.err = nullptr;
+        const_instruction->base.value.data.x_err_union.error_set = err_set_val;
         const_instruction->base.value.data.x_err_union.payload = val;
         return &const_instruction->base;
     }
@@ -9954,11 +10022,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
         if (!val)
             return ira->codegen->invalid_instruction;
 
+        ConstExprValue *err_set_val = create_const_vals(1);
+        err_set_val->special = ConstValSpecialStatic;
+        err_set_val->type = wanted_type->data.error_union.err_set_type;
+        err_set_val->data.x_err_set = val->data.x_err_set;
+
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
                 source_instr->scope, source_instr->source_node);
         const_instruction->base.value.type = wanted_type;
         const_instruction->base.value.special = ConstValSpecialStatic;
-        const_instruction->base.value.data.x_err_union.err = val->data.x_err_set;
+        const_instruction->base.value.data.x_err_union.error_set = err_set_val;
         const_instruction->base.value.data.x_err_union.payload = nullptr;
         return &const_instruction->base;
     }
@@ -9980,8 +10053,9 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so
     IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, source_instr->scope, source_instr->source_node);
     const_instruction->base.value.special = ConstValSpecialStatic;
     if (get_codegen_ptr_type(wanted_type) != nullptr) {
-        const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
-        const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0;
+        const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialNull;
+    } else if (is_opt_err_set(wanted_type)) {
+        const_instruction->base.value.data.x_err_set = nullptr;
     } else {
         const_instruction->base.value.data.x_optional = nullptr;
     }
@@ -10014,7 +10088,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
             source_instruction->source_node, value, is_const, is_volatile);
     new_instruction->value.type = ptr_type;
     new_instruction->value.data.rh_ptr = RuntimeHintPtrStack;
-    if (type_has_bits(ptr_type)) {
+    if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) {
         ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
         assert(fn_entry);
         fn_entry->alloca_list.append(new_instruction);
@@ -10040,20 +10114,17 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
     ZigType *array_type = array->value.type;
     assert(array_type->id == ZigTypeIdArray);
 
-    if (instr_is_comptime(array)) {
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+    if (instr_is_comptime(array) || array_type->data.array.len == 0) {
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true);
         result->value.type = wanted_type;
         return result;
     }
 
-    IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope,
-            source_instr->source_node, ira->codegen->builtin_types.entry_usize);
+    IrInstruction *start = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize);
     init_const_usize(ira->codegen, &start->value, 0);
 
-    IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope,
-            source_instr->source_node, ira->codegen->builtin_types.entry_usize);
+    IrInstruction *end = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize);
     init_const_usize(ira->codegen, &end->value, array_type->data.array.len);
 
     if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
@@ -10092,8 +10163,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
         ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
         if (!val)
             return ira->codegen->invalid_instruction;
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
         return result;
     }
@@ -10103,8 +10173,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
         actual_type->data.enumeration.src_field_count == 1)
     {
         assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         init_const_bigint(&result->value, wanted_type,
                 &actual_type->data.enumeration.fields[0].value);
         return result;
@@ -10127,8 +10196,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
         ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
         if (!val)
             return ira->codegen->invalid_instruction;
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         result->value.special = ConstValSpecialStatic;
         result->value.type = wanted_type;
         bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag);
@@ -10139,8 +10207,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
     if (wanted_type->data.enumeration.layout == ContainerLayoutAuto &&
         wanted_type->data.enumeration.src_field_count == 1)
     {
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         result->value.special = ConstValSpecialStatic;
         result->value.type = wanted_type;
         TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field;
@@ -10157,8 +10224,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
 static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr,
         IrInstruction *target, ZigType *wanted_type)
 {
-    IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-            source_instr->source_node, wanted_type);
+    IrInstruction *result = ir_const(ira, source_instr, wanted_type);
     init_const_undefined(ira->codegen, &result->value);
     return result;
 }
@@ -10190,8 +10256,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so
                     buf_sprintf("field '%s' declared here", buf_ptr(union_field->name)));
             return ira->codegen->invalid_instruction;
         }
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         result->value.special = ConstValSpecialStatic;
         result->value.type = wanted_type;
         bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag);
@@ -10246,8 +10311,7 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
                 return ira->codegen->invalid_instruction;
             }
         }
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         result->value.type = wanted_type;
         if (wanted_type->id == ZigTypeIdInt) {
             bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint);
@@ -10301,8 +10365,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
             return ira->codegen->invalid_instruction;
         }
 
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
         bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint);
         return result;
     }
@@ -10320,8 +10383,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
     if (!val)
         return ira->codegen->invalid_instruction;
 
-    IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-            source_instr->source_node, wanted_type);
+    IrInstruction *result = ir_const(ira, source_instr, wanted_type);
     if (wanted_type->id == ZigTypeIdComptimeFloat) {
         float_init_float(&result->value, val);
     } else if (wanted_type->id == ZigTypeIdComptimeInt) {
@@ -10344,8 +10406,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
         if (!val)
             return ira->codegen->invalid_instruction;
 
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
 
         if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
             return ira->codegen->invalid_instruction;
@@ -10409,12 +10470,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
         if (!val)
             return ira->codegen->invalid_instruction;
 
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, wanted_type);
+        IrInstruction *result = ir_const(ira, source_instr, wanted_type);
 
         ErrorTableEntry *err;
         if (err_type->id == ZigTypeIdErrorUnion) {
-            err = val->data.x_err_union.err;
+            err = val->data.x_err_union.error_set->data.x_err_set;
         } else if (err_type->id == ZigTypeIdErrorSet) {
             err = val->data.x_err_set;
         } else {
@@ -10449,15 +10509,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
             return ira->codegen->invalid_instruction;
         }
         if (err_set_type->data.error_set.err_count == 0) {
-            IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                    source_instr->source_node, wanted_type);
-            result->value.type = wanted_type;
+            IrInstruction *result = ir_const(ira, source_instr, wanted_type);
             bigint_init_unsigned(&result->value.data.x_bigint, 0);
             return result;
         } else if (err_set_type->data.error_set.err_count == 1) {
-            IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
-                    source_instr->source_node, wanted_type);
-            result->value.type = wanted_type;
+            IrInstruction *result = ir_const(ira, source_instr, wanted_type);
             ErrorTableEntry *err = err_set_type->data.error_set.errors[0];
             bigint_init_unsigned(&result->value.data.x_bigint, err->value);
             return result;
@@ -10504,8 +10560,8 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou
             array_val->type = array_type;
             array_val->data.x_array.special = ConstArraySpecialNone;
             array_val->data.x_array.data.s_none.elements = pointee;
-            array_val->data.x_array.data.s_none.parent.id = ConstParentIdScalar;
-            array_val->data.x_array.data.s_none.parent.data.p_scalar.scalar_val = pointee;
+            array_val->parent.id = ConstParentIdScalar;
+            array_val->parent.data.p_scalar.scalar_val = pointee;
 
             IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
                     source_instr->scope, source_instr->source_node);
@@ -10653,12 +10709,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
             false).id == ConstCastResultIdOk)
         {
-            return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
+            return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type);
         } else if (actual_type->id == ZigTypeIdComptimeInt ||
                    actual_type->id == ZigTypeIdComptimeFloat)
         {
             if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
-                return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
+                return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type);
             } else {
                 return ira->codegen->invalid_instruction;
             }
@@ -10682,7 +10738,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
                         wanted_child_type);
                 if (type_is_invalid(cast1->value.type))
                     return ira->codegen->invalid_instruction;
-                return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type);
+                return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type);
             }
         }
     }
@@ -10735,6 +10791,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt ||
         wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat))
     {
+        if (value->value.special == ConstValSpecialUndef) {
+            IrInstruction *result = ir_const(ira, source_instr, wanted_type);
+            result->value.special = ConstValSpecialUndef;
+            return result;
+        }
         if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
             if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) {
                 IrInstruction *result = ir_const(ira, source_instr, wanted_type);
@@ -10788,6 +10849,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
 
 
     // cast from [N]T to []const T
+    // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this
     if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) {
         ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
         assert(ptr_type->id == ZigTypeIdPointer);
@@ -10800,6 +10862,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
     }
 
     // cast from [N]T to ?[]const T
+    // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this
     if (wanted_type->id == ZigTypeIdOptional &&
         is_slice(wanted_type->data.maybe.child_type) &&
         actual_type->id == ZigTypeIdArray)
@@ -10894,7 +10957,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         }
     }
 
-    // cast from error set to error union type
+    // cast from E to E!T
     if (wanted_type->id == ZigTypeIdErrorUnion &&
         actual_type->id == ZigTypeIdErrorSet)
     {
@@ -11046,8 +11109,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
         ZigType *child_type = type_entry->data.pointer.child_type;
         // dereferencing a *u0 is comptime known to be 0
         if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) {
-            IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
-                source_instruction->source_node, child_type);
+            IrInstruction *result = ir_const(ira, source_instruction, child_type);
             init_const_unsigned_negative(&result->value, child_type, 0, false);
             return result;
         }
@@ -11061,8 +11123,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
             {
                 ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
                 if (pointee->special != ConstValSpecialRuntime) {
-                    IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
-                        source_instruction->source_node, child_type);
+                    IrInstruction *result = ir_const(ira, source_instruction, child_type);
 
                     if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value,
                                     &ptr->value)))
@@ -11074,7 +11135,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
                 }
             }
         }
-        // TODO if the instruction is a const ref instruction we can skip it
+        // if the instruction is a const ref instruction we can skip it
+        if (ptr->id == IrInstructionIdRef) {
+            IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
+            return ref_inst->value;
+        }
         IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
                 source_instruction->source_node, ptr);
         load_ptr_instruction->value.type = child_type;
@@ -11321,8 +11386,7 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
 
 static IrInstruction *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *instruction) {
     IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
-    // TODO determine if we need to use copy_const_val here
-    result->value = instruction->base.value;
+    copy_const_val(&result->value, &instruction->base.value, true);
     return result;
 }
 
@@ -11397,6 +11461,8 @@ static bool optional_value_is_null(ConstExprValue *val) {
     if (get_codegen_ptr_type(val->type) != nullptr) {
         return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
             val->data.x_ptr.data.hard_coded_addr.addr == 0;
+    } else if (is_opt_err_set(val->type)) {
+        return val->data.x_err_set == nullptr;
     } else {
         return val->data.x_optional == nullptr;
     }
@@ -11596,19 +11662,18 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
     if (casted_op2 == ira->codegen->invalid_instruction)
         return ira->codegen->invalid_instruction;
 
-    bool requires_comptime;
-    switch (type_requires_comptime(ira->codegen, resolved_type)) {
-        case ReqCompTimeYes:
-            requires_comptime = true;
+    bool one_possible_value;
+    switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
+        case OnePossibleValueInvalid:
+            return ira->codegen->invalid_instruction;
+        case OnePossibleValueYes:
+            one_possible_value = true;
             break;
-        case ReqCompTimeNo:
-            requires_comptime = false;
+        case OnePossibleValueNo:
+            one_possible_value = false;
             break;
-        case ReqCompTimeInvalid:
-            return ira->codegen->invalid_instruction;
     }
 
-    bool one_possible_value = !requires_comptime && !type_has_bits(resolved_type);
     if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
         ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
         if (op1_val == nullptr)
@@ -12497,13 +12562,15 @@ static IrInstruction *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructio
     zig_unreachable();
 }
 
-static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
+static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
+        IrInstructionDeclVarSrc *decl_var_instruction)
+{
     Error err;
     ZigVar *var = decl_var_instruction->var;
 
     IrInstruction *init_value = decl_var_instruction->init_value->child;
     if (type_is_invalid(init_value->value.type)) {
-        var->value->type = ira->codegen->builtin_types.entry_invalid;
+        var->var_type = ira->codegen->builtin_types.entry_invalid;
         return ira->codegen->invalid_instruction;
     }
 
@@ -12514,7 +12581,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
         ZigType *proposed_type = ir_resolve_type(ira, var_type);
         explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
         if (type_is_invalid(explicit_type)) {
-            var->value->type = ira->codegen->builtin_types.entry_invalid;
+            var->var_type = ira->codegen->builtin_types.entry_invalid;
             return ira->codegen->invalid_instruction;
         }
     }
@@ -12539,7 +12606,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
     case ReqCompTimeInvalid:
         result_type = ira->codegen->builtin_types.entry_invalid;
         break;
-    case ReqCompTimeYes: {
+    case ReqCompTimeYes:
         var_class_requires_const = true;
         if (!var->gen_is_const && !is_comptime_var) {
             ir_add_error_node(ira, source_node,
@@ -12548,7 +12615,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
             result_type = ira->codegen->builtin_types.entry_invalid;
         }
         break;
-    }
     case ReqCompTimeNo:
         if (casted_init_value->value.special == ConstValSpecialStatic &&
             casted_init_value->value.type->id == ZigTypeIdFn &&
@@ -12567,7 +12633,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
         break;
     }
 
-    if (var->value->type != nullptr && !is_comptime_var) {
+    if (var->var_type != nullptr && !is_comptime_var) {
         // This is at least the second time we've seen this variable declaration during analysis.
         // This means that this is actually a different variable due to, e.g. an inline while loop.
         // We make a new variable so that it can hold a different type, and so the debug info can
@@ -12589,8 +12655,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
     // This must be done after possibly creating a new variable above
     var->ref_count = 0;
 
-    var->value->type = result_type;
-    assert(var->value->type);
+    var->var_type = result_type;
+    assert(var->var_type);
 
     if (type_is_invalid(result_type)) {
         return ir_const_void(ira, &decl_var_instruction->base);
@@ -12598,13 +12664,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
 
     if (decl_var_instruction->align_value == nullptr) {
         if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) {
-            var->value->type = ira->codegen->builtin_types.entry_invalid;
+            var->var_type = ira->codegen->builtin_types.entry_invalid;
             return ir_const_void(ira, &decl_var_instruction->base);
         }
         var->align_bytes = get_abi_alignment(ira->codegen, result_type);
     } else {
         if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) {
-            var->value->type = ira->codegen->builtin_types.entry_invalid;
+            var->var_type = ira->codegen->builtin_types.entry_invalid;
         }
     }
 
@@ -12621,7 +12687,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
     } else if (is_comptime_var) {
         ir_add_error(ira, &decl_var_instruction->base,
                 buf_sprintf("cannot store runtime value in compile time variable"));
-        var->value->type = ira->codegen->builtin_types.entry_invalid;
+        var->var_type = ira->codegen->builtin_types.entry_invalid;
         return ira->codegen->invalid_instruction;
     }
 
@@ -12629,11 +12695,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
     if (fn_entry)
         fn_entry->variable_list.append(var);
 
-    IrInstruction *result = ir_build_var_decl(&ira->new_irb,
-        decl_var_instruction->base.scope, decl_var_instruction->base.source_node,
-        var, var_type, nullptr, casted_init_value);
-    result->value.type = ira->codegen->builtin_types.entry_void;
-    return result;
+    return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value);
 }
 
 static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {
@@ -12963,7 +13025,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node
 
     Buf *param_name = param_decl_node->data.param_decl.name;
     ZigVar *var = add_variable(ira->codegen, param_decl_node,
-        *exec_scope, param_name, true, arg_val, nullptr);
+        *exec_scope, param_name, true, arg_val, nullptr, arg_val->type);
     *exec_scope = var->child_scope;
     *next_proto_i += 1;
 
@@ -13021,7 +13083,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
     if (!param_name) return false;
     if (!is_var_args) {
         ZigVar *var = add_variable(ira->codegen, param_decl_node,
-            *child_scope, param_name, true, arg_val, nullptr);
+            *child_scope, param_name, true, arg_val, nullptr, arg_val->type);
         *child_scope = var->child_scope;
         var->shadowable = !comptime_arg;
 
@@ -13075,9 +13137,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) {
     return fn_entry->variable_list.at(next_var_i);
 }
 
-static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
-        ZigVar *var)
-{
+static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) {
     while (var->next_var != nullptr) {
         var = var->next_var;
     }
@@ -13086,14 +13146,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
         assert(ira->codegen->errors.length != 0);
         return ira->codegen->invalid_instruction;
     }
-    if (var->value->type == nullptr || type_is_invalid(var->value->type))
+    if (var->var_type == nullptr || type_is_invalid(var->var_type))
         return ira->codegen->invalid_instruction;
 
     bool comptime_var_mem = ir_get_var_is_comptime(var);
 
     ConstExprValue *mem_slot = nullptr;
-    if (var->value->special == ConstValSpecialStatic) {
-        mem_slot = var->value;
+    if (var->const_value->special == ConstValSpecialStatic) {
+        mem_slot = var->const_value;
     } else {
         if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) {
             // find the relevant exec_context
@@ -13122,7 +13182,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
                     assert(!comptime_var_mem);
                     ptr_mut = ConstPtrMutRuntimeVar;
                 }
-                return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
+                return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type,
                         ptr_mut, is_const, is_volatile, var->align_bytes);
             }
         }
@@ -13133,7 +13193,7 @@ no_mem_slot:
 
     IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
             instruction->scope, instruction->source_node, var);
-    var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
+    var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type,
             var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0);
 
     bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
@@ -13142,6 +13202,96 @@ no_mem_slot:
     return var_ptr_instruction;
 }
 
+static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
+        IrInstruction *ptr, IrInstruction *uncasted_value)
+{
+    if (ptr->value.type->id != ZigTypeIdPointer) {
+        ir_add_error(ira, ptr,
+            buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
+        return ira->codegen->invalid_instruction;
+    }
+
+    if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
+        return ir_const_void(ira, source_instr);
+    }
+
+    if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
+        ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
+        return ira->codegen->invalid_instruction;
+    }
+
+    ZigType *child_type = ptr->value.type->data.pointer.child_type;
+    IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type);
+    if (value == ira->codegen->invalid_instruction)
+        return ira->codegen->invalid_instruction;
+
+    if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+        if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
+            ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
+            return ira->codegen->invalid_instruction;
+        }
+        if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
+            if (instr_is_comptime(value)) {
+                ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, source_instr->source_node);
+                if (dest_val == nullptr)
+                    return ira->codegen->invalid_instruction;
+                if (dest_val->special != ConstValSpecialRuntime) {
+                    // TODO this allows a value stored to have the original value modified and then
+                    // have that affect what should be a copy. We need some kind of advanced copy-on-write
+                    // system to make these two tests pass at the same time:
+                    // * "string literal used as comptime slice is memoized"
+                    // * "comptime modification of const struct field" - except modified to avoid
+                    //   ConstPtrMutComptimeVar, thus defeating the logic below.
+                    bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar;
+                    copy_const_val(dest_val, &value->value, same_global_refs);
+                    if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
+                        switch (type_has_one_possible_value(ira->codegen, child_type)) {
+                            case OnePossibleValueInvalid:
+                                return ira->codegen->invalid_instruction;
+                            case OnePossibleValueNo:
+                                ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
+                                break;
+                            case OnePossibleValueYes:
+                                break;
+                        }
+                    }
+                    return ir_const_void(ira, source_instr);
+                }
+            }
+            ir_add_error(ira, source_instr,
+                    buf_sprintf("cannot store runtime value in compile time variable"));
+            ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
+            dest_val->type = ira->codegen->builtin_types.entry_invalid;
+
+            return ira->codegen->invalid_instruction;
+        }
+    }
+
+    switch (type_requires_comptime(ira->codegen, child_type)) {
+        case ReqCompTimeInvalid:
+            return ira->codegen->invalid_instruction;
+        case ReqCompTimeYes:
+            switch (type_has_one_possible_value(ira->codegen, ptr->value.type)) {
+                case OnePossibleValueInvalid:
+                    return ira->codegen->invalid_instruction;
+                case OnePossibleValueNo:
+                    ir_add_error(ira, source_instr,
+                            buf_sprintf("cannot store runtime value in type '%s'", buf_ptr(&child_type->name)));
+                    return ira->codegen->invalid_instruction;
+                case OnePossibleValueYes:
+                    return ir_const_void(ira, source_instr);
+            }
+            zig_unreachable();
+        case ReqCompTimeNo:
+            break;
+    }
+
+    IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
+        ptr, value);
+    result->value.type = ira->codegen->builtin_types.entry_void;
+    return result;
+}
+
 static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
     ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref,
     IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline)
@@ -13286,7 +13436,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
         }
 
         bool cacheable = fn_eval_cacheable(exec_scope, return_type);
-        IrInstruction *result = nullptr;
+        ConstExprValue *result = nullptr;
         if (cacheable) {
             auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);
             if (entry)
@@ -13302,18 +13452,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
 
             if (inferred_err_set_type != nullptr) {
                 inferred_err_set_type->data.error_set.infer_fn = nullptr;
-                if (result->value.type->id == ZigTypeIdErrorUnion) {
-                    if (result->value.data.x_err_union.err != nullptr) {
+                if (result->type->id == ZigTypeIdErrorUnion) {
+                    ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set;
+                    if (err != nullptr) {
                         inferred_err_set_type->data.error_set.err_count = 1;
                         inferred_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1);
-                        inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err;
+                        inferred_err_set_type->data.error_set.errors[0] = err;
                     }
-                    ZigType *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type;
+                    ZigType *fn_inferred_err_set_type = result->type->data.error_union.err_set_type;
                     inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count;
                     inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors;
-                } else if (result->value.type->id == ZigTypeIdErrorSet) {
-                    inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count;
-                    inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors;
+                } else if (result->type->id == ZigTypeIdErrorSet) {
+                    inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count;
+                    inferred_err_set_type->data.error_set.errors = result->type->data.error_set.errors;
                 }
             }
 
@@ -13321,13 +13472,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
                 ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
             }
 
-            if (type_is_invalid(result->value.type))
+            if (type_is_invalid(result->type))
                 return ira->codegen->invalid_instruction;
         }
 
-        IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->value.type);
-        // TODO should we use copy_const_val?
-        new_instruction->value = result->value;
+        IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type);
+        copy_const_val(&new_instruction->value, result, true);
         new_instruction->value.type = return_type;
         return ir_finish_anal(ira, new_instruction);
     }
@@ -13486,18 +13636,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
             ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen,
                     first_var_arg, inst_fn_type_id.param_count);
             ZigVar *var = add_variable(ira->codegen, param_decl_node,
-                impl_fn->child_scope, param_name, true, var_args_val, nullptr);
+                impl_fn->child_scope, param_name, true, var_args_val, nullptr, var_args_val->type);
             impl_fn->child_scope = var->child_scope;
         }
 
         if (fn_proto_node->data.fn_proto.align_expr != nullptr) {
-            IrInstruction *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
+            ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
                     fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen),
                     ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
                     nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec);
+            IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
+                    impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr);
+            const_instruction->base.value = *align_result;
 
             uint32_t align_bytes = 0;
-            ir_resolve_align(ira, align_result, &align_bytes);
+            ir_resolve_align(ira, &const_instruction->base, &align_bytes);
             impl_fn->align_bytes = align_bytes;
             inst_fn_type_id.alignment = align_bytes;
         }
@@ -13575,12 +13728,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
             ira->codegen->fn_defs.append(impl_fn);
         }
 
-        ZigType *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
-        if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) {
+        FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id;
+        if (fn_type_can_fail(impl_fn_type_id)) {
             parent_fn_entry->calls_or_awaits_errorable_fn = true;
         }
 
-        size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
+        size_t impl_param_count = impl_fn_type_id->param_count;
         if (call_instruction->is_async) {
             IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
                     fn_ref, casted_args, impl_param_count, async_allocator_inst);
@@ -13593,9 +13746,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
                 call_instruction->base.scope, call_instruction->base.source_node,
                 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
                 call_instruction->is_async, nullptr, casted_new_stack);
-        new_call_instruction->value.type = return_type;
+        new_call_instruction->value.type = impl_fn_type_id->return_type;
 
-        ir_add_alloca(ira, new_call_instruction, return_type);
+        ir_add_alloca(ira, new_call_instruction, impl_fn_type_id->return_type);
 
         return ir_finish_anal(ira, new_call_instruction);
     }
@@ -13790,6 +13943,13 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
     switch (ptr_val->data.x_ptr.special) {
         case ConstPtrSpecialInvalid:
             zig_unreachable();
+        case ConstPtrSpecialNull:
+            if (dst_size == 0)
+                return ErrorNone;
+            opt_ir_add_error_node(ira, codegen, source_node,
+                buf_sprintf("attempt to read %zu bytes from null pointer",
+                dst_size));
+            return ErrorSemanticAnalyzeFail;
         case ConstPtrSpecialRef: {
             opt_ir_add_error_node(ira, codegen, source_node,
                 buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes",
@@ -13822,6 +13982,9 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
             return ErrorNone;
         }
         case ConstPtrSpecialBaseStruct:
+        case ConstPtrSpecialBaseErrorUnionCode:
+        case ConstPtrSpecialBaseErrorUnionPayload:
+        case ConstPtrSpecialBaseOptionalPayload:
         case ConstPtrSpecialDiscard:
         case ConstPtrSpecialHardCodedAddr:
         case ConstPtrSpecialFunction:
@@ -14017,9 +14180,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
     if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime))
         return ir_unreach_error(ira);
 
-    if (is_comptime || instr_is_comptime(condition)) {
+    ZigType *bool_type = ira->codegen->builtin_types.entry_bool;
+    IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type);
+    if (type_is_invalid(casted_condition->value.type))
+        return ir_unreach_error(ira);
+
+    if (is_comptime || instr_is_comptime(casted_condition)) {
         bool cond_is_true;
-        if (!ir_resolve_bool(ira, condition, &cond_is_true))
+        if (!ir_resolve_bool(ira, casted_condition, &cond_is_true))
             return ir_unreach_error(ira);
 
         IrBasicBlock *old_dest_block = cond_is_true ?
@@ -14038,11 +14206,6 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
         return ir_finish_anal(ira, result);
     }
 
-    ZigType *bool_type = ira->codegen->builtin_types.entry_bool;
-    IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type);
-    if (casted_condition == ira->codegen->invalid_instruction)
-        return ir_unreach_error(ira);
-
     assert(cond_br_instruction->then_block != cond_br_instruction->else_block);
     IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base);
     if (new_then_block == nullptr)
@@ -14081,8 +14244,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
 
             if (value->value.special != ConstValSpecialRuntime) {
                 IrInstruction *result = ir_const(ira, &phi_instruction->base, nullptr);
-                // TODO use copy_const_val?
-                result->value = value->value;
+                copy_const_val(&result->value, &value->value, true);
                 return result;
             } else {
                 return value;
@@ -14131,14 +14293,24 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
     if (type_is_invalid(resolved_type))
         return ira->codegen->invalid_instruction;
 
-    if (resolved_type->id == ZigTypeIdComptimeFloat ||
-        resolved_type->id == ZigTypeIdComptimeInt ||
-        resolved_type->id == ZigTypeIdNull ||
-        resolved_type->id == ZigTypeIdUndefined)
-    {
+    switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
+    case OnePossibleValueInvalid:
+        return ira->codegen->invalid_instruction;
+    case OnePossibleValueYes:
+        return ir_const(ira, &phi_instruction->base, resolved_type);
+    case OnePossibleValueNo:
+        break;
+    }
+
+    switch (type_requires_comptime(ira->codegen, resolved_type)) {
+    case ReqCompTimeInvalid:
+        return ira->codegen->invalid_instruction;
+    case ReqCompTimeYes:
         ir_add_error_node(ira, phi_instruction->base.source_node,
-                buf_sprintf("unable to infer expression type"));
+                buf_sprintf("values of type '%s' must be comptime known", buf_ptr(&resolved_type->name)));
         return ira->codegen->invalid_instruction;
+    case ReqCompTimeNo:
+        break;
     }
 
     bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer);
@@ -14428,10 +14600,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
                             }
                         case ConstPtrSpecialBaseStruct:
                             zig_panic("TODO elem ptr on a const inner struct");
+                        case ConstPtrSpecialBaseErrorUnionCode:
+                            zig_panic("TODO elem ptr on a const inner error union code");
+                        case ConstPtrSpecialBaseErrorUnionPayload:
+                            zig_panic("TODO elem ptr on a const inner error union payload");
+                        case ConstPtrSpecialBaseOptionalPayload:
+                            zig_panic("TODO elem ptr on a const inner optional payload");
                         case ConstPtrSpecialHardCodedAddr:
                             zig_unreachable();
                         case ConstPtrSpecialFunction:
                             zig_panic("TODO element ptr of a function casted to a ptr");
+                        case ConstPtrSpecialNull:
+                            zig_panic("TODO elem ptr on a null pointer");
                     }
                     if (new_index >= mem_size) {
                         ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
@@ -14481,10 +14661,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
                             }
                         case ConstPtrSpecialBaseStruct:
                             zig_panic("TODO elem ptr on a slice backed by const inner struct");
+                        case ConstPtrSpecialBaseErrorUnionCode:
+                            zig_panic("TODO elem ptr on a slice backed by const inner error union code");
+                        case ConstPtrSpecialBaseErrorUnionPayload:
+                            zig_panic("TODO elem ptr on a slice backed by const inner error union payload");
+                        case ConstPtrSpecialBaseOptionalPayload:
+                            zig_panic("TODO elem ptr on a slice backed by const optional payload");
                         case ConstPtrSpecialHardCodedAddr:
                             zig_unreachable();
                         case ConstPtrSpecialFunction:
                             zig_panic("TODO elem ptr on a slice that was ptrcast from a function");
+                        case ConstPtrSpecialNull:
+                            zig_panic("TODO elem ptr on a slice has a null pointer");
                     }
                     return result;
                 } else if (array_type->id == ZigTypeIdArray) {
@@ -15171,74 +15359,23 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
     }
 }
 
-static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) {
-    IrInstruction *ptr = load_ptr_instruction->ptr->child;
-    if (type_is_invalid(ptr->value.type))
-        return ira->codegen->invalid_instruction;
-    return ir_get_deref(ira, &load_ptr_instruction->base, ptr);
-}
-
-static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) {
-    IrInstruction *ptr = store_ptr_instruction->ptr->child;
+static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) {
+    IrInstruction *ptr = instruction->ptr->child;
     if (type_is_invalid(ptr->value.type))
         return ira->codegen->invalid_instruction;
 
-    IrInstruction *value = store_ptr_instruction->value->child;
+    IrInstruction *value = instruction->value->child;
     if (type_is_invalid(value->value.type))
         return ira->codegen->invalid_instruction;
 
-    if (ptr->value.type->id != ZigTypeIdPointer) {
-        ir_add_error(ira, ptr,
-            buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
-        return ira->codegen->invalid_instruction;
-    }
-
-    if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
-        return ir_const_void(ira, &store_ptr_instruction->base);
-    }
-
-    if (ptr->value.type->data.pointer.is_const && !store_ptr_instruction->base.is_gen) {
-        ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant"));
-        return ira->codegen->invalid_instruction;
-    }
+    return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
+}
 
-    ZigType *child_type = ptr->value.type->data.pointer.child_type;
-    IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
-    if (casted_value == ira->codegen->invalid_instruction)
+static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
+    IrInstruction *ptr = instruction->ptr->child;
+    if (type_is_invalid(ptr->value.type))
         return ira->codegen->invalid_instruction;
-
-    if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
-        if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
-            ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant"));
-            return ira->codegen->invalid_instruction;
-        }
-        if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
-            if (instr_is_comptime(casted_value)) {
-                ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, store_ptr_instruction->base.source_node);
-                if (dest_val == nullptr)
-                    return ira->codegen->invalid_instruction;
-                if (dest_val->special != ConstValSpecialRuntime) {
-                    *dest_val = casted_value->value;
-                    if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
-                        ira->new_irb.current_basic_block->must_be_comptime_source_instr = &store_ptr_instruction->base;
-                    }
-                    return ir_const_void(ira, &store_ptr_instruction->base);
-                }
-            }
-            ir_add_error(ira, &store_ptr_instruction->base,
-                    buf_sprintf("cannot store runtime value in compile time variable"));
-            ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
-            dest_val->type = ira->codegen->builtin_types.entry_invalid;
-
-            return ira->codegen->invalid_instruction;
-        }
-    }
-
-    IrInstruction *result = ir_build_store_ptr(&ira->new_irb,
-        store_ptr_instruction->base.scope, store_ptr_instruction->base.source_node,
-        ptr, casted_value);
-    result->value.type = ira->codegen->builtin_types.entry_void;
-    return result;
+    return ir_get_deref(ira, &instruction->base, ptr);
 }
 
 static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@@ -15709,11 +15846,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
     zig_unreachable();
 }
 
-static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) {
-    IrInstruction *value = instruction->value->child;
-    if (type_is_invalid(value->value.type))
-        return ira->codegen->invalid_instruction;
-
+static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) {
     ZigType *type_entry = value->value.type;
 
     if (type_entry->id == ZigTypeIdOptional) {
@@ -15722,60 +15855,66 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns
             if (!maybe_val)
                 return ira->codegen->invalid_instruction;
 
-            return ir_const_bool(ira, &instruction->base, !optional_value_is_null(maybe_val));
+            return ir_const_bool(ira, source_inst, !optional_value_is_null(maybe_val));
         }
 
         IrInstruction *result = ir_build_test_nonnull(&ira->new_irb,
-            instruction->base.scope, instruction->base.source_node, value);
+            source_inst->scope, source_inst->source_node, value);
         result->value.type = ira->codegen->builtin_types.entry_bool;
         return result;
     } else if (type_entry->id == ZigTypeIdNull) {
-        return ir_const_bool(ira, &instruction->base, false);
+        return ir_const_bool(ira, source_inst, false);
     } else {
-        return ir_const_bool(ira, &instruction->base, true);
+        return ir_const_bool(ira, source_inst, true);
     }
 }
 
-static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
-        IrInstructionUnwrapOptional *unwrap_maybe_instruction)
-{
-    IrInstruction *value = unwrap_maybe_instruction->value->child;
+static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) {
+    IrInstruction *value = instruction->value->child;
     if (type_is_invalid(value->value.type))
         return ira->codegen->invalid_instruction;
 
-    ZigType *ptr_type = value->value.type;
+    return ir_analyze_test_non_null(ira, &instruction->base, value);
+}
+
+static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
+        IrInstruction *base_ptr, bool safety_check_on)
+{
+    ZigType *ptr_type = base_ptr->value.type;
     assert(ptr_type->id == ZigTypeIdPointer);
 
     ZigType *type_entry = ptr_type->data.pointer.child_type;
-    if (type_is_invalid(type_entry)) {
+    if (type_is_invalid(type_entry))
         return ira->codegen->invalid_instruction;
-    } else if (type_entry->id != ZigTypeIdOptional) {
-        ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node,
+
+    if (type_entry->id != ZigTypeIdOptional) {
+        ir_add_error_node(ira, base_ptr->source_node,
                 buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name)));
         return ira->codegen->invalid_instruction;
     }
+
     ZigType *child_type = type_entry->data.maybe.child_type;
     ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
             ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
 
-    if (instr_is_comptime(value)) {
-        ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
+    if (instr_is_comptime(base_ptr)) {
+        ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad);
         if (!val)
             return ira->codegen->invalid_instruction;
-        ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, unwrap_maybe_instruction->base.source_node);
+        ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node);
         if (maybe_val == nullptr)
             return ira->codegen->invalid_instruction;
 
         if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) {
             if (optional_value_is_null(maybe_val)) {
-                ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null"));
+                ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null"));
                 return ira->codegen->invalid_instruction;
             }
-            IrInstruction *result = ir_const(ira, &unwrap_maybe_instruction->base, result_type);
+            IrInstruction *result = ir_const(ira, source_instr, result_type);
             ConstExprValue *out_val = &result->value;
             out_val->data.x_ptr.special = ConstPtrSpecialRef;
             out_val->data.x_ptr.mut = val->data.x_ptr.mut;
-            if (type_is_codegen_pointer(child_type)) {
+            if (types_have_same_zig_comptime_repr(type_entry, child_type)) {
                 out_val->data.x_ptr.data.ref.pointee = maybe_val;
             } else {
                 out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional;
@@ -15784,13 +15923,22 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
         }
     }
 
-    IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb,
-            unwrap_maybe_instruction->base.scope, unwrap_maybe_instruction->base.source_node,
-            value, unwrap_maybe_instruction->safety_check_on);
+    IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope,
+            source_instr->source_node, base_ptr, safety_check_on);
     result->value.type = result_type;
     return result;
 }
 
+static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira,
+        IrInstructionOptionalUnwrapPtr *instruction)
+{
+    IrInstruction *base_ptr = instruction->base_ptr->child;
+    if (type_is_invalid(base_ptr->value.type))
+        return ira->codegen->invalid_instruction;
+
+    return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on);
+}
+
 static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) {
     IrInstruction *value = ctz_instruction->value->child;
     if (type_is_invalid(value->value.type)) {
@@ -16091,9 +16239,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
                 return result;
             }
 
-            IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
-                switch_target_instruction->base.scope, switch_target_instruction->base.source_node,
-                target_value_ptr);
+            IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
             result->value.type = target_type;
             return result;
         }
@@ -16123,8 +16269,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
                 return result;
             }
 
-            IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
-                switch_target_instruction->base.source_node, target_value_ptr);
+            IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
             union_value->value.type = target_type;
 
             IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
@@ -16148,8 +16293,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
                 return result;
             }
 
-            IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
-                switch_target_instruction->base.source_node, target_value_ptr);
+            IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
             enum_value->value.type = target_type;
             return enum_value;
         }
@@ -16306,7 +16450,7 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
     Error err;
     assert(container_type->id == ZigTypeIdUnion);
 
-    if ((err = ensure_complete_type(ira->codegen, container_type)))
+    if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     if (instr_field_count != 1) {
@@ -16350,12 +16494,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
         ConstExprValue *out_val = &result->value;
         out_val->data.x_union.payload = field_val;
         out_val->data.x_union.tag = type_field->enum_field->value;
-
-        ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
-        if (parent != nullptr) {
-            parent->id = ConstParentIdUnion;
-            parent->data.p_union.union_val = out_val;
-        }
+        out_val->parent.id = ConstParentIdUnion;
+        out_val->parent.data.p_union.union_val = out_val;
 
         return result;
     }
@@ -16382,7 +16522,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
         return ira->codegen->invalid_instruction;
     }
 
-    if ((err = ensure_complete_type(ira->codegen, container_type)))
+    if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     size_t actual_field_count = container_type->data.structure.src_field_count;
@@ -16461,9 +16601,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
     if (const_val.special == ConstValSpecialStatic) {
         IrInstruction *result = ir_const(ira, instruction, nullptr);
         ConstExprValue *out_val = &result->value;
-        // TODO copy_const_val?
-        *out_val = const_val;
-        result->value.type = container_type;
+        copy_const_val(out_val, &const_val, true);
+        out_val->type = container_type;
 
         for (size_t i = 0; i < instr_field_count; i += 1) {
             ConstExprValue *field_val = &out_val->data.x_struct.fields[i];
@@ -16495,127 +16634,119 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
 static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
         IrInstructionContainerInitList *instruction)
 {
-    IrInstruction *container_type_value = instruction->container_type->child;
-    if (type_is_invalid(container_type_value->value.type))
+    ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child);
+    if (type_is_invalid(container_type))
         return ira->codegen->invalid_instruction;
 
     size_t elem_count = instruction->item_count;
-    if (container_type_value->value.type->id == ZigTypeIdMetaType) {
-        ZigType *container_type = ir_resolve_type(ira, container_type_value);
-        if (type_is_invalid(container_type))
-            return ira->codegen->invalid_instruction;
 
-        if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) {
-            return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
-                    0, nullptr);
-        } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) {
-            // array is same as slice init but we make a compile error if the length is wrong
-            ZigType *child_type;
-            if (container_type->id == ZigTypeIdArray) {
-                child_type = container_type->data.array.child_type;
-                if (container_type->data.array.len != elem_count) {
-                    ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
+    if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) {
+        return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
+                0, nullptr);
+    } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) {
+        // array is same as slice init but we make a compile error if the length is wrong
+        ZigType *child_type;
+        if (container_type->id == ZigTypeIdArray) {
+            child_type = container_type->data.array.child_type;
+            if (container_type->data.array.len != elem_count) {
+                ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
 
-                    ir_add_error(ira, &instruction->base,
-                        buf_sprintf("expected %s literal, found %s literal",
-                            buf_ptr(&container_type->name), buf_ptr(&literal_type->name)));
-                    return ira->codegen->invalid_instruction;
-                }
-            } else {
-                ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
-                assert(pointer_type->id == ZigTypeIdPointer);
-                child_type = pointer_type->data.pointer.child_type;
+                ir_add_error(ira, &instruction->base,
+                    buf_sprintf("expected %s literal, found %s literal",
+                        buf_ptr(&container_type->name), buf_ptr(&literal_type->name)));
+                return ira->codegen->invalid_instruction;
             }
+        } else {
+            ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
+            assert(pointer_type->id == ZigTypeIdPointer);
+            child_type = pointer_type->data.pointer.child_type;
+        }
 
-            ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
+        ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
 
-            ConstExprValue const_val = {};
-            const_val.special = ConstValSpecialStatic;
-            const_val.type = fixed_size_array_type;
-            const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count);
+        ConstExprValue const_val = {};
+        const_val.special = ConstValSpecialStatic;
+        const_val.type = fixed_size_array_type;
+        const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count);
 
-            bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
+        bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
 
-            IrInstruction **new_items = allocate<IrInstruction *>(elem_count);
+        IrInstruction **new_items = allocate<IrInstruction *>(elem_count);
 
-            IrInstruction *first_non_const_instruction = nullptr;
+        IrInstruction *first_non_const_instruction = nullptr;
 
-            for (size_t i = 0; i < elem_count; i += 1) {
-                IrInstruction *arg_value = instruction->items[i]->child;
-                if (type_is_invalid(arg_value->value.type))
-                    return ira->codegen->invalid_instruction;
+        for (size_t i = 0; i < elem_count; i += 1) {
+            IrInstruction *arg_value = instruction->items[i]->child;
+            if (type_is_invalid(arg_value->value.type))
+                return ira->codegen->invalid_instruction;
 
-                IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
-                if (casted_arg == ira->codegen->invalid_instruction)
-                    return ira->codegen->invalid_instruction;
+            IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
+            if (casted_arg == ira->codegen->invalid_instruction)
+                return ira->codegen->invalid_instruction;
 
-                new_items[i] = casted_arg;
+            new_items[i] = casted_arg;
 
-                if (const_val.special == ConstValSpecialStatic) {
-                    if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) {
-                        ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
-                        if (!elem_val)
-                            return ira->codegen->invalid_instruction;
+            if (const_val.special == ConstValSpecialStatic) {
+                if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) {
+                    ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
+                    if (!elem_val)
+                        return ira->codegen->invalid_instruction;
 
-                        copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true);
-                    } else {
-                        first_non_const_instruction = casted_arg;
-                        const_val.special = ConstValSpecialRuntime;
-                    }
+                    copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true);
+                } else {
+                    first_non_const_instruction = casted_arg;
+                    const_val.special = ConstValSpecialRuntime;
                 }
             }
+        }
 
-            if (const_val.special == ConstValSpecialStatic) {
-                IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
-                ConstExprValue *out_val = &result->value;
-                // TODO copy_const_val?
-                *out_val = const_val;
-                result->value.type = fixed_size_array_type;
-                for (size_t i = 0; i < elem_count; i += 1) {
-                    ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i];
-                    ConstParent *parent = get_const_val_parent(ira->codegen, elem_val);
-                    if (parent != nullptr) {
-                        parent->id = ConstParentIdArray;
-                        parent->data.p_array.array_val = out_val;
-                        parent->data.p_array.elem_index = i;
-                    }
+        if (const_val.special == ConstValSpecialStatic) {
+            IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
+            ConstExprValue *out_val = &result->value;
+            copy_const_val(out_val, &const_val, true);
+            result->value.type = fixed_size_array_type;
+            for (size_t i = 0; i < elem_count; i += 1) {
+                ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i];
+                ConstParent *parent = get_const_val_parent(ira->codegen, elem_val);
+                if (parent != nullptr) {
+                    parent->id = ConstParentIdArray;
+                    parent->data.p_array.array_val = out_val;
+                    parent->data.p_array.elem_index = i;
                 }
-                return result;
             }
+            return result;
+        }
 
-            if (is_comptime) {
-                ir_add_error_node(ira, first_non_const_instruction->source_node,
-                    buf_sprintf("unable to evaluate constant expression"));
-                return ira->codegen->invalid_instruction;
-            }
+        if (is_comptime) {
+            ir_add_error_node(ira, first_non_const_instruction->source_node,
+                buf_sprintf("unable to evaluate constant expression"));
+            return ira->codegen->invalid_instruction;
+        }
 
-            IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb,
-                instruction->base.scope, instruction->base.source_node,
-                container_type_value, elem_count, new_items);
-            new_instruction->value.type = fixed_size_array_type;
-            ir_add_alloca(ira, new_instruction, fixed_size_array_type);
-            return new_instruction;
-        } else if (container_type->id == ZigTypeIdVoid) {
-            if (elem_count != 0) {
-                ir_add_error_node(ira, instruction->base.source_node,
-                    buf_sprintf("void expression expects no arguments"));
-                return ira->codegen->invalid_instruction;
-            }
-            return ir_const_void(ira, &instruction->base);
-        } else {
+        IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb,
+            instruction->base.scope, instruction->base.source_node,
+            nullptr, elem_count, new_items);
+        new_instruction->value.type = fixed_size_array_type;
+        ir_add_alloca(ira, new_instruction, fixed_size_array_type);
+        return new_instruction;
+    } else if (container_type->id == ZigTypeIdVoid) {
+        if (elem_count != 0) {
             ir_add_error_node(ira, instruction->base.source_node,
-                buf_sprintf("type '%s' does not support array initialization",
-                    buf_ptr(&container_type->name)));
+                buf_sprintf("void expression expects no arguments"));
             return ira->codegen->invalid_instruction;
         }
+        return ir_const_void(ira, &instruction->base);
     } else {
-        ir_add_error(ira, container_type_value,
-            buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name)));
+        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->invalid_instruction;
     }
 }
 
-static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) {
+static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira,
+        IrInstructionContainerInitFields *instruction)
+{
     IrInstruction *container_type_value = instruction->container_type->child;
     ZigType *container_type = ir_resolve_type(ira, container_type_value);
     if (type_is_invalid(container_type))
@@ -16675,7 +16806,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct
     if (type_is_invalid(value->value.type))
         return ira->codegen->invalid_instruction;
 
-    IrInstruction *casted_value = ir_implicit_cast(ira, value, value->value.type);
+    IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set);
     if (type_is_invalid(casted_value->value.type))
         return ira->codegen->invalid_instruction;
 
@@ -16936,10 +17067,11 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig
 
     ZigVar *var = tld->var;
 
-    if ((err = ensure_complete_type(ira->codegen, var->value->type)))
+    if ((err = ensure_complete_type(ira->codegen, var->const_value->type)))
         return ira->codegen->builtin_types.entry_invalid;
-    assert(var->value->type->id == ZigTypeIdMetaType);
-    return var->value->data.x_type;
+
+    assert(var->const_value->type->id == ZigTypeIdMetaType);
+    return var->const_value->data.x_type;
 }
 
 static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) {
@@ -16994,7 +17126,6 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
     definition_array->special = ConstValSpecialStatic;
     definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count);
     definition_array->data.x_array.special = ConstArraySpecialNone;
-    definition_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
     definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count);
     init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false);
 
@@ -17025,33 +17156,30 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
         inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub;
         inner_fields[2].special = ConstValSpecialStatic;
         inner_fields[2].type = type_info_definition_data_type;
-        inner_fields[2].data.x_union.parent.id = ConstParentIdStruct;
-        inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val;
-        inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1;
+        inner_fields[2].parent.id = ConstParentIdStruct;
+        inner_fields[2].parent.data.p_struct.struct_val = definition_val;
+        inner_fields[2].parent.data.p_struct.field_index = 1;
 
         switch (curr_entry->value->id) {
             case TldIdVar:
                 {
                     ZigVar *var = ((TldVar *)curr_entry->value)->var;
-                    if ((err = ensure_complete_type(ira->codegen, var->value->type)))
+                    if ((err = ensure_complete_type(ira->codegen, var->const_value->type)))
                         return ErrorSemanticAnalyzeFail;
 
-                    if (var->value->type->id == ZigTypeIdMetaType)
-                    {
+                    if (var->const_value->type->id == ZigTypeIdMetaType) {
                         // We have a variable of type 'type', so it's actually a type definition.
                         // 0: Data.Type: type
                         bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);
-                        inner_fields[2].data.x_union.payload = var->value;
-                    }
-                    else
-                    {
+                        inner_fields[2].data.x_union.payload = var->const_value;
+                    } else {
                         // We have a variable of another type, so we store the type of the variable.
                         // 1: Data.Var: type
                         bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1);
 
                         ConstExprValue *payload = create_const_vals(1);
                         payload->type = ira->codegen->builtin_types.entry_type;
-                        payload->data.x_type = var->value->type;
+                        payload->data.x_type = var->const_value->type;
 
                         inner_fields[2].data.x_union.payload = payload;
                     }
@@ -17071,8 +17199,8 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
                     ConstExprValue *fn_def_val = create_const_vals(1);
                     fn_def_val->special = ConstValSpecialStatic;
                     fn_def_val->type = type_info_fn_def_type;
-                    fn_def_val->data.x_struct.parent.id = ConstParentIdUnion;
-                    fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2];
+                    fn_def_val->parent.id = ConstParentIdUnion;
+                    fn_def_val->parent.data.p_union.union_val = &inner_fields[2];
 
                     ConstExprValue *fn_def_fields = create_const_vals(9);
                     fn_def_val->data.x_struct.fields = fn_def_fields;
@@ -17136,20 +17264,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
                     fn_arg_name_array->type = get_array_type(ira->codegen,
                             get_slice_type(ira->codegen, u8_ptr), fn_arg_count);
                     fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
-                    fn_arg_name_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
                     fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
 
                     init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false);
 
-                    for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++)
-                    {
+                    for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
                         ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index);
                         ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index];
                         ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name);
                         init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true);
-                        fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray;
-                        fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array;
-                        fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
+                        fn_arg_name_val->parent.id = ConstParentIdArray;
+                        fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array;
+                        fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index;
                     }
 
                     inner_fields[2].data.x_union.payload = fn_def_val;
@@ -17442,7 +17568,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                 enum_field_array->special = ConstValSpecialStatic;
                 enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count);
                 enum_field_array->data.x_array.special = ConstArraySpecialNone;
-                enum_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
                 enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count);
 
                 init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false);
@@ -17452,9 +17577,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                     TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index];
                     ConstExprValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index];
                     make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type);
-                    enum_field_val->data.x_struct.parent.id = ConstParentIdArray;
-                    enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array;
-                    enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index;
+                    enum_field_val->parent.id = ConstParentIdArray;
+                    enum_field_val->parent.data.p_array.array_val = enum_field_array;
+                    enum_field_val->parent.data.p_array.elem_index = enum_field_index;
                 }
                 // defs: []TypeInfo.Definition
                 ensure_field_index(result->type, "defs", 3);
@@ -17481,7 +17606,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                 error_array->special = ConstValSpecialStatic;
                 error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count);
                 error_array->data.x_array.special = ConstArraySpecialNone;
-                error_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
                 error_array->data.x_array.data.s_none.elements = create_const_vals(error_count);
 
                 init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false);
@@ -17505,9 +17629,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                     bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value);
 
                     error_val->data.x_struct.fields = inner_fields;
-                    error_val->data.x_struct.parent.id = ConstParentIdArray;
-                    error_val->data.x_struct.parent.data.p_array.array_val = error_array;
-                    error_val->data.x_struct.parent.data.p_array.elem_index = error_index;
+                    error_val->parent.id = ConstParentIdArray;
+                    error_val->parent.data.p_array.array_val = error_array;
+                    error_val->parent.data.p_array.elem_index = error_index;
                 }
 
                 break;
@@ -17576,7 +17700,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                 union_field_array->special = ConstValSpecialStatic;
                 union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count);
                 union_field_array->data.x_array.special = ConstArraySpecialNone;
-                union_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
                 union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count);
 
                 init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false);
@@ -17609,9 +17732,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                     init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true);
 
                     union_field_val->data.x_struct.fields = inner_fields;
-                    union_field_val->data.x_struct.parent.id = ConstParentIdArray;
-                    union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array;
-                    union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index;
+                    union_field_val->parent.id = ConstParentIdArray;
+                    union_field_val->parent.data.p_array.array_val = union_field_array;
+                    union_field_val->parent.data.p_array.elem_index = union_field_index;
                 }
                 // defs: []TypeInfo.Definition
                 ensure_field_index(result->type, "defs", 3);
@@ -17651,7 +17774,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                 struct_field_array->special = ConstValSpecialStatic;
                 struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count);
                 struct_field_array->data.x_array.special = ConstArraySpecialNone;
-                struct_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
                 struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count);
 
                 init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false);
@@ -17685,9 +17807,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                     init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true);
 
                     struct_field_val->data.x_struct.fields = inner_fields;
-                    struct_field_val->data.x_struct.parent.id = ConstParentIdArray;
-                    struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array;
-                    struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index;
+                    struct_field_val->parent.id = ConstParentIdArray;
+                    struct_field_val->parent.data.p_array.array_val = struct_field_array;
+                    struct_field_val->parent.data.p_array.elem_index = struct_field_index;
                 }
                 // defs: []TypeInfo.Definition
                 ensure_field_index(result->type, "defs", 2);
@@ -17757,7 +17879,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                 fn_arg_array->special = ConstValSpecialStatic;
                 fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count);
                 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
-                fn_arg_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
                 fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
 
                 init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false);
@@ -17794,9 +17915,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
                     }
 
                     fn_arg_val->data.x_struct.fields = inner_fields;
-                    fn_arg_val->data.x_struct.parent.id = ConstParentIdArray;
-                    fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array;
-                    fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
+                    fn_arg_val->parent.id = ConstParentIdArray;
+                    fn_arg_val->parent.data.p_array.array_val = fn_arg_array;
+                    fn_arg_val->parent.data.p_array.elem_index = fn_arg_index;
                 }
 
                 break;
@@ -17840,8 +17961,8 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira,
 
     if (payload != nullptr) {
         assert(payload->type->id == ZigTypeIdStruct);
-        payload->data.x_struct.parent.id = ConstParentIdUnion;
-        payload->data.x_struct.parent.data.p_union.union_val = out_val;
+        payload->parent.id = ConstParentIdUnion;
+        payload->parent.data.p_union.union_val = out_val;
     }
 
     return result;
@@ -17913,10 +18034,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
 
     // Execute the C import block like an inline function
     ZigType *void_type = ira->codegen->builtin_types.entry_void;
-    IrInstruction *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
+    ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
         ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
         &cimport_scope->buf, block_node, nullptr, nullptr);
-    if (type_is_invalid(cimport_result->value.type))
+    if (type_is_invalid(cimport_result->type))
         return ira->codegen->invalid_instruction;
 
     find_libc_include_path(ira->codegen);
@@ -18066,7 +18187,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
     return result;
 }
 
-static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
+static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchgSrc *instruction) {
     ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child);
     if (type_is_invalid(operand_type))
         return ira->codegen->invalid_instruction;
@@ -18138,9 +18259,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
         zig_panic("TODO compile-time execution of cmpxchg");
     }
 
-    IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
-            nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
-            operand_type, success_order, failure_order);
+    IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base,
+            casted_ptr, casted_cmp_value, casted_new_value,
+            success_order, failure_order, instruction->is_weak);
     result->value.type = get_optional_type(ira->codegen, operand_type);
     ir_add_alloca(ira, result, result->value.type);
     return result;
@@ -18312,18 +18433,6 @@ static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInst
     return ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type);
 }
 
-static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
-    Error err;
-
-    if (ty->id == ZigTypeIdPointer) {
-        if ((err = type_resolve(ira->codegen, ty->data.pointer.child_type, ResolveStatusAlignmentKnown)))
-            return err;
-    }
-
-    *result_align = get_ptr_align(ira->codegen, ty);
-    return ErrorNone;
-}
-
 static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
     Error err;
 
@@ -18442,6 +18551,20 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct
     return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
 }
 
+static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
+    Error err;
+
+    ZigType *ptr_type = get_src_ptr_type(ty);
+    assert(ptr_type != nullptr);
+    if (ptr_type->id == ZigTypeIdPointer) {
+        if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+            return err;
+    }
+
+    *result_align = get_ptr_align(ira->codegen, ty);
+    return ErrorNone;
+}
+
 static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
     ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
     if (type_is_invalid(dest_type))
@@ -18646,10 +18769,18 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio
                 }
             case ConstPtrSpecialBaseStruct:
                 zig_panic("TODO memset on const inner struct");
+            case ConstPtrSpecialBaseErrorUnionCode:
+                zig_panic("TODO memset on const inner error union code");
+            case ConstPtrSpecialBaseErrorUnionPayload:
+                zig_panic("TODO memset on const inner error union payload");
+            case ConstPtrSpecialBaseOptionalPayload:
+                zig_panic("TODO memset on const inner optional payload");
             case ConstPtrSpecialHardCodedAddr:
                 zig_unreachable();
             case ConstPtrSpecialFunction:
                 zig_panic("TODO memset on ptr cast from function");
+            case ConstPtrSpecialNull:
+                zig_panic("TODO memset on null ptr");
         }
 
         size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint);
@@ -18761,10 +18892,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
                 }
             case ConstPtrSpecialBaseStruct:
                 zig_panic("TODO memcpy on const inner struct");
+            case ConstPtrSpecialBaseErrorUnionCode:
+                zig_panic("TODO memcpy on const inner error union code");
+            case ConstPtrSpecialBaseErrorUnionPayload:
+                zig_panic("TODO memcpy on const inner error union payload");
+            case ConstPtrSpecialBaseOptionalPayload:
+                zig_panic("TODO memcpy on const inner optional payload");
             case ConstPtrSpecialHardCodedAddr:
                 zig_unreachable();
             case ConstPtrSpecialFunction:
                 zig_panic("TODO memcpy on ptr cast from function");
+            case ConstPtrSpecialNull:
+                zig_panic("TODO memcpy on null ptr");
         }
 
         if (dest_start + count > dest_end) {
@@ -18797,10 +18936,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
                 }
             case ConstPtrSpecialBaseStruct:
                 zig_panic("TODO memcpy on const inner struct");
+            case ConstPtrSpecialBaseErrorUnionCode:
+                zig_panic("TODO memcpy on const inner error union code");
+            case ConstPtrSpecialBaseErrorUnionPayload:
+                zig_panic("TODO memcpy on const inner error union payload");
+            case ConstPtrSpecialBaseOptionalPayload:
+                zig_panic("TODO memcpy on const inner optional payload");
             case ConstPtrSpecialHardCodedAddr:
                 zig_unreachable();
             case ConstPtrSpecialFunction:
                 zig_panic("TODO memcpy on ptr cast from function");
+            case ConstPtrSpecialNull:
+                zig_panic("TODO memcpy on null ptr");
         }
 
         if (src_start + count > src_end) {
@@ -18828,9 +18975,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
     if (type_is_invalid(ptr_ptr->value.type))
         return ira->codegen->invalid_instruction;
 
-    ZigType *ptr_type = ptr_ptr->value.type;
-    assert(ptr_type->id == ZigTypeIdPointer);
-    ZigType *array_type = ptr_type->data.pointer.child_type;
+    ZigType *ptr_ptr_type = ptr_ptr->value.type;
+    assert(ptr_ptr_type->id == ZigTypeIdPointer);
+    ZigType *array_type = ptr_ptr_type->data.pointer.child_type;
 
     IrInstruction *start = instruction->start->child;
     if (type_is_invalid(start->value.type))
@@ -18859,10 +19006,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
         bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic &&
             ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst;
         ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
-            ptr_type->data.pointer.is_const || is_comptime_const,
-            ptr_type->data.pointer.is_volatile,
+            ptr_ptr_type->data.pointer.is_const || is_comptime_const,
+            ptr_ptr_type->data.pointer.is_volatile,
             PtrLenUnknown,
-            ptr_type->data.pointer.explicit_alignment, 0, 0);
+            ptr_ptr_type->data.pointer.explicit_alignment, 0, 0);
         return_type = get_slice_type(ira->codegen, slice_ptr_type);
     } else if (array_type->id == ZigTypeIdPointer) {
         if (array_type->data.pointer.ptr_len == PtrLenSingle) {
@@ -18960,6 +19107,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
                     break;
                 case ConstPtrSpecialBaseStruct:
                     zig_panic("TODO slice const inner struct");
+                case ConstPtrSpecialBaseErrorUnionCode:
+                    zig_panic("TODO slice const inner error union code");
+                case ConstPtrSpecialBaseErrorUnionPayload:
+                    zig_panic("TODO slice const inner error union payload");
+                case ConstPtrSpecialBaseOptionalPayload:
+                    zig_panic("TODO slice const inner optional payload");
                 case ConstPtrSpecialHardCodedAddr:
                     array_val = nullptr;
                     abs_offset = 0;
@@ -18967,6 +19120,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
                     break;
                 case ConstPtrSpecialFunction:
                     zig_panic("TODO slice of ptr cast from function");
+                case ConstPtrSpecialNull:
+                    zig_panic("TODO slice of null ptr");
             }
         } else if (is_slice(array_type)) {
             ConstExprValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node);
@@ -18997,6 +19152,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
                     break;
                 case ConstPtrSpecialBaseStruct:
                     zig_panic("TODO slice const inner struct");
+                case ConstPtrSpecialBaseErrorUnionCode:
+                    zig_panic("TODO slice const inner error union code");
+                case ConstPtrSpecialBaseErrorUnionPayload:
+                    zig_panic("TODO slice const inner error union payload");
+                case ConstPtrSpecialBaseOptionalPayload:
+                    zig_panic("TODO slice const inner optional payload");
                 case ConstPtrSpecialHardCodedAddr:
                     array_val = nullptr;
                     abs_offset = 0;
@@ -19004,6 +19165,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
                     break;
                 case ConstPtrSpecialFunction:
                     zig_panic("TODO slice of slice cast from function");
+                case ConstPtrSpecialNull:
+                    zig_panic("TODO slice of null");
             }
         } else {
             zig_unreachable();
@@ -19069,6 +19232,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
                 zig_unreachable();
             case ConstPtrSpecialBaseStruct:
                 zig_panic("TODO");
+            case ConstPtrSpecialBaseErrorUnionCode:
+                zig_panic("TODO");
+            case ConstPtrSpecialBaseErrorUnionPayload:
+                zig_panic("TODO");
+            case ConstPtrSpecialBaseOptionalPayload:
+                zig_panic("TODO");
             case ConstPtrSpecialHardCodedAddr:
                 init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
                     parent_ptr->type->data.pointer.child_type,
@@ -19077,6 +19246,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
                 break;
             case ConstPtrSpecialFunction:
                 zig_panic("TODO");
+            case ConstPtrSpecialNull:
+                zig_panic("TODO");
         }
 
         ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
@@ -19432,7 +19603,8 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
                 return ira->codegen->invalid_instruction;
 
             if (err_union_val->special != ConstValSpecialRuntime) {
-                return ir_const_bool(ira, &instruction->base, (err_union_val->data.x_err_union.err != nullptr));
+                ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+                return ir_const_bool(ira, &instruction->base, (err != nullptr));
             }
         }
 
@@ -19458,48 +19630,47 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
     }
 }
 
-static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
-    IrInstructionUnwrapErrCode *instruction)
-{
-    IrInstruction *value = instruction->value->child;
-    if (type_is_invalid(value->value.type))
+static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) {
+    IrInstruction *base_ptr = instruction->err_union->child;
+    if (type_is_invalid(base_ptr->value.type))
         return ira->codegen->invalid_instruction;
-    ZigType *ptr_type = value->value.type;
+    ZigType *ptr_type = base_ptr->value.type;
 
     // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
     assert(ptr_type->id == ZigTypeIdPointer);
 
     ZigType *type_entry = ptr_type->data.pointer.child_type;
-    if (type_is_invalid(type_entry)) {
+    if (type_is_invalid(type_entry))
         return ira->codegen->invalid_instruction;
-    } else if (type_entry->id == ZigTypeIdErrorUnion) {
-        if (instr_is_comptime(value)) {
-            ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
-            if (!ptr_val)
-                return ira->codegen->invalid_instruction;
-            ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
-            if (err_union_val == nullptr)
-                return ira->codegen->invalid_instruction;
-            if (err_union_val->special != ConstValSpecialRuntime) {
-                ErrorTableEntry *err = err_union_val->data.x_err_union.err;
-                assert(err);
-
-                IrInstruction *result = ir_const(ira, &instruction->base,
-                        type_entry->data.error_union.err_set_type);
-                result->value.data.x_err_set = err;
-                return result;
-            }
-        }
 
-        IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb,
-            instruction->base.scope, instruction->base.source_node, value);
-        result->value.type = type_entry->data.error_union.err_set_type;
-        return result;
-    } else {
-        ir_add_error(ira, value,
+    if (type_entry->id != ZigTypeIdErrorUnion) {
+        ir_add_error(ira, base_ptr,
             buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
         return ira->codegen->invalid_instruction;
     }
+
+    if (instr_is_comptime(base_ptr)) {
+        ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
+        if (!ptr_val)
+            return ira->codegen->invalid_instruction;
+        ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
+        if (err_union_val == nullptr)
+            return ira->codegen->invalid_instruction;
+        if (err_union_val->special != ConstValSpecialRuntime) {
+            ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+            assert(err);
+
+            IrInstruction *result = ir_const(ira, &instruction->base,
+                    type_entry->data.error_union.err_set_type);
+            result->value.data.x_err_set = err;
+            return result;
+        }
+    }
+
+    IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb,
+        instruction->base.scope, instruction->base.source_node, base_ptr);
+    result->value.type = type_entry->data.error_union.err_set_type;
+    return result;
 }
 
 static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
@@ -19515,48 +19686,48 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
     assert(ptr_type->id == ZigTypeIdPointer);
 
     ZigType *type_entry = ptr_type->data.pointer.child_type;
-    if (type_is_invalid(type_entry)) {
+    if (type_is_invalid(type_entry))
         return ira->codegen->invalid_instruction;
-    } else if (type_entry->id == ZigTypeIdErrorUnion) {
-        ZigType *payload_type = type_entry->data.error_union.payload_type;
-        if (type_is_invalid(payload_type)) {
-            return ira->codegen->invalid_instruction;
-        }
-        ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
-                ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
-                PtrLenSingle, 0, 0, 0);
-        if (instr_is_comptime(value)) {
-            ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
-            if (!ptr_val)
-                return ira->codegen->invalid_instruction;
-            ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
-            if (err_union_val == nullptr)
-                return ira->codegen->invalid_instruction;
-            if (err_union_val->special != ConstValSpecialRuntime) {
-                ErrorTableEntry *err = err_union_val->data.x_err_union.err;
-                if (err != nullptr) {
-                    ir_add_error(ira, &instruction->base,
-                        buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
-                    return ira->codegen->invalid_instruction;
-                }
 
-                IrInstruction *result = ir_const(ira, &instruction->base, result_type);
-                result->value.data.x_ptr.special = ConstPtrSpecialRef;
-                result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
-                return result;
-            }
-        }
-
-        IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb,
-            instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on);
-        result->value.type = result_type;
-        return result;
-    } else {
+    if (type_entry->id != ZigTypeIdErrorUnion) {
         ir_add_error(ira, value,
             buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
         return ira->codegen->invalid_instruction;
     }
 
+    ZigType *payload_type = type_entry->data.error_union.payload_type;
+    if (type_is_invalid(payload_type))
+        return ira->codegen->invalid_instruction;
+
+    ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
+            ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+            PtrLenSingle, 0, 0, 0);
+    if (instr_is_comptime(value)) {
+        ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
+        if (!ptr_val)
+            return ira->codegen->invalid_instruction;
+        ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
+        if (err_union_val == nullptr)
+            return ira->codegen->invalid_instruction;
+        if (err_union_val->special != ConstValSpecialRuntime) {
+            ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+            if (err != nullptr) {
+                ir_add_error(ira, &instruction->base,
+                    buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
+                return ira->codegen->invalid_instruction;
+            }
+
+            IrInstruction *result = ir_const(ira, &instruction->base, result_type);
+            result->value.data.x_ptr.special = ConstPtrSpecialRef;
+            result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
+            return result;
+        }
+    }
+
+    IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb,
+        instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on);
+    result->value.type = result_type;
+    return result;
 }
 
 static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) {
@@ -19973,7 +20144,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
             return ira->codegen->invalid_instruction;
         }
 
-        IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type);
+        IrInstruction *result = ir_const(ira, target, result_type);
         copy_const_val(&result->value, val, false);
         result->value.type = result_type;
         return result;
@@ -20021,8 +20192,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
         if (!val)
             return ira->codegen->invalid_instruction;
 
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node,
-                dest_type);
+        IrInstruction *result = ir_const(ira, source_instr, dest_type);
         copy_const_val(&result->value, val, false);
         result->value.type = dest_type;
         return result;
@@ -20045,9 +20215,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
         return ira->codegen->invalid_instruction;
     }
 
-    IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope,
-            source_instr->source_node, nullptr, ptr);
-    casted_ptr->value.type = dest_type;
+    IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr);
 
     if (type_has_bits(dest_type) && !type_has_bits(src_type)) {
         ErrorMsg *msg = ir_add_error(ira, source_instr,
@@ -20073,7 +20241,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
     return result;
 }
 
-static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
+static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCastSrc *instruction) {
     IrInstruction *dest_type_value = instruction->dest_type->child;
     ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
     if (type_is_invalid(dest_type))
@@ -20211,15 +20379,29 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
                         if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem)))
                             return err;
                     }
-                    break;
+                    return ErrorNone;
                 case ConstArraySpecialUndef:
                     zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type");
                 case ConstArraySpecialBuf:
                     zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type");
             }
-
-            return ErrorNone;
+            zig_unreachable();
         }
+        case ZigTypeIdEnum:
+            switch (val->type->data.enumeration.layout) {
+                case ContainerLayoutAuto:
+                    zig_panic("TODO buf_read_value_bytes enum auto");
+                case ContainerLayoutPacked:
+                    zig_panic("TODO buf_read_value_bytes enum packed");
+                case ContainerLayoutExtern: {
+                    ZigType *tag_int_type = val->type->data.enumeration.tag_int_type;
+                    assert(tag_int_type->id == ZigTypeIdInt);
+                    bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count,
+                            codegen->is_big_endian, tag_int_type->data.integral.is_signed);
+                    return ErrorNone;
+                }
+            }
+            zig_unreachable();
         case ZigTypeIdStruct:
             switch (val->type->data.structure.layout) {
                 case ContainerLayoutAuto: {
@@ -20258,8 +20440,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
             zig_panic("TODO buf_read_value_bytes error union");
         case ZigTypeIdErrorSet:
             zig_panic("TODO buf_read_value_bytes pure error type");
-        case ZigTypeIdEnum:
-            zig_panic("TODO buf_read_value_bytes enum type");
         case ZigTypeIdFn:
             zig_panic("TODO buf_read_value_bytes fn type");
         case ZigTypeIdUnion:
@@ -20426,8 +20606,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
         case TldIdContainer:
         case TldIdCompTime:
             zig_unreachable();
-        case TldIdVar:
-        {
+        case TldIdVar: {
             TldVar *tld_var = (TldVar *)tld;
             ZigVar *var = tld_var->var;
 
@@ -20445,8 +20624,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
                 return ir_get_deref(ira, &instruction->base, var_ptr);
             }
         }
-        case TldIdFn:
-        {
+        case TldIdFn: {
             TldFn *tld_fn = (TldFn *)tld;
             ZigFn *fn_entry = tld_fn->fn_entry;
             assert(fn_entry->type_entry);
@@ -20492,8 +20670,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru
         if (!val)
             return ira->codegen->invalid_instruction;
         if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
-            IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope,
-                    instruction->base.source_node, usize);
+            IrInstruction *result = ir_const(ira, &instruction->base, usize);
             bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);
             result->value.type = usize;
             return result;
@@ -21331,6 +21508,9 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
         case IrInstructionIdErrWrapCode:
         case IrInstructionIdErrWrapPayload:
         case IrInstructionIdCast:
+        case IrInstructionIdDeclVarGen:
+        case IrInstructionIdPtrCastGen:
+        case IrInstructionIdCmpxchgGen:
             zig_unreachable();
 
         case IrInstructionIdReturn:
@@ -21341,8 +21521,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
             return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction);
         case IrInstructionIdBinOp:
             return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction);
-        case IrInstructionIdDeclVar:
-            return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction);
+        case IrInstructionIdDeclVarSrc:
+            return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVarSrc *)instruction);
         case IrInstructionIdLoadPtr:
             return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction);
         case IrInstructionIdStorePtr:
@@ -21387,8 +21567,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
             return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
         case IrInstructionIdTestNonNull:
             return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction);
-        case IrInstructionIdUnwrapOptional:
-            return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction);
+        case IrInstructionIdOptionalUnwrapPtr:
+            return ir_analyze_instruction_optional_unwrap_ptr(ira, (IrInstructionOptionalUnwrapPtr *)instruction);
         case IrInstructionIdClz:
             return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);
         case IrInstructionIdCtz:
@@ -21429,8 +21609,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
             return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction);
         case IrInstructionIdEmbedFile:
             return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction);
-        case IrInstructionIdCmpxchg:
-            return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);
+        case IrInstructionIdCmpxchgSrc:
+            return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchgSrc *)instruction);
         case IrInstructionIdFence:
             return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
         case IrInstructionIdTruncate:
@@ -21497,8 +21677,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
             return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
         case IrInstructionIdPanic:
             return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
-        case IrInstructionIdPtrCast:
-            return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction);
+        case IrInstructionIdPtrCastSrc:
+            return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction);
         case IrInstructionIdBitCast:
             return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction);
         case IrInstructionIdIntToPtr:
@@ -21682,7 +21862,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdBr:
         case IrInstructionIdCondBr:
         case IrInstructionIdSwitchBr:
-        case IrInstructionIdDeclVar:
+        case IrInstructionIdDeclVarSrc:
+        case IrInstructionIdDeclVarGen:
         case IrInstructionIdStorePtr:
         case IrInstructionIdCall:
         case IrInstructionIdReturn:
@@ -21697,7 +21878,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdCInclude:
         case IrInstructionIdCDefine:
         case IrInstructionIdCUndef:
-        case IrInstructionIdCmpxchg:
         case IrInstructionIdFence:
         case IrInstructionIdMemset:
         case IrInstructionIdMemcpy:
@@ -21725,6 +21905,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdMergeErrRetTraces:
         case IrInstructionIdMarkErrRetTracePtr:
         case IrInstructionIdAtomicRmw:
+        case IrInstructionIdCmpxchgGen:
+        case IrInstructionIdCmpxchgSrc:
             return true;
 
         case IrInstructionIdPhi:
@@ -21750,7 +21932,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdSliceType:
         case IrInstructionIdSizeOf:
         case IrInstructionIdTestNonNull:
-        case IrInstructionIdUnwrapOptional:
+        case IrInstructionIdOptionalUnwrapPtr:
         case IrInstructionIdClz:
         case IrInstructionIdCtz:
         case IrInstructionIdPopCount:
@@ -21777,7 +21959,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdErrWrapPayload:
         case IrInstructionIdFnProto:
         case IrInstructionIdTestComptime:
-        case IrInstructionIdPtrCast:
+        case IrInstructionIdPtrCastSrc:
+        case IrInstructionIdPtrCastGen:
         case IrInstructionIdBitCast:
         case IrInstructionIdWidenOrShorten:
         case IrInstructionIdPtrToInt:
src/ir.hpp
@@ -13,7 +13,7 @@
 bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable);
 bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
 
-IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
+ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
         ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
         ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
         IrExecutable *parent_exec);
src/ir_print.cpp
@@ -172,7 +172,7 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction
     }
 }
 
-static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instruction) {
+static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) {
     const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
     const char *name = buf_ptr(&decl_var_instruction->var->name);
     if (decl_var_instruction->var_type) {
@@ -332,8 +332,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
 }
 
 static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
-    fprintf(irp->f, "*");
     ir_print_other_instruction(irp, instruction->ptr);
+    fprintf(irp->f, ".*");
 }
 
 static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
@@ -479,15 +479,15 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
     fprintf(irp->f, ")");
 }
 
-static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
-    fprintf(irp->f, "*");
+static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
     ir_print_other_instruction(irp, instruction->value);
     fprintf(irp->f, " != null");
 }
 
-static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
-    fprintf(irp->f, "&??*");
-    ir_print_other_instruction(irp, instruction->value);
+static void ir_print_optional_unwrap_ptr(IrPrint *irp, IrInstructionOptionalUnwrapPtr *instruction) {
+    fprintf(irp->f, "&");
+    ir_print_other_instruction(irp, instruction->base_ptr);
+    fprintf(irp->f, ".*.?");
     if (!instruction->safety_check_on) {
         fprintf(irp->f, " // no safety");
     }
@@ -613,7 +613,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio
     fprintf(irp->f, ")");
 }
 
-static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
+static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruction) {
     fprintf(irp->f, "@cmpxchg(");
     ir_print_other_instruction(irp, instruction->ptr);
     fprintf(irp->f, ", ");
@@ -627,6 +627,16 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
     fprintf(irp->f, ")");
 }
 
+static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) {
+    fprintf(irp->f, "@cmpxchg(");
+    ir_print_other_instruction(irp, instruction->ptr);
+    fprintf(irp->f, ", ");
+    ir_print_other_instruction(irp, instruction->cmp_value);
+    fprintf(irp->f, ", ");
+    ir_print_other_instruction(irp, instruction->new_value);
+    fprintf(irp->f, ", TODO print atomic orders)");
+}
+
 static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
     fprintf(irp->f, "@fence(");
     ir_print_other_instruction(irp, instruction->order_value);
@@ -820,13 +830,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) {
 }
 
 static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) {
-    fprintf(irp->f, "@unwrapErrorCode(");
-    ir_print_other_instruction(irp, instruction->value);
+    fprintf(irp->f, "UnwrapErrorCode(");
+    ir_print_other_instruction(irp, instruction->err_union);
     fprintf(irp->f, ")");
 }
 
 static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) {
-    fprintf(irp->f, "@unwrapErrorPayload(");
+    fprintf(irp->f, "ErrorUnionFieldPayload(");
     ir_print_other_instruction(irp, instruction->value);
     fprintf(irp->f, ")");
     if (!instruction->safety_check_on) {
@@ -879,7 +889,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
     fprintf(irp->f, ")");
 }
 
-static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
+static void ir_print_ptr_cast_src(IrPrint *irp, IrInstructionPtrCastSrc *instruction) {
     fprintf(irp->f, "@ptrCast(");
     if (instruction->dest_type) {
         ir_print_other_instruction(irp, instruction->dest_type);
@@ -889,6 +899,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
     fprintf(irp->f, ")");
 }
 
+static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruction) {
+    fprintf(irp->f, "@ptrCast(");
+    ir_print_other_instruction(irp, instruction->ptr);
+    fprintf(irp->f, ")");
+}
+
 static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
     fprintf(irp->f, "@bitCast(");
     if (instruction->dest_type) {
@@ -900,7 +916,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
 }
 
 static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
-    fprintf(irp->f, "@widenOrShorten(");
+    fprintf(irp->f, "WidenOrShorten(");
     ir_print_other_instruction(irp, instruction->target);
     fprintf(irp->f, ")");
 }
@@ -1323,6 +1339,20 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
     fprintf(irp->f, ")");
 }
 
+static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_var_instruction) {
+    ZigVar *var = decl_var_instruction->var;
+    const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
+    const char *name = buf_ptr(&decl_var_instruction->var->name);
+    fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name),
+            var->align_bytes);
+
+    ir_print_other_instruction(irp, decl_var_instruction->init_value);
+    if (decl_var_instruction->var->is_comptime != nullptr) {
+        fprintf(irp->f, " // comptime = ");
+        ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
+    }
+}
+
 static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) {
     fprintf(irp->f, "@bswap(");
     if (instruction->type != nullptr) {
@@ -1361,8 +1391,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdBinOp:
             ir_print_bin_op(irp, (IrInstructionBinOp *)instruction);
             break;
-        case IrInstructionIdDeclVar:
-            ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction);
+        case IrInstructionIdDeclVarSrc:
+            ir_print_decl_var_src(irp, (IrInstructionDeclVarSrc *)instruction);
             break;
         case IrInstructionIdCast:
             ir_print_cast(irp, (IrInstructionCast *)instruction);
@@ -1452,10 +1482,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
             ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
             break;
         case IrInstructionIdTestNonNull:
-            ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
+            ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction);
             break;
-        case IrInstructionIdUnwrapOptional:
-            ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction);
+        case IrInstructionIdOptionalUnwrapPtr:
+            ir_print_optional_unwrap_ptr(irp, (IrInstructionOptionalUnwrapPtr *)instruction);
             break;
         case IrInstructionIdCtz:
             ir_print_ctz(irp, (IrInstructionCtz *)instruction);
@@ -1508,8 +1538,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdEmbedFile:
             ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction);
             break;
-        case IrInstructionIdCmpxchg:
-            ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction);
+        case IrInstructionIdCmpxchgSrc:
+            ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction);
+            break;
+        case IrInstructionIdCmpxchgGen:
+            ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction);
             break;
         case IrInstructionIdFence:
             ir_print_fence(irp, (IrInstructionFence *)instruction);
@@ -1607,8 +1640,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdTestComptime:
             ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
             break;
-        case IrInstructionIdPtrCast:
-            ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
+        case IrInstructionIdPtrCastSrc:
+            ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction);
+            break;
+        case IrInstructionIdPtrCastGen:
+            ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction);
             break;
         case IrInstructionIdBitCast:
             ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
@@ -1775,6 +1811,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdCheckRuntimeScope:
             ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction);
             break;
+        case IrInstructionIdDeclVarGen:
+            ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction);
+            break;
     }
     fprintf(irp->f, "\n");
 }
src/parser.cpp
@@ -381,7 +381,7 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse
         else_body = ast_expect(pc, body_parser);
     }
 
-    assert(res->type == NodeTypeTestExpr);
+    assert(res->type == NodeTypeIfOptional);
     if (err_payload != nullptr) {
         AstNodeTestExpr old = res->data.test_expr;
         res->type = NodeTypeIfErrorExpr;
@@ -990,7 +990,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) {
     if (requires_semi && else_body == nullptr)
         expect_token(pc, TokenIdSemicolon);
 
-    assert(res->type == NodeTypeTestExpr);
+    assert(res->type == NodeTypeIfOptional);
     if (err_payload != nullptr) {
         AstNodeTestExpr old = res->data.test_expr;
         res->type = NodeTypeIfErrorExpr;
@@ -2204,7 +2204,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) {
     Optional<PtrPayload> opt_payload = ast_parse_ptr_payload(pc);
 
     PtrPayload payload;
-    AstNode *res = ast_create_node(pc, NodeTypeTestExpr, first);
+    AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first);
     res->data.test_expr.target_node = condition;
     if (opt_payload.unwrap(&payload)) {
         res->data.test_expr.var_symbol = token_buf(payload.payload);
@@ -2999,7 +2999,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
             visit_field(&node->data.if_err_expr.then_node, visit, context);
             visit_field(&node->data.if_err_expr.else_node, visit, context);
             break;
-        case NodeTypeTestExpr:
+        case NodeTypeIfOptional:
             visit_field(&node->data.test_expr.target_node, visit, context);
             visit_field(&node->data.test_expr.then_node, visit, context);
             visit_field(&node->data.test_expr.else_node, visit, context);
std/event/fs.zig
@@ -1307,32 +1307,29 @@ pub fn Watch(comptime V: type) type {
 
 const test_tmp_dir = "std_event_fs_test";
 
-test "write a file, watch it, write it again" {
-    if (builtin.os == builtin.Os.windows) {
-        // TODO this test is disabled on windows until the coroutine rewrite is finished.
-        // https://github.com/ziglang/zig/issues/1363
-        return error.SkipZigTest;
-    }
-    var da = std.heap.DirectAllocator.init();
-    defer da.deinit();
-
-    const allocator = &da.allocator;
-
-    // TODO move this into event loop too
-    try os.makePath(allocator, test_tmp_dir);
-    defer os.deleteTree(allocator, test_tmp_dir) catch {};
-
-    var loop: Loop = undefined;
-    try loop.initMultiThreaded(allocator);
-    defer loop.deinit();
-
-    var result: anyerror!void = error.ResultNeverWritten;
-    const handle = try async<allocator> testFsWatchCantFail(&loop, &result);
-    defer cancel handle;
-
-    loop.run();
-    return result;
-}
+// TODO this test is disabled until the coroutine rewrite is finished.
+//test "write a file, watch it, write it again" {
+//    return error.SkipZigTest;
+//    var da = std.heap.DirectAllocator.init();
+//    defer da.deinit();
+//
+//    const allocator = &da.allocator;
+//
+//    // TODO move this into event loop too
+//    try os.makePath(allocator, test_tmp_dir);
+//    defer os.deleteTree(allocator, test_tmp_dir) catch {};
+//
+//    var loop: Loop = undefined;
+//    try loop.initMultiThreaded(allocator);
+//    defer loop.deinit();
+//
+//    var result: anyerror!void = error.ResultNeverWritten;
+//    const handle = try async<allocator> testFsWatchCantFail(&loop, &result);
+//    defer cancel handle;
+//
+//    loop.run();
+//    return result;
+//}
 
 async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
     result.* = await (async testFsWatch(loop) catch unreachable);
test/cases/array.zig
@@ -1,173 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-
-test "arrays" {
-    var array: [5]u32 = undefined;
-
-    var i: u32 = 0;
-    while (i < 5) {
-        array[i] = i + 1;
-        i = array[i];
-    }
-
-    i = 0;
-    var accumulator = u32(0);
-    while (i < 5) {
-        accumulator += array[i];
-
-        i += 1;
-    }
-
-    assert(accumulator == 15);
-    assert(getArrayLen(array) == 5);
-}
-fn getArrayLen(a: []const u32) usize {
-    return a.len;
-}
-
-test "void arrays" {
-    var array: [4]void = undefined;
-    array[0] = void{};
-    array[1] = array[2];
-    assert(@sizeOf(@typeOf(array)) == 0);
-    assert(array.len == 4);
-}
-
-test "array literal" {
-    const hex_mult = []u16{
-        4096,
-        256,
-        16,
-        1,
-    };
-
-    assert(hex_mult.len == 4);
-    assert(hex_mult[1] == 256);
-}
-
-test "array dot len const expr" {
-    assert(comptime x: {
-        break :x some_array.len == 4;
-    });
-}
-
-const ArrayDotLenConstExpr = struct {
-    y: [some_array.len]u8,
-};
-const some_array = []u8{
-    0,
-    1,
-    2,
-    3,
-};
-
-test "nested arrays" {
-    const array_of_strings = [][]const u8{
-        "hello",
-        "this",
-        "is",
-        "my",
-        "thing",
-    };
-    for (array_of_strings) |s, i| {
-        if (i == 0) assert(mem.eql(u8, s, "hello"));
-        if (i == 1) assert(mem.eql(u8, s, "this"));
-        if (i == 2) assert(mem.eql(u8, s, "is"));
-        if (i == 3) assert(mem.eql(u8, s, "my"));
-        if (i == 4) assert(mem.eql(u8, s, "thing"));
-    }
-}
-
-var s_array: [8]Sub = undefined;
-const Sub = struct {
-    b: u8,
-};
-const Str = struct {
-    a: []Sub,
-};
-test "set global var array via slice embedded in struct" {
-    var s = Str{ .a = s_array[0..] };
-
-    s.a[0].b = 1;
-    s.a[1].b = 2;
-    s.a[2].b = 3;
-
-    assert(s_array[0].b == 1);
-    assert(s_array[1].b == 2);
-    assert(s_array[2].b == 3);
-}
-
-test "array literal with specified size" {
-    var array = [2]u8{
-        1,
-        2,
-    };
-    assert(array[0] == 1);
-    assert(array[1] == 2);
-}
-
-test "array child property" {
-    var x: [5]i32 = undefined;
-    assert(@typeOf(x).Child == i32);
-}
-
-test "array len property" {
-    var x: [5]i32 = undefined;
-    assert(@typeOf(x).len == 5);
-}
-
-test "array len field" {
-    var arr = [4]u8{ 0, 0, 0, 0 };
-    var ptr = &arr;
-    assert(arr.len == 4);
-    comptime assert(arr.len == 4);
-    assert(ptr.len == 4);
-    comptime assert(ptr.len == 4);
-}
-
-test "single-item pointer to array indexing and slicing" {
-    testSingleItemPtrArrayIndexSlice();
-    comptime testSingleItemPtrArrayIndexSlice();
-}
-
-fn testSingleItemPtrArrayIndexSlice() void {
-    var array = "aaaa";
-    doSomeMangling(&array);
-    assert(mem.eql(u8, "azya", array));
-}
-
-fn doSomeMangling(array: *[4]u8) void {
-    array[1] = 'z';
-    array[2..3][0] = 'y';
-}
-
-test "implicit cast single-item pointer" {
-    testImplicitCastSingleItemPtr();
-    comptime testImplicitCastSingleItemPtr();
-}
-
-fn testImplicitCastSingleItemPtr() void {
-    var byte: u8 = 100;
-    const slice = (*[1]u8)(&byte)[0..];
-    slice[0] += 1;
-    assert(byte == 101);
-}
-
-fn testArrayByValAtComptime(b: [2]u8) u8 {
-    return b[0];
-}
-
-test "comptime evalutating function that takes array by value" {
-    const arr = []u8{ 0, 1 };
-    _ = comptime testArrayByValAtComptime(arr);
-    _ = comptime testArrayByValAtComptime(arr);
-}
-
-test "implicit comptime in array type size" {
-    var arr: [plusOne(10)]bool = undefined;
-    assert(arr.len == 11);
-}
-
-fn plusOne(x: u32) u32 {
-    return x + 1;
-}
test/cases/asm.zig
@@ -1,48 +0,0 @@
-const config = @import("builtin");
-const assert = @import("std").debug.assert;
-
-comptime {
-    if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
-        asm volatile (
-            \\.globl aoeu;
-            \\.type aoeu, @function;
-            \\.set aoeu, derp;
-        );
-    }
-}
-
-test "module level assembly" {
-    if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
-        assert(aoeu() == 1234);
-    }
-}
-
-test "output constraint modifiers" {
-    // This is only testing compilation.
-    var a: u32 = 3;
-    asm volatile ("" : [_]"=m,r"(a) : : "");
-    asm volatile ("" : [_]"=r,m"(a) : : "");
-}
-
-test "alternative constraints" {
-    // Make sure we allow commas as a separator for alternative constraints.
-    var a: u32 = 3;
-    asm volatile ("" : [_]"=r,m"(a) : [_]"r,m"(a) : "");
-}
-
-test "sized integer/float in asm input" {
-    asm volatile ("" : : [_]"m"(usize(3)) : "");
-    asm volatile ("" : : [_]"m"(i15(-3)) : "");
-    asm volatile ("" : : [_]"m"(u3(3)) : "");
-    asm volatile ("" : : [_]"m"(i3(3)) : "");
-    asm volatile ("" : : [_]"m"(u121(3)) : "");
-    asm volatile ("" : : [_]"m"(i121(3)) : "");
-    asm volatile ("" : : [_]"m"(f32(3.17)) : "");
-    asm volatile ("" : : [_]"m"(f64(3.17)) : "");
-}
-
-extern fn aoeu() i32;
-
-export fn derp() i32 {
-    return 1234;
-}
test/cases/bitreverse.zig
@@ -1,81 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const minInt = std.math.minInt;
-
-test "@bitreverse" {
-    comptime testBitReverse();
-    testBitReverse();
-}
-
-fn testBitReverse() void {
-    // using comptime_ints, unsigned
-    assert(@bitreverse(u0,   0) == 0);
-    assert(@bitreverse(u5,   0x12) == 0x9);
-    assert(@bitreverse(u8,   0x12) == 0x48);
-    assert(@bitreverse(u16,  0x1234) == 0x2c48);
-    assert(@bitreverse(u24,  0x123456) == 0x6a2c48);
-    assert(@bitreverse(u32,  0x12345678) == 0x1e6a2c48);
-    assert(@bitreverse(u40,  0x123456789a) == 0x591e6a2c48);
-    assert(@bitreverse(u48,  0x123456789abc) == 0x3d591e6a2c48);
-    assert(@bitreverse(u56,  0x123456789abcde) == 0x7b3d591e6a2c48);
-    assert(@bitreverse(u64,  0x123456789abcdef1) == 0x8f7b3d591e6a2c48);
-    assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48);
-
-    // using runtime uints, unsigned
-    var num0: u0 = 0;
-    assert(@bitreverse(u0,   num0) == 0);
-    var num5: u5 = 0x12;
-    assert(@bitreverse(u5,   num5) == 0x9);
-    var num8: u8 = 0x12;
-    assert(@bitreverse(u8,   num8) == 0x48);
-    var num16: u16 = 0x1234;
-    assert(@bitreverse(u16,  num16) == 0x2c48);
-    var num24: u24 = 0x123456;
-    assert(@bitreverse(u24,  num24) == 0x6a2c48);
-    var num32: u32 = 0x12345678;
-    assert(@bitreverse(u32,  num32) == 0x1e6a2c48);
-    var num40: u40 = 0x123456789a;
-    assert(@bitreverse(u40,  num40) == 0x591e6a2c48);
-    var num48: u48 = 0x123456789abc;
-    assert(@bitreverse(u48,  num48) == 0x3d591e6a2c48);
-    var num56: u56 = 0x123456789abcde;
-    assert(@bitreverse(u56,  num56) == 0x7b3d591e6a2c48);
-    var num64: u64 = 0x123456789abcdef1;
-    assert(@bitreverse(u64,  num64) == 0x8f7b3d591e6a2c48);
-    var num128: u128 = 0x123456789abcdef11121314151617181;
-    assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48);
-
-    // using comptime_ints, signed, positive
-    assert(@bitreverse(i0,   0) == 0);
-    assert(@bitreverse(i8,   @bitCast(i8,  u8(0x92))) == @bitCast(i8, u8( 0x49)));
-    assert(@bitreverse(i16,  @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48)));
-    assert(@bitreverse(i24,  @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48)));
-    assert(@bitreverse(i32,  @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48)));
-    assert(@bitreverse(i40,  @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48)));
-    assert(@bitreverse(i48,  @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48)));
-    assert(@bitreverse(i56,  @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48)));
-    assert(@bitreverse(i64,  @bitCast(i64, u64(0x123456789abcdef1))) ==  @bitCast(i64,u64(0x8f7b3d591e6a2c48)));
-    assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) ==  @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48)));
-
-    // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm.
-    var neg5: i5 = minInt(i5) + 1;
-    assert(@bitreverse(i5,   minInt(i5) + 1) == @bitreverse(i5, neg5));
-    var neg8: i8 = -18;
-    assert(@bitreverse(i8,   -18) == @bitreverse(i8, neg8));
-    var neg16: i16 = -32694;
-    assert(@bitreverse(i16,   -32694) == @bitreverse(i16, neg16));
-    var neg24: i24 = -6773785;
-    assert(@bitreverse(i24,   -6773785) == @bitreverse(i24, neg24));
-    var neg32: i32 = -16773785;
-    assert(@bitreverse(i32,   -16773785) == @bitreverse(i32, neg32));
-    var neg40: i40 = minInt(i40) + 12345;
-    assert(@bitreverse(i40,   minInt(i40) + 12345) == @bitreverse(i40, neg40));
-    var neg48: i48 = minInt(i48) + 12345;
-    assert(@bitreverse(i48,   minInt(i48) + 12345) == @bitreverse(i48, neg48));
-    var neg56: i56 = minInt(i56) + 12345;
-    assert(@bitreverse(i56,   minInt(i56) + 12345) == @bitreverse(i56, neg56));
-    var neg64: i64 = minInt(i64) + 12345;
-    assert(@bitreverse(i64,   minInt(i64) + 12345) == @bitreverse(i64, neg64));
-    var neg128: i128 = minInt(i128) + 12345;
-    assert(@bitreverse(i128,   minInt(i128) + 12345) == @bitreverse(i128, neg128));
-}
test/cases/bswap.zig
@@ -1,32 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-test "@bswap" {
-    comptime testByteSwap();
-    testByteSwap();
-}
-
-fn testByteSwap() void {
-    assert(@bswap(u0, 0) == 0);
-    assert(@bswap(u8, 0x12) == 0x12);
-    assert(@bswap(u16, 0x1234) == 0x3412);
-    assert(@bswap(u24, 0x123456) == 0x563412);
-    assert(@bswap(u32, 0x12345678) == 0x78563412);
-    assert(@bswap(u40, 0x123456789a) == 0x9a78563412);
-    assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412);
-    assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412);
-    assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412);
-    assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412);
-
-    assert(@bswap(i0, 0) == 0);
-    assert(@bswap(i8, -50) == -50);
-    assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412)));
-    assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412)));
-    assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412)));
-    assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412)));
-    assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412)));
-    assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412)));
-    assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412)));
-    assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==
-        @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));
-}
test/cases/import.zig
@@ -1,10 +0,0 @@
-const assert = @import("std").debug.assert;
-const a_namespace = @import("import/a_namespace.zig");
-
-test "call fn via namespace lookup" {
-    assert(a_namespace.foo() == 1234);
-}
-
-test "importing the same thing gives the same import" {
-    assert(@import("std") == @import("std"));
-}
test/cases/optional.zig
@@ -1,30 +0,0 @@
-const assert = @import("std").debug.assert;
-
-pub const EmptyStruct = struct {};
-
-test "optional pointer to size zero struct" {
-    var e = EmptyStruct{};
-    var o: ?*EmptyStruct = &e;
-    assert(o != null);
-}
-
-test "equality compare nullable pointers" {
-    testNullPtrsEql();
-    comptime testNullPtrsEql();
-}
-
-fn testNullPtrsEql() void {
-    var number: i32 = 1234;
-
-    var x: ?*i32 = null;
-    var y: ?*i32 = null;
-    assert(x == y);
-    y = &number;
-    assert(x != y);
-    assert(x != &number);
-    assert(&number != x);
-    x = &number;
-    assert(x == y);
-    assert(x == &number);
-    assert(&number == x);
-}
test/cases/popcount.zig
@@ -1,24 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "@popCount" {
-    comptime testPopCount();
-    testPopCount();
-}
-
-fn testPopCount() void {
-    {
-        var x: u32 = 0xaa;
-        assert(@popCount(x) == 4);
-    }
-    {
-        var x: u32 = 0xaaaaaaaa;
-        assert(@popCount(x) == 16);
-    }
-    {
-        var x: i16 = -1;
-        assert(@popCount(x) == 16);
-    }
-    comptime {
-        assert(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24);
-    }
-}
test/cases/reflection.zig
@@ -1,95 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-const reflection = @This();
-
-test "reflection: array, pointer, optional, error union type child" {
-    comptime {
-        assert(([10]u8).Child == u8);
-        assert((*u8).Child == u8);
-        assert((anyerror!u8).Payload == u8);
-        assert((?u8).Child == u8);
-    }
-}
-
-test "reflection: function return type, var args, and param types" {
-    comptime {
-        assert(@typeOf(dummy).ReturnType == i32);
-        assert(!@typeOf(dummy).is_var_args);
-        assert(@typeOf(dummy_varargs).is_var_args);
-        assert(@typeOf(dummy).arg_count == 3);
-        assert(@ArgType(@typeOf(dummy), 0) == bool);
-        assert(@ArgType(@typeOf(dummy), 1) == i32);
-        assert(@ArgType(@typeOf(dummy), 2) == f32);
-    }
-}
-
-fn dummy(a: bool, b: i32, c: f32) i32 {
-    return 1234;
-}
-fn dummy_varargs(args: ...) void {}
-
-test "reflection: struct member types and names" {
-    comptime {
-        assert(@memberCount(Foo) == 3);
-
-        assert(@memberType(Foo, 0) == i32);
-        assert(@memberType(Foo, 1) == bool);
-        assert(@memberType(Foo, 2) == void);
-
-        assert(mem.eql(u8, @memberName(Foo, 0), "one"));
-        assert(mem.eql(u8, @memberName(Foo, 1), "two"));
-        assert(mem.eql(u8, @memberName(Foo, 2), "three"));
-    }
-}
-
-test "reflection: enum member types and names" {
-    comptime {
-        assert(@memberCount(Bar) == 4);
-
-        assert(@memberType(Bar, 0) == void);
-        assert(@memberType(Bar, 1) == i32);
-        assert(@memberType(Bar, 2) == bool);
-        assert(@memberType(Bar, 3) == f64);
-
-        assert(mem.eql(u8, @memberName(Bar, 0), "One"));
-        assert(mem.eql(u8, @memberName(Bar, 1), "Two"));
-        assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
-        assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
-    }
-}
-
-test "reflection: @field" {
-    var f = Foo{
-        .one = 42,
-        .two = true,
-        .three = void{},
-    };
-
-    assert(f.one == f.one);
-    assert(@field(f, "o" ++ "ne") == f.one);
-    assert(@field(f, "t" ++ "wo") == f.two);
-    assert(@field(f, "th" ++ "ree") == f.three);
-    assert(@field(Foo, "const" ++ "ant") == Foo.constant);
-    assert(@field(Bar, "O" ++ "ne") == Bar.One);
-    assert(@field(Bar, "T" ++ "wo") == Bar.Two);
-    assert(@field(Bar, "Th" ++ "ree") == Bar.Three);
-    assert(@field(Bar, "F" ++ "our") == Bar.Four);
-    assert(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2));
-    @field(f, "o" ++ "ne") = 4;
-    assert(f.one == 4);
-}
-
-const Foo = struct {
-    const constant = 52;
-
-    one: i32,
-    two: bool,
-    three: void,
-};
-
-const Bar = union(enum) {
-    One: void,
-    Two: i32,
-    Three: bool,
-    Four: f64,
-};
test/cases/sizeof_and_typeof.zig
@@ -1,69 +0,0 @@
-const builtin = @import("builtin");
-const assert = @import("std").debug.assert;
-
-test "@sizeOf and @typeOf" {
-    const y: @typeOf(x) = 120;
-    assert(@sizeOf(@typeOf(y)) == 2);
-}
-const x: u16 = 13;
-const z: @typeOf(x) = 19;
-
-const A = struct {
-    a: u8,
-    b: u32,
-    c: u8,
-    d: u3,
-    e: u5,
-    f: u16,
-    g: u16,
-};
-
-const P = packed struct {
-    a: u8,
-    b: u32,
-    c: u8,
-    d: u3,
-    e: u5,
-    f: u16,
-    g: u16,
-};
-
-test "@byteOffsetOf" {
-    // Packed structs have fixed memory layout
-    assert(@byteOffsetOf(P, "a") == 0);
-    assert(@byteOffsetOf(P, "b") == 1);
-    assert(@byteOffsetOf(P, "c") == 5);
-    assert(@byteOffsetOf(P, "d") == 6);
-    assert(@byteOffsetOf(P, "e") == 6);
-    assert(@byteOffsetOf(P, "f") == 7);
-    assert(@byteOffsetOf(P, "g") == 9);
-
-    // Normal struct fields can be moved/padded
-    var a: A = undefined;
-    assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
-    assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b"));
-    assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c"));
-    assert(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d"));
-    assert(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e"));
-    assert(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f"));
-    assert(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g"));
-}
-
-test "@bitOffsetOf" {
-    // Packed structs have fixed memory layout
-    assert(@bitOffsetOf(P, "a") == 0);
-    assert(@bitOffsetOf(P, "b") == 8);
-    assert(@bitOffsetOf(P, "c") == 40);
-    assert(@bitOffsetOf(P, "d") == 48);
-    assert(@bitOffsetOf(P, "e") == 51);
-    assert(@bitOffsetOf(P, "f") == 56);
-    assert(@bitOffsetOf(P, "g") == 72);
-
-    assert(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
-    assert(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
-    assert(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
-    assert(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
-    assert(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
-    assert(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
-    assert(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
-}
test/cases/type_info.zig
@@ -1,264 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-const TypeInfo = @import("builtin").TypeInfo;
-const TypeId = @import("builtin").TypeId;
-
-test "type info: tag type, void info" {
-    testBasic();
-    comptime testBasic();
-}
-
-fn testBasic() void {
-    assert(@TagType(TypeInfo) == TypeId);
-    const void_info = @typeInfo(void);
-    assert(TypeId(void_info) == TypeId.Void);
-    assert(void_info.Void == {});
-}
-
-test "type info: integer, floating point type info" {
-    testIntFloat();
-    comptime testIntFloat();
-}
-
-fn testIntFloat() void {
-    const u8_info = @typeInfo(u8);
-    assert(TypeId(u8_info) == TypeId.Int);
-    assert(!u8_info.Int.is_signed);
-    assert(u8_info.Int.bits == 8);
-
-    const f64_info = @typeInfo(f64);
-    assert(TypeId(f64_info) == TypeId.Float);
-    assert(f64_info.Float.bits == 64);
-}
-
-test "type info: pointer type info" {
-    testPointer();
-    comptime testPointer();
-}
-
-fn testPointer() void {
-    const u32_ptr_info = @typeInfo(*u32);
-    assert(TypeId(u32_ptr_info) == TypeId.Pointer);
-    assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
-    assert(u32_ptr_info.Pointer.is_const == false);
-    assert(u32_ptr_info.Pointer.is_volatile == false);
-    assert(u32_ptr_info.Pointer.alignment == @alignOf(u32));
-    assert(u32_ptr_info.Pointer.child == u32);
-}
-
-test "type info: unknown length pointer type info" {
-    testUnknownLenPtr();
-    comptime testUnknownLenPtr();
-}
-
-fn testUnknownLenPtr() void {
-    const u32_ptr_info = @typeInfo([*]const volatile f64);
-    assert(TypeId(u32_ptr_info) == TypeId.Pointer);
-    assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
-    assert(u32_ptr_info.Pointer.is_const == true);
-    assert(u32_ptr_info.Pointer.is_volatile == true);
-    assert(u32_ptr_info.Pointer.alignment == @alignOf(f64));
-    assert(u32_ptr_info.Pointer.child == f64);
-}
-
-test "type info: slice type info" {
-    testSlice();
-    comptime testSlice();
-}
-
-fn testSlice() void {
-    const u32_slice_info = @typeInfo([]u32);
-    assert(TypeId(u32_slice_info) == TypeId.Pointer);
-    assert(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
-    assert(u32_slice_info.Pointer.is_const == false);
-    assert(u32_slice_info.Pointer.is_volatile == false);
-    assert(u32_slice_info.Pointer.alignment == 4);
-    assert(u32_slice_info.Pointer.child == u32);
-}
-
-test "type info: array type info" {
-    testArray();
-    comptime testArray();
-}
-
-fn testArray() void {
-    const arr_info = @typeInfo([42]bool);
-    assert(TypeId(arr_info) == TypeId.Array);
-    assert(arr_info.Array.len == 42);
-    assert(arr_info.Array.child == bool);
-}
-
-test "type info: optional type info" {
-    testOptional();
-    comptime testOptional();
-}
-
-fn testOptional() void {
-    const null_info = @typeInfo(?void);
-    assert(TypeId(null_info) == TypeId.Optional);
-    assert(null_info.Optional.child == void);
-}
-
-test "type info: promise info" {
-    testPromise();
-    comptime testPromise();
-}
-
-fn testPromise() void {
-    const null_promise_info = @typeInfo(promise);
-    assert(TypeId(null_promise_info) == TypeId.Promise);
-    assert(null_promise_info.Promise.child == null);
-
-    const promise_info = @typeInfo(promise->usize);
-    assert(TypeId(promise_info) == TypeId.Promise);
-    assert(promise_info.Promise.child.? == usize);
-}
-
-test "type info: error set, error union info" {
-    testErrorSet();
-    comptime testErrorSet();
-}
-
-fn testErrorSet() void {
-    const TestErrorSet = error{
-        First,
-        Second,
-        Third,
-    };
-
-    const error_set_info = @typeInfo(TestErrorSet);
-    assert(TypeId(error_set_info) == TypeId.ErrorSet);
-    assert(error_set_info.ErrorSet.errors.len == 3);
-    assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
-    assert(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
-
-    const error_union_info = @typeInfo(TestErrorSet!usize);
-    assert(TypeId(error_union_info) == TypeId.ErrorUnion);
-    assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
-    assert(error_union_info.ErrorUnion.payload == usize);
-}
-
-test "type info: enum info" {
-    testEnum();
-    comptime testEnum();
-}
-
-fn testEnum() void {
-    const Os = enum {
-        Windows,
-        Macos,
-        Linux,
-        FreeBSD,
-    };
-
-    const os_info = @typeInfo(Os);
-    assert(TypeId(os_info) == TypeId.Enum);
-    assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
-    assert(os_info.Enum.fields.len == 4);
-    assert(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
-    assert(os_info.Enum.fields[3].value == 3);
-    assert(os_info.Enum.tag_type == u2);
-    assert(os_info.Enum.defs.len == 0);
-}
-
-test "type info: union info" {
-    testUnion();
-    comptime testUnion();
-}
-
-fn testUnion() void {
-    const typeinfo_info = @typeInfo(TypeInfo);
-    assert(TypeId(typeinfo_info) == TypeId.Union);
-    assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
-    assert(typeinfo_info.Union.tag_type.? == TypeId);
-    assert(typeinfo_info.Union.fields.len == 24);
-    assert(typeinfo_info.Union.fields[4].enum_field != null);
-    assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
-    assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
-    assert(typeinfo_info.Union.defs.len == 20);
-
-    const TestNoTagUnion = union {
-        Foo: void,
-        Bar: u32,
-    };
-
-    const notag_union_info = @typeInfo(TestNoTagUnion);
-    assert(TypeId(notag_union_info) == TypeId.Union);
-    assert(notag_union_info.Union.tag_type == null);
-    assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
-    assert(notag_union_info.Union.fields.len == 2);
-    assert(notag_union_info.Union.fields[0].enum_field == null);
-    assert(notag_union_info.Union.fields[1].field_type == u32);
-
-    const TestExternUnion = extern union {
-        foo: *c_void,
-    };
-
-    const extern_union_info = @typeInfo(TestExternUnion);
-    assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
-    assert(extern_union_info.Union.tag_type == null);
-    assert(extern_union_info.Union.fields[0].enum_field == null);
-    assert(extern_union_info.Union.fields[0].field_type == *c_void);
-}
-
-test "type info: struct info" {
-    testStruct();
-    comptime testStruct();
-}
-
-fn testStruct() void {
-    const struct_info = @typeInfo(TestStruct);
-    assert(TypeId(struct_info) == TypeId.Struct);
-    assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
-    assert(struct_info.Struct.fields.len == 3);
-    assert(struct_info.Struct.fields[1].offset == null);
-    assert(struct_info.Struct.fields[2].field_type == *TestStruct);
-    assert(struct_info.Struct.defs.len == 2);
-    assert(struct_info.Struct.defs[0].is_pub);
-    assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
-    assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
-    assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
-    assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void);
-}
-
-const TestStruct = packed struct {
-    const Self = @This();
-
-    fieldA: usize,
-    fieldB: void,
-    fieldC: *Self,
-
-    pub fn foo(self: *const Self) void {}
-};
-
-test "type info: function type info" {
-    testFunction();
-    comptime testFunction();
-}
-
-fn testFunction() void {
-    const fn_info = @typeInfo(@typeOf(foo));
-    assert(TypeId(fn_info) == TypeId.Fn);
-    assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
-    assert(fn_info.Fn.is_generic);
-    assert(fn_info.Fn.args.len == 2);
-    assert(fn_info.Fn.is_var_args);
-    assert(fn_info.Fn.return_type == null);
-    assert(fn_info.Fn.async_allocator_type == null);
-
-    const test_instance: TestStruct = undefined;
-    const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
-    assert(TypeId(bound_fn_info) == TypeId.BoundFn);
-    assert(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
-}
-
-fn foo(comptime a: usize, b: bool, args: ...) usize {
-    return 0;
-}
-
-test "typeInfo with comptime parameter in struct fn def" {
-    const S = struct {
-        pub fn func(comptime x: f32) void {}
-    };
-    comptime var info = @typeInfo(S);
-}
test/cases/bugs/1076.zig → test/stage1/behavior/bugs/1076.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 const mem = std.mem;
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 test "comptime code should not modify constant data" {
     testCastPtrOfArrayToSliceAndPtr();
@@ -11,6 +11,6 @@ fn testCastPtrOfArrayToSliceAndPtr() void {
     var array = "aoeu";
     const x: [*]u8 = &array;
     x[0] += 1;
-    assert(mem.eql(u8, array[0..], "boeu"));
+    assertOrPanic(mem.eql(u8, array[0..], "boeu"));
 }
 
test/cases/bugs/1111.zig → test/stage1/behavior/bugs/1111.zig
File renamed without changes
test/cases/bugs/1277.zig → test/stage1/behavior/bugs/1277.zig
File renamed without changes
test/cases/bugs/1322.zig → test/stage1/behavior/bugs/1322.zig
@@ -13,7 +13,7 @@ const C = struct {};
 
 test "tagged union with all void fields but a meaningful tag" {
     var a: A = A{ .b = B{ .c = C{} } };
-    std.debug.assert(@TagType(B)(a.b) == @TagType(B).c);
+    std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).c);
     a = A{ .b = B.None };
-    std.debug.assert(@TagType(B)(a.b) == @TagType(B).None);
+    std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).None);
 }
test/cases/bugs/1381.zig → test/stage1/behavior/bugs/1381.zig
File renamed without changes
test/cases/bugs/1421.zig → test/stage1/behavior/bugs/1421.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 const S = struct {
     fn method() builtin.TypeInfo {
@@ -10,5 +10,5 @@ const S = struct {
 
 test "functions with return type required to be comptime are generic" {
     const ti = S.method();
-    assert(builtin.TypeId(ti) == builtin.TypeId.Struct);
+    assertOrPanic(builtin.TypeId(ti) == builtin.TypeId.Struct);
 }
test/cases/bugs/1442.zig → test/stage1/behavior/bugs/1442.zig
File renamed without changes
test/cases/bugs/1486.zig → test/stage1/behavior/bugs/1486.zig
@@ -1,11 +1,11 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 const ptr = &global;
 var global: u64 = 123;
 
 test "constant pointer to global variable causes runtime load" {
     global = 1234;
-    assert(&global == ptr);
-    assert(ptr.* == 1234);
+    assertOrPanic(&global == ptr);
+    assertOrPanic(ptr.* == 1234);
 }
 
test/cases/bugs/394.zig → test/stage1/behavior/bugs/394.zig
@@ -7,12 +7,12 @@ const S = struct {
     y: E,
 };
 
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "bug 394 fixed" {
     const x = S{
         .x = 3,
         .y = E{ .B = 1 },
     };
-    assert(x.x == 3);
+    assertOrPanic(x.x == 3);
 }
test/cases/bugs/655.zig → test/stage1/behavior/bugs/655.zig
@@ -3,10 +3,10 @@ const other_file = @import("655_other_file.zig");
 
 test "function with *const parameter with type dereferenced by namespace" {
     const x: other_file.Integer = 1234;
-    comptime std.debug.assert(@typeOf(&x) == *const other_file.Integer);
+    comptime std.debug.assertOrPanic(@typeOf(&x) == *const other_file.Integer);
     foo(&x);
 }
 
 fn foo(x: *const other_file.Integer) void {
-    std.debug.assert(x.* == 1234);
+    std.debug.assertOrPanic(x.* == 1234);
 }
test/cases/bugs/655_other_file.zig → test/stage1/behavior/bugs/655_other_file.zig
File renamed without changes
test/cases/bugs/656.zig → test/stage1/behavior/bugs/656.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 const PrefixOp = union(enum) {
     Return,
@@ -22,7 +22,7 @@ fn foo(a: bool, b: bool) void {
             PrefixOp.AddrOf => |addr_of_info| {
                 if (b) {}
                 if (addr_of_info.align_expr) |align_expr| {
-                    assert(align_expr == 1234);
+                    assertOrPanic(align_expr == 1234);
                 }
             },
             PrefixOp.Return => {},
test/cases/bugs/726.zig → test/stage1/behavior/bugs/726.zig
@@ -1,9 +1,9 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "@ptrCast from const to nullable" {
     const c: u8 = 4;
     var x: ?*const u8 = @ptrCast(?*const u8, &c);
-    assert(x.?.* == 4);
+    assertOrPanic(x.?.* == 4);
 }
 
 test "@ptrCast from var in empty struct to nullable" {
@@ -11,6 +11,6 @@ test "@ptrCast from var in empty struct to nullable" {
         var c: u8 = 4;
     };
     var x: ?*const u8 = @ptrCast(?*const u8, &container.c);
-    assert(x.?.* == 4);
+    assertOrPanic(x.?.* == 4);
 }
 
test/cases/bugs/828.zig → test/stage1/behavior/bugs/828.zig
File renamed without changes
test/cases/bugs/920.zig → test/stage1/behavior/bugs/920.zig
@@ -60,6 +60,6 @@ test "bug 920 fixed" {
     };
 
     for (NormalDist1.f) |_, i| {
-        std.debug.assert(NormalDist1.f[i] == NormalDist.f[i]);
+        std.debug.assertOrPanic(NormalDist1.f[i] == NormalDist.f[i]);
     }
 }
test/cases/import/a_namespace.zig → test/stage1/behavior/import/a_namespace.zig
File renamed without changes
test/cases/namespace_depends_on_compile_var/a.zig → test/stage1/behavior/namespace_depends_on_compile_var/a.zig
File renamed without changes
test/cases/namespace_depends_on_compile_var/b.zig → test/stage1/behavior/namespace_depends_on_compile_var/b.zig
File renamed without changes
test/cases/namespace_depends_on_compile_var/index.zig → test/stage1/behavior/namespace_depends_on_compile_var/index.zig
@@ -1,11 +1,11 @@
 const builtin = @import("builtin");
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "namespace depends on compile var" {
     if (some_namespace.a_bool) {
-        assert(some_namespace.a_bool);
+        assertOrPanic(some_namespace.a_bool);
     } else {
-        assert(!some_namespace.a_bool);
+        assertOrPanic(!some_namespace.a_bool);
     }
 }
 const some_namespace = switch (builtin.os) {
test/cases/pub_enum/index.zig → test/stage1/behavior/pub_enum/index.zig
@@ -1,13 +1,13 @@
 const other = @import("other.zig");
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "pub enum" {
     pubEnumTest(other.APubEnum.Two);
 }
 fn pubEnumTest(foo: other.APubEnum) void {
-    assert(foo == other.APubEnum.Two);
+    assertOrPanic(foo == other.APubEnum.Two);
 }
 
 test "cast with imported symbol" {
-    assert(other.size_t(42) == 42);
+    assertOrPanic(other.size_t(42) == 42);
 }
test/cases/pub_enum/other.zig → test/stage1/behavior/pub_enum/other.zig
File renamed without changes
test/cases/align.zig → test/stage1/behavior/align.zig
@@ -1,13 +1,13 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 const builtin = @import("builtin");
 
 var foo: u8 align(4) = 100;
 
 test "global variable alignment" {
-    assert(@typeOf(&foo).alignment == 4);
-    assert(@typeOf(&foo) == *align(4) u8);
+    assertOrPanic(@typeOf(&foo).alignment == 4);
+    assertOrPanic(@typeOf(&foo) == *align(4) u8);
     const slice = (*[1]u8)(&foo)[0..];
-    assert(@typeOf(slice) == []align(4) u8);
+    assertOrPanic(@typeOf(slice) == []align(4) u8);
 }
 
 fn derp() align(@sizeOf(usize) * 2) i32 {
@@ -17,9 +17,9 @@ fn noop1() align(1) void {}
 fn noop4() align(4) void {}
 
 test "function alignment" {
-    assert(derp() == 1234);
-    assert(@typeOf(noop1) == fn () align(1) void);
-    assert(@typeOf(noop4) == fn () align(4) void);
+    assertOrPanic(derp() == 1234);
+    assertOrPanic(@typeOf(noop1) == fn () align(1) void);
+    assertOrPanic(@typeOf(noop4) == fn () align(4) void);
     noop1();
     noop4();
 }
@@ -30,7 +30,7 @@ var baz: packed struct {
 } = undefined;
 
 test "packed struct alignment" {
-    assert(@typeOf(&baz.b) == *align(1) u32);
+    assertOrPanic(@typeOf(&baz.b) == *align(1) u32);
 }
 
 const blah: packed struct {
@@ -40,17 +40,17 @@ const blah: packed struct {
 } = undefined;
 
 test "bit field alignment" {
-    assert(@typeOf(&blah.b) == *align(1:3:1) const u3);
+    assertOrPanic(@typeOf(&blah.b) == *align(1:3:1) const u3);
 }
 
 test "default alignment allows unspecified in type syntax" {
-    assert(*u32 == *align(@alignOf(u32)) u32);
+    assertOrPanic(*u32 == *align(@alignOf(u32)) u32);
 }
 
 test "implicitly decreasing pointer alignment" {
     const a: u32 align(4) = 3;
     const b: u32 align(8) = 4;
-    assert(addUnaligned(&a, &b) == 7);
+    assertOrPanic(addUnaligned(&a, &b) == 7);
 }
 
 fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
@@ -60,7 +60,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
 test "implicitly decreasing slice alignment" {
     const a: u32 align(4) = 3;
     const b: u32 align(8) = 4;
-    assert(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7);
+    assertOrPanic(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7);
 }
 fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
     return a[0] + b[0];
@@ -77,7 +77,7 @@ fn testBytesAlign(b: u8) void {
         b,
     };
     const ptr = @ptrCast(*u32, &bytes[0]);
-    assert(ptr.* == 0x33333333);
+    assertOrPanic(ptr.* == 0x33333333);
 }
 
 test "specifying alignment allows slice cast" {
@@ -91,13 +91,13 @@ fn testBytesAlignSlice(b: u8) void {
         b,
     };
     const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
-    assert(slice[0] == 0x33333333);
+    assertOrPanic(slice[0] == 0x33333333);
 }
 
 test "@alignCast pointers" {
     var x: u32 align(4) = 1;
     expectsOnly1(&x);
-    assert(x == 2);
+    assertOrPanic(x == 2);
 }
 fn expectsOnly1(x: *align(1) u32) void {
     expects4(@alignCast(4, x));
@@ -113,7 +113,7 @@ test "@alignCast slices" {
     };
     const slice = array[0..];
     sliceExpectsOnly1(slice);
-    assert(slice[0] == 2);
+    assertOrPanic(slice[0] == 2);
 }
 fn sliceExpectsOnly1(slice: []align(1) u32) void {
     sliceExpects4(@alignCast(4, slice));
@@ -128,7 +128,7 @@ test "implicitly decreasing fn alignment" {
 }
 
 fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void {
-    assert(ptr() == answer);
+    assertOrPanic(ptr() == answer);
 }
 
 fn alignedSmall() align(8) i32 {
@@ -139,7 +139,7 @@ fn alignedBig() align(16) i32 {
 }
 
 test "@alignCast functions" {
-    assert(fnExpectsOnly1(simple4) == 0x19);
+    assertOrPanic(fnExpectsOnly1(simple4) == 0x19);
 }
 fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 {
     return fnExpects4(@alignCast(4, ptr));
@@ -152,9 +152,9 @@ fn simple4() align(4) i32 {
 }
 
 test "generic function with align param" {
-    assert(whyWouldYouEverDoThis(1) == 0x1);
-    assert(whyWouldYouEverDoThis(4) == 0x1);
-    assert(whyWouldYouEverDoThis(8) == 0x1);
+    assertOrPanic(whyWouldYouEverDoThis(1) == 0x1);
+    assertOrPanic(whyWouldYouEverDoThis(4) == 0x1);
+    assertOrPanic(whyWouldYouEverDoThis(8) == 0x1);
 }
 
 fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
@@ -164,28 +164,28 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
 test "@ptrCast preserves alignment of bigger source" {
     var x: u32 align(16) = 1234;
     const ptr = @ptrCast(*u8, &x);
-    assert(@typeOf(ptr) == *align(16) u8);
+    assertOrPanic(@typeOf(ptr) == *align(16) u8);
 }
 
 test "runtime known array index has best alignment possible" {
     // take full advantage of over-alignment
     var array align(4) = []u8{ 1, 2, 3, 4 };
-    assert(@typeOf(&array[0]) == *align(4) u8);
-    assert(@typeOf(&array[1]) == *u8);
-    assert(@typeOf(&array[2]) == *align(2) u8);
-    assert(@typeOf(&array[3]) == *u8);
+    assertOrPanic(@typeOf(&array[0]) == *align(4) u8);
+    assertOrPanic(@typeOf(&array[1]) == *u8);
+    assertOrPanic(@typeOf(&array[2]) == *align(2) u8);
+    assertOrPanic(@typeOf(&array[3]) == *u8);
 
     // because align is too small but we still figure out to use 2
     var bigger align(2) = []u64{ 1, 2, 3, 4 };
-    assert(@typeOf(&bigger[0]) == *align(2) u64);
-    assert(@typeOf(&bigger[1]) == *align(2) u64);
-    assert(@typeOf(&bigger[2]) == *align(2) u64);
-    assert(@typeOf(&bigger[3]) == *align(2) u64);
+    assertOrPanic(@typeOf(&bigger[0]) == *align(2) u64);
+    assertOrPanic(@typeOf(&bigger[1]) == *align(2) u64);
+    assertOrPanic(@typeOf(&bigger[2]) == *align(2) u64);
+    assertOrPanic(@typeOf(&bigger[3]) == *align(2) u64);
 
     // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
     var smaller align(2) = []u32{ 1, 2, 3, 4 };
-    comptime assert(@typeOf(smaller[0..]) == []align(2) u32);
-    comptime assert(@typeOf(smaller[0..].ptr) == [*]align(2) u32);
+    comptime assertOrPanic(@typeOf(smaller[0..]) == []align(2) u32);
+    comptime assertOrPanic(@typeOf(smaller[0..].ptr) == [*]align(2) u32);
     testIndex(smaller[0..].ptr, 0, *align(2) u32);
     testIndex(smaller[0..].ptr, 1, *align(2) u32);
     testIndex(smaller[0..].ptr, 2, *align(2) u32);
@@ -198,14 +198,14 @@ test "runtime known array index has best alignment possible" {
     testIndex2(array[0..].ptr, 3, *u8);
 }
 fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {
-    comptime assert(@typeOf(&smaller[index]) == T);
+    comptime assertOrPanic(@typeOf(&smaller[index]) == T);
 }
 fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void {
-    comptime assert(@typeOf(&ptr[index]) == T);
+    comptime assertOrPanic(@typeOf(&ptr[index]) == T);
 }
 
 test "alignstack" {
-    assert(fnWithAlignedStack() == 1234);
+    assertOrPanic(fnWithAlignedStack() == 1234);
 }
 
 fn fnWithAlignedStack() i32 {
@@ -214,7 +214,7 @@ fn fnWithAlignedStack() i32 {
 }
 
 test "alignment of structs" {
-    assert(@alignOf(struct {
+    assertOrPanic(@alignOf(struct {
         a: i32,
         b: *i32,
     }) == @alignOf(usize));
test/cases/alignof.zig → test/stage1/behavior/alignof.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const builtin = @import("builtin");
 const maxInt = std.math.maxInt;
 
@@ -10,8 +10,9 @@ const Foo = struct {
 };
 
 test "@alignOf(T) before referencing T" {
-    comptime assert(@alignOf(Foo) != maxInt(usize));
+    comptime assertOrPanic(@alignOf(Foo) != maxInt(usize));
     if (builtin.arch == builtin.Arch.x86_64) {
-        comptime assert(@alignOf(Foo) == 4);
+        comptime assertOrPanic(@alignOf(Foo) == 4);
     }
 }
+
test/stage1/behavior/array.zig
@@ -0,0 +1,270 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+
+test "arrays" {
+    var array: [5]u32 = undefined;
+
+    var i: u32 = 0;
+    while (i < 5) {
+        array[i] = i + 1;
+        i = array[i];
+    }
+
+    i = 0;
+    var accumulator = u32(0);
+    while (i < 5) {
+        accumulator += array[i];
+
+        i += 1;
+    }
+
+    assertOrPanic(accumulator == 15);
+    assertOrPanic(getArrayLen(array) == 5);
+}
+fn getArrayLen(a: []const u32) usize {
+    return a.len;
+}
+
+test "void arrays" {
+    var array: [4]void = undefined;
+    array[0] = void{};
+    array[1] = array[2];
+    assertOrPanic(@sizeOf(@typeOf(array)) == 0);
+    assertOrPanic(array.len == 4);
+}
+
+test "array literal" {
+    const hex_mult = []u16{
+        4096,
+        256,
+        16,
+        1,
+    };
+
+    assertOrPanic(hex_mult.len == 4);
+    assertOrPanic(hex_mult[1] == 256);
+}
+
+test "array dot len const expr" {
+    assertOrPanic(comptime x: {
+        break :x some_array.len == 4;
+    });
+}
+
+const ArrayDotLenConstExpr = struct {
+    y: [some_array.len]u8,
+};
+const some_array = []u8{
+    0,
+    1,
+    2,
+    3,
+};
+
+test "nested arrays" {
+    const array_of_strings = [][]const u8{
+        "hello",
+        "this",
+        "is",
+        "my",
+        "thing",
+    };
+    for (array_of_strings) |s, i| {
+        if (i == 0) assertOrPanic(mem.eql(u8, s, "hello"));
+        if (i == 1) assertOrPanic(mem.eql(u8, s, "this"));
+        if (i == 2) assertOrPanic(mem.eql(u8, s, "is"));
+        if (i == 3) assertOrPanic(mem.eql(u8, s, "my"));
+        if (i == 4) assertOrPanic(mem.eql(u8, s, "thing"));
+    }
+}
+
+var s_array: [8]Sub = undefined;
+const Sub = struct {
+    b: u8,
+};
+const Str = struct {
+    a: []Sub,
+};
+test "set global var array via slice embedded in struct" {
+    var s = Str{ .a = s_array[0..] };
+
+    s.a[0].b = 1;
+    s.a[1].b = 2;
+    s.a[2].b = 3;
+
+    assertOrPanic(s_array[0].b == 1);
+    assertOrPanic(s_array[1].b == 2);
+    assertOrPanic(s_array[2].b == 3);
+}
+
+test "array literal with specified size" {
+    var array = [2]u8{
+        1,
+        2,
+    };
+    assertOrPanic(array[0] == 1);
+    assertOrPanic(array[1] == 2);
+}
+
+test "array child property" {
+    var x: [5]i32 = undefined;
+    assertOrPanic(@typeOf(x).Child == i32);
+}
+
+test "array len property" {
+    var x: [5]i32 = undefined;
+    assertOrPanic(@typeOf(x).len == 5);
+}
+
+test "array len field" {
+    var arr = [4]u8{ 0, 0, 0, 0 };
+    var ptr = &arr;
+    assertOrPanic(arr.len == 4);
+    comptime assertOrPanic(arr.len == 4);
+    assertOrPanic(ptr.len == 4);
+    comptime assertOrPanic(ptr.len == 4);
+}
+
+test "single-item pointer to array indexing and slicing" {
+    testSingleItemPtrArrayIndexSlice();
+    comptime testSingleItemPtrArrayIndexSlice();
+}
+
+fn testSingleItemPtrArrayIndexSlice() void {
+    var array = "aaaa";
+    doSomeMangling(&array);
+    assertOrPanic(mem.eql(u8, "azya", array));
+}
+
+fn doSomeMangling(array: *[4]u8) void {
+    array[1] = 'z';
+    array[2..3][0] = 'y';
+}
+
+test "implicit cast single-item pointer" {
+    testImplicitCastSingleItemPtr();
+    comptime testImplicitCastSingleItemPtr();
+}
+
+fn testImplicitCastSingleItemPtr() void {
+    var byte: u8 = 100;
+    const slice = (*[1]u8)(&byte)[0..];
+    slice[0] += 1;
+    assertOrPanic(byte == 101);
+}
+
+fn testArrayByValAtComptime(b: [2]u8) u8 {
+    return b[0];
+}
+
+test "comptime evalutating function that takes array by value" {
+    const arr = []u8{ 0, 1 };
+    _ = comptime testArrayByValAtComptime(arr);
+    _ = comptime testArrayByValAtComptime(arr);
+}
+
+test "implicit comptime in array type size" {
+    var arr: [plusOne(10)]bool = undefined;
+    assertOrPanic(arr.len == 11);
+}
+
+fn plusOne(x: u32) u32 {
+    return x + 1;
+}
+
+test "array literal as argument to function" {
+    const S = struct {
+        fn entry(two: i32) void {
+            foo([]i32{
+                1,
+                2,
+                3,
+            });
+            foo([]i32{
+                1,
+                two,
+                3,
+            });
+            foo2(true, []i32{
+                1,
+                2,
+                3,
+            });
+            foo2(true, []i32{
+                1,
+                two,
+                3,
+            });
+        }
+        fn foo(x: []const i32) void {
+            assertOrPanic(x[0] == 1);
+            assertOrPanic(x[1] == 2);
+            assertOrPanic(x[2] == 3);
+        }
+        fn foo2(trash: bool, x: []const i32) void {
+            assertOrPanic(trash);
+            assertOrPanic(x[0] == 1);
+            assertOrPanic(x[1] == 2);
+            assertOrPanic(x[2] == 3);
+        }
+    };
+    S.entry(2);
+    comptime S.entry(2);
+}
+
+test "double nested array to const slice cast in array literal" {
+    const S = struct {
+        fn entry(two: i32) void {
+            const cases = [][]const []const i32{
+                [][]const i32{[]i32{1}},
+                [][]const i32{[]i32{ 2, 3 }},
+                [][]const i32{
+                    []i32{4},
+                    []i32{ 5, 6, 7 },
+                },
+            };
+            check(cases);
+
+            const cases2 = [][]const i32{
+                []i32{1},
+                []i32{ two, 3 },
+            };
+            assertOrPanic(cases2.len == 2);
+            assertOrPanic(cases2[0].len == 1);
+            assertOrPanic(cases2[0][0] == 1);
+            assertOrPanic(cases2[1].len == 2);
+            assertOrPanic(cases2[1][0] == 2);
+            assertOrPanic(cases2[1][1] == 3);
+
+            const cases3 = [][]const []const i32{
+                [][]const i32{[]i32{1}},
+                [][]const i32{[]i32{ two, 3 }},
+                [][]const i32{
+                    []i32{4},
+                    []i32{ 5, 6, 7 },
+                },
+            };
+            check(cases3);
+        }
+
+        fn check(cases: []const []const []const i32) void {
+            assertOrPanic(cases.len == 3);
+            assertOrPanic(cases[0].len == 1);
+            assertOrPanic(cases[0][0].len == 1);
+            assertOrPanic(cases[0][0][0] == 1);
+            assertOrPanic(cases[1].len == 1);
+            assertOrPanic(cases[1][0].len == 2);
+            assertOrPanic(cases[1][0][0] == 2);
+            assertOrPanic(cases[1][0][1] == 3);
+            assertOrPanic(cases[2].len == 2);
+            assertOrPanic(cases[2][0].len == 1);
+            assertOrPanic(cases[2][0][0] == 4);
+            assertOrPanic(cases[2][1].len == 3);
+            assertOrPanic(cases[2][1][0] == 5);
+            assertOrPanic(cases[2][1][1] == 6);
+            assertOrPanic(cases[2][1][2] == 7);
+        }
+    };
+    S.entry(2);
+    comptime S.entry(2);
+}
test/stage1/behavior/asm.zig
@@ -0,0 +1,92 @@
+const config = @import("builtin");
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+comptime {
+    if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
+        asm volatile (
+            \\.globl aoeu;
+            \\.type aoeu, @function;
+            \\.set aoeu, derp;
+        );
+    }
+}
+
+test "module level assembly" {
+    if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
+        assertOrPanic(aoeu() == 1234);
+    }
+}
+
+test "output constraint modifiers" {
+    // This is only testing compilation.
+    var a: u32 = 3;
+    asm volatile (""
+        : [_] "=m,r" (a)
+        :
+        : ""
+    );
+    asm volatile (""
+        : [_] "=r,m" (a)
+        :
+        : ""
+    );
+}
+
+test "alternative constraints" {
+    // Make sure we allow commas as a separator for alternative constraints.
+    var a: u32 = 3;
+    asm volatile (""
+        : [_] "=r,m" (a)
+        : [_] "r,m" (a)
+        : ""
+    );
+}
+
+test "sized integer/float in asm input" {
+    asm volatile (""
+        :
+        : [_] "m" (usize(3))
+        : ""
+    );
+    asm volatile (""
+        :
+        : [_] "m" (i15(-3))
+        : ""
+    );
+    asm volatile (""
+        :
+        : [_] "m" (u3(3))
+        : ""
+    );
+    asm volatile (""
+        :
+        : [_] "m" (i3(3))
+        : ""
+    );
+    asm volatile (""
+        :
+        : [_] "m" (u121(3))
+        : ""
+    );
+    asm volatile (""
+        :
+        : [_] "m" (i121(3))
+        : ""
+    );
+    asm volatile (""
+        :
+        : [_] "m" (f32(3.17))
+        : ""
+    );
+    asm volatile (""
+        :
+        : [_] "m" (f64(3.17))
+        : ""
+    );
+}
+
+extern fn aoeu() i32;
+
+export fn derp() i32 {
+    return 1234;
+}
test/cases/atomics.zig → test/stage1/behavior/atomics.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const builtin = @import("builtin");
 const AtomicRmwOp = builtin.AtomicRmwOp;
 const AtomicOrder = builtin.AtomicOrder;
@@ -7,18 +7,18 @@ const AtomicOrder = builtin.AtomicOrder;
 test "cmpxchg" {
     var x: i32 = 1234;
     if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
-        assert(x1 == 1234);
+        assertOrPanic(x1 == 1234);
     } else {
         @panic("cmpxchg should have failed");
     }
 
     while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
-        assert(x1 == 1234);
+        assertOrPanic(x1 == 1234);
     }
-    assert(x == 5678);
+    assertOrPanic(x == 5678);
 
-    assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
-    assert(x == 42);
+    assertOrPanic(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+    assertOrPanic(x == 42);
 }
 
 test "fence" {
@@ -30,24 +30,24 @@ test "fence" {
 test "atomicrmw and atomicload" {
     var data: u8 = 200;
     testAtomicRmw(&data);
-    assert(data == 42);
+    assertOrPanic(data == 42);
     testAtomicLoad(&data);
 }
 
 fn testAtomicRmw(ptr: *u8) void {
     const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
-    assert(prev_value == 200);
+    assertOrPanic(prev_value == 200);
     comptime {
         var x: i32 = 1234;
         const y: i32 = 12345;
-        assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
-        assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
+        assertOrPanic(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
+        assertOrPanic(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
     }
 }
 
 fn testAtomicLoad(ptr: *u8) void {
     const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
-    assert(x == 42);
+    assertOrPanic(x == 42);
 }
 
 test "cmpxchg with ptr" {
@@ -56,16 +56,16 @@ test "cmpxchg with ptr" {
     var data3: i32 = 9101;
     var x: *i32 = &data1;
     if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
-        assert(x1 == &data1);
+        assertOrPanic(x1 == &data1);
     } else {
         @panic("cmpxchg should have failed");
     }
 
     while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
-        assert(x1 == &data1);
+        assertOrPanic(x1 == &data1);
     }
-    assert(x == &data3);
+    assertOrPanic(x == &data3);
 
-    assert(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
-    assert(x == &data2);
+    assertOrPanic(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+    assertOrPanic(x == &data2);
 }
test/cases/bit_shifting.zig → test/stage1/behavior/bit_shifting.zig
@@ -1,9 +1,9 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type {
-    assert(Key == @IntType(false, Key.bit_count));
-    assert(Key.bit_count >= mask_bit_count);
+    assertOrPanic(Key == @IntType(false, Key.bit_count));
+    assertOrPanic(Key.bit_count >= mask_bit_count);
     const ShardKey = @IntType(false, mask_bit_count);
     const shift_amount = Key.bit_count - ShardKey.bit_count;
     return struct {
@@ -77,12 +77,12 @@ fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, c
     var node_buffer: [node_count]Table.Node = undefined;
     for (node_buffer) |*node, i| {
         const key = @intCast(Key, i);
-        assert(table.get(key) == null);
+        assertOrPanic(table.get(key) == null);
         node.init(key, {});
         table.put(node);
     }
 
     for (node_buffer) |*node, i| {
-        assert(table.get(@intCast(Key, i)) == node);
+        assertOrPanic(table.get(@intCast(Key, i)) == node);
     }
 }
test/cases/bitcast.zig → test/stage1/behavior/bitcast.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const maxInt = std.math.maxInt;
 
 test "@bitCast i32 -> u32" {
@@ -8,8 +8,8 @@ test "@bitCast i32 -> u32" {
 }
 
 fn testBitCast_i32_u32() void {
-    assert(conv(-1) == maxInt(u32));
-    assert(conv2(maxInt(u32)) == -1);
+    assertOrPanic(conv(-1) == maxInt(u32));
+    assertOrPanic(conv2(maxInt(u32)) == -1);
 }
 
 fn conv(x: i32) u32 {
@@ -27,11 +27,10 @@ test "@bitCast extern enum to its integer type" {
         fn testBitCastExternEnum() void {
             var SOCK_DGRAM = @This().B;
             var sock_dgram = @bitCast(c_int, SOCK_DGRAM);
-            assert(sock_dgram == 1);
+            assertOrPanic(sock_dgram == 1);
         }
     };
 
     SOCK.testBitCastExternEnum();
     comptime SOCK.testBitCastExternEnum();
 }
-
test/stage1/behavior/bitreverse.zig
@@ -0,0 +1,81 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const minInt = std.math.minInt;
+
+test "@bitreverse" {
+    comptime testBitReverse();
+    testBitReverse();
+}
+
+fn testBitReverse() void {
+    // using comptime_ints, unsigned
+    assertOrPanic(@bitreverse(u0, 0) == 0);
+    assertOrPanic(@bitreverse(u5, 0x12) == 0x9);
+    assertOrPanic(@bitreverse(u8, 0x12) == 0x48);
+    assertOrPanic(@bitreverse(u16, 0x1234) == 0x2c48);
+    assertOrPanic(@bitreverse(u24, 0x123456) == 0x6a2c48);
+    assertOrPanic(@bitreverse(u32, 0x12345678) == 0x1e6a2c48);
+    assertOrPanic(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48);
+    assertOrPanic(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48);
+    assertOrPanic(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48);
+    assertOrPanic(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48);
+    assertOrPanic(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48);
+
+    // using runtime uints, unsigned
+    var num0: u0 = 0;
+    assertOrPanic(@bitreverse(u0, num0) == 0);
+    var num5: u5 = 0x12;
+    assertOrPanic(@bitreverse(u5, num5) == 0x9);
+    var num8: u8 = 0x12;
+    assertOrPanic(@bitreverse(u8, num8) == 0x48);
+    var num16: u16 = 0x1234;
+    assertOrPanic(@bitreverse(u16, num16) == 0x2c48);
+    var num24: u24 = 0x123456;
+    assertOrPanic(@bitreverse(u24, num24) == 0x6a2c48);
+    var num32: u32 = 0x12345678;
+    assertOrPanic(@bitreverse(u32, num32) == 0x1e6a2c48);
+    var num40: u40 = 0x123456789a;
+    assertOrPanic(@bitreverse(u40, num40) == 0x591e6a2c48);
+    var num48: u48 = 0x123456789abc;
+    assertOrPanic(@bitreverse(u48, num48) == 0x3d591e6a2c48);
+    var num56: u56 = 0x123456789abcde;
+    assertOrPanic(@bitreverse(u56, num56) == 0x7b3d591e6a2c48);
+    var num64: u64 = 0x123456789abcdef1;
+    assertOrPanic(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48);
+    var num128: u128 = 0x123456789abcdef11121314151617181;
+    assertOrPanic(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48);
+
+    // using comptime_ints, signed, positive
+    assertOrPanic(@bitreverse(i0, 0) == 0);
+    assertOrPanic(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49)));
+    assertOrPanic(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48)));
+    assertOrPanic(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48)));
+    assertOrPanic(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48)));
+    assertOrPanic(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48)));
+    assertOrPanic(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48)));
+    assertOrPanic(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48)));
+    assertOrPanic(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48)));
+    assertOrPanic(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48)));
+
+    // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm.
+    var neg5: i5 = minInt(i5) + 1;
+    assertOrPanic(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5));
+    var neg8: i8 = -18;
+    assertOrPanic(@bitreverse(i8, -18) == @bitreverse(i8, neg8));
+    var neg16: i16 = -32694;
+    assertOrPanic(@bitreverse(i16, -32694) == @bitreverse(i16, neg16));
+    var neg24: i24 = -6773785;
+    assertOrPanic(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24));
+    var neg32: i32 = -16773785;
+    assertOrPanic(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32));
+    var neg40: i40 = minInt(i40) + 12345;
+    assertOrPanic(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40));
+    var neg48: i48 = minInt(i48) + 12345;
+    assertOrPanic(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48));
+    var neg56: i56 = minInt(i56) + 12345;
+    assertOrPanic(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56));
+    var neg64: i64 = minInt(i64) + 12345;
+    assertOrPanic(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64));
+    var neg128: i128 = minInt(i128) + 12345;
+    assertOrPanic(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128));
+}
test/cases/bool.zig → test/stage1/behavior/bool.zig
@@ -1,25 +1,25 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "bool literals" {
-    assert(true);
-    assert(!false);
+    assertOrPanic(true);
+    assertOrPanic(!false);
 }
 
 test "cast bool to int" {
     const t = true;
     const f = false;
-    assert(@boolToInt(t) == u32(1));
-    assert(@boolToInt(f) == u32(0));
+    assertOrPanic(@boolToInt(t) == u32(1));
+    assertOrPanic(@boolToInt(f) == u32(0));
     nonConstCastBoolToInt(t, f);
 }
 
 fn nonConstCastBoolToInt(t: bool, f: bool) void {
-    assert(@boolToInt(t) == u32(1));
-    assert(@boolToInt(f) == u32(0));
+    assertOrPanic(@boolToInt(t) == u32(1));
+    assertOrPanic(@boolToInt(f) == u32(0));
 }
 
 test "bool cmp" {
-    assert(testBoolCmp(true, false) == false);
+    assertOrPanic(testBoolCmp(true, false) == false);
 }
 fn testBoolCmp(a: bool, b: bool) bool {
     return a == b;
@@ -30,6 +30,6 @@ const global_t = true;
 const not_global_f = !global_f;
 const not_global_t = !global_t;
 test "compile time bool not" {
-    assert(not_global_f);
-    assert(!not_global_t);
+    assertOrPanic(not_global_f);
+    assertOrPanic(!not_global_t);
 }
test/stage1/behavior/bswap.zig
@@ -0,0 +1,32 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "@bswap" {
+    comptime testByteSwap();
+    testByteSwap();
+}
+
+fn testByteSwap() void {
+    assertOrPanic(@bswap(u0, 0) == 0);
+    assertOrPanic(@bswap(u8, 0x12) == 0x12);
+    assertOrPanic(@bswap(u16, 0x1234) == 0x3412);
+    assertOrPanic(@bswap(u24, 0x123456) == 0x563412);
+    assertOrPanic(@bswap(u32, 0x12345678) == 0x78563412);
+    assertOrPanic(@bswap(u40, 0x123456789a) == 0x9a78563412);
+    assertOrPanic(@bswap(u48, 0x123456789abc) == 0xbc9a78563412);
+    assertOrPanic(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412);
+    assertOrPanic(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412);
+    assertOrPanic(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412);
+
+    assertOrPanic(@bswap(i0, 0) == 0);
+    assertOrPanic(@bswap(i8, -50) == -50);
+    assertOrPanic(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412)));
+    assertOrPanic(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412)));
+    assertOrPanic(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412)));
+    assertOrPanic(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412)));
+    assertOrPanic(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412)));
+    assertOrPanic(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412)));
+    assertOrPanic(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412)));
+    assertOrPanic(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==
+        @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));
+}
test/cases/byval_arg_var.zig → test/stage1/behavior/byval_arg_var.zig
@@ -2,11 +2,11 @@ const std = @import("std");
 
 var result: []const u8 = "wrong";
 
-test "aoeu" {
+test "pass string literal byvalue to a generic var param" {
     start();
     blowUpStack(10);
 
-    std.debug.assert(std.mem.eql(u8, result, "string literal"));
+    std.debug.assertOrPanic(std.mem.eql(u8, result, "string literal"));
 }
 
 fn start() void {
test/cases/cancel.zig → test/stage1/behavior/cancel.zig
@@ -10,9 +10,9 @@ test "cancel forwards" {
 
     const p = async<&da.allocator> f1() catch unreachable;
     cancel p;
-    std.debug.assert(defer_f1);
-    std.debug.assert(defer_f2);
-    std.debug.assert(defer_f3);
+    std.debug.assertOrPanic(defer_f1);
+    std.debug.assertOrPanic(defer_f2);
+    std.debug.assertOrPanic(defer_f3);
 }
 
 async fn f1() void {
@@ -47,10 +47,10 @@ test "cancel backwards" {
 
     const p = async<&da.allocator> b1() catch unreachable;
     cancel p;
-    std.debug.assert(defer_b1);
-    std.debug.assert(defer_b2);
-    std.debug.assert(defer_b3);
-    std.debug.assert(defer_b4);
+    std.debug.assertOrPanic(defer_b1);
+    std.debug.assertOrPanic(defer_b2);
+    std.debug.assertOrPanic(defer_b3);
+    std.debug.assertOrPanic(defer_b4);
 }
 
 async fn b1() void {
test/cases/cast.zig → test/stage1/behavior/cast.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const mem = std.mem;
 const maxInt = std.math.maxInt;
 
@@ -7,12 +7,12 @@ test "int to ptr cast" {
     const x = usize(13);
     const y = @intToPtr(*u8, x);
     const z = @ptrToInt(y);
-    assert(z == 13);
+    assertOrPanic(z == 13);
 }
 
 test "integer literal to pointer cast" {
     const vga_mem = @intToPtr(*u16, 0xB8000);
-    assert(@ptrToInt(vga_mem) == 0xB8000);
+    assertOrPanic(@ptrToInt(vga_mem) == 0xB8000);
 }
 
 test "pointer reinterpret const float to int" {
@@ -20,7 +20,7 @@ test "pointer reinterpret const float to int" {
     const float_ptr = &float;
     const int_ptr = @ptrCast(*const i32, float_ptr);
     const int_val = int_ptr.*;
-    assert(int_val == 858993411);
+    assertOrPanic(int_val == 858993411);
 }
 
 test "implicitly cast indirect pointer to maybe-indirect pointer" {
@@ -44,10 +44,10 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
     const p = &s;
     const q = &p;
     const r = &q;
-    assert(42 == S.constConst(q));
-    assert(42 == S.maybeConstConst(q));
-    assert(42 == S.constConstConst(r));
-    assert(42 == S.maybeConstConstConst(r));
+    assertOrPanic(42 == S.constConst(q));
+    assertOrPanic(42 == S.maybeConstConst(q));
+    assertOrPanic(42 == S.constConstConst(r));
+    assertOrPanic(42 == S.maybeConstConstConst(r));
 }
 
 test "explicit cast from integer to error type" {
@@ -57,14 +57,14 @@ test "explicit cast from integer to error type" {
 fn testCastIntToErr(err: anyerror) void {
     const x = @errorToInt(err);
     const y = @intToError(x);
-    assert(error.ItBroke == y);
+    assertOrPanic(error.ItBroke == y);
 }
 
 test "peer resolve arrays of different size to const slice" {
-    assert(mem.eql(u8, boolToStr(true), "true"));
-    assert(mem.eql(u8, boolToStr(false), "false"));
-    comptime assert(mem.eql(u8, boolToStr(true), "true"));
-    comptime assert(mem.eql(u8, boolToStr(false), "false"));
+    assertOrPanic(mem.eql(u8, boolToStr(true), "true"));
+    assertOrPanic(mem.eql(u8, boolToStr(false), "false"));
+    comptime assertOrPanic(mem.eql(u8, boolToStr(true), "true"));
+    comptime assertOrPanic(mem.eql(u8, boolToStr(false), "false"));
 }
 fn boolToStr(b: bool) []const u8 {
     return if (b) "true" else "false";
@@ -77,28 +77,29 @@ test "peer resolve array and const slice" {
 fn testPeerResolveArrayConstSlice(b: bool) void {
     const value1 = if (b) "aoeu" else ([]const u8)("zz");
     const value2 = if (b) ([]const u8)("zz") else "aoeu";
-    assert(mem.eql(u8, value1, "aoeu"));
-    assert(mem.eql(u8, value2, "zz"));
+    assertOrPanic(mem.eql(u8, value1, "aoeu"));
+    assertOrPanic(mem.eql(u8, value2, "zz"));
 }
 
 test "implicitly cast from T to anyerror!?T" {
     castToOptionalTypeError(1);
     comptime castToOptionalTypeError(1);
 }
+
 const A = struct {
     a: i32,
 };
 fn castToOptionalTypeError(z: i32) void {
     const x = i32(1);
     const y: anyerror!?i32 = x;
-    assert((try y).? == 1);
+    assertOrPanic((try y).? == 1);
 
     const f = z;
     const g: anyerror!?i32 = f;
 
     const a = A{ .a = z };
     const b: anyerror!?A = a;
-    assert((b catch unreachable).?.a == 1);
+    assertOrPanic((b catch unreachable).?.a == 1);
 }
 
 test "implicitly cast from int to anyerror!?T" {
@@ -113,7 +114,7 @@ fn implicitIntLitToOptional() void {
 test "return null from fn() anyerror!?&T" {
     const a = returnNullFromOptionalTypeErrorRef();
     const b = returnNullLitFromOptionalTypeErrorRef();
-    assert((try a) == null and (try b) == null);
+    assertOrPanic((try a) == null and (try b) == null);
 }
 fn returnNullFromOptionalTypeErrorRef() anyerror!?*A {
     const a: ?*A = null;
@@ -124,11 +125,11 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
 }
 
 test "peer type resolution: ?T and T" {
-    assert(peerTypeTAndOptionalT(true, false).? == 0);
-    assert(peerTypeTAndOptionalT(false, false).? == 3);
+    assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0);
+    assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3);
     comptime {
-        assert(peerTypeTAndOptionalT(true, false).? == 0);
-        assert(peerTypeTAndOptionalT(false, false).? == 3);
+        assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0);
+        assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3);
     }
 }
 fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
@@ -140,11 +141,11 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
 }
 
 test "peer type resolution: [0]u8 and []const u8" {
-    assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
-    assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
+    assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
+    assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
     comptime {
-        assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
-        assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
+        assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
+        assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
     }
 }
 fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
@@ -156,8 +157,8 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
 }
 
 test "implicitly cast from [N]T to ?[]const T" {
-    assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
-    comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
+    assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi"));
+    comptime assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi"));
 }
 
 fn castToOptionalSlice() ?[]const u8 {
@@ -170,7 +171,7 @@ test "implicitly cast from [0]T to anyerror![]T" {
 }
 
 fn testCastZeroArrayToErrSliceMut() void {
-    assert((gimmeErrOrSlice() catch unreachable).len == 0);
+    assertOrPanic((gimmeErrOrSlice() catch unreachable).len == 0);
 }
 
 fn gimmeErrOrSlice() anyerror![]u8 {
@@ -181,14 +182,14 @@ test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
     {
         var data = "hi";
         const slice = data[0..];
-        assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
-        assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+        assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+        assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
     }
     comptime {
         var data = "hi";
         const slice = data[0..];
-        assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
-        assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+        assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+        assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
     }
 }
 fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
@@ -206,7 +207,7 @@ test "resolve undefined with integer" {
 fn testResolveUndefWithInt(b: bool, x: i32) void {
     const value = if (b) x else undefined;
     if (b) {
-        assert(value == x);
+        assertOrPanic(value == x);
     }
 }
 
@@ -218,17 +219,17 @@ test "implicit cast from &const [N]T to []const T" {
 fn testCastConstArrayRefToConstSlice() void {
     const blah = "aoeu";
     const const_array_ref = &blah;
-    assert(@typeOf(const_array_ref) == *const [4]u8);
+    assertOrPanic(@typeOf(const_array_ref) == *const [4]u8);
     const slice: []const u8 = const_array_ref;
-    assert(mem.eql(u8, slice, "aoeu"));
+    assertOrPanic(mem.eql(u8, slice, "aoeu"));
 }
 
 test "peer type resolution: error and [N]T" {
     // TODO: implicit error!T to error!U where T can implicitly cast to U
-    //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
-    //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
-    assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
-    comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
+    //assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
+    //comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
+    assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
+    comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
 }
 
 //fn testPeerErrorAndArray(x: u8) error![]const u8 {
@@ -252,9 +253,9 @@ test "@floatToInt" {
 
 fn testFloatToInts() void {
     const x = i32(1e4);
-    assert(x == 10000);
+    assertOrPanic(x == 10000);
     const y = @floatToInt(i32, f32(1e4));
-    assert(y == 10000);
+    assertOrPanic(y == 10000);
     expectFloatToInt(f16, 255.1, u8, 255);
     expectFloatToInt(f16, 127.2, i8, 127);
     expectFloatToInt(f16, -128.2, i8, -128);
@@ -265,7 +266,7 @@ fn testFloatToInts() void {
 }
 
 fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void {
-    assert(@floatToInt(I, f) == i);
+    assertOrPanic(@floatToInt(I, f) == i);
 }
 
 test "cast u128 to f128 and back" {
@@ -274,7 +275,7 @@ test "cast u128 to f128 and back" {
 }
 
 fn testCast128() void {
-    assert(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
+    assertOrPanic(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
 }
 
 fn cast128Int(x: f128) u128 {
@@ -294,9 +295,9 @@ test "const slice widen cast" {
     };
 
     const u32_value = @bytesToSlice(u32, bytes[0..])[0];
-    assert(u32_value == 0x12121212);
+    assertOrPanic(u32_value == 0x12121212);
 
-    assert(@bitCast(u32, bytes) == 0x12121212);
+    assertOrPanic(@bitCast(u32, bytes) == 0x12121212);
 }
 
 test "single-item pointer of array to slice and to unknown length pointer" {
@@ -308,76 +309,76 @@ fn testCastPtrOfArrayToSliceAndPtr() void {
     var array = "aoeu";
     const x: [*]u8 = &array;
     x[0] += 1;
-    assert(mem.eql(u8, array[0..], "boeu"));
+    assertOrPanic(mem.eql(u8, array[0..], "boeu"));
     const y: []u8 = &array;
     y[0] += 1;
-    assert(mem.eql(u8, array[0..], "coeu"));
+    assertOrPanic(mem.eql(u8, array[0..], "coeu"));
 }
 
 test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
     const window_name = [1][*]const u8{c"window name"};
     const x: [*]const ?[*]const u8 = &window_name;
-    assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
+    assertOrPanic(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
 }
 
 test "@intCast comptime_int" {
     const result = @intCast(i32, 1234);
-    assert(@typeOf(result) == i32);
-    assert(result == 1234);
+    assertOrPanic(@typeOf(result) == i32);
+    assertOrPanic(result == 1234);
 }
 
 test "@floatCast comptime_int and comptime_float" {
     {
         const result = @floatCast(f16, 1234);
-        assert(@typeOf(result) == f16);
-        assert(result == 1234.0);
+        assertOrPanic(@typeOf(result) == f16);
+        assertOrPanic(result == 1234.0);
     }
     {
         const result = @floatCast(f16, 1234.0);
-        assert(@typeOf(result) == f16);
-        assert(result == 1234.0);
+        assertOrPanic(@typeOf(result) == f16);
+        assertOrPanic(result == 1234.0);
     }
     {
         const result = @floatCast(f32, 1234);
-        assert(@typeOf(result) == f32);
-        assert(result == 1234.0);
+        assertOrPanic(@typeOf(result) == f32);
+        assertOrPanic(result == 1234.0);
     }
     {
         const result = @floatCast(f32, 1234.0);
-        assert(@typeOf(result) == f32);
-        assert(result == 1234.0);
+        assertOrPanic(@typeOf(result) == f32);
+        assertOrPanic(result == 1234.0);
     }
 }
 
 test "comptime_int @intToFloat" {
     {
         const result = @intToFloat(f16, 1234);
-        assert(@typeOf(result) == f16);
-        assert(result == 1234.0);
+        assertOrPanic(@typeOf(result) == f16);
+        assertOrPanic(result == 1234.0);
     }
     {
         const result = @intToFloat(f32, 1234);
-        assert(@typeOf(result) == f32);
-        assert(result == 1234.0);
+        assertOrPanic(@typeOf(result) == f32);
+        assertOrPanic(result == 1234.0);
     }
 }
 
 test "@bytesToSlice keeps pointer alignment" {
     var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 };
     const numbers = @bytesToSlice(u32, bytes[0..]);
-    comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
+    comptime assertOrPanic(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
 }
 
 test "@intCast i32 to u7" {
     var x: u128 = maxInt(u128);
     var y: i32 = 120;
     var z = x >> @intCast(u7, y);
-    assert(z == 0xff);
+    assertOrPanic(z == 0xff);
 }
 
 test "implicit cast undefined to optional" {
-    assert(MakeType(void).getNull() == null);
-    assert(MakeType(void).getNonNull() != null);
+    assertOrPanic(MakeType(void).getNull() == null);
+    assertOrPanic(MakeType(void).getNonNull() != null);
 }
 
 fn MakeType(comptime T: type) type {
@@ -397,16 +398,16 @@ test "implicit cast from *[N]T to ?[*]T" {
     var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
 
     x = &y;
-    assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
+    assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4]));
     x.?[0] = 8;
     y[3] = 6;
-    assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
+    assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4]));
 }
 
 test "implicit cast from *T to ?*c_void" {
     var a: u8 = 1;
     incrementVoidPtrValue(&a);
-    std.debug.assert(a == 2);
+    std.debug.assertOrPanic(a == 2);
 }
 
 fn incrementVoidPtrValue(value: ?*c_void) void {
@@ -416,7 +417,7 @@ fn incrementVoidPtrValue(value: ?*c_void) void {
 test "implicit cast from [*]T to ?*c_void" {
     var a = []u8{ 3, 2, 1 };
     incrementVoidPtrArray(a[0..].ptr, 3);
-    assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
+    assertOrPanic(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
 }
 
 fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
@@ -440,27 +441,27 @@ pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
 pub const PFN_void = extern fn (*c_void) void;
 
 fn foobar(func: PFN_void) void {
-    std.debug.assert(@ptrToInt(func) == maxInt(usize));
+    std.debug.assertOrPanic(@ptrToInt(func) == maxInt(usize));
 }
 
 test "implicit ptr to *c_void" {
     var a: u32 = 1;
     var ptr: *c_void = &a;
     var b: *u32 = @ptrCast(*u32, ptr);
-    assert(b.* == 1);
+    assertOrPanic(b.* == 1);
     var ptr2: ?*c_void = &a;
     var c: *u32 = @ptrCast(*u32, ptr2.?);
-    assert(c.* == 1);
+    assertOrPanic(c.* == 1);
 }
 
 test "@intCast to comptime_int" {
-    assert(@intCast(comptime_int, 0) == 0);
+    assertOrPanic(@intCast(comptime_int, 0) == 0);
 }
 
 test "implicit cast comptime numbers to any type when the value fits" {
     const a: u64 = 255;
     var b: u8 = a;
-    assert(b == 255);
+    assertOrPanic(b == 255);
 }
 
 test "@intToEnum passed a comptime_int to an enum with one item" {
@@ -468,5 +469,5 @@ test "@intToEnum passed a comptime_int to an enum with one item" {
         A,
     };
     const x = @intToEnum(E, 0);
-    assert(x == E.A);
+    assertOrPanic(x == E.A);
 }
test/cases/const_slice_child.zig → test/stage1/behavior/const_slice_child.zig
@@ -1,5 +1,5 @@
 const debug = @import("std").debug;
-const assert = debug.assert;
+const assertOrPanic = debug.assertOrPanic;
 
 var argv: [*]const [*]const u8 = undefined;
 
@@ -15,10 +15,10 @@ test "const slice child" {
 }
 
 fn foo(args: [][]const u8) void {
-    assert(args.len == 3);
-    assert(streql(args[0], "one"));
-    assert(streql(args[1], "two"));
-    assert(streql(args[2], "three"));
+    assertOrPanic(args.len == 3);
+    assertOrPanic(streql(args[0], "one"));
+    assertOrPanic(streql(args[1], "two"));
+    assertOrPanic(streql(args[2], "three"));
 }
 
 fn bar(argc: usize) void {
test/cases/coroutine_await_struct.zig → test/stage1/behavior/coroutine_await_struct.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 const Foo = struct {
     x: i32,
@@ -18,8 +18,8 @@ test "coroutine await struct" {
     await_seq('f');
     resume await_a_promise;
     await_seq('i');
-    assert(await_final_result.x == 1234);
-    assert(std.mem.eql(u8, await_points, "abcdefghi"));
+    assertOrPanic(await_final_result.x == 1234);
+    assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi"));
 }
 async fn await_amain() void {
     await_seq('b');
test/cases/coroutines.zig → test/stage1/behavior/coroutines.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 var x: i32 = 1;
 
@@ -9,9 +9,9 @@ test "create a coroutine and cancel it" {
     defer da.deinit();
 
     const p = try async<&da.allocator> simpleAsyncFn();
-    comptime assert(@typeOf(p) == promise->void);
+    comptime assertOrPanic(@typeOf(p) == promise->void);
     cancel p;
-    assert(x == 2);
+    assertOrPanic(x == 2);
 }
 async fn simpleAsyncFn() void {
     x += 1;
@@ -31,7 +31,7 @@ test "coroutine suspend, resume, cancel" {
     cancel p;
     seq('g');
 
-    assert(std.mem.eql(u8, points, "abcdefg"));
+    assertOrPanic(std.mem.eql(u8, points, "abcdefg"));
 }
 async fn testAsyncSeq() void {
     defer seq('e');
@@ -53,9 +53,9 @@ test "coroutine suspend with block" {
     defer da.deinit();
 
     const p = try async<&da.allocator> testSuspendBlock();
-    std.debug.assert(!result);
+    std.debug.assertOrPanic(!result);
     resume a_promise;
-    std.debug.assert(result);
+    std.debug.assertOrPanic(result);
     cancel p;
 }
 
@@ -63,13 +63,13 @@ var a_promise: promise = undefined;
 var result = false;
 async fn testSuspendBlock() void {
     suspend {
-        comptime assert(@typeOf(@handle()) == promise->void);
+        comptime assertOrPanic(@typeOf(@handle()) == promise->void);
         a_promise = @handle();
     }
 
     //Test to make sure that @handle() works as advertised (issue #1296)
     //var our_handle: promise = @handle();
-    assert( a_promise == @handle() );
+    assertOrPanic(a_promise == @handle());
 
     result = true;
 }
@@ -86,8 +86,8 @@ test "coroutine await" {
     await_seq('f');
     resume await_a_promise;
     await_seq('i');
-    assert(await_final_result == 1234);
-    assert(std.mem.eql(u8, await_points, "abcdefghi"));
+    assertOrPanic(await_final_result == 1234);
+    assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi"));
 }
 async fn await_amain() void {
     await_seq('b');
@@ -123,8 +123,8 @@ test "coroutine await early return" {
     early_seq('a');
     const p = async<&da.allocator> early_amain() catch @panic("out of memory");
     early_seq('f');
-    assert(early_final_result == 1234);
-    assert(std.mem.eql(u8, early_points, "abcdef"));
+    assertOrPanic(early_final_result == 1234);
+    assertOrPanic(std.mem.eql(u8, early_points, "abcdef"));
 }
 async fn early_amain() void {
     early_seq('b');
@@ -170,7 +170,7 @@ test "async function with dot syntax" {
     defer da.deinit();
     const p = try async<&da.allocator> S.foo();
     cancel p;
-    assert(S.y == 2);
+    assertOrPanic(S.y == 2);
 }
 
 test "async fn pointer in a struct field" {
@@ -182,9 +182,9 @@ test "async fn pointer in a struct field" {
     var da = std.heap.DirectAllocator.init();
     defer da.deinit();
     const p = (async<&da.allocator> foo.bar(&data)) catch unreachable;
-    assert(data == 2);
+    assertOrPanic(data == 2);
     cancel p;
-    assert(data == 4);
+    assertOrPanic(data == 4);
 }
 async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
     defer y.* += 2;
@@ -199,6 +199,7 @@ test "async fn with inferred error set" {
     resume p;
     cancel p;
 }
+
 async fn failing() !void {
     suspend;
     return error.Fail;
@@ -220,8 +221,7 @@ test "error return trace across suspend points - async return" {
     cancel p2;
 }
 
-// TODO https://github.com/ziglang/zig/issues/760
-fn nonFailing() promise->(anyerror!void) {
+fn nonFailing() (promise->anyerror!void) {
     return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
 }
 async fn suspendThenFail() anyerror!void {
@@ -230,9 +230,9 @@ async fn suspendThenFail() anyerror!void {
 }
 async fn printTrace(p: promise->(anyerror!void)) void {
     (await p) catch |e| {
-        std.debug.assert(e == error.Fail);
+        std.debug.assertOrPanic(e == error.Fail);
         if (@errorReturnTrace()) |trace| {
-            assert(trace.index == 1);
+            assertOrPanic(trace.index == 1);
         } else switch (builtin.mode) {
             builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
             builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
@@ -246,7 +246,7 @@ test "break from suspend" {
     var my_result: i32 = 1;
     const p = try async<a> testBreakFromSuspend(&my_result);
     cancel p;
-    std.debug.assert(my_result == 2);
+    std.debug.assertOrPanic(my_result == 2);
 }
 async fn testBreakFromSuspend(my_result: *i32) void {
     suspend {
test/cases/defer.zig → test/stage1/behavior/defer.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 var result: [3]u8 = undefined;
 var index: usize = undefined;
@@ -21,18 +21,18 @@ fn runSomeErrorDefers(x: bool) !bool {
 }
 
 test "mixing normal and error defers" {
-    assert(runSomeErrorDefers(true) catch unreachable);
-    assert(result[0] == 'c');
-    assert(result[1] == 'a');
+    assertOrPanic(runSomeErrorDefers(true) catch unreachable);
+    assertOrPanic(result[0] == 'c');
+    assertOrPanic(result[1] == 'a');
 
     const ok = runSomeErrorDefers(false) catch |err| x: {
-        assert(err == error.FalseNotAllowed);
+        assertOrPanic(err == error.FalseNotAllowed);
         break :x true;
     };
-    assert(ok);
-    assert(result[0] == 'c');
-    assert(result[1] == 'b');
-    assert(result[2] == 'a');
+    assertOrPanic(ok);
+    assertOrPanic(result[0] == 'c');
+    assertOrPanic(result[1] == 'b');
+    assertOrPanic(result[2] == 'a');
 }
 
 test "break and continue inside loop inside defer expression" {
@@ -47,7 +47,7 @@ fn testBreakContInDefer(x: usize) void {
             if (i < 5) continue;
             if (i == 5) break;
         }
-        assert(i == 5);
+        assertOrPanic(i == 5);
     }
 }
 
@@ -59,11 +59,11 @@ test "defer and labeled break" {
         break :blk;
     }
 
-    assert(i == 1);
+    assertOrPanic(i == 1);
 }
 
 test "errdefer does not apply to fn inside fn" {
-    if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad);
+    if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assertOrPanic(e == error.Bad);
 }
 
 fn testNestedFnErrDefer() anyerror!void {
test/cases/enum.zig → test/stage1/behavior/enum.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 const mem = @import("std").mem;
 
 test "enum type" {
@@ -11,16 +11,16 @@ test "enum type" {
     };
     const bar = Bar.B;
 
-    assert(bar == Bar.B);
-    assert(@memberCount(Foo) == 3);
-    assert(@memberCount(Bar) == 4);
-    assert(@sizeOf(Foo) == @sizeOf(FooNoVoid));
-    assert(@sizeOf(Bar) == 1);
+    assertOrPanic(bar == Bar.B);
+    assertOrPanic(@memberCount(Foo) == 3);
+    assertOrPanic(@memberCount(Bar) == 4);
+    assertOrPanic(@sizeOf(Foo) == @sizeOf(FooNoVoid));
+    assertOrPanic(@sizeOf(Bar) == 1);
 }
 
 test "enum as return value" {
     switch (returnAnInt(13)) {
-        Foo.One => |value| assert(value == 13),
+        Foo.One => |value| assertOrPanic(value == 13),
         else => unreachable,
     }
 }
@@ -92,14 +92,14 @@ test "enum to int" {
 }
 
 fn shouldEqual(n: Number, expected: u3) void {
-    assert(@enumToInt(n) == expected);
+    assertOrPanic(@enumToInt(n) == expected);
 }
 
 test "int to enum" {
     testIntToEnumEval(3);
 }
 fn testIntToEnumEval(x: i32) void {
-    assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
+    assertOrPanic(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
 }
 const IntToEnumNumber = enum {
     Zero,
@@ -110,8 +110,8 @@ const IntToEnumNumber = enum {
 };
 
 test "@tagName" {
-    assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
-    comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+    assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+    comptime assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
 }
 
 fn testEnumTagNameBare(n: BareNumber) []const u8 {
@@ -126,8 +126,8 @@ const BareNumber = enum {
 
 test "enum alignment" {
     comptime {
-        assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
-        assert(@alignOf(AlignTestEnum) >= @alignOf(u64));
+        assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
+        assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf(u64));
     }
 }
 
@@ -663,10 +663,10 @@ const ValueCount257 = enum {
 
 test "enum sizes" {
     comptime {
-        assert(@sizeOf(ValueCount1) == 0);
-        assert(@sizeOf(ValueCount2) == 1);
-        assert(@sizeOf(ValueCount256) == 1);
-        assert(@sizeOf(ValueCount257) == 2);
+        assertOrPanic(@sizeOf(ValueCount1) == 0);
+        assertOrPanic(@sizeOf(ValueCount2) == 1);
+        assertOrPanic(@sizeOf(ValueCount256) == 1);
+        assertOrPanic(@sizeOf(ValueCount257) == 2);
     }
 }
 
@@ -685,12 +685,12 @@ test "set enum tag type" {
     {
         var x = Small.One;
         x = Small.Two;
-        comptime assert(@TagType(Small) == u2);
+        comptime assertOrPanic(@TagType(Small) == u2);
     }
     {
         var x = Small2.One;
         x = Small2.Two;
-        comptime assert(@TagType(Small2) == u2);
+        comptime assertOrPanic(@TagType(Small2) == u2);
     }
 }
 
@@ -737,17 +737,17 @@ const bit_field_1 = BitFieldOfEnums{
 
 test "bit field access with enum fields" {
     var data = bit_field_1;
-    assert(getA(&data) == A.Two);
-    assert(getB(&data) == B.Three3);
-    assert(getC(&data) == C.Four4);
-    comptime assert(@sizeOf(BitFieldOfEnums) == 1);
+    assertOrPanic(getA(&data) == A.Two);
+    assertOrPanic(getB(&data) == B.Three3);
+    assertOrPanic(getC(&data) == C.Four4);
+    comptime assertOrPanic(@sizeOf(BitFieldOfEnums) == 1);
 
     data.b = B.Four3;
-    assert(data.b == B.Four3);
+    assertOrPanic(data.b == B.Four3);
 
     data.a = A.Three;
-    assert(data.a == A.Three);
-    assert(data.b == B.Four3);
+    assertOrPanic(data.a == A.Three);
+    assertOrPanic(data.b == B.Four3);
 }
 
 fn getA(data: *const BitFieldOfEnums) A {
@@ -768,7 +768,7 @@ test "casting enum to its tag type" {
 }
 
 fn testCastEnumToTagType(value: Small2) void {
-    assert(@enumToInt(value) == 1);
+    assertOrPanic(@enumToInt(value) == 1);
 }
 
 const MultipleChoice = enum(u32) {
@@ -784,8 +784,8 @@ test "enum with specified tag values" {
 }
 
 fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {
-    assert(@enumToInt(x) == 60);
-    assert(1234 == switch (x) {
+    assertOrPanic(@enumToInt(x) == 60);
+    assertOrPanic(1234 == switch (x) {
         MultipleChoice.A => 1,
         MultipleChoice.B => 2,
         MultipleChoice.C => u32(1234),
@@ -811,8 +811,8 @@ test "enum with specified and unspecified tag values" {
 }
 
 fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
-    assert(@enumToInt(x) == 1000);
-    assert(1234 == switch (x) {
+    assertOrPanic(@enumToInt(x) == 1000);
+    assertOrPanic(1234 == switch (x) {
         MultipleChoice2.A => 1,
         MultipleChoice2.B => 2,
         MultipleChoice2.C => 3,
@@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
 }
 
 test "cast integer literal to enum" {
-    assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
-    assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
+    assertOrPanic(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
+    assertOrPanic(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
 }
 
 const EnumWithOneMember = enum {
@@ -865,14 +865,14 @@ const EnumWithTagValues = enum(u4) {
     D = 1 << 3,
 };
 test "enum with tag values don't require parens" {
-    assert(@enumToInt(EnumWithTagValues.C) == 0b0100);
+    assertOrPanic(@enumToInt(EnumWithTagValues.C) == 0b0100);
 }
 
 test "enum with 1 field but explicit tag type should still have the tag type" {
     const Enum = enum(u8) {
         B = 2,
     };
-    comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
+    comptime @import("std").debug.assertOrPanic(@sizeOf(Enum) == @sizeOf(u8));
 }
 
 test "empty extern enum with members" {
@@ -881,14 +881,14 @@ test "empty extern enum with members" {
         B,
         C,
     };
-    assert(@sizeOf(E) == @sizeOf(c_int));
+    assertOrPanic(@sizeOf(E) == @sizeOf(c_int));
 }
 
-test "aoeu" {
+test "tag name with assigned enum values" {
     const LocalFoo = enum {
         A = 1,
         B = 0,
     };
     var b = LocalFoo.B;
-    assert(mem.eql(u8, @tagName(b), "B"));
+    assertOrPanic(mem.eql(u8, @tagName(b), "B"));
 }
test/cases/enum_with_members.zig → test/stage1/behavior/enum_with_members.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 const mem = @import("std").mem;
 const fmt = @import("std").fmt;
 
@@ -19,9 +19,9 @@ test "enum with members" {
     const b = ET{ .UINT = 42 };
     var buf: [20]u8 = undefined;
 
-    assert((a.print(buf[0..]) catch unreachable) == 3);
-    assert(mem.eql(u8, buf[0..3], "-42"));
+    assertOrPanic((a.print(buf[0..]) catch unreachable) == 3);
+    assertOrPanic(mem.eql(u8, buf[0..3], "-42"));
 
-    assert((b.print(buf[0..]) catch unreachable) == 2);
-    assert(mem.eql(u8, buf[0..2], "42"));
+    assertOrPanic((b.print(buf[0..]) catch unreachable) == 2);
+    assertOrPanic(mem.eql(u8, buf[0..2], "42"));
 }
test/cases/error.zig → test/stage1/behavior/error.zig
@@ -1,5 +1,6 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
+const assertError = std.debug.assertError;
 const mem = std.mem;
 const builtin = @import("builtin");
 
@@ -18,7 +19,7 @@ pub fn baz() anyerror!i32 {
 }
 
 test "error wrapping" {
-    assert((baz() catch unreachable) == 15);
+    assertOrPanic((baz() catch unreachable) == 15);
 }
 
 fn gimmeItBroke() []const u8 {
@@ -26,14 +27,14 @@ fn gimmeItBroke() []const u8 {
 }
 
 test "@errorName" {
-    assert(mem.eql(u8, @errorName(error.AnError), "AnError"));
-    assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
+    assertOrPanic(mem.eql(u8, @errorName(error.AnError), "AnError"));
+    assertOrPanic(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
 }
 
 test "error values" {
     const a = @errorToInt(error.err1);
     const b = @errorToInt(error.err2);
-    assert(a != b);
+    assertOrPanic(a != b);
 }
 
 test "redefinition of error values allowed" {
@@ -46,8 +47,8 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void {
 test "error binary operator" {
     const a = errBinaryOperatorG(true) catch 3;
     const b = errBinaryOperatorG(false) catch 3;
-    assert(a == 3);
-    assert(b == 10);
+    assertOrPanic(a == 3);
+    assertOrPanic(b == 10);
 }
 fn errBinaryOperatorG(x: bool) anyerror!isize {
     return if (x) error.ItBroke else isize(10);
@@ -55,7 +56,7 @@ fn errBinaryOperatorG(x: bool) anyerror!isize {
 
 test "unwrap simple value from error" {
     const i = unwrapSimpleValueFromErrorDo() catch unreachable;
-    assert(i == 13);
+    assertOrPanic(i == 13);
 }
 fn unwrapSimpleValueFromErrorDo() anyerror!isize {
     return 13;
@@ -81,13 +82,13 @@ test "error union type " {
 
 fn testErrorUnionType() void {
     const x: anyerror!i32 = 1234;
-    if (x) |value| assert(value == 1234) else |_| unreachable;
-    assert(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion);
-    assert(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet);
-    assert(@typeOf(x).ErrorSet == anyerror);
+    if (x) |value| assertOrPanic(value == 1234) else |_| unreachable;
+    assertOrPanic(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion);
+    assertOrPanic(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet);
+    assertOrPanic(@typeOf(x).ErrorSet == anyerror);
 }
 
-test "error set type " {
+test "error set type" {
     testErrorSetType();
     comptime testErrorSetType();
 }
@@ -98,12 +99,12 @@ const MyErrSet = error{
 };
 
 fn testErrorSetType() void {
-    assert(@memberCount(MyErrSet) == 2);
+    assertOrPanic(@memberCount(MyErrSet) == 2);
 
     const a: MyErrSet!i32 = 5678;
     const b: MyErrSet!i32 = MyErrSet.OutOfMemory;
 
-    if (a) |value| assert(value == 5678) else |err| switch (err) {
+    if (a) |value| assertOrPanic(value == 5678) else |err| switch (err) {
         error.OutOfMemory => unreachable,
         error.FileNotFound => unreachable,
     }
@@ -126,7 +127,7 @@ const Set2 = error{
 fn testExplicitErrorSetCast(set1: Set1) void {
     var x = @errSetCast(Set2, set1);
     var y = @errSetCast(Set1, x);
-    assert(y == error.A);
+    assertOrPanic(y == error.A);
 }
 
 test "comptime test error for empty error set" {
@@ -137,12 +138,12 @@ test "comptime test error for empty error set" {
 const EmptyErrorSet = error{};
 
 fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
-    if (x) |v| assert(v == 1234) else |err| @compileError("bad");
+    if (x) |v| assertOrPanic(v == 1234) else |err| @compileError("bad");
 }
 
 test "syntax: optional operator in front of error union operator" {
     comptime {
-        assert(?(anyerror!i32) == ?(anyerror!i32));
+        assertOrPanic(?(anyerror!i32) == ?(anyerror!i32));
     }
 }
 
@@ -161,7 +162,6 @@ fn testErrToIntWithOnePossibleValue(
 
 test "error union peer type resolution" {
     testErrorUnionPeerTypeResolution(1);
-    comptime testErrorUnionPeerTypeResolution(1);
 }
 
 fn testErrorUnionPeerTypeResolution(x: i32) void {
@@ -170,6 +170,11 @@ fn testErrorUnionPeerTypeResolution(x: i32) void {
         2 => baz_1(),
         else => quux_1(),
     };
+    if (y) |_| {
+        @panic("expected error");
+    } else |e| {
+        assertOrPanic(e == error.A);
+    }
 }
 
 fn bar_1() anyerror {
@@ -243,3 +248,85 @@ fn intLiteral(str: []const u8) !?i64 {
 
     return error.T;
 }
+
+test "nested error union function call in optional unwrap" {
+    const S = struct {
+        const Foo = struct {
+            a: i32,
+        };
+
+        fn errorable() !i32 {
+            var x: Foo = (try getFoo()) orelse return error.Other;
+            return x.a;
+        }
+
+        fn errorable2() !i32 {
+            var x: Foo = (try getFoo2()) orelse return error.Other;
+            return x.a;
+        }
+
+        fn errorable3() !i32 {
+            var x: Foo = (try getFoo3()) orelse return error.Other;
+            return x.a;
+        }
+
+        fn getFoo() anyerror!?Foo {
+            return Foo{ .a = 1234 };
+        }
+
+        fn getFoo2() anyerror!?Foo {
+            return error.Failure;
+        }
+
+        fn getFoo3() anyerror!?Foo {
+            return null;
+        }
+    };
+    assertOrPanic((try S.errorable()) == 1234);
+    assertError(S.errorable2(), error.Failure);
+    assertError(S.errorable3(), error.Other);
+    comptime {
+        assertOrPanic((try S.errorable()) == 1234);
+        assertError(S.errorable2(), error.Failure);
+        assertError(S.errorable3(), error.Other);
+    }
+}
+
+test "widen cast integer payload of error union function call" {
+    const S = struct {
+        fn errorable() !u64 {
+            var x = u64(try number());
+            return x;
+        }
+
+        fn number() anyerror!u32 {
+            return 1234;
+        }
+    };
+    assertOrPanic((try S.errorable()) == 1234);
+}
+
+test "return function call to error set from error union function" {
+    const S = struct {
+        fn errorable() anyerror!i32 {
+            return fail();
+        }
+
+        fn fail() anyerror {
+            return error.Failure;
+        }
+    };
+    assertError(S.errorable(), error.Failure);
+    comptime assertError(S.errorable(), error.Failure);
+}
+
+test "optional error set is the same size as error set" {
+    comptime assertOrPanic(@sizeOf(?anyerror) == @sizeOf(anyerror));
+    const S = struct {
+        fn returnsOptErrSet() ?anyerror {
+            return null;
+        }
+    };
+    assertOrPanic(S.returnsOptErrSet() == null);
+    comptime assertOrPanic(S.returnsOptErrSet() == null);
+}
test/cases/eval.zig → test/stage1/behavior/eval.zig
@@ -1,9 +1,9 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const builtin = @import("builtin");
 
 test "compile time recursion" {
-    assert(some_data.len == 21);
+    assertOrPanic(some_data.len == 21);
 }
 var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined;
 fn fibonacci(x: i32) i32 {
@@ -16,7 +16,7 @@ fn unwrapAndAddOne(blah: ?i32) i32 {
 }
 const should_be_1235 = unwrapAndAddOne(1234);
 test "static add one" {
-    assert(should_be_1235 == 1235);
+    assertOrPanic(should_be_1235 == 1235);
 }
 
 test "inlined loop" {
@@ -24,7 +24,7 @@ test "inlined loop" {
     comptime var sum = 0;
     inline while (i <= 5) : (i += 1)
         sum += i;
-    assert(sum == 15);
+    assertOrPanic(sum == 15);
 }
 
 fn gimme1or2(comptime a: bool) i32 {
@@ -34,12 +34,12 @@ fn gimme1or2(comptime a: bool) i32 {
     return z;
 }
 test "inline variable gets result of const if" {
-    assert(gimme1or2(true) == 1);
-    assert(gimme1or2(false) == 2);
+    assertOrPanic(gimme1or2(true) == 1);
+    assertOrPanic(gimme1or2(false) == 2);
 }
 
 test "static function evaluation" {
-    assert(statically_added_number == 3);
+    assertOrPanic(statically_added_number == 3);
 }
 const statically_added_number = staticAdd(1, 2);
 fn staticAdd(a: i32, b: i32) i32 {
@@ -47,7 +47,8 @@ fn staticAdd(a: i32, b: i32) i32 {
 }
 
 test "const expr eval on single expr blocks" {
-    assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
+    assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
+    comptime assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
 }
 
 fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
@@ -63,10 +64,10 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
 }
 
 test "statically initialized list" {
-    assert(static_point_list[0].x == 1);
-    assert(static_point_list[0].y == 2);
-    assert(static_point_list[1].x == 3);
-    assert(static_point_list[1].y == 4);
+    assertOrPanic(static_point_list[0].x == 1);
+    assertOrPanic(static_point_list[0].y == 2);
+    assertOrPanic(static_point_list[1].x == 3);
+    assertOrPanic(static_point_list[1].y == 4);
 }
 const Point = struct {
     x: i32,
@@ -84,8 +85,8 @@ fn makePoint(x: i32, y: i32) Point {
 }
 
 test "static eval list init" {
-    assert(static_vec3.data[2] == 1.0);
-    assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
+    assertOrPanic(static_vec3.data[2] == 1.0);
+    assertOrPanic(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
 }
 const static_vec3 = vec3(0.0, 0.0, 1.0);
 pub const Vec3 = struct {
@@ -101,12 +102,12 @@ pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
 
 test "constant expressions" {
     var array: [array_size]u8 = undefined;
-    assert(@sizeOf(@typeOf(array)) == 20);
+    assertOrPanic(@sizeOf(@typeOf(array)) == 20);
 }
 const array_size: u8 = 20;
 
 test "constant struct with negation" {
-    assert(vertices[0].x == -0.6);
+    assertOrPanic(vertices[0].x == -0.6);
 }
 const Vertex = struct {
     x: f32,
@@ -141,7 +142,7 @@ const vertices = []Vertex{
 
 test "statically initialized struct" {
     st_init_str_foo.x += 1;
-    assert(st_init_str_foo.x == 14);
+    assertOrPanic(st_init_str_foo.x == 14);
 }
 const StInitStrFoo = struct {
     x: i32,
@@ -154,7 +155,7 @@ var st_init_str_foo = StInitStrFoo{
 
 test "statically initalized array literal" {
     const y: [4]u8 = st_init_arr_lit_x;
-    assert(y[3] == 4);
+    assertOrPanic(y[3] == 4);
 }
 const st_init_arr_lit_x = []u8{
     1,
@@ -166,15 +167,15 @@ const st_init_arr_lit_x = []u8{
 test "const slice" {
     comptime {
         const a = "1234567890";
-        assert(a.len == 10);
+        assertOrPanic(a.len == 10);
         const b = a[1..2];
-        assert(b.len == 1);
-        assert(b[0] == '2');
+        assertOrPanic(b.len == 1);
+        assertOrPanic(b[0] == '2');
     }
 }
 
 test "try to trick eval with runtime if" {
-    assert(testTryToTrickEvalWithRuntimeIf(true) == 10);
+    assertOrPanic(testTryToTrickEvalWithRuntimeIf(true) == 10);
 }
 
 fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
@@ -200,16 +201,16 @@ fn letsTryToCompareBools(a: bool, b: bool) bool {
     return max(bool, a, b);
 }
 test "inlined block and runtime block phi" {
-    assert(letsTryToCompareBools(true, true));
-    assert(letsTryToCompareBools(true, false));
-    assert(letsTryToCompareBools(false, true));
-    assert(!letsTryToCompareBools(false, false));
+    assertOrPanic(letsTryToCompareBools(true, true));
+    assertOrPanic(letsTryToCompareBools(true, false));
+    assertOrPanic(letsTryToCompareBools(false, true));
+    assertOrPanic(!letsTryToCompareBools(false, false));
 
     comptime {
-        assert(letsTryToCompareBools(true, true));
-        assert(letsTryToCompareBools(true, false));
-        assert(letsTryToCompareBools(false, true));
-        assert(!letsTryToCompareBools(false, false));
+        assertOrPanic(letsTryToCompareBools(true, true));
+        assertOrPanic(letsTryToCompareBools(true, false));
+        assertOrPanic(letsTryToCompareBools(false, true));
+        assertOrPanic(!letsTryToCompareBools(false, false));
     }
 }
 
@@ -254,14 +255,14 @@ fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
 }
 
 test "comptime iterate over fn ptr list" {
-    assert(performFn('t', 1) == 6);
-    assert(performFn('o', 0) == 1);
-    assert(performFn('w', 99) == 99);
+    assertOrPanic(performFn('t', 1) == 6);
+    assertOrPanic(performFn('o', 0) == 1);
+    assertOrPanic(performFn('w', 99) == 99);
 }
 
 test "eval @setRuntimeSafety at compile-time" {
     const result = comptime fnWithSetRuntimeSafety();
-    assert(result == 1234);
+    assertOrPanic(result == 1234);
 }
 
 fn fnWithSetRuntimeSafety() i32 {
@@ -271,7 +272,7 @@ fn fnWithSetRuntimeSafety() i32 {
 
 test "eval @setFloatMode at compile-time" {
     const result = comptime fnWithFloatMode();
-    assert(result == 1234.0);
+    assertOrPanic(result == 1234.0);
 }
 
 fn fnWithFloatMode() f32 {
@@ -292,15 +293,15 @@ var simple_struct = SimpleStruct{ .field = 1234 };
 const bound_fn = simple_struct.method;
 
 test "call method on bound fn referring to var instance" {
-    assert(bound_fn() == 1237);
+    assertOrPanic(bound_fn() == 1237);
 }
 
 test "ptr to local array argument at comptime" {
     comptime {
         var bytes: [10]u8 = undefined;
         modifySomeBytes(bytes[0..]);
-        assert(bytes[0] == 'a');
-        assert(bytes[9] == 'b');
+        assertOrPanic(bytes[0] == 'a');
+        assertOrPanic(bytes[9] == 'b');
     }
 }
 
@@ -328,9 +329,9 @@ fn testCompTimeUIntComparisons(x: u32) void {
 }
 
 test "const ptr to variable data changes at runtime" {
-    assert(foo_ref.name[0] == 'a');
+    assertOrPanic(foo_ref.name[0] == 'a');
     foo_ref.name = "b";
-    assert(foo_ref.name[0] == 'b');
+    assertOrPanic(foo_ref.name[0] == 'b');
 }
 
 const Foo = struct {
@@ -341,8 +342,8 @@ var foo_contents = Foo{ .name = "a" };
 const foo_ref = &foo_contents;
 
 test "create global array with for loop" {
-    assert(global_array[5] == 5 * 5);
-    assert(global_array[9] == 9 * 9);
+    assertOrPanic(global_array[5] == 5 * 5);
+    assertOrPanic(global_array[9] == 9 * 9);
 }
 
 const global_array = x: {
@@ -357,7 +358,7 @@ test "compile-time downcast when the bits fit" {
     comptime {
         const spartan_count: u16 = 255;
         const byte = @intCast(u8, spartan_count);
-        assert(byte == 255);
+        assertOrPanic(byte == 255);
     }
 }
 
@@ -365,44 +366,45 @@ const hi1 = "hi";
 const hi2 = hi1;
 test "const global shares pointer with other same one" {
     assertEqualPtrs(&hi1[0], &hi2[0]);
-    comptime assert(&hi1[0] == &hi2[0]);
+    comptime assertOrPanic(&hi1[0] == &hi2[0]);
 }
 fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void {
-    assert(ptr1 == ptr2);
+    assertOrPanic(ptr1 == ptr2);
 }
 
 test "@setEvalBranchQuota" {
     comptime {
-        // 1001 for the loop and then 1 more for the assert fn call
+        // 1001 for the loop and then 1 more for the assertOrPanic fn call
         @setEvalBranchQuota(1002);
         var i = 0;
         var sum = 0;
         while (i < 1001) : (i += 1) {
             sum += i;
         }
-        assert(sum == 500500);
+        assertOrPanic(sum == 500500);
     }
 }
 
 // TODO test "float literal at compile time not lossy" {
-// TODO     assert(16777216.0 + 1.0 == 16777217.0);
-// TODO     assert(9007199254740992.0 + 1.0 == 9007199254740993.0);
+// TODO     assertOrPanic(16777216.0 + 1.0 == 16777217.0);
+// TODO     assertOrPanic(9007199254740992.0 + 1.0 == 9007199254740993.0);
 // TODO }
 
 test "f32 at compile time is lossy" {
-    assert(f32(1 << 24) + 1 == 1 << 24);
+    assertOrPanic(f32(1 << 24) + 1 == 1 << 24);
 }
 
 test "f64 at compile time is lossy" {
-    assert(f64(1 << 53) + 1 == 1 << 53);
+    assertOrPanic(f64(1 << 53) + 1 == 1 << 53);
 }
 
 test "f128 at compile time is lossy" {
-    assert(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
+    assertOrPanic(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
 }
 
-// TODO need a better implementation of bigfloat_init_bigint
-// assert(f128(1 << 113) == 10384593717069655257060992658440192);
+comptime {
+    assertOrPanic(f128(1 << 113) == 10384593717069655257060992658440192);
+}
 
 pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
     return struct {
@@ -413,15 +415,15 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
 test "string literal used as comptime slice is memoized" {
     const a = "link";
     const b = "link";
-    comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
-    comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
+    comptime assertOrPanic(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
+    comptime assertOrPanic(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
 }
 
 test "comptime slice of undefined pointer of length 0" {
     const slice1 = ([*]i32)(undefined)[0..0];
-    assert(slice1.len == 0);
+    assertOrPanic(slice1.len == 0);
     const slice2 = ([*]i32)(undefined)[100..100];
-    assert(slice2.len == 0);
+    assertOrPanic(slice2.len == 0);
 }
 
 fn copyWithPartialInline(s: []u32, b: []u8) void {
@@ -443,16 +445,16 @@ test "binary math operator in partially inlined function" {
         r.* = @intCast(u8, i + 1);
 
     copyWithPartialInline(s[0..], b[0..]);
-    assert(s[0] == 0x1020304);
-    assert(s[1] == 0x5060708);
-    assert(s[2] == 0x90a0b0c);
-    assert(s[3] == 0xd0e0f10);
+    assertOrPanic(s[0] == 0x1020304);
+    assertOrPanic(s[1] == 0x5060708);
+    assertOrPanic(s[2] == 0x90a0b0c);
+    assertOrPanic(s[3] == 0xd0e0f10);
 }
 
 test "comptime function with the same args is memoized" {
     comptime {
-        assert(MakeType(i32) == MakeType(i32));
-        assert(MakeType(i32) != MakeType(f64));
+        assertOrPanic(MakeType(i32) == MakeType(i32));
+        assertOrPanic(MakeType(i32) != MakeType(f64));
     }
 }
 
@@ -468,7 +470,7 @@ test "comptime function with mutable pointer is not memoized" {
         const ptr = &x;
         increment(ptr);
         increment(ptr);
-        assert(x == 3);
+        assertOrPanic(x == 3);
     }
 }
 
@@ -494,14 +496,14 @@ fn doesAlotT(comptime T: type, value: usize) T {
 }
 
 test "@setEvalBranchQuota at same scope as generic function call" {
-    assert(doesAlotT(u32, 2) == 2);
+    assertOrPanic(doesAlotT(u32, 2) == 2);
 }
 
 test "comptime slice of slice preserves comptime var" {
     comptime {
         var buff: [10]u8 = undefined;
         buff[0..][0..][0] = 1;
-        assert(buff[0..][0..][0] == 1);
+        assertOrPanic(buff[0..][0..][0] == 1);
     }
 }
 
@@ -510,7 +512,7 @@ test "comptime slice of pointer preserves comptime var" {
         var buff: [10]u8 = undefined;
         var a = buff[0..].ptr;
         a[0..1][0] = 1;
-        assert(buff[0..][0..][0] == 1);
+        assertOrPanic(buff[0..][0..][0] == 1);
     }
 }
 
@@ -524,9 +526,9 @@ const SingleFieldStruct = struct {
 test "const ptr to comptime mutable data is not memoized" {
     comptime {
         var foo = SingleFieldStruct{ .x = 1 };
-        assert(foo.read_x() == 1);
+        assertOrPanic(foo.read_x() == 1);
         foo.x = 2;
-        assert(foo.read_x() == 2);
+        assertOrPanic(foo.read_x() == 2);
     }
 }
 
@@ -535,7 +537,7 @@ test "array concat of slices gives slice" {
         var a: []const u8 = "aoeu";
         var b: []const u8 = "asdf";
         const c = a ++ b;
-        assert(std.mem.eql(u8, c, "aoeuasdf"));
+        assertOrPanic(std.mem.eql(u8, c, "aoeuasdf"));
     }
 }
 
@@ -552,14 +554,14 @@ test "comptime shlWithOverflow" {
         break :amt amt;
     };
 
-    assert(ct_shifted == rt_shifted);
+    assertOrPanic(ct_shifted == rt_shifted);
 }
 
 test "runtime 128 bit integer division" {
     var a: u128 = 152313999999999991610955792383;
     var b: u128 = 10000000000000000000;
     var c = a / b;
-    assert(c == 15231399999);
+    assertOrPanic(c == 15231399999);
 }
 
 pub const Info = struct {
@@ -572,20 +574,20 @@ test "comptime modification of const struct field" {
     comptime {
         var res = diamond_info;
         res.version = 1;
-        assert(diamond_info.version == 0);
-        assert(res.version == 1);
+        assertOrPanic(diamond_info.version == 0);
+        assertOrPanic(res.version == 1);
     }
 }
 
 test "pointer to type" {
     comptime {
         var T: type = i32;
-        assert(T == i32);
+        assertOrPanic(T == i32);
         var ptr = &T;
-        assert(@typeOf(ptr) == *type);
+        assertOrPanic(@typeOf(ptr) == *type);
         ptr.* = f32;
-        assert(T == f32);
-        assert(*T == *f32);
+        assertOrPanic(T == f32);
+        assertOrPanic(*T == *f32);
     }
 }
 
@@ -594,17 +596,17 @@ test "slice of type" {
         var types_array = []type{ i32, f64, type };
         for (types_array) |T, i| {
             switch (i) {
-                0 => assert(T == i32),
-                1 => assert(T == f64),
-                2 => assert(T == type),
+                0 => assertOrPanic(T == i32),
+                1 => assertOrPanic(T == f64),
+                2 => assertOrPanic(T == type),
                 else => unreachable,
             }
         }
         for (types_array[0..]) |T, i| {
             switch (i) {
-                0 => assert(T == i32),
-                1 => assert(T == f64),
-                2 => assert(T == type),
+                0 => assertOrPanic(T == i32),
+                1 => assertOrPanic(T == f64),
+                2 => assertOrPanic(T == type),
                 else => unreachable,
             }
         }
@@ -621,7 +623,7 @@ fn wrap(comptime T: type) Wrapper {
 
 test "function which returns struct with type field causes implicit comptime" {
     const ty = wrap(i32).T;
-    assert(ty == i32);
+    assertOrPanic(ty == i32);
 }
 
 test "call method with comptime pass-by-non-copying-value self parameter" {
@@ -635,12 +637,12 @@ test "call method with comptime pass-by-non-copying-value self parameter" {
 
     const s = S{ .a = 2 };
     var b = s.b();
-    assert(b == 2);
+    assertOrPanic(b == 2);
 }
 
 test "@tagName of @typeId" {
     const str = @tagName(@typeId(u8));
-    assert(std.mem.eql(u8, str, "Int"));
+    assertOrPanic(std.mem.eql(u8, str, "Int"));
 }
 
 test "setting backward branch quota just before a generic fn call" {
@@ -661,8 +663,8 @@ fn testVarInsideInlineLoop(args: ...) void {
     comptime var i = 0;
     inline while (i < args.len) : (i += 1) {
         const x = args[i];
-        if (i == 0) assert(x);
-        if (i == 1) assert(x == 42);
+        if (i == 0) assertOrPanic(x);
+        if (i == 1) assertOrPanic(x == 42);
     }
 }
 
@@ -672,7 +674,7 @@ test "inline for with same type but different values" {
         var a: T = undefined;
         res += a.len;
     }
-    assert(res == 5);
+    assertOrPanic(res == 5);
 }
 
 test "refer to the type of a generic function" {
@@ -686,19 +688,19 @@ fn doNothingWithType(comptime T: type) void {}
 test "zero extend from u0 to u1" {
     var zero_u0: u0 = 0;
     var zero_u1: u1 = zero_u0;
-    assert(zero_u1 == 0);
+    assertOrPanic(zero_u1 == 0);
 }
 
 test "bit shift a u1" {
     var x: u1 = 1;
     var y = x << 0;
-    assert(y == 1);
+    assertOrPanic(y == 1);
 }
 
 test "@intCast to a u0" {
     var x: u8 = 0;
     var y: u0 = @intCast(u0, x);
-    assert(y == 0);
+    assertOrPanic(y == 0);
 }
 
 test "@bytesToslice on a packed struct" {
@@ -708,7 +710,7 @@ test "@bytesToslice on a packed struct" {
 
     var b = [1]u8{9};
     var f = @bytesToSlice(F, b);
-    assert(f[0].a == 9);
+    assertOrPanic(f[0].a == 9);
 }
 
 test "comptime pointer cast array and then slice" {
@@ -720,8 +722,8 @@ test "comptime pointer cast array and then slice" {
     const ptrB: [*]const u8 = &array;
     const sliceB: []const u8 = ptrB[0..2];
 
-    assert(sliceA[1] == 2);
-    assert(sliceB[1] == 2);
+    assertOrPanic(sliceA[1] == 2);
+    assertOrPanic(sliceB[1] == 2);
 }
 
 test "slice bounds in comptime concatenation" {
@@ -730,47 +732,47 @@ test "slice bounds in comptime concatenation" {
         break :blk b[0..1];
     };
     const str = "" ++ bs;
-    assert(str.len == 1);
-    assert(std.mem.eql(u8, str, "1"));
+    assertOrPanic(str.len == 1);
+    assertOrPanic(std.mem.eql(u8, str, "1"));
 
     const str2 = bs ++ "";
-    assert(str2.len == 1);
-    assert(std.mem.eql(u8, str2, "1"));
+    assertOrPanic(str2.len == 1);
+    assertOrPanic(std.mem.eql(u8, str2, "1"));
 }
 
 test "comptime bitwise operators" {
     comptime {
-        assert(3 & 1 == 1);
-        assert(3 & -1 == 3);
-        assert(-3 & -1 == -3);
-        assert(3 | -1 == -1);
-        assert(-3 | -1 == -1);
-        assert(3 ^ -1 == -4);
-        assert(-3 ^ -1 == 2);
-        assert(~i8(-1) == 0);
-        assert(~i128(-1) == 0);
-        assert(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
-        assert(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
-        assert(~u128(0) == 0xffffffffffffffffffffffffffffffff);
+        assertOrPanic(3 & 1 == 1);
+        assertOrPanic(3 & -1 == 3);
+        assertOrPanic(-3 & -1 == -3);
+        assertOrPanic(3 | -1 == -1);
+        assertOrPanic(-3 | -1 == -1);
+        assertOrPanic(3 ^ -1 == -4);
+        assertOrPanic(-3 ^ -1 == 2);
+        assertOrPanic(~i8(-1) == 0);
+        assertOrPanic(~i128(-1) == 0);
+        assertOrPanic(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
+        assertOrPanic(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
+        assertOrPanic(~u128(0) == 0xffffffffffffffffffffffffffffffff);
     }
 }
 
 test "*align(1) u16 is the same as *align(1:0:2) u16" {
     comptime {
-        assert(*align(1:0:2) u16 == *align(1) u16);
+        assertOrPanic(*align(1:0:2) u16 == *align(1) u16);
         // TODO add parsing support for this syntax
-        //assert(*align(:0:2) u16 == *u16);
+        //assertOrPanic(*align(:0:2) u16 == *u16);
     }
 }
 
 test "array concatenation forces comptime" {
     var a = oneItem(3) ++ oneItem(4);
-    assert(std.mem.eql(i32, a, []i32{3, 4}));
+    assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 4 }));
 }
 
 test "array multiplication forces comptime" {
     var a = oneItem(3) ** scalar(2);
-    assert(std.mem.eql(i32, a, []i32{3, 3}));
+    assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 3 }));
 }
 
 fn oneItem(x: i32) [1]i32 {
test/cases/field_parent_ptr.zig → test/stage1/behavior/field_parent_ptr.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "@fieldParentPtr non-first field" {
     testParentFieldPtr(&foo.c);
@@ -25,17 +25,17 @@ const foo = Foo{
 };
 
 fn testParentFieldPtr(c: *const i32) void {
-    assert(c == &foo.c);
+    assertOrPanic(c == &foo.c);
 
     const base = @fieldParentPtr(Foo, "c", c);
-    assert(base == &foo);
-    assert(&base.c == c);
+    assertOrPanic(base == &foo);
+    assertOrPanic(&base.c == c);
 }
 
 fn testParentFieldPtrFirst(a: *const bool) void {
-    assert(a == &foo.a);
+    assertOrPanic(a == &foo.a);
 
     const base = @fieldParentPtr(Foo, "a", a);
-    assert(base == &foo);
-    assert(&base.a == a);
+    assertOrPanic(base == &foo);
+    assertOrPanic(&base.a == a);
 }
test/cases/fn.zig → test/stage1/behavior/fn.zig
@@ -1,7 +1,7 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "params" {
-    assert(testParamsAdd(22, 11) == 33);
+    assertOrPanic(testParamsAdd(22, 11) == 33);
 }
 fn testParamsAdd(a: i32, b: i32) i32 {
     return a + b;
@@ -21,32 +21,32 @@ test "void parameters" {
 fn voidFun(a: i32, b: void, c: i32, d: void) void {
     const v = b;
     const vv: void = if (a == 1) v else {};
-    assert(a + c == 3);
+    assertOrPanic(a + c == 3);
     return vv;
 }
 
 test "mutable local variables" {
     var zero: i32 = 0;
-    assert(zero == 0);
+    assertOrPanic(zero == 0);
 
     var i = i32(0);
     while (i != 3) {
         i += 1;
     }
-    assert(i == 3);
+    assertOrPanic(i == 3);
 }
 
 test "separate block scopes" {
     {
         const no_conflict: i32 = 5;
-        assert(no_conflict == 5);
+        assertOrPanic(no_conflict == 5);
     }
 
     const c = x: {
         const no_conflict = i32(10);
         break :x no_conflict;
     };
-    assert(c == 10);
+    assertOrPanic(c == 10);
 }
 
 test "call function with empty string" {
@@ -59,7 +59,7 @@ fn @"weird function name"() i32 {
     return 1234;
 }
 test "weird function name" {
-    assert(@"weird function name"() == 1234);
+    assertOrPanic(@"weird function name"() == 1234);
 }
 
 test "implicit cast function unreachable return" {
@@ -80,7 +80,7 @@ test "function pointers" {
         fn4,
     };
     for (fns) |f, i| {
-        assert(f() == @intCast(u32, i) + 5);
+        assertOrPanic(f() == @intCast(u32, i) + 5);
     }
 }
 fn fn1() u32 {
@@ -97,7 +97,7 @@ fn fn4() u32 {
 }
 
 test "inline function call" {
-    assert(@inlineCall(add, 3, 9) == 12);
+    assertOrPanic(@inlineCall(add, 3, 9) == 12);
 }
 
 fn add(a: i32, b: i32) i32 {
@@ -110,7 +110,7 @@ test "number literal as an argument" {
 }
 
 fn numberLiteralArg(a: var) void {
-    assert(a == 3);
+    assertOrPanic(a == 3);
 }
 
 test "assign inline fn to const variable" {
@@ -121,7 +121,7 @@ test "assign inline fn to const variable" {
 inline fn inlineFn() void {}
 
 test "pass by non-copying value" {
-    assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
+    assertOrPanic(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
 }
 
 const Point = struct {
@@ -134,17 +134,17 @@ fn addPointCoords(pt: Point) i32 {
 }
 
 test "pass by non-copying value through var arg" {
-    assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
+    assertOrPanic(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
 }
 
 fn addPointCoordsVar(pt: var) i32 {
-    comptime assert(@typeOf(pt) == Point);
+    comptime assertOrPanic(@typeOf(pt) == Point);
     return pt.x + pt.y;
 }
 
 test "pass by non-copying value as method" {
     var pt = Point2{ .x = 1, .y = 2 };
-    assert(pt.addPointCoords() == 3);
+    assertOrPanic(pt.addPointCoords() == 3);
 }
 
 const Point2 = struct {
@@ -158,7 +158,7 @@ const Point2 = struct {
 
 test "pass by non-copying value as method, which is generic" {
     var pt = Point3{ .x = 1, .y = 2 };
-    assert(pt.addPointCoords(i32) == 3);
+    assertOrPanic(pt.addPointCoords(i32) == 3);
 }
 
 const Point3 = struct {
@@ -173,7 +173,7 @@ const Point3 = struct {
 test "pass by non-copying value as method, at comptime" {
     comptime {
         var pt = Point2{ .x = 1, .y = 2 };
-        assert(pt.addPointCoords() == 3);
+        assertOrPanic(pt.addPointCoords() == 3);
     }
 }
 
@@ -189,7 +189,7 @@ fn outer(y: u32) fn (u32) u32 {
 
 test "return inner function which references comptime variable of outer function" {
     var func = outer(10);
-    assert(func(3) == 7);
+    assertOrPanic(func(3) == 7);
 }
 
 test "extern struct with stdcallcc fn pointer" {
@@ -203,5 +203,6 @@ test "extern struct with stdcallcc fn pointer" {
 
     var s: S = undefined;
     s.ptr = S.foo;
-    assert(s.ptr() == 1234);
+    assertOrPanic(s.ptr() == 1234);
 }
+
test/cases/fn_in_struct_in_comptime.zig → test/stage1/behavior/fn_in_struct_in_comptime.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 fn get_foo() fn (*u8) usize {
     comptime {
@@ -13,5 +13,5 @@ fn get_foo() fn (*u8) usize {
 
 test "define a function in an anonymous struct in comptime" {
     const foo = get_foo();
-    assert(foo(@intToPtr(*u8, 12345)) == 12345);
+    assertOrPanic(foo(@intToPtr(*u8, 12345)) == 12345);
 }
test/cases/for.zig → test/stage1/behavior/for.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const mem = std.mem;
 
 test "continue in for loop" {
@@ -26,7 +26,7 @@ test "for loop with pointer elem var" {
     var target: [source.len]u8 = undefined;
     mem.copy(u8, target[0..], source);
     mangleString(target[0..]);
-    assert(mem.eql(u8, target, "bcdefgh"));
+    assertOrPanic(mem.eql(u8, target, "bcdefgh"));
 }
 fn mangleString(s: []u8) void {
     for (s) |*c| {
@@ -68,7 +68,7 @@ test "basic for loop" {
         buf_index += 1;
     }
 
-    assert(mem.eql(u8, buffer[0..buf_index], expected_result));
+    assertOrPanic(mem.eql(u8, buffer[0..buf_index], expected_result));
 }
 
 test "break from outer for loop" {
@@ -85,7 +85,7 @@ fn testBreakOuter() void {
             break :outer;
         }
     }
-    assert(count == 1);
+    assertOrPanic(count == 1);
 }
 
 test "continue outer for loop" {
@@ -102,5 +102,5 @@ fn testContinueOuter() void {
             continue :outer;
         }
     }
-    assert(counter == array.len);
+    assertOrPanic(counter == array.len);
 }
test/cases/generics.zig → test/stage1/behavior/generics.zig
@@ -1,9 +1,9 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "simple generic fn" {
-    assert(max(i32, 3, -1) == 3);
-    assert(max(f32, 0.123, 0.456) == 0.456);
-    assert(add(2, 3) == 5);
+    assertOrPanic(max(i32, 3, -1) == 3);
+    assertOrPanic(max(f32, 0.123, 0.456) == 0.456);
+    assertOrPanic(add(2, 3) == 5);
 }
 
 fn max(comptime T: type, a: T, b: T) T {
@@ -16,7 +16,7 @@ fn add(comptime a: i32, b: i32) i32 {
 
 const the_max = max(u32, 1234, 5678);
 test "compile time generic eval" {
-    assert(the_max == 5678);
+    assertOrPanic(the_max == 5678);
 }
 
 fn gimmeTheBigOne(a: u32, b: u32) u32 {
@@ -32,19 +32,19 @@ fn sameButWithFloats(a: f64, b: f64) f64 {
 }
 
 test "fn with comptime args" {
-    assert(gimmeTheBigOne(1234, 5678) == 5678);
-    assert(shouldCallSameInstance(34, 12) == 34);
-    assert(sameButWithFloats(0.43, 0.49) == 0.49);
+    assertOrPanic(gimmeTheBigOne(1234, 5678) == 5678);
+    assertOrPanic(shouldCallSameInstance(34, 12) == 34);
+    assertOrPanic(sameButWithFloats(0.43, 0.49) == 0.49);
 }
 
 test "var params" {
-    assert(max_i32(12, 34) == 34);
-    assert(max_f64(1.2, 3.4) == 3.4);
+    assertOrPanic(max_i32(12, 34) == 34);
+    assertOrPanic(max_f64(1.2, 3.4) == 3.4);
 }
 
 comptime {
-    assert(max_i32(12, 34) == 34);
-    assert(max_f64(1.2, 3.4) == 3.4);
+    assertOrPanic(max_i32(12, 34) == 34);
+    assertOrPanic(max_f64(1.2, 3.4) == 3.4);
 }
 
 fn max_var(a: var, b: var) @typeOf(a + b) {
@@ -76,8 +76,8 @@ test "function with return type type" {
     var list2: List(i32) = undefined;
     list.length = 10;
     list2.length = 10;
-    assert(list.prealloc_items.len == 8);
-    assert(list2.prealloc_items.len == 8);
+    assertOrPanic(list.prealloc_items.len == 8);
+    assertOrPanic(list2.prealloc_items.len == 8);
 }
 
 test "generic struct" {
@@ -89,9 +89,9 @@ test "generic struct" {
         .value = true,
         .next = null,
     };
-    assert(a1.value == 13);
-    assert(a1.value == a1.getVal());
-    assert(b1.getVal());
+    assertOrPanic(a1.value == 13);
+    assertOrPanic(a1.value == a1.getVal());
+    assertOrPanic(b1.getVal());
 }
 fn GenNode(comptime T: type) type {
     return struct {
@@ -104,7 +104,7 @@ fn GenNode(comptime T: type) type {
 }
 
 test "const decls in struct" {
-    assert(GenericDataThing(3).count_plus_one == 4);
+    assertOrPanic(GenericDataThing(3).count_plus_one == 4);
 }
 fn GenericDataThing(comptime count: isize) type {
     return struct {
@@ -113,15 +113,15 @@ fn GenericDataThing(comptime count: isize) type {
 }
 
 test "use generic param in generic param" {
-    assert(aGenericFn(i32, 3, 4) == 7);
+    assertOrPanic(aGenericFn(i32, 3, 4) == 7);
 }
 fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
     return a + b;
 }
 
 test "generic fn with implicit cast" {
-    assert(getFirstByte(u8, []u8{13}) == 13);
-    assert(getFirstByte(u16, []u16{
+    assertOrPanic(getFirstByte(u8, []u8{13}) == 13);
+    assertOrPanic(getFirstByte(u16, []u16{
         0,
         13,
     }) == 0);
@@ -146,6 +146,6 @@ fn foo2(arg: var) bool {
 }
 
 test "array of generic fns" {
-    assert(foos[0](true));
-    assert(!foos[1](true));
+    assertOrPanic(foos[0](true));
+    assertOrPanic(!foos[1](true));
 }
test/cases/if.zig → test/stage1/behavior/if.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "if statements" {
     shouldBeEqual(1, 1);
@@ -24,7 +24,7 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void {
 }
 
 test "else if expression" {
-    assert(elseIfExpressionF(1) == 1);
+    assertOrPanic(elseIfExpressionF(1) == 1);
 }
 fn elseIfExpressionF(c: u8) u8 {
     if (c == 0) {
test/stage1/behavior/import.zig
@@ -0,0 +1,10 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const a_namespace = @import("import/a_namespace.zig");
+
+test "call fn via namespace lookup" {
+    assertOrPanic(a_namespace.foo() == 1234);
+}
+
+test "importing the same thing gives the same import" {
+    assertOrPanic(@import("std") == @import("std"));
+}
test/cases/incomplete_struct_param_tld.zig → test/stage1/behavior/incomplete_struct_param_tld.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 const A = struct {
     b: B,
@@ -26,5 +26,5 @@ test "incomplete struct param top level declaration" {
             .c = C{ .x = 13 },
         },
     };
-    assert(foo(a) == 13);
+    assertOrPanic(foo(a) == 13);
 }
test/cases/inttoptr.zig → test/stage1/behavior/inttoptr.zig
@@ -24,4 +24,3 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
         return;
     }
 }
-    
test/cases/ir_block_deps.zig → test/stage1/behavior/ir_block_deps.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 fn foo(id: u64) !i32 {
     return switch (id) {
@@ -16,6 +16,6 @@ fn getErrInt() anyerror!i32 {
 }
 
 test "ir block deps" {
-    assert((foo(1) catch unreachable) == 0);
-    assert((foo(2) catch unreachable) == 0);
+    assertOrPanic((foo(1) catch unreachable) == 0);
+    assertOrPanic((foo(2) catch unreachable) == 0);
 }
test/cases/math.zig → test/stage1/behavior/math.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const maxInt = std.math.maxInt;
 const minInt = std.math.minInt;
 
@@ -8,57 +8,57 @@ test "division" {
     comptime testDivision();
 }
 fn testDivision() void {
-    assert(div(u32, 13, 3) == 4);
-    assert(div(f16, 1.0, 2.0) == 0.5);
-    assert(div(f32, 1.0, 2.0) == 0.5);
-
-    assert(divExact(u32, 55, 11) == 5);
-    assert(divExact(i32, -55, 11) == -5);
-    assert(divExact(f16, 55.0, 11.0) == 5.0);
-    assert(divExact(f16, -55.0, 11.0) == -5.0);
-    assert(divExact(f32, 55.0, 11.0) == 5.0);
-    assert(divExact(f32, -55.0, 11.0) == -5.0);
-
-    assert(divFloor(i32, 5, 3) == 1);
-    assert(divFloor(i32, -5, 3) == -2);
-    assert(divFloor(f16, 5.0, 3.0) == 1.0);
-    assert(divFloor(f16, -5.0, 3.0) == -2.0);
-    assert(divFloor(f32, 5.0, 3.0) == 1.0);
-    assert(divFloor(f32, -5.0, 3.0) == -2.0);
-    assert(divFloor(i32, -0x80000000, -2) == 0x40000000);
-    assert(divFloor(i32, 0, -0x80000000) == 0);
-    assert(divFloor(i32, -0x40000001, 0x40000000) == -2);
-    assert(divFloor(i32, -0x80000000, 1) == -0x80000000);
-
-    assert(divTrunc(i32, 5, 3) == 1);
-    assert(divTrunc(i32, -5, 3) == -1);
-    assert(divTrunc(f16, 5.0, 3.0) == 1.0);
-    assert(divTrunc(f16, -5.0, 3.0) == -1.0);
-    assert(divTrunc(f32, 5.0, 3.0) == 1.0);
-    assert(divTrunc(f32, -5.0, 3.0) == -1.0);
-    assert(divTrunc(f64, 5.0, 3.0) == 1.0);
-    assert(divTrunc(f64, -5.0, 3.0) == -1.0);
+    assertOrPanic(div(u32, 13, 3) == 4);
+    assertOrPanic(div(f16, 1.0, 2.0) == 0.5);
+    assertOrPanic(div(f32, 1.0, 2.0) == 0.5);
+
+    assertOrPanic(divExact(u32, 55, 11) == 5);
+    assertOrPanic(divExact(i32, -55, 11) == -5);
+    assertOrPanic(divExact(f16, 55.0, 11.0) == 5.0);
+    assertOrPanic(divExact(f16, -55.0, 11.0) == -5.0);
+    assertOrPanic(divExact(f32, 55.0, 11.0) == 5.0);
+    assertOrPanic(divExact(f32, -55.0, 11.0) == -5.0);
+
+    assertOrPanic(divFloor(i32, 5, 3) == 1);
+    assertOrPanic(divFloor(i32, -5, 3) == -2);
+    assertOrPanic(divFloor(f16, 5.0, 3.0) == 1.0);
+    assertOrPanic(divFloor(f16, -5.0, 3.0) == -2.0);
+    assertOrPanic(divFloor(f32, 5.0, 3.0) == 1.0);
+    assertOrPanic(divFloor(f32, -5.0, 3.0) == -2.0);
+    assertOrPanic(divFloor(i32, -0x80000000, -2) == 0x40000000);
+    assertOrPanic(divFloor(i32, 0, -0x80000000) == 0);
+    assertOrPanic(divFloor(i32, -0x40000001, 0x40000000) == -2);
+    assertOrPanic(divFloor(i32, -0x80000000, 1) == -0x80000000);
+
+    assertOrPanic(divTrunc(i32, 5, 3) == 1);
+    assertOrPanic(divTrunc(i32, -5, 3) == -1);
+    assertOrPanic(divTrunc(f16, 5.0, 3.0) == 1.0);
+    assertOrPanic(divTrunc(f16, -5.0, 3.0) == -1.0);
+    assertOrPanic(divTrunc(f32, 5.0, 3.0) == 1.0);
+    assertOrPanic(divTrunc(f32, -5.0, 3.0) == -1.0);
+    assertOrPanic(divTrunc(f64, 5.0, 3.0) == 1.0);
+    assertOrPanic(divTrunc(f64, -5.0, 3.0) == -1.0);
 
     comptime {
-        assert(
+        assertOrPanic(
             1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600,
         );
-        assert(
+        assertOrPanic(
             @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600,
         );
-        assert(
+        assertOrPanic(
             1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2,
         );
-        assert(
+        assertOrPanic(
             @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2,
         );
-        assert(
+        assertOrPanic(
             @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2,
         );
-        assert(
+        assertOrPanic(
             @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2,
         );
-        assert(
+        assertOrPanic(
             4126227191251978491697987544882340798050766755606969681711 % 10 == 1,
         );
     }
@@ -78,9 +78,9 @@ fn divTrunc(comptime T: type, a: T, b: T) T {
 
 test "@addWithOverflow" {
     var result: u8 = undefined;
-    assert(@addWithOverflow(u8, 250, 100, &result));
-    assert(!@addWithOverflow(u8, 100, 150, &result));
-    assert(result == 250);
+    assertOrPanic(@addWithOverflow(u8, 250, 100, &result));
+    assertOrPanic(!@addWithOverflow(u8, 100, 150, &result));
+    assertOrPanic(result == 250);
 }
 
 // TODO test mulWithOverflow
@@ -88,9 +88,9 @@ test "@addWithOverflow" {
 
 test "@shlWithOverflow" {
     var result: u16 = undefined;
-    assert(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
-    assert(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
-    assert(result == 0b1011111111111100);
+    assertOrPanic(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
+    assertOrPanic(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
+    assertOrPanic(result == 0b1011111111111100);
 }
 
 test "@clz" {
@@ -99,11 +99,11 @@ test "@clz" {
 }
 
 fn testClz() void {
-    assert(clz(u8(0b00001010)) == 4);
-    assert(clz(u8(0b10001010)) == 0);
-    assert(clz(u8(0b00000000)) == 8);
-    assert(clz(u128(0xffffffffffffffff)) == 64);
-    assert(clz(u128(0x10000000000000000)) == 63);
+    assertOrPanic(clz(u8(0b00001010)) == 4);
+    assertOrPanic(clz(u8(0b10001010)) == 0);
+    assertOrPanic(clz(u8(0b00000000)) == 8);
+    assertOrPanic(clz(u128(0xffffffffffffffff)) == 64);
+    assertOrPanic(clz(u128(0x10000000000000000)) == 63);
 }
 
 fn clz(x: var) usize {
@@ -116,9 +116,9 @@ test "@ctz" {
 }
 
 fn testCtz() void {
-    assert(ctz(u8(0b10100000)) == 5);
-    assert(ctz(u8(0b10001010)) == 1);
-    assert(ctz(u8(0b00000000)) == 8);
+    assertOrPanic(ctz(u8(0b10100000)) == 5);
+    assertOrPanic(ctz(u8(0b10001010)) == 1);
+    assertOrPanic(ctz(u8(0b00000000)) == 8);
 }
 
 fn ctz(x: var) usize {
@@ -128,27 +128,27 @@ fn ctz(x: var) usize {
 test "assignment operators" {
     var i: u32 = 0;
     i += 5;
-    assert(i == 5);
+    assertOrPanic(i == 5);
     i -= 2;
-    assert(i == 3);
+    assertOrPanic(i == 3);
     i *= 20;
-    assert(i == 60);
+    assertOrPanic(i == 60);
     i /= 3;
-    assert(i == 20);
+    assertOrPanic(i == 20);
     i %= 11;
-    assert(i == 9);
+    assertOrPanic(i == 9);
     i <<= 1;
-    assert(i == 18);
+    assertOrPanic(i == 18);
     i >>= 2;
-    assert(i == 4);
+    assertOrPanic(i == 4);
     i = 6;
     i &= 5;
-    assert(i == 4);
+    assertOrPanic(i == 4);
     i ^= 6;
-    assert(i == 2);
+    assertOrPanic(i == 2);
     i = 6;
     i |= 3;
-    assert(i == 7);
+    assertOrPanic(i == 7);
 }
 
 test "three expr in a row" {
@@ -170,14 +170,14 @@ fn testThreeExprInARow(f: bool, t: bool) void {
     assertFalse(i32(7) != --(i32(7)));
 }
 fn assertFalse(b: bool) void {
-    assert(!b);
+    assertOrPanic(!b);
 }
 
 test "const number literal" {
     const one = 1;
     const eleven = ten + one;
 
-    assert(eleven == 11);
+    assertOrPanic(eleven == 11);
 }
 const ten = 10;
 
@@ -187,9 +187,9 @@ test "unsigned wrapping" {
 }
 fn testUnsignedWrappingEval(x: u32) void {
     const zero = x +% 1;
-    assert(zero == 0);
+    assertOrPanic(zero == 0);
     const orig = zero -% 1;
-    assert(orig == maxInt(u32));
+    assertOrPanic(orig == maxInt(u32));
 }
 
 test "signed wrapping" {
@@ -198,9 +198,9 @@ test "signed wrapping" {
 }
 fn testSignedWrappingEval(x: i32) void {
     const min_val = x +% 1;
-    assert(min_val == minInt(i32));
+    assertOrPanic(min_val == minInt(i32));
     const max_val = min_val -% 1;
-    assert(max_val == maxInt(i32));
+    assertOrPanic(max_val == maxInt(i32));
 }
 
 test "negation wrapping" {
@@ -208,9 +208,9 @@ test "negation wrapping" {
     comptime testNegationWrappingEval(minInt(i16));
 }
 fn testNegationWrappingEval(x: i16) void {
-    assert(x == -32768);
+    assertOrPanic(x == -32768);
     const neg = -%x;
-    assert(neg == -32768);
+    assertOrPanic(neg == -32768);
 }
 
 test "unsigned 64-bit division" {
@@ -219,8 +219,8 @@ test "unsigned 64-bit division" {
 }
 fn test_u64_div() void {
     const result = divWithResult(1152921504606846976, 34359738365);
-    assert(result.quotient == 33554432);
-    assert(result.remainder == 100663296);
+    assertOrPanic(result.quotient == 33554432);
+    assertOrPanic(result.remainder == 100663296);
 }
 fn divWithResult(a: u64, b: u64) DivResult {
     return DivResult{
@@ -234,36 +234,36 @@ const DivResult = struct {
 };
 
 test "binary not" {
-    assert(comptime x: {
+    assertOrPanic(comptime x: {
         break :x ~u16(0b1010101010101010) == 0b0101010101010101;
     });
-    assert(comptime x: {
+    assertOrPanic(comptime x: {
         break :x ~u64(2147483647) == 18446744071562067968;
     });
     testBinaryNot(0b1010101010101010);
 }
 
 fn testBinaryNot(x: u16) void {
-    assert(~x == 0b0101010101010101);
+    assertOrPanic(~x == 0b0101010101010101);
 }
 
 test "small int addition" {
     var x: @IntType(false, 2) = 0;
-    assert(x == 0);
+    assertOrPanic(x == 0);
 
     x += 1;
-    assert(x == 1);
+    assertOrPanic(x == 1);
 
     x += 1;
-    assert(x == 2);
+    assertOrPanic(x == 2);
 
     x += 1;
-    assert(x == 3);
+    assertOrPanic(x == 3);
 
     var result: @typeOf(x) = 3;
-    assert(@addWithOverflow(@typeOf(x), x, 1, &result));
+    assertOrPanic(@addWithOverflow(@typeOf(x), x, 1, &result));
 
-    assert(result == 0);
+    assertOrPanic(result == 0);
 }
 
 test "float equality" {
@@ -276,20 +276,20 @@ test "float equality" {
 
 fn testFloatEqualityImpl(x: f64, y: f64) void {
     const y2 = x + 1.0;
-    assert(y == y2);
+    assertOrPanic(y == y2);
 }
 
 test "allow signed integer division/remainder when values are comptime known and positive or exact" {
-    assert(5 / 3 == 1);
-    assert(-5 / -3 == 1);
-    assert(-6 / 3 == -2);
+    assertOrPanic(5 / 3 == 1);
+    assertOrPanic(-5 / -3 == 1);
+    assertOrPanic(-6 / 3 == -2);
 
-    assert(5 % 3 == 2);
-    assert(-6 % 3 == 0);
+    assertOrPanic(5 % 3 == 2);
+    assertOrPanic(-6 % 3 == 0);
 }
 
 test "hex float literal parsing" {
-    comptime assert(0x1.0 == 1.0);
+    comptime assertOrPanic(0x1.0 == 1.0);
 }
 
 test "quad hex float literal parsing in range" {
@@ -304,7 +304,7 @@ test "quad hex float literal parsing accurate" {
 
     // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
     const expected: u128 = 0x3fff1111222233334444555566667777;
-    assert(@bitCast(u128, a) == expected);
+    assertOrPanic(@bitCast(u128, a) == expected);
 }
 
 test "hex float literal within range" {
@@ -319,7 +319,7 @@ test "truncating shift left" {
 }
 fn testShlTrunc(x: u16) void {
     const shifted = x << 1;
-    assert(shifted == 65534);
+    assertOrPanic(shifted == 65534);
 }
 
 test "truncating shift right" {
@@ -328,7 +328,7 @@ test "truncating shift right" {
 }
 fn testShrTrunc(x: u16) void {
     const shifted = x >> 1;
-    assert(shifted == 32767);
+    assertOrPanic(shifted == 32767);
 }
 
 test "exact shift left" {
@@ -337,7 +337,7 @@ test "exact shift left" {
 }
 fn testShlExact(x: u8) void {
     const shifted = @shlExact(x, 2);
-    assert(shifted == 0b11010100);
+    assertOrPanic(shifted == 0b11010100);
 }
 
 test "exact shift right" {
@@ -346,22 +346,22 @@ test "exact shift right" {
 }
 fn testShrExact(x: u8) void {
     const shifted = @shrExact(x, 2);
-    assert(shifted == 0b00101101);
+    assertOrPanic(shifted == 0b00101101);
 }
 
 test "comptime_int addition" {
     comptime {
-        assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
-        assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
+        assertOrPanic(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
+        assertOrPanic(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
     }
 }
 
 test "comptime_int multiplication" {
     comptime {
-        assert(
+        assertOrPanic(
             45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
         );
-        assert(
+        assertOrPanic(
             594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
         );
     }
@@ -369,7 +369,7 @@ test "comptime_int multiplication" {
 
 test "comptime_int shifting" {
     comptime {
-        assert((u128(1) << 127) == 0x80000000000000000000000000000000);
+        assertOrPanic((u128(1) << 127) == 0x80000000000000000000000000000000);
     }
 }
 
@@ -377,16 +377,16 @@ test "comptime_int multi-limb shift and mask" {
     comptime {
         var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
 
-        assert(u32(a & 0xffffffff) == 0xaaaaaaab);
+        assertOrPanic(u32(a & 0xffffffff) == 0xaaaaaaab);
         a >>= 32;
-        assert(u32(a & 0xffffffff) == 0xeeeeeeef);
+        assertOrPanic(u32(a & 0xffffffff) == 0xeeeeeeef);
         a >>= 32;
-        assert(u32(a & 0xffffffff) == 0xa0000001);
+        assertOrPanic(u32(a & 0xffffffff) == 0xa0000001);
         a >>= 32;
-        assert(u32(a & 0xffffffff) == 0xefffffff);
+        assertOrPanic(u32(a & 0xffffffff) == 0xefffffff);
         a >>= 32;
 
-        assert(a == 0);
+        assertOrPanic(a == 0);
     }
 }
 
@@ -394,7 +394,7 @@ test "comptime_int multi-limb partial shift right" {
     comptime {
         var a = 0x1ffffffffeeeeeeee;
         a >>= 16;
-        assert(a == 0x1ffffffffeeee);
+        assertOrPanic(a == 0x1ffffffffeeee);
     }
 }
 
@@ -404,23 +404,23 @@ test "xor" {
 }
 
 fn test_xor() void {
-    assert(0xFF ^ 0x00 == 0xFF);
-    assert(0xF0 ^ 0x0F == 0xFF);
-    assert(0xFF ^ 0xF0 == 0x0F);
-    assert(0xFF ^ 0x0F == 0xF0);
-    assert(0xFF ^ 0xFF == 0x00);
+    assertOrPanic(0xFF ^ 0x00 == 0xFF);
+    assertOrPanic(0xF0 ^ 0x0F == 0xFF);
+    assertOrPanic(0xFF ^ 0xF0 == 0x0F);
+    assertOrPanic(0xFF ^ 0x0F == 0xF0);
+    assertOrPanic(0xFF ^ 0xFF == 0x00);
 }
 
 test "comptime_int xor" {
     comptime {
-        assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
-        assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
-        assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
-        assert(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
-        assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
-        assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
-        assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
-        assert(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
+        assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+        assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+        assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
+        assertOrPanic(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
+        assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
+        assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+        assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
+        assertOrPanic(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
     }
 }
 
@@ -434,23 +434,23 @@ fn make_f128(x: f128) f128 {
 }
 
 fn test_f128() void {
-    assert(@sizeOf(f128) == 16);
-    assert(make_f128(1.0) == 1.0);
-    assert(make_f128(1.0) != 1.1);
-    assert(make_f128(1.0) > 0.9);
-    assert(make_f128(1.0) >= 0.9);
-    assert(make_f128(1.0) >= 1.0);
+    assertOrPanic(@sizeOf(f128) == 16);
+    assertOrPanic(make_f128(1.0) == 1.0);
+    assertOrPanic(make_f128(1.0) != 1.1);
+    assertOrPanic(make_f128(1.0) > 0.9);
+    assertOrPanic(make_f128(1.0) >= 0.9);
+    assertOrPanic(make_f128(1.0) >= 1.0);
     should_not_be_zero(1.0);
 }
 
 fn should_not_be_zero(x: f128) void {
-    assert(x != 0.0);
+    assertOrPanic(x != 0.0);
 }
 
 test "comptime float rem int" {
     comptime {
         var x = f32(1) % 2;
-        assert(x == 1.0);
+        assertOrPanic(x == 1.0);
     }
 }
 
@@ -465,8 +465,8 @@ test "remainder division" {
 }
 
 fn remdiv(comptime T: type) void {
-    assert(T(1) == T(1) % T(2));
-    assert(T(1) == T(7) % T(3));
+    assertOrPanic(T(1) == T(1) % T(2));
+    assertOrPanic(T(1) == T(7) % T(3));
 }
 
 test "@sqrt" {
@@ -480,19 +480,19 @@ test "@sqrt" {
     const x = 14.0;
     const y = x * x;
     const z = @sqrt(@typeOf(y), y);
-    comptime assert(z == x);
+    comptime assertOrPanic(z == x);
 }
 
 fn testSqrt(comptime T: type, x: T) void {
-    assert(@sqrt(T, x * x) == x);
+    assertOrPanic(@sqrt(T, x * x) == x);
 }
 
 test "comptime_int param and return" {
     const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
-    assert(a == 137114567242441932203689521744947848950);
+    assertOrPanic(a == 137114567242441932203689521744947848950);
 
     const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
-    assert(b == 985095453608931032642182098849559179469148836107390954364380);
+    assertOrPanic(b == 985095453608931032642182098849559179469148836107390954364380);
 }
 
 fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
test/cases/merge_error_sets.zig → test/stage1/behavior/merge_error_sets.zig
File renamed without changes
test/cases/misc.zig → test/stage1/behavior/misc.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const mem = std.mem;
 const cstr = std.cstr;
 const builtin = @import("builtin");
@@ -26,38 +26,38 @@ test "call disabled extern fn" {
 }
 
 test "@IntType builtin" {
-    assert(@IntType(true, 8) == i8);
-    assert(@IntType(true, 16) == i16);
-    assert(@IntType(true, 32) == i32);
-    assert(@IntType(true, 64) == i64);
-
-    assert(@IntType(false, 8) == u8);
-    assert(@IntType(false, 16) == u16);
-    assert(@IntType(false, 32) == u32);
-    assert(@IntType(false, 64) == u64);
-
-    assert(i8.bit_count == 8);
-    assert(i16.bit_count == 16);
-    assert(i32.bit_count == 32);
-    assert(i64.bit_count == 64);
-
-    assert(i8.is_signed);
-    assert(i16.is_signed);
-    assert(i32.is_signed);
-    assert(i64.is_signed);
-    assert(isize.is_signed);
-
-    assert(!u8.is_signed);
-    assert(!u16.is_signed);
-    assert(!u32.is_signed);
-    assert(!u64.is_signed);
-    assert(!usize.is_signed);
+    assertOrPanic(@IntType(true, 8) == i8);
+    assertOrPanic(@IntType(true, 16) == i16);
+    assertOrPanic(@IntType(true, 32) == i32);
+    assertOrPanic(@IntType(true, 64) == i64);
+
+    assertOrPanic(@IntType(false, 8) == u8);
+    assertOrPanic(@IntType(false, 16) == u16);
+    assertOrPanic(@IntType(false, 32) == u32);
+    assertOrPanic(@IntType(false, 64) == u64);
+
+    assertOrPanic(i8.bit_count == 8);
+    assertOrPanic(i16.bit_count == 16);
+    assertOrPanic(i32.bit_count == 32);
+    assertOrPanic(i64.bit_count == 64);
+
+    assertOrPanic(i8.is_signed);
+    assertOrPanic(i16.is_signed);
+    assertOrPanic(i32.is_signed);
+    assertOrPanic(i64.is_signed);
+    assertOrPanic(isize.is_signed);
+
+    assertOrPanic(!u8.is_signed);
+    assertOrPanic(!u16.is_signed);
+    assertOrPanic(!u32.is_signed);
+    assertOrPanic(!u64.is_signed);
+    assertOrPanic(!usize.is_signed);
 }
 
 test "floating point primitive bit counts" {
-    assert(f16.bit_count == 16);
-    assert(f32.bit_count == 32);
-    assert(f64.bit_count == 64);
+    assertOrPanic(f16.bit_count == 16);
+    assertOrPanic(f32.bit_count == 32);
+    assertOrPanic(f64.bit_count == 64);
 }
 
 test "short circuit" {
@@ -72,7 +72,7 @@ fn testShortCircuit(f: bool, t: bool) void {
     var hit_4 = f;
 
     if (t or x: {
-        assert(f);
+        assertOrPanic(f);
         break :x f;
     }) {
         hit_1 = t;
@@ -81,31 +81,31 @@ fn testShortCircuit(f: bool, t: bool) void {
         hit_2 = t;
         break :x f;
     }) {
-        assert(f);
+        assertOrPanic(f);
     }
 
     if (t and x: {
         hit_3 = t;
         break :x f;
     }) {
-        assert(f);
+        assertOrPanic(f);
     }
     if (f and x: {
-        assert(f);
+        assertOrPanic(f);
         break :x f;
     }) {
-        assert(f);
+        assertOrPanic(f);
     } else {
         hit_4 = t;
     }
-    assert(hit_1);
-    assert(hit_2);
-    assert(hit_3);
-    assert(hit_4);
+    assertOrPanic(hit_1);
+    assertOrPanic(hit_2);
+    assertOrPanic(hit_3);
+    assertOrPanic(hit_4);
 }
 
 test "truncate" {
-    assert(testTruncate(0x10fd) == 0xfd);
+    assertOrPanic(testTruncate(0x10fd) == 0xfd);
 }
 fn testTruncate(x: u32) u8 {
     return @truncate(u8, x);
@@ -116,16 +116,16 @@ fn first4KeysOfHomeRow() []const u8 {
 }
 
 test "return string from function" {
-    assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
+    assertOrPanic(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
 }
 
 const g1: i32 = 1233 + 1;
 var g2: i32 = 0;
 
 test "global variables" {
-    assert(g2 == 0);
+    assertOrPanic(g2 == 0);
     g2 = g1;
-    assert(g2 == 1234);
+    assertOrPanic(g2 == 1234);
 }
 
 test "memcpy and memset intrinsics" {
@@ -142,7 +142,7 @@ test "builtin static eval" {
     const x: i32 = comptime x: {
         break :x 1 + 2 + 3;
     };
-    assert(x == comptime 6);
+    assertOrPanic(x == comptime 6);
 }
 
 test "slicing" {
@@ -163,7 +163,7 @@ test "slicing" {
 
 test "constant equal function pointers" {
     const alias = emptyFn;
-    assert(comptime x: {
+    assertOrPanic(comptime x: {
         break :x emptyFn == alias;
     });
 }
@@ -171,25 +171,25 @@ test "constant equal function pointers" {
 fn emptyFn() void {}
 
 test "hex escape" {
-    assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
+    assertOrPanic(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
 }
 
 test "string concatenation" {
-    assert(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
+    assertOrPanic(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
 }
 
 test "array mult operator" {
-    assert(mem.eql(u8, "ab" ** 5, "ababababab"));
+    assertOrPanic(mem.eql(u8, "ab" ** 5, "ababababab"));
 }
 
 test "string escapes" {
-    assert(mem.eql(u8, "\"", "\x22"));
-    assert(mem.eql(u8, "\'", "\x27"));
-    assert(mem.eql(u8, "\n", "\x0a"));
-    assert(mem.eql(u8, "\r", "\x0d"));
-    assert(mem.eql(u8, "\t", "\x09"));
-    assert(mem.eql(u8, "\\", "\x5c"));
-    assert(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69"));
+    assertOrPanic(mem.eql(u8, "\"", "\x22"));
+    assertOrPanic(mem.eql(u8, "\'", "\x27"));
+    assertOrPanic(mem.eql(u8, "\n", "\x0a"));
+    assertOrPanic(mem.eql(u8, "\r", "\x0d"));
+    assertOrPanic(mem.eql(u8, "\t", "\x09"));
+    assertOrPanic(mem.eql(u8, "\\", "\x5c"));
+    assertOrPanic(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69"));
 }
 
 test "multiline string" {
@@ -199,7 +199,7 @@ test "multiline string" {
         \\three
     ;
     const s2 = "one\ntwo)\nthree";
-    assert(mem.eql(u8, s1, s2));
+    assertOrPanic(mem.eql(u8, s1, s2));
 }
 
 test "multiline C string" {
@@ -209,11 +209,11 @@ test "multiline C string" {
         c\\three
     ;
     const s2 = c"one\ntwo)\nthree";
-    assert(cstr.cmp(s1, s2) == 0);
+    assertOrPanic(cstr.cmp(s1, s2) == 0);
 }
 
 test "type equality" {
-    assert(*const u8 != *u8);
+    assertOrPanic(*const u8 != *u8);
 }
 
 const global_a: i32 = 1234;
@@ -221,7 +221,7 @@ const global_b: *const i32 = &global_a;
 const global_c: *const f32 = @ptrCast(*const f32, global_b);
 test "compile time global reinterpret" {
     const d = @ptrCast(*const i32, global_c);
-    assert(d.* == 1234);
+    assertOrPanic(d.* == 1234);
 }
 
 test "explicit cast maybe pointers" {
@@ -247,8 +247,8 @@ test "cast undefined" {
 fn testCastUndefined(x: []const u8) void {}
 
 test "cast small unsigned to larger signed" {
-    assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
-    assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
+    assertOrPanic(castSmallUnsignedToLargerSigned1(200) == i16(200));
+    assertOrPanic(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
 }
 fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
     return x;
@@ -258,7 +258,7 @@ fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
 }
 
 test "implicit cast after unreachable" {
-    assert(outer() == 1234);
+    assertOrPanic(outer() == 1234);
 }
 fn inner() i32 {
     return 1234;
@@ -273,13 +273,13 @@ test "pointer dereferencing" {
 
     y.* += 1;
 
-    assert(x == 4);
-    assert(y.* == 4);
+    assertOrPanic(x == 4);
+    assertOrPanic(y.* == 4);
 }
 
 test "call result of if else expression" {
-    assert(mem.eql(u8, f2(true), "a"));
-    assert(mem.eql(u8, f2(false), "b"));
+    assertOrPanic(mem.eql(u8, f2(true), "a"));
+    assertOrPanic(mem.eql(u8, f2(false), "b"));
 }
 fn f2(x: bool) []const u8 {
     return (if (x) fA else fB)();
@@ -321,8 +321,8 @@ const test3_bar = Test3Foo{ .Two = 13 };
 fn test3_1(f: Test3Foo) void {
     switch (f) {
         Test3Foo.Three => |pt| {
-            assert(pt.x == 3);
-            assert(pt.y == 4);
+            assertOrPanic(pt.x == 3);
+            assertOrPanic(pt.y == 4);
         },
         else => unreachable,
     }
@@ -330,14 +330,14 @@ fn test3_1(f: Test3Foo) void {
 fn test3_2(f: Test3Foo) void {
     switch (f) {
         Test3Foo.Two => |x| {
-            assert(x == 13);
+            assertOrPanic(x == 13);
         },
         else => unreachable,
     }
 }
 
 test "character literals" {
-    assert('\'' == single_quote);
+    assertOrPanic('\'' == single_quote);
 }
 const single_quote = '\'';
 
@@ -346,13 +346,13 @@ test "take address of parameter" {
 }
 fn testTakeAddressOfParameter(f: f32) void {
     const f_ptr = &f;
-    assert(f_ptr.* == 12.34);
+    assertOrPanic(f_ptr.* == 12.34);
 }
 
 test "pointer comparison" {
     const a = ([]const u8)("a");
     const b = &a;
-    assert(ptrEql(b, b));
+    assertOrPanic(ptrEql(b, b));
 }
 fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
     return a == b;
@@ -367,36 +367,31 @@ test "C string concatenation" {
     {
         var i: u32 = 0;
         while (i < len_with_null) : (i += 1) {
-            assert(a[i] == b[i]);
+            assertOrPanic(a[i] == b[i]);
         }
     }
-    assert(a[len] == 0);
-    assert(b[len] == 0);
+    assertOrPanic(a[len] == 0);
+    assertOrPanic(b[len] == 0);
 }
 
 test "cast slice to u8 slice" {
-    assert(@sizeOf(i32) == 4);
-    var big_thing_array = []i32{
-        1,
-        2,
-        3,
-        4,
-    };
+    assertOrPanic(@sizeOf(i32) == 4);
+    var big_thing_array = []i32{ 1, 2, 3, 4 };
     const big_thing_slice: []i32 = big_thing_array[0..];
     const bytes = @sliceToBytes(big_thing_slice);
-    assert(bytes.len == 4 * 4);
+    assertOrPanic(bytes.len == 4 * 4);
     bytes[4] = 0;
     bytes[5] = 0;
     bytes[6] = 0;
     bytes[7] = 0;
-    assert(big_thing_slice[1] == 0);
+    assertOrPanic(big_thing_slice[1] == 0);
     const big_thing_again = @bytesToSlice(i32, bytes);
-    assert(big_thing_again[2] == 3);
+    assertOrPanic(big_thing_again[2] == 3);
     big_thing_again[2] = -1;
-    assert(bytes[8] == maxInt(u8));
-    assert(bytes[9] == maxInt(u8));
-    assert(bytes[10] == maxInt(u8));
-    assert(bytes[11] == maxInt(u8));
+    assertOrPanic(bytes[8] == maxInt(u8));
+    assertOrPanic(bytes[9] == maxInt(u8));
+    assertOrPanic(bytes[10] == maxInt(u8));
+    assertOrPanic(bytes[11] == maxInt(u8));
 }
 
 test "pointer to void return type" {
@@ -413,7 +408,7 @@ fn testPointerToVoidReturnType2() *const void {
 
 test "non const ptr to aliased type" {
     const int = i32;
-    assert(?*int == ?*i32);
+    assertOrPanic(?*int == ?*i32);
 }
 
 test "array 2D const double ptr" {
@@ -426,8 +421,8 @@ test "array 2D const double ptr" {
 
 fn testArray2DConstDoublePtr(ptr: *const f32) void {
     const ptr2 = @ptrCast([*]const f32, ptr);
-    assert(ptr2[0] == 1.0);
-    assert(ptr2[1] == 2.0);
+    assertOrPanic(ptr2[0] == 1.0);
+    assertOrPanic(ptr2[1] == 2.0);
 }
 
 const Tid = builtin.TypeId;
@@ -449,32 +444,32 @@ const AUnion = union {
 
 test "@typeId" {
     comptime {
-        assert(@typeId(type) == Tid.Type);
-        assert(@typeId(void) == Tid.Void);
-        assert(@typeId(bool) == Tid.Bool);
-        assert(@typeId(noreturn) == Tid.NoReturn);
-        assert(@typeId(i8) == Tid.Int);
-        assert(@typeId(u8) == Tid.Int);
-        assert(@typeId(i64) == Tid.Int);
-        assert(@typeId(u64) == Tid.Int);
-        assert(@typeId(f32) == Tid.Float);
-        assert(@typeId(f64) == Tid.Float);
-        assert(@typeId(*f32) == Tid.Pointer);
-        assert(@typeId([2]u8) == Tid.Array);
-        assert(@typeId(AStruct) == Tid.Struct);
-        assert(@typeId(@typeOf(1)) == Tid.ComptimeInt);
-        assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
-        assert(@typeId(@typeOf(undefined)) == Tid.Undefined);
-        assert(@typeId(@typeOf(null)) == Tid.Null);
-        assert(@typeId(?i32) == Tid.Optional);
-        assert(@typeId(anyerror!i32) == Tid.ErrorUnion);
-        assert(@typeId(anyerror) == Tid.ErrorSet);
-        assert(@typeId(AnEnum) == Tid.Enum);
-        assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
-        assert(@typeId(AUnionEnum) == Tid.Union);
-        assert(@typeId(AUnion) == Tid.Union);
-        assert(@typeId(fn () void) == Tid.Fn);
-        assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
+        assertOrPanic(@typeId(type) == Tid.Type);
+        assertOrPanic(@typeId(void) == Tid.Void);
+        assertOrPanic(@typeId(bool) == Tid.Bool);
+        assertOrPanic(@typeId(noreturn) == Tid.NoReturn);
+        assertOrPanic(@typeId(i8) == Tid.Int);
+        assertOrPanic(@typeId(u8) == Tid.Int);
+        assertOrPanic(@typeId(i64) == Tid.Int);
+        assertOrPanic(@typeId(u64) == Tid.Int);
+        assertOrPanic(@typeId(f32) == Tid.Float);
+        assertOrPanic(@typeId(f64) == Tid.Float);
+        assertOrPanic(@typeId(*f32) == Tid.Pointer);
+        assertOrPanic(@typeId([2]u8) == Tid.Array);
+        assertOrPanic(@typeId(AStruct) == Tid.Struct);
+        assertOrPanic(@typeId(@typeOf(1)) == Tid.ComptimeInt);
+        assertOrPanic(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
+        assertOrPanic(@typeId(@typeOf(undefined)) == Tid.Undefined);
+        assertOrPanic(@typeId(@typeOf(null)) == Tid.Null);
+        assertOrPanic(@typeId(?i32) == Tid.Optional);
+        assertOrPanic(@typeId(anyerror!i32) == Tid.ErrorUnion);
+        assertOrPanic(@typeId(anyerror) == Tid.ErrorSet);
+        assertOrPanic(@typeId(AnEnum) == Tid.Enum);
+        assertOrPanic(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
+        assertOrPanic(@typeId(AUnionEnum) == Tid.Union);
+        assertOrPanic(@typeId(AUnion) == Tid.Union);
+        assertOrPanic(@typeId(fn () void) == Tid.Fn);
+        assertOrPanic(@typeId(@typeOf(builtin)) == Tid.Namespace);
         // TODO bound fn
         // TODO arg tuple
         // TODO opaque
@@ -490,13 +485,13 @@ test "@typeName" {
         Unused,
     };
     comptime {
-        assert(mem.eql(u8, @typeName(i64), "i64"));
-        assert(mem.eql(u8, @typeName(*usize), "*usize"));
+        assertOrPanic(mem.eql(u8, @typeName(i64), "i64"));
+        assertOrPanic(mem.eql(u8, @typeName(*usize), "*usize"));
         // https://github.com/ziglang/zig/issues/675
-        assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
-        assert(mem.eql(u8, @typeName(Struct), "Struct"));
-        assert(mem.eql(u8, @typeName(Union), "Union"));
-        assert(mem.eql(u8, @typeName(Enum), "Enum"));
+        assertOrPanic(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
+        assertOrPanic(mem.eql(u8, @typeName(Struct), "Struct"));
+        assertOrPanic(mem.eql(u8, @typeName(Union), "Union"));
+        assertOrPanic(mem.eql(u8, @typeName(Enum), "Enum"));
     }
 }
 
@@ -504,28 +499,16 @@ fn TypeFromFn(comptime T: type) type {
     return struct {};
 }
 
-test "volatile load and store" {
-    var number: i32 = 1234;
-    const ptr = (*volatile i32)(&number);
-    ptr.* += 1;
-    assert(ptr.* == 1235);
+test "double implicit cast in same expression" {
+    var x = i32(u16(nine()));
+    assertOrPanic(x == 9);
 }
-
-test "slice string literal has type []const u8" {
-    comptime {
-        assert(@typeOf("aoeu"[0..]) == []const u8);
-        const array = []i32{
-            1,
-            2,
-            3,
-            4,
-        };
-        assert(@typeOf(array[0..]) == []const i32);
-    }
+fn nine() u8 {
+    return 9;
 }
 
 test "global variable initialized to global variable array element" {
-    assert(global_ptr == &gdt[0]);
+    assertOrPanic(global_ptr == &gdt[0]);
 }
 const GDTEntry = struct {
     field: i32,
@@ -543,16 +526,12 @@ export fn writeToVRam() void {
     vram[0] = 'X';
 }
 
-test "pointer child field" {
-    assert((*u32).Child == u32);
-}
-
 const OpaqueA = @OpaqueType();
 const OpaqueB = @OpaqueType();
 test "@OpaqueType" {
-    assert(*OpaqueA != *OpaqueB);
-    assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
-    assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
+    assertOrPanic(*OpaqueA != *OpaqueB);
+    assertOrPanic(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
+    assertOrPanic(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
 }
 
 test "variable is allowed to be a pointer to an opaque type" {
@@ -581,25 +560,6 @@ test "implicit comptime while" {
     }
 }
 
-test "struct inside function" {
-    testStructInFn();
-    comptime testStructInFn();
-}
-
-fn testStructInFn() void {
-    const BlockKind = u32;
-
-    const Block = struct {
-        kind: BlockKind,
-    };
-
-    var block = Block{ .kind = 1234 };
-
-    block.kind += 1;
-
-    assert(block.kind == 1235);
-}
-
 fn fnThatClosesOverLocalConst() type {
     const c = 1;
     return struct {
@@ -611,7 +571,7 @@ fn fnThatClosesOverLocalConst() type {
 
 test "function closes over local const" {
     const x = fnThatClosesOverLocalConst().g();
-    assert(x == 1);
+    assertOrPanic(x == 1);
 }
 
 test "cold function" {
@@ -648,21 +608,21 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: Pack
 test "slicing zero length array" {
     const s1 = ""[0..];
     const s2 = ([]u32{})[0..];
-    assert(s1.len == 0);
-    assert(s2.len == 0);
-    assert(mem.eql(u8, s1, ""));
-    assert(mem.eql(u32, s2, []u32{}));
+    assertOrPanic(s1.len == 0);
+    assertOrPanic(s2.len == 0);
+    assertOrPanic(mem.eql(u8, s1, ""));
+    assertOrPanic(mem.eql(u32, s2, []u32{}));
 }
 
 const addr1 = @ptrCast(*const u8, emptyFn);
 test "comptime cast fn to ptr" {
     const addr2 = @ptrCast(*const u8, emptyFn);
-    comptime assert(addr1 == addr2);
+    comptime assertOrPanic(addr1 == addr2);
 }
 
 test "equality compare fn ptrs" {
     var a = emptyFn;
-    assert(a == a);
+    assertOrPanic(a == a);
 }
 
 test "self reference through fn ptr field" {
@@ -677,5 +637,51 @@ test "self reference through fn ptr field" {
     };
     var a: S.A = undefined;
     a.f = S.foo;
-    assert(a.f(a) == 12);
+    assertOrPanic(a.f(a) == 12);
+}
+
+test "volatile load and store" {
+    var number: i32 = 1234;
+    const ptr = (*volatile i32)(&number);
+    ptr.* += 1;
+    assertOrPanic(ptr.* == 1235);
+}
+
+test "slice string literal has type []const u8" {
+    comptime {
+        assertOrPanic(@typeOf("aoeu"[0..]) == []const u8);
+        const array = []i32{ 1, 2, 3, 4 };
+        assertOrPanic(@typeOf(array[0..]) == []const i32);
+    }
+}
+
+test "pointer child field" {
+    assertOrPanic((*u32).Child == u32);
+}
+
+test "struct inside function" {
+    testStructInFn();
+    comptime testStructInFn();
+}
+
+fn testStructInFn() void {
+    const BlockKind = u32;
+
+    const Block = struct {
+        kind: BlockKind,
+    };
+
+    var block = Block{ .kind = 1234 };
+
+    block.kind += 1;
+
+    assertOrPanic(block.kind == 1235);
+}
+
+test "fn call returning scalar optional in equality expression" {
+    assertOrPanic(getNull() == null);
+}
+
+fn getNull() ?*i32 {
+    return null;
 }
test/cases/new_stack_call.zig → test/stage1/behavior/new_stack_call.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 var new_stack_bytes: [1024]u8 = undefined;
 
@@ -10,17 +10,17 @@ test "calling a function with a new stack" {
     const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
     _ = targetFunction(arg);
 
-    assert(arg == 1234);
-    assert(a < b);
+    assertOrPanic(arg == 1234);
+    assertOrPanic(a < b);
 }
 
 fn targetFunction(x: i32) usize {
-    assert(x == 1234);
+    assertOrPanic(x == 1234);
 
     var local_variable: i32 = 42;
     const ptr = &local_variable;
     ptr.* += 1;
 
-    assert(local_variable == 43);
+    assertOrPanic(local_variable == 43);
     return @ptrToInt(ptr);
 }
test/cases/null.zig → test/stage1/behavior/null.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "optional type" {
     const x: ?bool = true;
@@ -17,13 +17,13 @@ test "optional type" {
 
     const z = next_x orelse 1234;
 
-    assert(z == 1234);
+    assertOrPanic(z == 1234);
 
     const final_x: ?i32 = 13;
 
     const num = final_x orelse unreachable;
 
-    assert(num == 13);
+    assertOrPanic(num == 13);
 }
 
 test "test maybe object and get a pointer to the inner value" {
@@ -33,7 +33,7 @@ test "test maybe object and get a pointer to the inner value" {
         b.* = false;
     }
 
-    assert(maybe_bool.? == false);
+    assertOrPanic(maybe_bool.? == false);
 }
 
 test "rhs maybe unwrap return" {
@@ -47,9 +47,9 @@ test "maybe return" {
 }
 
 fn maybeReturnImpl() void {
-    assert(foo(1235).?);
+    assertOrPanic(foo(1235).?);
     if (foo(null) != null) unreachable;
-    assert(!foo(1234).?);
+    assertOrPanic(!foo(1234).?);
 }
 
 fn foo(x: ?i32) ?bool {
@@ -58,7 +58,7 @@ fn foo(x: ?i32) ?bool {
 }
 
 test "if var maybe pointer" {
-    assert(shouldBeAPlus1(Particle{
+    assertOrPanic(shouldBeAPlus1(Particle{
         .a = 14,
         .b = 1,
         .c = 1,
@@ -84,10 +84,10 @@ const Particle = struct {
 
 test "null literal outside function" {
     const is_null = here_is_a_null_literal.context == null;
-    assert(is_null);
+    assertOrPanic(is_null);
 
     const is_non_null = here_is_a_null_literal.context != null;
-    assert(!is_non_null);
+    assertOrPanic(!is_non_null);
 }
 const SillyStruct = struct {
     context: ?i32,
@@ -98,8 +98,8 @@ test "test null runtime" {
     testTestNullRuntime(null);
 }
 fn testTestNullRuntime(x: ?i32) void {
-    assert(x == null);
-    assert(!(x != null));
+    assertOrPanic(x == null);
+    assertOrPanic(!(x != null));
 }
 
 test "optional void" {
@@ -108,8 +108,8 @@ test "optional void" {
 }
 
 fn optionalVoidImpl() void {
-    assert(bar(null) == null);
-    assert(bar({}) != null);
+    assertOrPanic(bar(null) == null);
+    assertOrPanic(bar({}) != null);
 }
 
 fn bar(x: ?void) ?void {
@@ -133,7 +133,7 @@ test "unwrap optional which is field of global var" {
     }
     struct_with_optional.field = 1234;
     if (struct_with_optional.field) |payload| {
-        assert(payload == 1234);
+        assertOrPanic(payload == 1234);
     } else {
         unreachable;
     }
@@ -141,13 +141,13 @@ test "unwrap optional which is field of global var" {
 
 test "null with default unwrap" {
     const x: i32 = null orelse 1;
-    assert(x == 1);
+    assertOrPanic(x == 1);
 }
 
 test "optional types" {
     comptime {
         const opt_type_struct = StructWithOptionalType{ .t = u8 };
-        assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);
+        assertOrPanic(opt_type_struct.t != null and opt_type_struct.t.? == u8);
     }
 }
 
@@ -158,5 +158,5 @@ const StructWithOptionalType = struct {
 test "optional pointer to 0 bit type null value at runtime" {
     const EmptyStruct = struct {};
     var x: ?*EmptyStruct = null;
-    assert(x == null);
+    assertOrPanic(x == null);
 }
test/stage1/behavior/optional.zig
@@ -0,0 +1,81 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+pub const EmptyStruct = struct {};
+
+test "optional pointer to size zero struct" {
+    var e = EmptyStruct{};
+    var o: ?*EmptyStruct = &e;
+    assertOrPanic(o != null);
+}
+
+test "equality compare nullable pointers" {
+    testNullPtrsEql();
+    comptime testNullPtrsEql();
+}
+
+fn testNullPtrsEql() void {
+    var number: i32 = 1234;
+
+    var x: ?*i32 = null;
+    var y: ?*i32 = null;
+    assertOrPanic(x == y);
+    y = &number;
+    assertOrPanic(x != y);
+    assertOrPanic(x != &number);
+    assertOrPanic(&number != x);
+    x = &number;
+    assertOrPanic(x == y);
+    assertOrPanic(x == &number);
+    assertOrPanic(&number == x);
+}
+
+test "address of unwrap optional" {
+    const S = struct {
+        const Foo = struct {
+            a: i32,
+        };
+
+        var global: ?Foo = null;
+
+        pub fn getFoo() anyerror!*Foo {
+            return &global.?;
+        }
+    };
+    S.global = S.Foo{ .a = 1234 };
+    const foo = S.getFoo() catch unreachable;
+    assertOrPanic(foo.a == 1234);
+}
+
+test "passing an optional integer as a parameter" {
+    const S = struct {
+        fn entry() bool {
+            var x: i32 = 1234;
+            return foo(x);
+        }
+
+        fn foo(x: ?i32) bool {
+            return x.? == 1234;
+        }
+    };
+    assertOrPanic(S.entry());
+    comptime assertOrPanic(S.entry());
+}
+
+test "unwrap function call with optional pointer return value" {
+    const S = struct {
+        fn entry() void {
+            assertOrPanic(foo().?.* == 1234);
+            assertOrPanic(bar() == null);
+        }
+        const global: i32 = 1234;
+        fn foo() ?*const i32 {
+            return &global;
+        }
+        fn bar() ?*i32 {
+            return null;
+        }
+    };
+    S.entry();
+    // TODO https://github.com/ziglang/zig/issues/1901
+    //comptime S.entry();
+}
test/cases/pointers.zig → test/stage1/behavior/pointers.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 test "dereference pointer" {
     comptime testDerefPtr();
@@ -10,33 +10,33 @@ fn testDerefPtr() void {
     var x: i32 = 1234;
     var y = &x;
     y.* += 1;
-    assert(x == 1235);
+    assertOrPanic(x == 1235);
 }
 
 test "pointer arithmetic" {
     var ptr = c"abcd";
 
-    assert(ptr[0] == 'a');
+    assertOrPanic(ptr[0] == 'a');
     ptr += 1;
-    assert(ptr[0] == 'b');
+    assertOrPanic(ptr[0] == 'b');
     ptr += 1;
-    assert(ptr[0] == 'c');
+    assertOrPanic(ptr[0] == 'c');
     ptr += 1;
-    assert(ptr[0] == 'd');
+    assertOrPanic(ptr[0] == 'd');
     ptr += 1;
-    assert(ptr[0] == 0);
+    assertOrPanic(ptr[0] == 0);
     ptr -= 1;
-    assert(ptr[0] == 'd');
+    assertOrPanic(ptr[0] == 'd');
     ptr -= 1;
-    assert(ptr[0] == 'c');
+    assertOrPanic(ptr[0] == 'c');
     ptr -= 1;
-    assert(ptr[0] == 'b');
+    assertOrPanic(ptr[0] == 'b');
     ptr -= 1;
-    assert(ptr[0] == 'a');
+    assertOrPanic(ptr[0] == 'a');
 }
 
 test "double pointer parsing" {
-    comptime assert(PtrOf(PtrOf(i32)) == **i32);
+    comptime assertOrPanic(PtrOf(PtrOf(i32)) == **i32);
 }
 
 fn PtrOf(comptime T: type) type {
test/stage1/behavior/popcount.zig
@@ -0,0 +1,25 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "@popCount" {
+    comptime testPopCount();
+    testPopCount();
+}
+
+fn testPopCount() void {
+    {
+        var x: u32 = 0xaa;
+        assertOrPanic(@popCount(x) == 4);
+    }
+    {
+        var x: u32 = 0xaaaaaaaa;
+        assertOrPanic(@popCount(x) == 16);
+    }
+    {
+        var x: i16 = -1;
+        assertOrPanic(@popCount(x) == 16);
+    }
+    comptime {
+        assertOrPanic(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24);
+    }
+}
+
test/cases/ptrcast.zig → test/stage1/behavior/ptrcast.zig
File renamed without changes
test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig → test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig
@@ -1,14 +1,14 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 const mem = @import("std").mem;
 
 var ok: bool = false;
 test "reference a variable in an if after an if in the 2nd switch prong" {
     foo(true, Num.Two, false, "aoeu");
-    assert(!ok);
+    assertOrPanic(!ok);
     foo(false, Num.One, false, "aoeu");
-    assert(!ok);
+    assertOrPanic(!ok);
     foo(true, Num.One, false, "aoeu");
-    assert(ok);
+    assertOrPanic(ok);
 }
 
 const Num = enum {
@@ -32,6 +32,6 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {
 }
 
 fn a(x: []const u8) void {
-    assert(mem.eql(u8, x, "aoeu"));
+    assertOrPanic(mem.eql(u8, x, "aoeu"));
     ok = true;
 }
test/stage1/behavior/reflection.zig
@@ -0,0 +1,96 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+const reflection = @This();
+
+test "reflection: array, pointer, optional, error union type child" {
+    comptime {
+        assertOrPanic(([10]u8).Child == u8);
+        assertOrPanic((*u8).Child == u8);
+        assertOrPanic((anyerror!u8).Payload == u8);
+        assertOrPanic((?u8).Child == u8);
+    }
+}
+
+test "reflection: function return type, var args, and param types" {
+    comptime {
+        assertOrPanic(@typeOf(dummy).ReturnType == i32);
+        assertOrPanic(!@typeOf(dummy).is_var_args);
+        assertOrPanic(@typeOf(dummy_varargs).is_var_args);
+        assertOrPanic(@typeOf(dummy).arg_count == 3);
+        assertOrPanic(@ArgType(@typeOf(dummy), 0) == bool);
+        assertOrPanic(@ArgType(@typeOf(dummy), 1) == i32);
+        assertOrPanic(@ArgType(@typeOf(dummy), 2) == f32);
+    }
+}
+
+fn dummy(a: bool, b: i32, c: f32) i32 {
+    return 1234;
+}
+fn dummy_varargs(args: ...) void {}
+
+test "reflection: struct member types and names" {
+    comptime {
+        assertOrPanic(@memberCount(Foo) == 3);
+
+        assertOrPanic(@memberType(Foo, 0) == i32);
+        assertOrPanic(@memberType(Foo, 1) == bool);
+        assertOrPanic(@memberType(Foo, 2) == void);
+
+        assertOrPanic(mem.eql(u8, @memberName(Foo, 0), "one"));
+        assertOrPanic(mem.eql(u8, @memberName(Foo, 1), "two"));
+        assertOrPanic(mem.eql(u8, @memberName(Foo, 2), "three"));
+    }
+}
+
+test "reflection: enum member types and names" {
+    comptime {
+        assertOrPanic(@memberCount(Bar) == 4);
+
+        assertOrPanic(@memberType(Bar, 0) == void);
+        assertOrPanic(@memberType(Bar, 1) == i32);
+        assertOrPanic(@memberType(Bar, 2) == bool);
+        assertOrPanic(@memberType(Bar, 3) == f64);
+
+        assertOrPanic(mem.eql(u8, @memberName(Bar, 0), "One"));
+        assertOrPanic(mem.eql(u8, @memberName(Bar, 1), "Two"));
+        assertOrPanic(mem.eql(u8, @memberName(Bar, 2), "Three"));
+        assertOrPanic(mem.eql(u8, @memberName(Bar, 3), "Four"));
+    }
+}
+
+test "reflection: @field" {
+    var f = Foo{
+        .one = 42,
+        .two = true,
+        .three = void{},
+    };
+
+    assertOrPanic(f.one == f.one);
+    assertOrPanic(@field(f, "o" ++ "ne") == f.one);
+    assertOrPanic(@field(f, "t" ++ "wo") == f.two);
+    assertOrPanic(@field(f, "th" ++ "ree") == f.three);
+    assertOrPanic(@field(Foo, "const" ++ "ant") == Foo.constant);
+    assertOrPanic(@field(Bar, "O" ++ "ne") == Bar.One);
+    assertOrPanic(@field(Bar, "T" ++ "wo") == Bar.Two);
+    assertOrPanic(@field(Bar, "Th" ++ "ree") == Bar.Three);
+    assertOrPanic(@field(Bar, "F" ++ "our") == Bar.Four);
+    assertOrPanic(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2));
+    @field(f, "o" ++ "ne") = 4;
+    assertOrPanic(f.one == 4);
+}
+
+const Foo = struct {
+    const constant = 52;
+
+    one: i32,
+    two: bool,
+    three: void,
+};
+
+const Bar = union(enum) {
+    One: void,
+    Two: i32,
+    Three: bool,
+    Four: f64,
+};
+
test/stage1/behavior/sizeof_and_typeof.zig
@@ -0,0 +1,69 @@
+const builtin = @import("builtin");
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "@sizeOf and @typeOf" {
+    const y: @typeOf(x) = 120;
+    assertOrPanic(@sizeOf(@typeOf(y)) == 2);
+}
+const x: u16 = 13;
+const z: @typeOf(x) = 19;
+
+const A = struct {
+    a: u8,
+    b: u32,
+    c: u8,
+    d: u3,
+    e: u5,
+    f: u16,
+    g: u16,
+};
+
+const P = packed struct {
+    a: u8,
+    b: u32,
+    c: u8,
+    d: u3,
+    e: u5,
+    f: u16,
+    g: u16,
+};
+
+test "@byteOffsetOf" {
+    // Packed structs have fixed memory layout
+    assertOrPanic(@byteOffsetOf(P, "a") == 0);
+    assertOrPanic(@byteOffsetOf(P, "b") == 1);
+    assertOrPanic(@byteOffsetOf(P, "c") == 5);
+    assertOrPanic(@byteOffsetOf(P, "d") == 6);
+    assertOrPanic(@byteOffsetOf(P, "e") == 6);
+    assertOrPanic(@byteOffsetOf(P, "f") == 7);
+    assertOrPanic(@byteOffsetOf(P, "g") == 9);
+
+    // Normal struct fields can be moved/padded
+    var a: A = undefined;
+    assertOrPanic(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
+    assertOrPanic(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b"));
+    assertOrPanic(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c"));
+    assertOrPanic(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d"));
+    assertOrPanic(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e"));
+    assertOrPanic(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f"));
+    assertOrPanic(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g"));
+}
+
+test "@bitOffsetOf" {
+    // Packed structs have fixed memory layout
+    assertOrPanic(@bitOffsetOf(P, "a") == 0);
+    assertOrPanic(@bitOffsetOf(P, "b") == 8);
+    assertOrPanic(@bitOffsetOf(P, "c") == 40);
+    assertOrPanic(@bitOffsetOf(P, "d") == 48);
+    assertOrPanic(@bitOffsetOf(P, "e") == 51);
+    assertOrPanic(@bitOffsetOf(P, "f") == 56);
+    assertOrPanic(@bitOffsetOf(P, "g") == 72);
+
+    assertOrPanic(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
+    assertOrPanic(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
+    assertOrPanic(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
+    assertOrPanic(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
+    assertOrPanic(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
+    assertOrPanic(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
+    assertOrPanic(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
+}
test/cases/slice.zig → test/stage1/behavior/slice.zig
@@ -1,20 +1,20 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 const mem = @import("std").mem;
 
 const x = @intToPtr([*]i32, 0x1000)[0..0x500];
 const y = x[0x100..];
 test "compile time slice of pointer to hard coded address" {
-    assert(@ptrToInt(x.ptr) == 0x1000);
-    assert(x.len == 0x500);
+    assertOrPanic(@ptrToInt(x.ptr) == 0x1000);
+    assertOrPanic(x.len == 0x500);
 
-    assert(@ptrToInt(y.ptr) == 0x1100);
-    assert(y.len == 0x400);
+    assertOrPanic(@ptrToInt(y.ptr) == 0x1100);
+    assertOrPanic(y.len == 0x400);
 }
 
 test "slice child property" {
     var array: [5]i32 = undefined;
     var slice = array[0..];
-    assert(@typeOf(slice).Child == i32);
+    assertOrPanic(@typeOf(slice).Child == i32);
 }
 
 test "runtime safety lets us slice from len..len" {
@@ -23,7 +23,7 @@ test "runtime safety lets us slice from len..len" {
         2,
         3,
     };
-    assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
+    assertOrPanic(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
 }
 
 fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
@@ -36,5 +36,5 @@ test "implicitly cast array of size 0 to slice" {
 }
 
 fn assertLenIsZero(msg: []const u8) void {
-    assert(msg.len == 0);
+    assertOrPanic(msg.len == 0);
 }
test/cases/struct.zig → test/stage1/behavior/struct.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const builtin = @import("builtin");
 const maxInt = std.math.maxInt;
 
@@ -12,7 +12,7 @@ const empty_global_instance = StructWithNoFields{};
 
 test "call struct static method" {
     const result = StructWithNoFields.add(3, 4);
-    assert(result == 7);
+    assertOrPanic(result == 7);
 }
 
 test "return empty struct instance" {
@@ -24,8 +24,8 @@ fn returnEmptyStructInstance() StructWithNoFields {
 
 const should_be_11 = StructWithNoFields.add(5, 6);
 
-test "invake static method in global scope" {
-    assert(should_be_11 == 11);
+test "invoke static method in global scope" {
+    assertOrPanic(should_be_11 == 11);
 }
 
 test "void struct fields" {
@@ -34,8 +34,8 @@ test "void struct fields" {
         .b = 1,
         .c = void{},
     };
-    assert(foo.b == 1);
-    assert(@sizeOf(VoidStructFieldsFoo) == 4);
+    assertOrPanic(foo.b == 1);
+    assertOrPanic(@sizeOf(VoidStructFieldsFoo) == 4);
 }
 const VoidStructFieldsFoo = struct {
     a: void,
@@ -50,7 +50,7 @@ test "structs" {
     foo.b = foo.a == 1;
     testFoo(foo);
     testMutation(&foo);
-    assert(foo.c == 100);
+    assertOrPanic(foo.c == 100);
 }
 const StructFoo = struct {
     a: i32,
@@ -58,7 +58,7 @@ const StructFoo = struct {
     c: f32,
 };
 fn testFoo(foo: StructFoo) void {
-    assert(foo.b);
+    assertOrPanic(foo.b);
 }
 fn testMutation(foo: *StructFoo) void {
     foo.c = 100;
@@ -83,7 +83,7 @@ test "struct point to self" {
 
     root.next = &node;
 
-    assert(node.next.next.next.val.x == 1);
+    assertOrPanic(node.next.next.next.val.x == 1);
 }
 
 test "struct byval assign" {
@@ -92,18 +92,18 @@ test "struct byval assign" {
 
     foo1.a = 1234;
     foo2.a = 0;
-    assert(foo2.a == 0);
+    assertOrPanic(foo2.a == 0);
     foo2 = foo1;
-    assert(foo2.a == 1234);
+    assertOrPanic(foo2.a == 1234);
 }
 
 fn structInitializer() void {
     const val = Val{ .x = 42 };
-    assert(val.x == 42);
+    assertOrPanic(val.x == 42);
 }
 
 test "fn call of struct field" {
-    assert(callStructField(Foo{ .ptr = aFunc }) == 13);
+    assertOrPanic(callStructField(Foo{ .ptr = aFunc }) == 13);
 }
 
 const Foo = struct {
@@ -122,7 +122,7 @@ test "store member function in variable" {
     const instance = MemberFnTestFoo{ .x = 1234 };
     const memberFn = MemberFnTestFoo.member;
     const result = memberFn(instance);
-    assert(result == 1234);
+    assertOrPanic(result == 1234);
 }
 const MemberFnTestFoo = struct {
     x: i32,
@@ -134,12 +134,12 @@ const MemberFnTestFoo = struct {
 test "call member function directly" {
     const instance = MemberFnTestFoo{ .x = 1234 };
     const result = MemberFnTestFoo.member(instance);
-    assert(result == 1234);
+    assertOrPanic(result == 1234);
 }
 
 test "member functions" {
     const r = MemberFnRand{ .seed = 1234 };
-    assert(r.getSeed() == 1234);
+    assertOrPanic(r.getSeed() == 1234);
 }
 const MemberFnRand = struct {
     seed: u32,
@@ -150,7 +150,7 @@ const MemberFnRand = struct {
 
 test "return struct byval from function" {
     const bar = makeBar(1234, 5678);
-    assert(bar.y == 5678);
+    assertOrPanic(bar.y == 5678);
 }
 const Bar = struct {
     x: i32,
@@ -165,7 +165,7 @@ fn makeBar(x: i32, y: i32) Bar {
 
 test "empty struct method call" {
     const es = EmptyStruct{};
-    assert(es.method() == 1234);
+    assertOrPanic(es.method() == 1234);
 }
 const EmptyStruct = struct {
     fn method(es: *const EmptyStruct) i32 {
@@ -182,7 +182,7 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 {
 }
 
 test "pass slice of empty struct to fn" {
-    assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1);
+    assertOrPanic(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1);
 }
 fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
     return slice.len;
@@ -200,7 +200,7 @@ test "packed struct" {
     };
     foo.y += 1;
     const four = foo.x + foo.y;
-    assert(four == 4);
+    assertOrPanic(four == 4);
 }
 
 const BitField1 = packed struct {
@@ -217,17 +217,17 @@ const bit_field_1 = BitField1{
 
 test "bit field access" {
     var data = bit_field_1;
-    assert(getA(&data) == 1);
-    assert(getB(&data) == 2);
-    assert(getC(&data) == 3);
-    comptime assert(@sizeOf(BitField1) == 1);
+    assertOrPanic(getA(&data) == 1);
+    assertOrPanic(getB(&data) == 2);
+    assertOrPanic(getC(&data) == 3);
+    comptime assertOrPanic(@sizeOf(BitField1) == 1);
 
     data.b += 1;
-    assert(data.b == 3);
+    assertOrPanic(data.b == 3);
 
     data.a += 1;
-    assert(data.a == 2);
-    assert(data.b == 3);
+    assertOrPanic(data.a == 2);
+    assertOrPanic(data.b == 3);
 }
 
 fn getA(data: *const BitField1) u3 {
@@ -254,8 +254,8 @@ const Foo96Bits = packed struct {
 
 test "packed struct 24bits" {
     comptime {
-        assert(@sizeOf(Foo24Bits) == 3);
-        assert(@sizeOf(Foo96Bits) == 12);
+        assertOrPanic(@sizeOf(Foo24Bits) == 3);
+        assertOrPanic(@sizeOf(Foo96Bits) == 12);
     }
 
     var value = Foo96Bits{
@@ -265,28 +265,28 @@ test "packed struct 24bits" {
         .d = 0,
     };
     value.a += 1;
-    assert(value.a == 1);
-    assert(value.b == 0);
-    assert(value.c == 0);
-    assert(value.d == 0);
+    assertOrPanic(value.a == 1);
+    assertOrPanic(value.b == 0);
+    assertOrPanic(value.c == 0);
+    assertOrPanic(value.d == 0);
 
     value.b += 1;
-    assert(value.a == 1);
-    assert(value.b == 1);
-    assert(value.c == 0);
-    assert(value.d == 0);
+    assertOrPanic(value.a == 1);
+    assertOrPanic(value.b == 1);
+    assertOrPanic(value.c == 0);
+    assertOrPanic(value.d == 0);
 
     value.c += 1;
-    assert(value.a == 1);
-    assert(value.b == 1);
-    assert(value.c == 1);
-    assert(value.d == 0);
+    assertOrPanic(value.a == 1);
+    assertOrPanic(value.b == 1);
+    assertOrPanic(value.c == 1);
+    assertOrPanic(value.d == 0);
 
     value.d += 1;
-    assert(value.a == 1);
-    assert(value.b == 1);
-    assert(value.c == 1);
-    assert(value.d == 1);
+    assertOrPanic(value.a == 1);
+    assertOrPanic(value.b == 1);
+    assertOrPanic(value.c == 1);
+    assertOrPanic(value.d == 1);
 }
 
 const FooArray24Bits = packed struct {
@@ -297,43 +297,43 @@ const FooArray24Bits = packed struct {
 
 test "packed array 24bits" {
     comptime {
-        assert(@sizeOf([9]Foo24Bits) == 9 * 3);
-        assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
+        assertOrPanic(@sizeOf([9]Foo24Bits) == 9 * 3);
+        assertOrPanic(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
     }
 
     var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
     bytes[bytes.len - 1] = 0xaa;
     const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
-    assert(ptr.a == 0);
-    assert(ptr.b[0].field == 0);
-    assert(ptr.b[1].field == 0);
-    assert(ptr.c == 0);
+    assertOrPanic(ptr.a == 0);
+    assertOrPanic(ptr.b[0].field == 0);
+    assertOrPanic(ptr.b[1].field == 0);
+    assertOrPanic(ptr.c == 0);
 
     ptr.a = maxInt(u16);
-    assert(ptr.a == maxInt(u16));
-    assert(ptr.b[0].field == 0);
-    assert(ptr.b[1].field == 0);
-    assert(ptr.c == 0);
+    assertOrPanic(ptr.a == maxInt(u16));
+    assertOrPanic(ptr.b[0].field == 0);
+    assertOrPanic(ptr.b[1].field == 0);
+    assertOrPanic(ptr.c == 0);
 
     ptr.b[0].field = maxInt(u24);
-    assert(ptr.a == maxInt(u16));
-    assert(ptr.b[0].field == maxInt(u24));
-    assert(ptr.b[1].field == 0);
-    assert(ptr.c == 0);
+    assertOrPanic(ptr.a == maxInt(u16));
+    assertOrPanic(ptr.b[0].field == maxInt(u24));
+    assertOrPanic(ptr.b[1].field == 0);
+    assertOrPanic(ptr.c == 0);
 
     ptr.b[1].field = maxInt(u24);
-    assert(ptr.a == maxInt(u16));
-    assert(ptr.b[0].field == maxInt(u24));
-    assert(ptr.b[1].field == maxInt(u24));
-    assert(ptr.c == 0);
+    assertOrPanic(ptr.a == maxInt(u16));
+    assertOrPanic(ptr.b[0].field == maxInt(u24));
+    assertOrPanic(ptr.b[1].field == maxInt(u24));
+    assertOrPanic(ptr.c == 0);
 
     ptr.c = maxInt(u16);
-    assert(ptr.a == maxInt(u16));
-    assert(ptr.b[0].field == maxInt(u24));
-    assert(ptr.b[1].field == maxInt(u24));
-    assert(ptr.c == maxInt(u16));
+    assertOrPanic(ptr.a == maxInt(u16));
+    assertOrPanic(ptr.b[0].field == maxInt(u24));
+    assertOrPanic(ptr.b[1].field == maxInt(u24));
+    assertOrPanic(ptr.c == maxInt(u16));
 
-    assert(bytes[bytes.len - 1] == 0xaa);
+    assertOrPanic(bytes[bytes.len - 1] == 0xaa);
 }
 
 const FooStructAligned = packed struct {
@@ -347,17 +347,17 @@ const FooArrayOfAligned = packed struct {
 
 test "aligned array of packed struct" {
     comptime {
-        assert(@sizeOf(FooStructAligned) == 2);
-        assert(@sizeOf(FooArrayOfAligned) == 2 * 2);
+        assertOrPanic(@sizeOf(FooStructAligned) == 2);
+        assertOrPanic(@sizeOf(FooArrayOfAligned) == 2 * 2);
     }
 
     var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
     const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0];
 
-    assert(ptr.a[0].a == 0xbb);
-    assert(ptr.a[0].b == 0xbb);
-    assert(ptr.a[1].a == 0xbb);
-    assert(ptr.a[1].b == 0xbb);
+    assertOrPanic(ptr.a[0].a == 0xbb);
+    assertOrPanic(ptr.a[0].b == 0xbb);
+    assertOrPanic(ptr.a[1].a == 0xbb);
+    assertOrPanic(ptr.a[1].b == 0xbb);
 }
 
 test "runtime struct initialization of bitfield" {
@@ -370,10 +370,10 @@ test "runtime struct initialization of bitfield" {
         .y = @intCast(u4, x2),
     };
 
-    assert(s1.x == x1);
-    assert(s1.y == x1);
-    assert(s2.x == @intCast(u4, x2));
-    assert(s2.y == @intCast(u4, x2));
+    assertOrPanic(s1.x == x1);
+    assertOrPanic(s1.y == x1);
+    assertOrPanic(s2.x == @intCast(u4, x2));
+    assertOrPanic(s2.y == @intCast(u4, x2));
 }
 
 var x1 = u4(1);
@@ -400,18 +400,18 @@ test "native bit field understands endianness" {
     @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8);
     var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*;
 
-    assert(bitfields.f1 == 0x1111);
-    assert(bitfields.f2 == 0x2222);
-    assert(bitfields.f3 == 0x33);
-    assert(bitfields.f4 == 0x44);
-    assert(bitfields.f5 == 0x5);
-    assert(bitfields.f6 == 0x6);
-    assert(bitfields.f7 == 0x77);
+    assertOrPanic(bitfields.f1 == 0x1111);
+    assertOrPanic(bitfields.f2 == 0x2222);
+    assertOrPanic(bitfields.f3 == 0x33);
+    assertOrPanic(bitfields.f4 == 0x44);
+    assertOrPanic(bitfields.f5 == 0x5);
+    assertOrPanic(bitfields.f6 == 0x6);
+    assertOrPanic(bitfields.f7 == 0x77);
 }
 
 test "align 1 field before self referential align 8 field as slice return type" {
     const result = alloc(Expr);
-    assert(result.len == 0);
+    assertOrPanic(result.len == 0);
 }
 
 const Expr = union(enum) {
@@ -434,10 +434,10 @@ test "call method with mutable reference to struct with no fields" {
     };
 
     var s = S{};
-    assert(S.doC(&s));
-    assert(s.doC());
-    assert(S.do(&s));
-    assert(s.do());
+    assertOrPanic(S.doC(&s));
+    assertOrPanic(s.doC());
+    assertOrPanic(S.do(&s));
+    assertOrPanic(s.do());
 }
 
 test "implicit cast packed struct field to const ptr" {
@@ -453,7 +453,7 @@ test "implicit cast packed struct field to const ptr" {
     var lup: LevelUpMove = undefined;
     lup.level = 12;
     const res = LevelUpMove.toInt(lup.level);
-    assert(res == 12);
+    assertOrPanic(res == 12);
 }
 
 test "pointer to packed struct member in a stack variable" {
@@ -464,7 +464,7 @@ test "pointer to packed struct member in a stack variable" {
 
     var s = S{ .a = 2, .b = 0 };
     var b_ptr = &s.b;
-    assert(s.b == 0);
+    assertOrPanic(s.b == 0);
     b_ptr.* = 2;
-    assert(s.b == 2);
+    assertOrPanic(s.b == 2);
 }
test/cases/struct_contains_null_ptr_itself.zig → test/stage1/behavior/struct_contains_null_ptr_itself.zig
@@ -1,9 +1,9 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 test "struct contains null pointer which contains original struct" {
     var x: ?*NodeLineComment = null;
-    assert(x == null);
+    assertOrPanic(x == null);
 }
 
 pub const Node = struct {
test/cases/struct_contains_slice_of_itself.zig → test/stage1/behavior/struct_contains_slice_of_itself.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 const Node = struct {
     payload: i32,
@@ -39,12 +39,12 @@ test "struct contains slice of itself" {
         .payload = 1234,
         .children = nodes[0..],
     };
-    assert(root.payload == 1234);
-    assert(root.children[0].payload == 1);
-    assert(root.children[1].payload == 2);
-    assert(root.children[2].payload == 3);
-    assert(root.children[2].children[0].payload == 31);
-    assert(root.children[2].children[1].payload == 32);
+    assertOrPanic(root.payload == 1234);
+    assertOrPanic(root.children[0].payload == 1);
+    assertOrPanic(root.children[1].payload == 2);
+    assertOrPanic(root.children[2].payload == 3);
+    assertOrPanic(root.children[2].children[0].payload == 31);
+    assertOrPanic(root.children[2].children[1].payload == 32);
 }
 
 test "struct contains aligned slice of itself" {
@@ -76,10 +76,10 @@ test "struct contains aligned slice of itself" {
         .payload = 1234,
         .children = nodes[0..],
     };
-    assert(root.payload == 1234);
-    assert(root.children[0].payload == 1);
-    assert(root.children[1].payload == 2);
-    assert(root.children[2].payload == 3);
-    assert(root.children[2].children[0].payload == 31);
-    assert(root.children[2].children[1].payload == 32);
+    assertOrPanic(root.payload == 1234);
+    assertOrPanic(root.children[0].payload == 1);
+    assertOrPanic(root.children[1].payload == 2);
+    assertOrPanic(root.children[2].payload == 3);
+    assertOrPanic(root.children[2].children[0].payload == 31);
+    assertOrPanic(root.children[2].children[1].payload == 32);
 }
test/cases/switch.zig → test/stage1/behavior/switch.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "switch with numbers" {
     testSwitchWithNumbers(13);
@@ -10,14 +10,14 @@ fn testSwitchWithNumbers(x: u32) void {
         13 => true,
         else => false,
     };
-    assert(result);
+    assertOrPanic(result);
 }
 
 test "switch with all ranges" {
-    assert(testSwitchWithAllRanges(50, 3) == 1);
-    assert(testSwitchWithAllRanges(101, 0) == 2);
-    assert(testSwitchWithAllRanges(300, 5) == 3);
-    assert(testSwitchWithAllRanges(301, 6) == 6);
+    assertOrPanic(testSwitchWithAllRanges(50, 3) == 1);
+    assertOrPanic(testSwitchWithAllRanges(101, 0) == 2);
+    assertOrPanic(testSwitchWithAllRanges(300, 5) == 3);
+    assertOrPanic(testSwitchWithAllRanges(301, 6) == 6);
 }
 
 fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
@@ -40,7 +40,7 @@ test "implicit comptime switch" {
     };
 
     comptime {
-        assert(result + 1 == 14);
+        assertOrPanic(result + 1 == 14);
     }
 }
 
@@ -71,7 +71,7 @@ fn nonConstSwitch(foo: SwitchStatmentFoo) void {
         SwitchStatmentFoo.C => 3,
         SwitchStatmentFoo.D => 4,
     };
-    assert(val == 3);
+    assertOrPanic(val == 3);
 }
 const SwitchStatmentFoo = enum {
     A,
@@ -93,10 +93,10 @@ const SwitchProngWithVarEnum = union(enum) {
 fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void {
     switch (a) {
         SwitchProngWithVarEnum.One => |x| {
-            assert(x == 13);
+            assertOrPanic(x == 13);
         },
         SwitchProngWithVarEnum.Two => |x| {
-            assert(x == 13.0);
+            assertOrPanic(x == 13.0);
         },
         SwitchProngWithVarEnum.Meh => |x| {
             const v: void = x;
@@ -116,7 +116,7 @@ fn testSwitchEnumPtrCapture() void {
         else => unreachable,
     }
     switch (value) {
-        SwitchProngWithVarEnum.One => |x| assert(x == 1235),
+        SwitchProngWithVarEnum.One => |x| assertOrPanic(x == 1235),
         else => unreachable,
     }
 }
@@ -127,7 +127,7 @@ test "switch with multiple expressions" {
         4, 5, 6 => 2,
         else => i32(3),
     };
-    assert(x == 2);
+    assertOrPanic(x == 2);
 }
 fn returnsFive() i32 {
     return 5;
@@ -149,12 +149,12 @@ fn returnsFalse() bool {
     }
 }
 test "switch on const enum with var" {
-    assert(!returnsFalse());
+    assertOrPanic(!returnsFalse());
 }
 
 test "switch on type" {
-    assert(trueIfBoolFalseOtherwise(bool));
-    assert(!trueIfBoolFalseOtherwise(i32));
+    assertOrPanic(trueIfBoolFalseOtherwise(bool));
+    assertOrPanic(!trueIfBoolFalseOtherwise(i32));
 }
 
 fn trueIfBoolFalseOtherwise(comptime T: type) bool {
@@ -170,16 +170,16 @@ test "switch handles all cases of number" {
 }
 
 fn testSwitchHandleAllCases() void {
-    assert(testSwitchHandleAllCasesExhaustive(0) == 3);
-    assert(testSwitchHandleAllCasesExhaustive(1) == 2);
-    assert(testSwitchHandleAllCasesExhaustive(2) == 1);
-    assert(testSwitchHandleAllCasesExhaustive(3) == 0);
+    assertOrPanic(testSwitchHandleAllCasesExhaustive(0) == 3);
+    assertOrPanic(testSwitchHandleAllCasesExhaustive(1) == 2);
+    assertOrPanic(testSwitchHandleAllCasesExhaustive(2) == 1);
+    assertOrPanic(testSwitchHandleAllCasesExhaustive(3) == 0);
 
-    assert(testSwitchHandleAllCasesRange(100) == 0);
-    assert(testSwitchHandleAllCasesRange(200) == 1);
-    assert(testSwitchHandleAllCasesRange(201) == 2);
-    assert(testSwitchHandleAllCasesRange(202) == 4);
-    assert(testSwitchHandleAllCasesRange(230) == 3);
+    assertOrPanic(testSwitchHandleAllCasesRange(100) == 0);
+    assertOrPanic(testSwitchHandleAllCasesRange(200) == 1);
+    assertOrPanic(testSwitchHandleAllCasesRange(201) == 2);
+    assertOrPanic(testSwitchHandleAllCasesRange(202) == 4);
+    assertOrPanic(testSwitchHandleAllCasesRange(230) == 3);
 }
 
 fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
@@ -207,8 +207,8 @@ test "switch all prongs unreachable" {
 }
 
 fn testAllProngsUnreachable() void {
-    assert(switchWithUnreachable(1) == 2);
-    assert(switchWithUnreachable(2) == 10);
+    assertOrPanic(switchWithUnreachable(1) == 2);
+    assertOrPanic(switchWithUnreachable(2) == 10);
 }
 
 fn switchWithUnreachable(x: i32) i32 {
@@ -230,7 +230,7 @@ test "capture value of switch with all unreachable prongs" {
     const x = return_a_number() catch |err| switch (err) {
         else => unreachable,
     };
-    assert(x == 1);
+    assertOrPanic(x == 1);
 }
 
 test "switching on booleans" {
@@ -239,14 +239,14 @@ test "switching on booleans" {
 }
 
 fn testSwitchOnBools() void {
-    assert(testSwitchOnBoolsTrueAndFalse(true) == false);
-    assert(testSwitchOnBoolsTrueAndFalse(false) == true);
+    assertOrPanic(testSwitchOnBoolsTrueAndFalse(true) == false);
+    assertOrPanic(testSwitchOnBoolsTrueAndFalse(false) == true);
 
-    assert(testSwitchOnBoolsTrueWithElse(true) == false);
-    assert(testSwitchOnBoolsTrueWithElse(false) == true);
+    assertOrPanic(testSwitchOnBoolsTrueWithElse(true) == false);
+    assertOrPanic(testSwitchOnBoolsTrueWithElse(false) == true);
 
-    assert(testSwitchOnBoolsFalseWithElse(true) == false);
-    assert(testSwitchOnBoolsFalseWithElse(false) == true);
+    assertOrPanic(testSwitchOnBoolsFalseWithElse(true) == false);
+    assertOrPanic(testSwitchOnBoolsFalseWithElse(false) == true);
 }
 
 fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
test/cases/switch_prong_err_enum.zig → test/stage1/behavior/switch_prong_err_enum.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 var read_count: u64 = 0;
 
@@ -22,9 +22,9 @@ fn doThing(form_id: u64) anyerror!FormValue {
 test "switch prong returns error enum" {
     switch (doThing(17) catch unreachable) {
         FormValue.Address => |payload| {
-            assert(payload == 1);
+            assertOrPanic(payload == 1);
         },
         else => unreachable,
     }
-    assert(read_count == 1);
+    assertOrPanic(read_count == 1);
 }
test/cases/switch_prong_implicit_cast.zig → test/stage1/behavior/switch_prong_implicit_cast.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 const FormValue = union(enum) {
     One: void,
@@ -18,5 +18,5 @@ test "switch prong implicit cast" {
         FormValue.One => false,
         FormValue.Two => |x| x,
     };
-    assert(result);
+    assertOrPanic(result);
 }
test/cases/syntax.zig → test/stage1/behavior/syntax.zig
@@ -57,3 +57,4 @@ fn asm_lists() void {
             :::"a","b",);
     }
 }
+
test/cases/this.zig → test/stage1/behavior/this.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 const module = @This();
 
@@ -20,7 +20,7 @@ fn add(x: i32, y: i32) i32 {
 }
 
 test "this refer to module call private fn" {
-    assert(module.add(1, 2) == 3);
+    assertOrPanic(module.add(1, 2) == 3);
 }
 
 test "this refer to container" {
@@ -29,6 +29,7 @@ test "this refer to container" {
         .y = 34,
     };
     pt.addOne();
-    assert(pt.x == 13);
-    assert(pt.y == 35);
+    assertOrPanic(pt.x == 13);
+    assertOrPanic(pt.y == 35);
 }
+
test/cases/truncate.zig → test/stage1/behavior/truncate.zig
@@ -1,8 +1,8 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 test "truncate u0 to larger integer allowed and has comptime known result" {
     var x: u0 = 0;
     const y = @truncate(u8, x);
-    comptime assert(y == 0);
+    comptime assertOrPanic(y == 0);
 }
test/cases/try.zig → test/stage1/behavior/try.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "try on error union" {
     tryOnErrorUnionImpl();
@@ -11,7 +11,7 @@ fn tryOnErrorUnionImpl() void {
         error.CrappedOut => i32(2),
         else => unreachable,
     };
-    assert(x == 11);
+    assertOrPanic(x == 11);
 }
 
 fn returnsTen() anyerror!i32 {
@@ -20,10 +20,10 @@ fn returnsTen() anyerror!i32 {
 
 test "try without vars" {
     const result1 = if (failIfTrue(true)) 1 else |_| i32(2);
-    assert(result1 == 2);
+    assertOrPanic(result1 == 2);
 
     const result2 = if (failIfTrue(false)) 1 else |_| i32(2);
-    assert(result2 == 1);
+    assertOrPanic(result2 == 1);
 }
 
 fn failIfTrue(ok: bool) anyerror!void {
@@ -38,6 +38,6 @@ test "try then not executed with assignment" {
     if (failIfTrue(true)) {
         unreachable;
     } else |err| {
-        assert(err == error.ItBroke);
+        assertOrPanic(err == error.ItBroke);
     }
 }
test/stage1/behavior/type_info.zig
@@ -0,0 +1,264 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+const TypeInfo = @import("builtin").TypeInfo;
+const TypeId = @import("builtin").TypeId;
+
+test "type info: tag type, void info" {
+    testBasic();
+    comptime testBasic();
+}
+
+fn testBasic() void {
+    assertOrPanic(@TagType(TypeInfo) == TypeId);
+    const void_info = @typeInfo(void);
+    assertOrPanic(TypeId(void_info) == TypeId.Void);
+    assertOrPanic(void_info.Void == {});
+}
+
+test "type info: integer, floating point type info" {
+    testIntFloat();
+    comptime testIntFloat();
+}
+
+fn testIntFloat() void {
+    const u8_info = @typeInfo(u8);
+    assertOrPanic(TypeId(u8_info) == TypeId.Int);
+    assertOrPanic(!u8_info.Int.is_signed);
+    assertOrPanic(u8_info.Int.bits == 8);
+
+    const f64_info = @typeInfo(f64);
+    assertOrPanic(TypeId(f64_info) == TypeId.Float);
+    assertOrPanic(f64_info.Float.bits == 64);
+}
+
+test "type info: pointer type info" {
+    testPointer();
+    comptime testPointer();
+}
+
+fn testPointer() void {
+    const u32_ptr_info = @typeInfo(*u32);
+    assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer);
+    assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
+    assertOrPanic(u32_ptr_info.Pointer.is_const == false);
+    assertOrPanic(u32_ptr_info.Pointer.is_volatile == false);
+    assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(u32));
+    assertOrPanic(u32_ptr_info.Pointer.child == u32);
+}
+
+test "type info: unknown length pointer type info" {
+    testUnknownLenPtr();
+    comptime testUnknownLenPtr();
+}
+
+fn testUnknownLenPtr() void {
+    const u32_ptr_info = @typeInfo([*]const volatile f64);
+    assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer);
+    assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
+    assertOrPanic(u32_ptr_info.Pointer.is_const == true);
+    assertOrPanic(u32_ptr_info.Pointer.is_volatile == true);
+    assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(f64));
+    assertOrPanic(u32_ptr_info.Pointer.child == f64);
+}
+
+test "type info: slice type info" {
+    testSlice();
+    comptime testSlice();
+}
+
+fn testSlice() void {
+    const u32_slice_info = @typeInfo([]u32);
+    assertOrPanic(TypeId(u32_slice_info) == TypeId.Pointer);
+    assertOrPanic(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
+    assertOrPanic(u32_slice_info.Pointer.is_const == false);
+    assertOrPanic(u32_slice_info.Pointer.is_volatile == false);
+    assertOrPanic(u32_slice_info.Pointer.alignment == 4);
+    assertOrPanic(u32_slice_info.Pointer.child == u32);
+}
+
+test "type info: array type info" {
+    testArray();
+    comptime testArray();
+}
+
+fn testArray() void {
+    const arr_info = @typeInfo([42]bool);
+    assertOrPanic(TypeId(arr_info) == TypeId.Array);
+    assertOrPanic(arr_info.Array.len == 42);
+    assertOrPanic(arr_info.Array.child == bool);
+}
+
+test "type info: optional type info" {
+    testOptional();
+    comptime testOptional();
+}
+
+fn testOptional() void {
+    const null_info = @typeInfo(?void);
+    assertOrPanic(TypeId(null_info) == TypeId.Optional);
+    assertOrPanic(null_info.Optional.child == void);
+}
+
+test "type info: promise info" {
+    testPromise();
+    comptime testPromise();
+}
+
+fn testPromise() void {
+    const null_promise_info = @typeInfo(promise);
+    assertOrPanic(TypeId(null_promise_info) == TypeId.Promise);
+    assertOrPanic(null_promise_info.Promise.child == null);
+
+    const promise_info = @typeInfo(promise->usize);
+    assertOrPanic(TypeId(promise_info) == TypeId.Promise);
+    assertOrPanic(promise_info.Promise.child.? == usize);
+}
+
+test "type info: error set, error union info" {
+    testErrorSet();
+    comptime testErrorSet();
+}
+
+fn testErrorSet() void {
+    const TestErrorSet = error{
+        First,
+        Second,
+        Third,
+    };
+
+    const error_set_info = @typeInfo(TestErrorSet);
+    assertOrPanic(TypeId(error_set_info) == TypeId.ErrorSet);
+    assertOrPanic(error_set_info.ErrorSet.errors.len == 3);
+    assertOrPanic(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
+    assertOrPanic(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
+
+    const error_union_info = @typeInfo(TestErrorSet!usize);
+    assertOrPanic(TypeId(error_union_info) == TypeId.ErrorUnion);
+    assertOrPanic(error_union_info.ErrorUnion.error_set == TestErrorSet);
+    assertOrPanic(error_union_info.ErrorUnion.payload == usize);
+}
+
+test "type info: enum info" {
+    testEnum();
+    comptime testEnum();
+}
+
+fn testEnum() void {
+    const Os = enum {
+        Windows,
+        Macos,
+        Linux,
+        FreeBSD,
+    };
+
+    const os_info = @typeInfo(Os);
+    assertOrPanic(TypeId(os_info) == TypeId.Enum);
+    assertOrPanic(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
+    assertOrPanic(os_info.Enum.fields.len == 4);
+    assertOrPanic(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
+    assertOrPanic(os_info.Enum.fields[3].value == 3);
+    assertOrPanic(os_info.Enum.tag_type == u2);
+    assertOrPanic(os_info.Enum.defs.len == 0);
+}
+
+test "type info: union info" {
+    testUnion();
+    comptime testUnion();
+}
+
+fn testUnion() void {
+    const typeinfo_info = @typeInfo(TypeInfo);
+    assertOrPanic(TypeId(typeinfo_info) == TypeId.Union);
+    assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
+    assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId);
+    assertOrPanic(typeinfo_info.Union.fields.len == 24);
+    assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null);
+    assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
+    assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
+    assertOrPanic(typeinfo_info.Union.defs.len == 20);
+
+    const TestNoTagUnion = union {
+        Foo: void,
+        Bar: u32,
+    };
+
+    const notag_union_info = @typeInfo(TestNoTagUnion);
+    assertOrPanic(TypeId(notag_union_info) == TypeId.Union);
+    assertOrPanic(notag_union_info.Union.tag_type == null);
+    assertOrPanic(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
+    assertOrPanic(notag_union_info.Union.fields.len == 2);
+    assertOrPanic(notag_union_info.Union.fields[0].enum_field == null);
+    assertOrPanic(notag_union_info.Union.fields[1].field_type == u32);
+
+    const TestExternUnion = extern union {
+        foo: *c_void,
+    };
+
+    const extern_union_info = @typeInfo(TestExternUnion);
+    assertOrPanic(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
+    assertOrPanic(extern_union_info.Union.tag_type == null);
+    assertOrPanic(extern_union_info.Union.fields[0].enum_field == null);
+    assertOrPanic(extern_union_info.Union.fields[0].field_type == *c_void);
+}
+
+test "type info: struct info" {
+    testStruct();
+    comptime testStruct();
+}
+
+fn testStruct() void {
+    const struct_info = @typeInfo(TestStruct);
+    assertOrPanic(TypeId(struct_info) == TypeId.Struct);
+    assertOrPanic(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
+    assertOrPanic(struct_info.Struct.fields.len == 3);
+    assertOrPanic(struct_info.Struct.fields[1].offset == null);
+    assertOrPanic(struct_info.Struct.fields[2].field_type == *TestStruct);
+    assertOrPanic(struct_info.Struct.defs.len == 2);
+    assertOrPanic(struct_info.Struct.defs[0].is_pub);
+    assertOrPanic(!struct_info.Struct.defs[0].data.Fn.is_extern);
+    assertOrPanic(struct_info.Struct.defs[0].data.Fn.lib_name == null);
+    assertOrPanic(struct_info.Struct.defs[0].data.Fn.return_type == void);
+    assertOrPanic(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void);
+}
+
+const TestStruct = packed struct {
+    const Self = @This();
+
+    fieldA: usize,
+    fieldB: void,
+    fieldC: *Self,
+
+    pub fn foo(self: *const Self) void {}
+};
+
+test "type info: function type info" {
+    testFunction();
+    comptime testFunction();
+}
+
+fn testFunction() void {
+    const fn_info = @typeInfo(@typeOf(foo));
+    assertOrPanic(TypeId(fn_info) == TypeId.Fn);
+    assertOrPanic(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
+    assertOrPanic(fn_info.Fn.is_generic);
+    assertOrPanic(fn_info.Fn.args.len == 2);
+    assertOrPanic(fn_info.Fn.is_var_args);
+    assertOrPanic(fn_info.Fn.return_type == null);
+    assertOrPanic(fn_info.Fn.async_allocator_type == null);
+
+    const test_instance: TestStruct = undefined;
+    const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
+    assertOrPanic(TypeId(bound_fn_info) == TypeId.BoundFn);
+    assertOrPanic(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
+}
+
+fn foo(comptime a: usize, b: bool, args: ...) usize {
+    return 0;
+}
+
+test "typeInfo with comptime parameter in struct fn def" {
+    const S = struct {
+        pub fn func(comptime x: f32) void {}
+    };
+    comptime var info = @typeInfo(S);
+}
test/cases/undefined.zig → test/stage1/behavior/undefined.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 const mem = @import("std").mem;
 
 fn initStaticArray() [10]i32 {
@@ -11,16 +11,16 @@ fn initStaticArray() [10]i32 {
 }
 const static_array = initStaticArray();
 test "init static array to undefined" {
-    assert(static_array[0] == 1);
-    assert(static_array[4] == 2);
-    assert(static_array[7] == 3);
-    assert(static_array[9] == 4);
+    assertOrPanic(static_array[0] == 1);
+    assertOrPanic(static_array[4] == 2);
+    assertOrPanic(static_array[7] == 3);
+    assertOrPanic(static_array[9] == 4);
 
     comptime {
-        assert(static_array[0] == 1);
-        assert(static_array[4] == 2);
-        assert(static_array[7] == 3);
-        assert(static_array[9] == 4);
+        assertOrPanic(static_array[0] == 1);
+        assertOrPanic(static_array[4] == 2);
+        assertOrPanic(static_array[7] == 3);
+        assertOrPanic(static_array[9] == 4);
     }
 }
 
@@ -40,12 +40,12 @@ test "assign undefined to struct" {
     comptime {
         var foo: Foo = undefined;
         setFooX(&foo);
-        assert(foo.x == 2);
+        assertOrPanic(foo.x == 2);
     }
     {
         var foo: Foo = undefined;
         setFooX(&foo);
-        assert(foo.x == 2);
+        assertOrPanic(foo.x == 2);
     }
 }
 
@@ -53,16 +53,17 @@ test "assign undefined to struct with method" {
     comptime {
         var foo: Foo = undefined;
         foo.setFooXMethod();
-        assert(foo.x == 3);
+        assertOrPanic(foo.x == 3);
     }
     {
         var foo: Foo = undefined;
         foo.setFooXMethod();
-        assert(foo.x == 3);
+        assertOrPanic(foo.x == 3);
     }
 }
 
 test "type name of undefined" {
     const x = undefined;
-    assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
+    assertOrPanic(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
 }
+
test/cases/underscore.zig → test/stage1/behavior/underscore.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 
 test "ignore lval with underscore" {
     _ = false;
test/cases/union.zig → test/stage1/behavior/union.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 const Value = union(enum) {
     Int: u64,
@@ -27,11 +27,11 @@ const array = []Value{
 
 test "unions embedded in aggregate types" {
     switch (array[1]) {
-        Value.Array => |arr| assert(arr[4] == 3),
+        Value.Array => |arr| assertOrPanic(arr[4] == 3),
         else => unreachable,
     }
     switch ((err catch unreachable).val1) {
-        Value.Int => |x| assert(x == 1234),
+        Value.Int => |x| assertOrPanic(x == 1234),
         else => unreachable,
     }
 }
@@ -43,18 +43,18 @@ const Foo = union {
 
 test "basic unions" {
     var foo = Foo{ .int = 1 };
-    assert(foo.int == 1);
+    assertOrPanic(foo.int == 1);
     foo = Foo{ .float = 12.34 };
-    assert(foo.float == 12.34);
+    assertOrPanic(foo.float == 12.34);
 }
 
 test "comptime union field access" {
     comptime {
         var foo = Foo{ .int = 0 };
-        assert(foo.int == 0);
+        assertOrPanic(foo.int == 0);
 
         foo = Foo{ .float = 42.42 };
-        assert(foo.float == 42.42);
+        assertOrPanic(foo.float == 42.42);
     }
 }
 
@@ -62,10 +62,10 @@ test "init union with runtime value" {
     var foo: Foo = undefined;
 
     setFloat(&foo, 12.34);
-    assert(foo.float == 12.34);
+    assertOrPanic(foo.float == 12.34);
 
     setInt(&foo, 42);
-    assert(foo.int == 42);
+    assertOrPanic(foo.int == 42);
 }
 
 fn setFloat(foo: *Foo, x: f64) void {
@@ -83,9 +83,9 @@ const FooExtern = extern union {
 
 test "basic extern unions" {
     var foo = FooExtern{ .int = 1 };
-    assert(foo.int == 1);
+    assertOrPanic(foo.int == 1);
     foo.float = 12.34;
-    assert(foo.float == 12.34);
+    assertOrPanic(foo.float == 12.34);
 }
 
 const Letter = enum {
@@ -105,11 +105,11 @@ test "union with specified enum tag" {
 }
 
 fn doTest() void {
-    assert(bar(Payload{ .A = 1234 }) == -10);
+    assertOrPanic(bar(Payload{ .A = 1234 }) == -10);
 }
 
 fn bar(value: Payload) i32 {
-    assert(Letter(value) == Letter.A);
+    assertOrPanic(Letter(value) == Letter.A);
     return switch (value) {
         Payload.A => |x| return x - 1244,
         Payload.B => |x| if (x == 12.34) i32(20) else 21,
@@ -125,8 +125,8 @@ const MultipleChoice = union(enum(u32)) {
 };
 test "simple union(enum(u32))" {
     var x = MultipleChoice.C;
-    assert(x == MultipleChoice.C);
-    assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
+    assertOrPanic(x == MultipleChoice.C);
+    assertOrPanic(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
 }
 
 const MultipleChoice2 = union(enum(u32)) {
@@ -142,14 +142,14 @@ const MultipleChoice2 = union(enum(u32)) {
 };
 
 test "union(enum(u32)) with specified and unspecified tag values" {
-    comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
+    comptime assertOrPanic(@TagType(@TagType(MultipleChoice2)) == u32);
     testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
     comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
 }
 
 fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
-    assert(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
-    assert(1123 == switch (x) {
+    assertOrPanic(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
+    assertOrPanic(1123 == switch (x) {
         MultipleChoice2.A => 1,
         MultipleChoice2.B => 2,
         MultipleChoice2.C => |v| i32(1000) + v,
@@ -167,7 +167,7 @@ const ExternPtrOrInt = extern union {
     int: u64,
 };
 test "extern union size" {
-    comptime assert(@sizeOf(ExternPtrOrInt) == 8);
+    comptime assertOrPanic(@sizeOf(ExternPtrOrInt) == 8);
 }
 
 const PackedPtrOrInt = packed union {
@@ -175,14 +175,14 @@ const PackedPtrOrInt = packed union {
     int: u64,
 };
 test "extern union size" {
-    comptime assert(@sizeOf(PackedPtrOrInt) == 8);
+    comptime assertOrPanic(@sizeOf(PackedPtrOrInt) == 8);
 }
 
 const ZeroBits = union {
     OnlyField: void,
 };
 test "union with only 1 field which is void should be zero bits" {
-    comptime assert(@sizeOf(ZeroBits) == 0);
+    comptime assertOrPanic(@sizeOf(ZeroBits) == 0);
 }
 
 const TheTag = enum {
@@ -196,9 +196,9 @@ const TheUnion = union(TheTag) {
     C: i32,
 };
 test "union field access gives the enum values" {
-    assert(TheUnion.A == TheTag.A);
-    assert(TheUnion.B == TheTag.B);
-    assert(TheUnion.C == TheTag.C);
+    assertOrPanic(TheUnion.A == TheTag.A);
+    assertOrPanic(TheUnion.B == TheTag.B);
+    assertOrPanic(TheUnion.C == TheTag.C);
 }
 
 test "cast union to tag type of union" {
@@ -207,12 +207,12 @@ test "cast union to tag type of union" {
 }
 
 fn testCastUnionToTagType(x: TheUnion) void {
-    assert(TheTag(x) == TheTag.B);
+    assertOrPanic(TheTag(x) == TheTag.B);
 }
 
 test "cast tag type of union to union" {
     var x: Value2 = Letter2.B;
-    assert(Letter2(x) == Letter2.B);
+    assertOrPanic(Letter2(x) == Letter2.B);
 }
 const Letter2 = enum {
     A,
@@ -227,11 +227,11 @@ const Value2 = union(Letter2) {
 
 test "implicit cast union to its tag type" {
     var x: Value2 = Letter2.B;
-    assert(x == Letter2.B);
+    assertOrPanic(x == Letter2.B);
     giveMeLetterB(x);
 }
 fn giveMeLetterB(x: Letter2) void {
-    assert(x == Value2.B);
+    assertOrPanic(x == Value2.B);
 }
 
 pub const PackThis = union(enum) {
@@ -244,7 +244,7 @@ test "constant packed union" {
 }
 
 fn testConstPackedUnion(expected_tokens: []const PackThis) void {
-    assert(expected_tokens[0].StringLiteral == 1);
+    assertOrPanic(expected_tokens[0].StringLiteral == 1);
 }
 
 test "switch on union with only 1 field" {
@@ -256,7 +256,7 @@ test "switch on union with only 1 field" {
             z = PartialInstWithPayload{ .Compiled = 1234 };
             switch (z) {
                 PartialInstWithPayload.Compiled => |x| {
-                    assert(x == 1234);
+                    assertOrPanic(x == 1234);
                     return;
                 },
             }
@@ -282,11 +282,11 @@ test "access a member of tagged union with conflicting enum tag name" {
         const B = void;
     };
 
-    comptime assert(Bar.A == u8);
+    comptime assertOrPanic(Bar.A == u8);
 }
 
 test "tagged union initialization with runtime void" {
-    assert(testTaggedUnionInit({}));
+    assertOrPanic(testTaggedUnionInit({}));
 }
 
 const TaggedUnionWithAVoid = union(enum) {
@@ -324,9 +324,9 @@ test "union with only 1 field casted to its enum type" {
 
     var e = Expr{ .Literal = Literal{ .Bool = true } };
     const Tag = @TagType(Expr);
-    comptime assert(@TagType(Tag) == comptime_int);
+    comptime assertOrPanic(@TagType(Tag) == comptime_int);
     var t = Tag(e);
-    assert(t == Expr.Literal);
+    assertOrPanic(t == Expr.Literal);
 }
 
 test "union with only 1 field casted to its enum type which has enum value specified" {
@@ -344,9 +344,9 @@ test "union with only 1 field casted to its enum type which has enum value speci
     };
 
     var e = Expr{ .Literal = Literal{ .Bool = true } };
-    comptime assert(@TagType(Tag) == comptime_int);
+    comptime assertOrPanic(@TagType(Tag) == comptime_int);
     var t = Tag(e);
-    assert(t == Expr.Literal);
-    assert(@enumToInt(t) == 33);
-    comptime assert(@enumToInt(t) == 33);
+    assertOrPanic(t == Expr.Literal);
+    assertOrPanic(@enumToInt(t) == 33);
+    comptime assertOrPanic(@enumToInt(t) == 33);
 }
test/cases/var_args.zig → test/stage1/behavior/var_args.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 fn add(args: ...) i32 {
     var sum = i32(0);
@@ -12,9 +12,9 @@ fn add(args: ...) i32 {
 }
 
 test "add arbitrary args" {
-    assert(add(i32(1), i32(2), i32(3), i32(4)) == 10);
-    assert(add(i32(1234)) == 1234);
-    assert(add() == 0);
+    assertOrPanic(add(i32(1), i32(2), i32(3), i32(4)) == 10);
+    assertOrPanic(add(i32(1234)) == 1234);
+    assertOrPanic(add() == 0);
 }
 
 fn readFirstVarArg(args: ...) void {
@@ -26,9 +26,9 @@ test "send void arg to var args" {
 }
 
 test "pass args directly" {
-    assert(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10);
-    assert(addSomeStuff(i32(1234)) == 1234);
-    assert(addSomeStuff() == 0);
+    assertOrPanic(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10);
+    assertOrPanic(addSomeStuff(i32(1234)) == 1234);
+    assertOrPanic(addSomeStuff() == 0);
 }
 
 fn addSomeStuff(args: ...) i32 {
@@ -36,24 +36,24 @@ fn addSomeStuff(args: ...) i32 {
 }
 
 test "runtime parameter before var args" {
-    assert(extraFn(10) == 0);
-    assert(extraFn(10, false) == 1);
-    assert(extraFn(10, false, true) == 2);
+    assertOrPanic(extraFn(10) == 0);
+    assertOrPanic(extraFn(10, false) == 1);
+    assertOrPanic(extraFn(10, false, true) == 2);
 
     // TODO issue #313
     //comptime {
-    //    assert(extraFn(10) == 0);
-    //    assert(extraFn(10, false) == 1);
-    //    assert(extraFn(10, false, true) == 2);
+    //    assertOrPanic(extraFn(10) == 0);
+    //    assertOrPanic(extraFn(10, false) == 1);
+    //    assertOrPanic(extraFn(10, false, true) == 2);
     //}
 }
 
 fn extraFn(extra: u32, args: ...) usize {
     if (args.len >= 1) {
-        assert(args[0] == false);
+        assertOrPanic(args[0] == false);
     }
     if (args.len >= 2) {
-        assert(args[1] == true);
+        assertOrPanic(args[1] == true);
     }
     return args.len;
 }
@@ -71,8 +71,8 @@ fn foo2(args: ...) bool {
 }
 
 test "array of var args functions" {
-    assert(foos[0]());
-    assert(!foos[1]());
+    assertOrPanic(foos[0]());
+    assertOrPanic(!foos[1]());
 }
 
 test "pass zero length array to var args param" {
test/cases/void.zig → test/stage1/behavior/void.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 const Foo = struct {
     a: void,
@@ -13,14 +13,14 @@ test "compare void with void compile time known" {
             .b = 1,
             .c = {},
         };
-        assert(foo.a == {});
+        assertOrPanic(foo.a == {});
     }
 }
 
 test "iterate over a void slice" {
     var j: usize = 0;
     for (times(10)) |_, i| {
-        assert(i == j);
+        assertOrPanic(i == j);
         j += 1;
     }
 }
@@ -28,3 +28,8 @@ test "iterate over a void slice" {
 fn times(n: usize) []const void {
     return ([*]void)(undefined)[0..n];
 }
+
+test "void optional" {
+    var x: ?void = {};
+    assertOrPanic(x != null);
+}
test/cases/while.zig → test/stage1/behavior/while.zig
@@ -1,12 +1,12 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
 
 test "while loop" {
     var i: i32 = 0;
     while (i < 4) {
         i += 1;
     }
-    assert(i == 4);
-    assert(whileLoop1() == 1);
+    assertOrPanic(i == 4);
+    assertOrPanic(whileLoop1() == 1);
 }
 fn whileLoop1() i32 {
     return whileLoop2();
@@ -16,8 +16,9 @@ fn whileLoop2() i32 {
         return 1;
     }
 }
+
 test "static eval while" {
-    assert(static_eval_while_number == 1);
+    assertOrPanic(static_eval_while_number == 1);
 }
 const static_eval_while_number = staticWhileLoop1();
 fn staticWhileLoop1() i32 {
@@ -31,7 +32,7 @@ fn staticWhileLoop2() i32 {
 
 test "continue and break" {
     runContinueAndBreakTest();
-    assert(continue_and_break_counter == 8);
+    assertOrPanic(continue_and_break_counter == 8);
 }
 var continue_and_break_counter: i32 = 0;
 fn runContinueAndBreakTest() void {
@@ -44,7 +45,7 @@ fn runContinueAndBreakTest() void {
         }
         break;
     }
-    assert(i == 4);
+    assertOrPanic(i == 4);
 }
 
 test "return with implicit cast from while loop" {
@@ -65,7 +66,7 @@ test "while with continue expression" {
             sum += i;
         }
     }
-    assert(sum == 40);
+    assertOrPanic(sum == 40);
 }
 
 test "while with else" {
@@ -77,8 +78,8 @@ test "while with else" {
     } else {
         got_else += 1;
     }
-    assert(sum == 10);
-    assert(got_else == 1);
+    assertOrPanic(sum == 10);
+    assertOrPanic(got_else == 1);
 }
 
 test "while with optional as condition" {
@@ -87,7 +88,7 @@ test "while with optional as condition" {
     while (getNumberOrNull()) |value| {
         sum += value;
     }
-    assert(sum == 45);
+    assertOrPanic(sum == 45);
 }
 
 test "while with optional as condition with else" {
@@ -96,12 +97,12 @@ test "while with optional as condition with else" {
     var got_else: i32 = 0;
     while (getNumberOrNull()) |value| {
         sum += value;
-        assert(got_else == 0);
+        assertOrPanic(got_else == 0);
     } else {
         got_else += 1;
     }
-    assert(sum == 45);
-    assert(got_else == 1);
+    assertOrPanic(sum == 45);
+    assertOrPanic(got_else == 1);
 }
 
 test "while with error union condition" {
@@ -111,11 +112,11 @@ test "while with error union condition" {
     while (getNumberOrErr()) |value| {
         sum += value;
     } else |err| {
-        assert(err == error.OutOfNumbers);
+        assertOrPanic(err == error.OutOfNumbers);
         got_else += 1;
     }
-    assert(sum == 45);
-    assert(got_else == 1);
+    assertOrPanic(sum == 45);
+    assertOrPanic(got_else == 1);
 }
 
 var numbers_left: i32 = undefined;
@@ -137,7 +138,7 @@ test "while on optional with else result follow else prong" {
         break value;
     } else
         i32(2);
-    assert(result == 2);
+    assertOrPanic(result == 2);
 }
 
 test "while on optional with else result follow break prong" {
@@ -145,7 +146,7 @@ test "while on optional with else result follow break prong" {
         break value;
     } else
         i32(2);
-    assert(result == 10);
+    assertOrPanic(result == 10);
 }
 
 test "while on error union with else result follow else prong" {
@@ -153,7 +154,7 @@ test "while on error union with else result follow else prong" {
         break value;
     } else |err|
         i32(2);
-    assert(result == 2);
+    assertOrPanic(result == 2);
 }
 
 test "while on error union with else result follow break prong" {
@@ -161,7 +162,7 @@ test "while on error union with else result follow break prong" {
         break value;
     } else |err|
         i32(2);
-    assert(result == 10);
+    assertOrPanic(result == 10);
 }
 
 test "while on bool with else result follow else prong" {
@@ -169,7 +170,7 @@ test "while on bool with else result follow else prong" {
         break i32(10);
     } else
         i32(2);
-    assert(result == 2);
+    assertOrPanic(result == 2);
 }
 
 test "while on bool with else result follow break prong" {
@@ -177,7 +178,7 @@ test "while on bool with else result follow break prong" {
         break i32(10);
     } else
         i32(2);
-    assert(result == 10);
+    assertOrPanic(result == 10);
 }
 
 test "break from outer while loop" {
test/cases/widening.zig → test/stage1/behavior/widening.zig
@@ -1,5 +1,5 @@
 const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
 const mem = std.mem;
 
 test "integer widening" {
@@ -9,13 +9,13 @@ test "integer widening" {
     var d: u64 = c;
     var e: u64 = d;
     var f: u128 = e;
-    assert(f == a);
+    assertOrPanic(f == a);
 }
 
 test "implicit unsigned integer to signed integer" {
     var a: u8 = 250;
     var b: i16 = a;
-    assert(b == 250);
+    assertOrPanic(b == 250);
 }
 
 test "float widening" {
@@ -23,5 +23,6 @@ test "float widening" {
     var b: f32 = a;
     var c: f64 = b;
     var d: f128 = c;
-    assert(d == a);
+    assertOrPanic(d == a);
 }
+
test/stage1/behavior.zig
@@ -0,0 +1,80 @@
+comptime {
+    _ = @import("behavior/align.zig");
+    _ = @import("behavior/alignof.zig");
+    _ = @import("behavior/array.zig");
+    _ = @import("behavior/asm.zig");
+    _ = @import("behavior/atomics.zig");
+    _ = @import("behavior/bit_shifting.zig");
+    _ = @import("behavior/bitcast.zig");
+    _ = @import("behavior/bitreverse.zig");
+    _ = @import("behavior/bool.zig");
+    _ = @import("behavior/bswap.zig");
+    _ = @import("behavior/bugs/1076.zig");
+    _ = @import("behavior/bugs/1111.zig");
+    _ = @import("behavior/bugs/1277.zig");
+    _ = @import("behavior/bugs/1322.zig");
+    _ = @import("behavior/bugs/1381.zig");
+    _ = @import("behavior/bugs/1421.zig");
+    _ = @import("behavior/bugs/1442.zig");
+    _ = @import("behavior/bugs/1486.zig");
+    _ = @import("behavior/bugs/394.zig");
+    _ = @import("behavior/bugs/655.zig");
+    _ = @import("behavior/bugs/656.zig");
+    _ = @import("behavior/bugs/726.zig");
+    _ = @import("behavior/bugs/828.zig");
+    _ = @import("behavior/bugs/920.zig");
+    _ = @import("behavior/byval_arg_var.zig");
+    _ = @import("behavior/cancel.zig");
+    _ = @import("behavior/cast.zig");
+    _ = @import("behavior/const_slice_child.zig");
+    _ = @import("behavior/coroutine_await_struct.zig");
+    _ = @import("behavior/coroutines.zig");
+    _ = @import("behavior/defer.zig");
+    _ = @import("behavior/enum.zig");
+    _ = @import("behavior/enum_with_members.zig");
+    _ = @import("behavior/error.zig");
+    _ = @import("behavior/eval.zig");
+    _ = @import("behavior/field_parent_ptr.zig");
+    _ = @import("behavior/fn.zig");
+    _ = @import("behavior/fn_in_struct_in_comptime.zig");
+    _ = @import("behavior/for.zig");
+    _ = @import("behavior/generics.zig");
+    _ = @import("behavior/if.zig");
+    _ = @import("behavior/import.zig");
+    _ = @import("behavior/incomplete_struct_param_tld.zig");
+    _ = @import("behavior/inttoptr.zig");
+    _ = @import("behavior/ir_block_deps.zig");
+    _ = @import("behavior/math.zig");
+    _ = @import("behavior/merge_error_sets.zig");
+    _ = @import("behavior/misc.zig");
+    _ = @import("behavior/namespace_depends_on_compile_var/index.zig");
+    _ = @import("behavior/new_stack_call.zig");
+    _ = @import("behavior/null.zig");
+    _ = @import("behavior/optional.zig");
+    _ = @import("behavior/pointers.zig");
+    _ = @import("behavior/popcount.zig");
+    _ = @import("behavior/ptrcast.zig");
+    _ = @import("behavior/pub_enum/index.zig");
+    _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
+    _ = @import("behavior/reflection.zig");
+    _ = @import("behavior/sizeof_and_typeof.zig");
+    _ = @import("behavior/slice.zig");
+    _ = @import("behavior/struct.zig");
+    _ = @import("behavior/struct_contains_null_ptr_itself.zig");
+    _ = @import("behavior/struct_contains_slice_of_itself.zig");
+    _ = @import("behavior/switch.zig");
+    _ = @import("behavior/switch_prong_err_enum.zig");
+    _ = @import("behavior/switch_prong_implicit_cast.zig");
+    _ = @import("behavior/syntax.zig");
+    _ = @import("behavior/this.zig");
+    _ = @import("behavior/truncate.zig");
+    _ = @import("behavior/try.zig");
+    _ = @import("behavior/type_info.zig");
+    _ = @import("behavior/undefined.zig");
+    _ = @import("behavior/underscore.zig");
+    _ = @import("behavior/union.zig");
+    _ = @import("behavior/var_args.zig");
+    _ = @import("behavior/void.zig");
+    _ = @import("behavior/while.zig");
+    _ = @import("behavior/widening.zig");
+}
test/behavior.zig
@@ -1,82 +0,0 @@
-const builtin = @import("builtin");
-
-comptime {
-    _ = @import("cases/align.zig");
-    _ = @import("cases/alignof.zig");
-    _ = @import("cases/array.zig");
-    _ = @import("cases/asm.zig");
-    _ = @import("cases/atomics.zig");
-    _ = @import("cases/bitcast.zig");
-    _ = @import("cases/bool.zig");
-    _ = @import("cases/bswap.zig");
-    _ = @import("cases/bitreverse.zig");
-    _ = @import("cases/bugs/1076.zig");
-    _ = @import("cases/bugs/1111.zig");
-    _ = @import("cases/bugs/1277.zig");
-    _ = @import("cases/bugs/1322.zig");
-    _ = @import("cases/bugs/1381.zig");
-    _ = @import("cases/bugs/1421.zig");
-    _ = @import("cases/bugs/1442.zig");
-    _ = @import("cases/bugs/1486.zig");
-    _ = @import("cases/bugs/394.zig");
-    _ = @import("cases/bugs/655.zig");
-    _ = @import("cases/bugs/656.zig");
-    _ = @import("cases/bugs/726.zig");
-    _ = @import("cases/bugs/828.zig");
-    _ = @import("cases/bugs/920.zig");
-    _ = @import("cases/byval_arg_var.zig");
-    _ = @import("cases/cancel.zig");
-    _ = @import("cases/cast.zig");
-    _ = @import("cases/const_slice_child.zig");
-    _ = @import("cases/coroutine_await_struct.zig");
-    _ = @import("cases/coroutines.zig");
-    _ = @import("cases/defer.zig");
-    _ = @import("cases/enum.zig");
-    _ = @import("cases/enum_with_members.zig");
-    _ = @import("cases/error.zig");
-    _ = @import("cases/eval.zig");
-    _ = @import("cases/field_parent_ptr.zig");
-    _ = @import("cases/fn.zig");
-    _ = @import("cases/fn_in_struct_in_comptime.zig");
-    _ = @import("cases/for.zig");
-    _ = @import("cases/generics.zig");
-    _ = @import("cases/if.zig");
-    _ = @import("cases/import.zig");
-    _ = @import("cases/incomplete_struct_param_tld.zig");
-    _ = @import("cases/inttoptr.zig");
-    _ = @import("cases/ir_block_deps.zig");
-    _ = @import("cases/math.zig");
-    _ = @import("cases/merge_error_sets.zig");
-    _ = @import("cases/misc.zig");
-    _ = @import("cases/namespace_depends_on_compile_var/index.zig");
-    _ = @import("cases/new_stack_call.zig");
-    _ = @import("cases/null.zig");
-    _ = @import("cases/optional.zig");
-    _ = @import("cases/pointers.zig");
-    _ = @import("cases/popcount.zig");
-    _ = @import("cases/ptrcast.zig");
-    _ = @import("cases/pub_enum/index.zig");
-    _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
-    _ = @import("cases/reflection.zig");
-    _ = @import("cases/sizeof_and_typeof.zig");
-    _ = @import("cases/slice.zig");
-    _ = @import("cases/struct.zig");
-    _ = @import("cases/struct_contains_null_ptr_itself.zig");
-    _ = @import("cases/struct_contains_slice_of_itself.zig");
-    _ = @import("cases/switch.zig");
-    _ = @import("cases/switch_prong_err_enum.zig");
-    _ = @import("cases/switch_prong_implicit_cast.zig");
-    _ = @import("cases/syntax.zig");
-    _ = @import("cases/this.zig");
-    _ = @import("cases/truncate.zig");
-    _ = @import("cases/try.zig");
-    _ = @import("cases/type_info.zig");
-    _ = @import("cases/undefined.zig");
-    _ = @import("cases/underscore.zig");
-    _ = @import("cases/union.zig");
-    _ = @import("cases/var_args.zig");
-    _ = @import("cases/void.zig");
-    _ = @import("cases/while.zig");
-    _ = @import("cases/widening.zig");
-    _ = @import("cases/bit_shifting.zig");
-}
test/compile_errors.zig
@@ -3220,7 +3220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    return 2;
         \\}
     ,
-        ".tmp_source.zig:2:15: error: unable to infer expression type",
+        ".tmp_source.zig:2:15: error: values of type 'comptime_int' must be comptime known",
     );
 
     cases.add(
@@ -3566,7 +3566,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\
         \\export fn entry() usize { return @sizeOf(@typeOf(a)); }
     ,
-        ".tmp_source.zig:2:11: error: expected type, found 'i32'",
+        ".tmp_source.zig:2:11: error: expected type 'type', found 'i32'",
     );
 
     cases.add(
build.zig
@@ -104,7 +104,7 @@ pub fn build(b: *Builder) !void {
     }
     const modes = chosen_modes[0..chosen_mode_index];
 
-    test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes));
+    test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));
 
     test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes));
 
@@ -299,8 +299,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
     } else if (exe.target.isFreeBSD()) {
         try addCxxKnownPath(b, ctx, exe, "libc++.a", null);
         exe.linkSystemLibrary("pthread");
-    }
-    else if (exe.target.isDarwin()) {
+    } else if (exe.target.isDarwin()) {
         if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
             // Compiler is GCC.
             try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);