Commit 20bb81166f

mlugg <mlugg@mlugg.co.uk>
2023-10-24 05:36:35
InternPool: remove runtime_value representation
The main goal of this commit is to remove the `runtime_value` field from `InternPool.Key` (and its associated representation), but there are a few dominos. Specifically, this mostly eliminates the "maybe runtime" concept from value resolution in Sema: so some resolution functions like `resolveMaybeUndefValAllowVariablesMaybeRuntime` are gone. This required a small change to struct/union/array initializers, to no longer use `runtime_value` if a field was a `variable` - I'm not convinced this case was even reachable, as `variable` should only ever exist as the trivial value of a global runtime `var` decl. Now, the only case in which a `Sema.resolveMaybeUndefVal`-esque function can return the `variable` key is `resolveMaybeUndefValAllowVariables`, which is directly called from `Sema.resolveInstValueAllowVariables` (previously `Sema.resolveInstValue`), which is only used for resolving the value of a Decl from `Module.semaDecl`. While changing these functions, I also slightly reordered and restructured some of them, and updated their doc comments.
1 parent bb04195
src/arch/wasm/CodeGen.zig
@@ -3224,16 +3224,11 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
 
 /// This function is intended to assert that `isByRef` returns `false` for `ty`.
 /// However such an assertion fails on the behavior tests currently.
-fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
+fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
     const mod = func.bin_file.base.options.module.?;
     // TODO: enable this assertion
     //assert(!isByRef(ty, mod));
     const ip = &mod.intern_pool;
-    var val = arg_val;
-    switch (ip.indexToKey(val.ip_index)) {
-        .runtime_value => |rt| val = rt.val.toValue(),
-        else => {},
-    }
     if (val.isUndefDeep(mod)) return func.emitUndefined(ty);
 
     switch (ip.indexToKey(val.ip_index)) {
@@ -3255,7 +3250,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
         .inferred_error_set_type,
         => unreachable, // types, not values
 
-        .undef, .runtime_value => unreachable, // handled above
+        .undef => unreachable, // handled above
         .simple_value => |simple_value| switch (simple_value) {
             .undefined,
             .void,
src/codegen/c.zig
@@ -772,17 +772,12 @@ pub const DeclGen = struct {
         dg: *DeclGen,
         writer: anytype,
         ty: Type,
-        arg_val: Value,
+        val: Value,
         location: ValueRenderLocation,
     ) error{ OutOfMemory, AnalysisFail }!void {
         const mod = dg.module;
         const ip = &mod.intern_pool;
 
-        var val = arg_val;
-        switch (ip.indexToKey(val.ip_index)) {
-            .runtime_value => |rt| val = rt.val.toValue(),
-            else => {},
-        }
         const target = mod.getTarget();
         const initializer_type: ValueRenderLocation = switch (location) {
             .StaticInitializer => .StaticInitializer,
@@ -1005,7 +1000,7 @@ pub const DeclGen = struct {
             .memoized_call,
             => unreachable,
 
-            .undef, .runtime_value => unreachable, // handled above
+            .undef => unreachable, // handled above
             .simple_value => |simple_value| switch (simple_value) {
                 // non-runtime values
                 .undefined => unreachable,
src/codegen/llvm.zig
@@ -3560,7 +3560,6 @@ pub const Object = struct {
                 .error_set_type, .inferred_error_set_type => try o.errorIntType(),
                 // values, not types
                 .undef,
-                .runtime_value,
                 .simple_value,
                 .variable,
                 .extern_func,
@@ -3672,17 +3671,13 @@ pub const Object = struct {
         const ip = &mod.intern_pool;
         const target = mod.getTarget();
 
-        var val = arg_val.toValue();
-        const arg_val_key = ip.indexToKey(arg_val);
-        switch (arg_val_key) {
-            .runtime_value => |rt| val = rt.val.toValue(),
-            else => {},
-        }
+        const val = arg_val.toValue();
+        const val_key = ip.indexToKey(val.toIntern());
+
         if (val.isUndefDeep(mod)) {
-            return o.builder.undefConst(try o.lowerType(arg_val_key.typeOf().toType()));
+            return o.builder.undefConst(try o.lowerType(val_key.typeOf().toType()));
         }
 
-        const val_key = ip.indexToKey(val.toIntern());
         const ty = val_key.typeOf().toType();
         return switch (val_key) {
             .int_type,
@@ -3703,7 +3698,7 @@ pub const Object = struct {
             .inferred_error_set_type,
             => unreachable, // types, not values
 
-            .undef, .runtime_value => unreachable, // handled above
+            .undef => unreachable, // handled above
             .simple_value => |simple_value| switch (simple_value) {
                 .undefined,
                 .void,
src/codegen/spirv.zig
@@ -644,11 +644,7 @@ const DeclGen = struct {
         const result_ty_ref = try self.resolveType(ty, repr);
         const ip = &mod.intern_pool;
 
-        var val = arg_val;
-        switch (ip.indexToKey(val.toIntern())) {
-            .runtime_value => |rt| val = rt.val.toValue(),
-            else => {},
-        }
+        const val = arg_val;
 
         log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(ty, mod) });
         if (val.isUndefDeep(mod)) {
@@ -674,7 +670,7 @@ const DeclGen = struct {
             .inferred_error_set_type,
             => unreachable, // types, not values
 
-            .undef, .runtime_value => unreachable, // handled above
+            .undef => unreachable, // handled above
 
             .variable,
             .extern_func,
src/codegen.zig
@@ -167,11 +167,7 @@ pub fn generateSymbol(
 
     const mod = bin_file.options.module.?;
     const ip = &mod.intern_pool;
-    var typed_value = arg_tv;
-    switch (ip.indexToKey(typed_value.val.toIntern())) {
-        .runtime_value => |rt| typed_value.val = rt.val.toValue(),
-        else => {},
-    }
+    const typed_value = arg_tv;
 
     const target = mod.getTarget();
     const endian = target.cpu.arch.endian();
@@ -206,7 +202,7 @@ pub fn generateSymbol(
         .inferred_error_set_type,
         => unreachable, // types, not values
 
-        .undef, .runtime_value => unreachable, // handled above
+        .undef => unreachable, // handled above
         .simple_value => |simple_value| switch (simple_value) {
             .undefined,
             .void,
@@ -970,11 +966,7 @@ pub fn genTypedValue(
     owner_decl_index: Module.Decl.Index,
 ) CodeGenError!GenResult {
     const mod = bin_file.options.module.?;
-    var typed_value = arg_tv;
-    switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) {
-        .runtime_value => |rt| typed_value.val = rt.val.toValue(),
-        else => {},
-    }
+    const typed_value = arg_tv;
 
     log.debug("genTypedValue: ty = {}, val = {}", .{
         typed_value.ty.fmt(mod),
src/InternPool.zig
@@ -237,7 +237,6 @@ pub const Key = union(enum) {
     /// Typed `undefined`. This will never be `none`; untyped `undefined` is represented
     /// via `simple_value` and has a named `Index` tag for it.
     undef: Index,
-    runtime_value: TypeValue,
     simple_value: SimpleValue,
     variable: Variable,
     extern_func: ExternFunc,
@@ -1181,8 +1180,6 @@ pub const Key = union(enum) {
                 .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),
             },
 
-            .runtime_value => |x| Hash.hash(seed, asBytes(&x.val)),
-
             inline .opaque_type,
             .enum_type,
             .variable,
@@ -1413,10 +1410,6 @@ pub const Key = union(enum) {
                 const b_info = b.undef;
                 return a_info == b_info;
             },
-            .runtime_value => |a_info| {
-                const b_info = b.runtime_value;
-                return a_info.val == b_info.val;
-            },
             .opt => |a_info| {
                 const b_info = b.opt;
                 return std.meta.eql(a_info, b_info);
@@ -1703,8 +1696,7 @@ pub const Key = union(enum) {
             .func_type,
             => .type_type,
 
-            inline .runtime_value,
-            .ptr,
+            inline .ptr,
             .int,
             .float,
             .opt,
@@ -2138,7 +2130,6 @@ pub const Index = enum(u32) {
         },
 
         undef: DataIsIndex,
-        runtime_value: struct { data: *Tag.TypeValue },
         simple_value: struct { data: SimpleValue },
         ptr_decl: struct { data: *PtrDecl },
         ptr_mut_decl: struct { data: *PtrMutDecl },
@@ -2580,10 +2571,6 @@ pub const Tag = enum(u8) {
     /// `data` is `Index` of the type.
     /// Untyped `undefined` is stored instead via `simple_value`.
     undef,
-    /// A wrapper for values which are comptime-known but should
-    /// semantically be runtime-known.
-    /// data is extra index of `TypeValue`.
-    runtime_value,
     /// A value that can be represented with only an enum tag.
     /// data is SimpleValue enum value.
     simple_value,
@@ -2795,7 +2782,6 @@ pub const Tag = enum(u8) {
             .type_function => TypeFunction,
 
             .undef => unreachable,
-            .runtime_value => TypeValue,
             .simple_value => unreachable,
             .ptr_decl => PtrDecl,
             .ptr_mut_decl => PtrMutDecl,
@@ -3730,7 +3716,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
         .type_function => .{ .func_type = ip.extraFuncType(data) },
 
         .undef => .{ .undef = @as(Index, @enumFromInt(data)) },
-        .runtime_value => .{ .runtime_value = ip.extraData(Tag.TypeValue, data) },
         .opt_null => .{ .opt = .{
             .ty = @as(Index, @enumFromInt(data)),
             .val = .none,
@@ -4556,13 +4541,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
                 .data = @intFromEnum(ty),
             });
         },
-        .runtime_value => |runtime_value| {
-            assert(runtime_value.ty == ip.typeOf(runtime_value.val));
-            ip.items.appendAssumeCapacity(.{
-                .tag = .runtime_value,
-                .data = try ip.addExtra(gpa, runtime_value),
-            });
-        },
 
         .struct_type => unreachable, // use getStructType() instead
         .anon_struct_type => unreachable, // use getAnonStructType() instead
@@ -7237,7 +7215,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
             },
 
             .undef => 0,
-            .runtime_value => @sizeOf(Tag.TypeValue),
             .simple_type => 0,
             .simple_value => 0,
             .ptr_decl => @sizeOf(PtrDecl),
@@ -7370,7 +7347,6 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
             .type_union,
             .type_function,
             .undef,
-            .runtime_value,
             .ptr_decl,
             .ptr_mut_decl,
             .ptr_anon_decl,
@@ -7793,7 +7769,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
             .ptr_slice,
             .opt_payload,
             .error_union_payload,
-            .runtime_value,
             .int_small,
             .int_lazy_align,
             .int_lazy_size,
@@ -7906,10 +7881,6 @@ pub fn isUndef(ip: *const InternPool, val: Index) bool {
     return val == .undef or ip.items.items(.tag)[@intFromEnum(val)] == .undef;
 }
 
-pub fn isRuntimeValue(ip: *const InternPool, val: Index) bool {
-    return ip.items.items(.tag)[@intFromEnum(val)] == .runtime_value;
-}
-
 pub fn isVariable(ip: *const InternPool, val: Index) bool {
     return ip.items.items(.tag)[@intFromEnum(val)] == .variable;
 }
@@ -8116,7 +8087,6 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
 
             // values, not types
             .undef,
-            .runtime_value,
             .simple_value,
             .ptr_decl,
             .ptr_mut_decl,
src/Module.zig
@@ -3757,7 +3757,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
     const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 };
     const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
     const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
-    const decl_tv = try sema.resolveInstValue(&block_scope, init_src, result_ref, .{
+    const decl_tv = try sema.resolveInstValueAllowVariables(&block_scope, init_src, result_ref, .{
         .needed_comptime_reason = "global variable initializer must be comptime-known",
     });
 
src/Sema.zig
@@ -2071,25 +2071,18 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
     try block.instructions.insertSlice(gpa, last_arg_index, err_trace_block.instructions.items);
 }
 
-/// May return Value Tags: `variable`, `undef`.
-/// See `resolveConstValue` for an alternative.
-/// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
-fn resolveValue(
-    sema: *Sema,
-    block: *Block,
-    src: LazySrcLoc,
-    air_ref: Air.Inst.Ref,
-    reason: NeededComptimeReason,
-) CompileError!Value {
-    if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| {
-        if (val.isGenericPoison()) return error.GenericPoison;
-        return val;
-    }
-    return sema.failWithNeededComptime(block, src, reason);
+/// Return the Value corresponding to a given AIR ref, or `null` if it
+/// refers to a runtime value.
+/// InternPool key `variable` is considered a runtime value.
+/// Generic poison causes `error.GenericPoison` to be returned.
+fn resolveMaybeUndefVal(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
+    const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
+    if (val.isGenericPoison()) return error.GenericPoison;
+    if (sema.mod.intern_pool.isVariable(val.toIntern())) return null;
+    return val;
 }
 
-/// Value Tag `variable` will cause a compile error.
-/// Value Tag `undef` may be returned.
+/// Like `resolveMaybeUndefVal`, but emits an error if the value is not comptime-known.
 fn resolveConstMaybeUndefVal(
     sema: *Sema,
     block: *Block,
@@ -2097,17 +2090,12 @@ fn resolveConstMaybeUndefVal(
     inst: Air.Inst.Ref,
     reason: NeededComptimeReason,
 ) CompileError!Value {
-    if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| {
-        if (val.isGenericPoison()) return error.GenericPoison;
-        if (sema.mod.intern_pool.isVariable(val.toIntern()))
-            return sema.failWithNeededComptime(block, src, reason);
-        return val;
-    }
-    return sema.failWithNeededComptime(block, src, reason);
+    return try sema.resolveMaybeUndefVal(inst) orelse {
+        return sema.failWithNeededComptime(block, src, reason);
+    };
 }
 
-/// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
-/// See `resolveValue` for an alternative.
+/// Like `resolveMaybeUndefVal`, but emits an error if the value is not comptime-known or is undefined.
 fn resolveConstValue(
     sema: *Sema,
     block: *Block,
@@ -2115,30 +2103,12 @@ fn resolveConstValue(
     air_ref: Air.Inst.Ref,
     reason: NeededComptimeReason,
 ) CompileError!Value {
-    if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| {
-        if (val.isGenericPoison()) return error.GenericPoison;
-        if (val.isUndef(sema.mod)) return sema.failWithUseOfUndef(block, src);
-        if (sema.mod.intern_pool.isVariable(val.toIntern()))
-            return sema.failWithNeededComptime(block, src, reason);
-        return val;
-    }
-    return sema.failWithNeededComptime(block, src, reason);
-}
-
-/// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
-/// Lazy values are recursively resolved.
-fn resolveConstLazyValue(
-    sema: *Sema,
-    block: *Block,
-    src: LazySrcLoc,
-    air_ref: Air.Inst.Ref,
-    reason: NeededComptimeReason,
-) CompileError!Value {
-    return sema.resolveLazyValue(try sema.resolveConstValue(block, src, air_ref, reason));
+    const val = try sema.resolveConstMaybeUndefVal(block, src, air_ref, reason);
+    if (val.isUndef(sema.mod)) return sema.failWithUseOfUndef(block, src);
+    return val;
 }
 
-/// Value Tag `variable` causes this function to return `null`.
-/// Value Tag `undef` causes this function to return a compile error.
+/// Like `resolveMaybeUndefVal`, but emits an error if the value is comptime-known to be undefined.
 fn resolveDefinedValue(
     sema: *Sema,
     block: *Block,
@@ -2146,44 +2116,24 @@ fn resolveDefinedValue(
     air_ref: Air.Inst.Ref,
 ) CompileError!?Value {
     const mod = sema.mod;
-    if (try sema.resolveMaybeUndefVal(air_ref)) |val| {
-        if (val.isUndef(mod)) {
-            if (block.is_typeof) return null;
-            return sema.failWithUseOfUndef(block, src);
-        }
-        return val;
+    const val = try sema.resolveMaybeUndefVal(air_ref) orelse return null;
+    if (val.isUndef(mod)) {
+        if (block.is_typeof) return null;
+        return sema.failWithUseOfUndef(block, src);
     }
-    return null;
-}
-
-/// Value Tag `variable` causes this function to return `null`.
-/// Value Tag `undef` causes this function to return the Value.
-/// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
-fn resolveMaybeUndefVal(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
-    const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
-    if (val.isGenericPoison()) return error.GenericPoison;
-    if (val.ip_index != .none and sema.mod.intern_pool.isVariable(val.toIntern())) return null;
     return val;
 }
 
-/// Value Tag `variable` causes this function to return `null`.
-/// Value Tag `undef` causes this function to return the Value.
-/// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
-/// Lazy values are recursively resolved.
+/// Like `resolveMaybeUndefVal`, but recursively resolves lazy values.
 fn resolveMaybeUndefLazyVal(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
     return try sema.resolveLazyValue((try sema.resolveMaybeUndefVal(inst)) orelse return null);
 }
 
-/// Value Tag `variable` results in `null`.
-/// Value Tag `undef` results in the Value.
-/// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
-/// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`.
+/// Like `resolveMaybeUndefVal`, but any pointer value which does not correspond
+/// to a comptime-known integer (e.g. a decl pointer) returns `null`.
 /// Lazy values are recursively resolved.
 fn resolveMaybeUndefValIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
-    const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
-    if (val.isGenericPoison()) return error.GenericPoison;
-    if (val.ip_index == .none) return val;
-    if (sema.mod.intern_pool.isVariable(val.toIntern())) return null;
+    const val = (try sema.resolveMaybeUndefVal(inst)) orelse return null;
     if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) {
         .decl, .anon_decl, .mut_decl, .comptime_field => return null,
         .int => {},
@@ -2192,22 +2142,8 @@ fn resolveMaybeUndefValIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Va
     return try sema.resolveLazyValue(val);
 }
 
-/// Returns all Value tags including `variable` and `undef`.
+/// Returns all InternPool keys representing values, including `variable`, `undef`, and `generic_poison`.
 fn resolveMaybeUndefValAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
-    var make_runtime = false;
-    if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(inst, &make_runtime)) |val| {
-        if (make_runtime) return null;
-        return val;
-    }
-    return null;
-}
-
-/// Returns all Value tags including `variable`, `undef` and `runtime_value`.
-fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
-    sema: *Sema,
-    inst: Air.Inst.Ref,
-    make_runtime: *bool,
-) CompileError!?Value {
     assert(inst != .none);
     // First section of indexes correspond to a set number of constant values.
     if (@intFromEnum(inst) < InternPool.static_len) {
@@ -2230,11 +2166,47 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
         }
     };
     const val = ip_index.toValue();
-    if (val.isRuntimeValue(sema.mod)) make_runtime.* = true;
-    if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;
+    if (val.isPtrToThreadLocal(sema.mod)) return null;
     return val;
 }
 
+/// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
+/// a function that does not.
+pub fn resolveInstConst(
+    sema: *Sema,
+    block: *Block,
+    src: LazySrcLoc,
+    zir_ref: Zir.Inst.Ref,
+    reason: NeededComptimeReason,
+) CompileError!TypedValue {
+    const air_ref = try sema.resolveInst(zir_ref);
+    const val = try sema.resolveConstValue(block, src, air_ref, reason);
+    return .{
+        .ty = sema.typeOf(air_ref),
+        .val = val,
+    };
+}
+
+/// Value Tag may be `undef` or `variable`.
+/// See `resolveInstConst` for an alternative.
+pub fn resolveInstValueAllowVariables(
+    sema: *Sema,
+    block: *Block,
+    src: LazySrcLoc,
+    zir_ref: Zir.Inst.Ref,
+    reason: NeededComptimeReason,
+) CompileError!TypedValue {
+    const air_ref = try sema.resolveInst(zir_ref);
+    const val = try sema.resolveMaybeUndefValAllowVariables(air_ref) orelse {
+        return sema.failWithNeededComptime(block, src, reason);
+    };
+    if (val.isGenericPoison()) return error.GenericPoison;
+    return .{
+        .ty = sema.typeOf(air_ref),
+        .val = val,
+    };
+}
+
 fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: NeededComptimeReason) CompileError {
     const msg = msg: {
         const msg = try sema.errMsg(block, src, "unable to resolve comptime value", .{});
@@ -2672,40 +2644,6 @@ fn analyzeAsInt(
     return (try val.getUnsignedIntAdvanced(mod, sema)).?;
 }
 
-// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
-// a function that does not.
-pub fn resolveInstConst(
-    sema: *Sema,
-    block: *Block,
-    src: LazySrcLoc,
-    zir_ref: Zir.Inst.Ref,
-    reason: NeededComptimeReason,
-) CompileError!TypedValue {
-    const air_ref = try sema.resolveInst(zir_ref);
-    const val = try sema.resolveConstValue(block, src, air_ref, reason);
-    return TypedValue{
-        .ty = sema.typeOf(air_ref),
-        .val = val,
-    };
-}
-
-// Value Tag may be `undef` or `variable`.
-// See `resolveInstConst` for an alternative.
-pub fn resolveInstValue(
-    sema: *Sema,
-    block: *Block,
-    src: LazySrcLoc,
-    zir_ref: Zir.Inst.Ref,
-    reason: NeededComptimeReason,
-) CompileError!TypedValue {
-    const air_ref = try sema.resolveInst(zir_ref);
-    const val = try sema.resolveValue(block, src, air_ref, reason);
-    return TypedValue{
-        .ty = sema.typeOf(air_ref),
-        .val = val,
-    };
-}
-
 pub fn getStructType(
     sema: *Sema,
     decl: Module.Decl.Index,
@@ -3681,7 +3619,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
                 else => {
                     const decl_index = ptr_val.pointerDecl(mod) orelse break :implicit_ct;
                     const decl_val = mod.declPtr(decl_index).val.toIntern();
-                    if (mod.intern_pool.isRuntimeValue(decl_val)) break :implicit_ct;
+                    if (mod.intern_pool.isVariable(decl_val)) break :implicit_ct;
                 },
             }
         }
@@ -4637,7 +4575,6 @@ fn validateUnionInit(
     var first_block_index = block.instructions.items.len;
     var block_index = block.instructions.items.len - 1;
     var init_val: ?Value = null;
-    var make_runtime = false;
     while (block_index > 0) : (block_index -= 1) {
         const store_inst = block.instructions.items[block_index];
         if (Air.indexToRef(store_inst) == field_ptr_ref) break;
@@ -4659,7 +4596,7 @@ fn validateUnionInit(
             ).?
         else
             block_index, first_block_index);
-        init_val = try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime);
+        init_val = try sema.resolveMaybeUndefVal(bin_op.rhs);
         break;
     }
 
@@ -4693,15 +4630,11 @@ fn validateUnionInit(
         }
         block.instructions.shrinkRetainingCapacity(block_index);
 
-        var union_val = try mod.intern(.{ .un = .{
+        const union_val = try mod.intern(.{ .un = .{
             .ty = union_ty.toIntern(),
             .tag = tag_val.toIntern(),
             .val = val.toIntern(),
         } });
-        if (make_runtime) union_val = try mod.intern(.{ .runtime_value = .{
-            .ty = union_ty.toIntern(),
-            .val = union_val,
-        } });
         const union_init = Air.internedToRef(union_val);
         try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
         return;
@@ -4830,7 +4763,6 @@ fn validateStructInit(
 
     var struct_is_comptime = true;
     var first_block_index = block.instructions.items.len;
-    var make_runtime = false;
 
     const require_comptime = try sema.typeRequiresComptime(struct_ty);
     const air_tags = sema.air_instructions.items(.tag);
@@ -4898,7 +4830,7 @@ fn validateStructInit(
                     ).?
                 else
                     block_index, first_block_index);
-                if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| {
+                if (try sema.resolveMaybeUndefVal(bin_op.rhs)) |val| {
                     field_values[i] = val.toIntern();
                 } else if (require_comptime) {
                     const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
@@ -4989,14 +4921,10 @@ fn validateStructInit(
         }
         block.instructions.shrinkRetainingCapacity(block_index);
 
-        var struct_val = try mod.intern(.{ .aggregate = .{
+        const struct_val = try mod.intern(.{ .aggregate = .{
             .ty = struct_ty.toIntern(),
             .storage = .{ .elems = field_values },
         } });
-        if (make_runtime) struct_val = try mod.intern(.{ .runtime_value = .{
-            .ty = struct_ty.toIntern(),
-            .val = struct_val,
-        } });
         const struct_init = Air.internedToRef(struct_val);
         try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
         return;
@@ -5095,7 +5023,6 @@ fn zirValidatePtrArrayInit(
 
     var array_is_comptime = true;
     var first_block_index = block.instructions.items.len;
-    var make_runtime = false;
 
     // Collect the comptime element values in case the array literal ends up
     // being comptime-known.
@@ -5159,7 +5086,7 @@ fn zirValidatePtrArrayInit(
                 ).?
             else
                 block_index, first_block_index);
-            if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| {
+            if (try sema.resolveMaybeUndefVal(bin_op.rhs)) |val| {
                 element_vals[i] = val.toIntern();
             } else {
                 array_is_comptime = false;
@@ -5211,14 +5138,10 @@ fn zirValidatePtrArrayInit(
         }
         block.instructions.shrinkRetainingCapacity(block_index);
 
-        var array_val = try mod.intern(.{ .aggregate = .{
+        const array_val = try mod.intern(.{ .aggregate = .{
             .ty = array_ty.toIntern(),
             .storage = .{ .elems = element_vals },
         } });
-        if (make_runtime) array_val = try mod.intern(.{ .runtime_value = .{
-            .ty = array_ty.toIntern(),
-            .val = array_val,
-        } });
         const array_init = Air.internedToRef(array_val);
         try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
     }
@@ -5452,8 +5375,7 @@ fn storeToInferredAllocComptime(
     const operand_ty = sema.typeOf(operand);
     // There will be only one store_to_inferred_ptr because we are running at comptime.
     // The alloc will turn into a Decl.
-    if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: {
-        if (operand_val.getVariable(sema.mod) != null) break :store;
+    if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
         var anon_decl = try block.startAnonDecl(); // TODO: comptime value mutation without Decl
         defer anon_decl.deinit();
         iac.decl_index = try anon_decl.finish(operand_ty, operand_val, iac.alignment);
@@ -12049,7 +11971,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
         // `item` is already guaranteed to be constant known.
 
         const analyze_body = if (union_originally) blk: {
-            const item_val = sema.resolveConstLazyValue(block, .unneeded, item, undefined) catch unreachable;
+            const unresolved_item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
+            const item_val = sema.resolveLazyValue(unresolved_item_val) catch unreachable;
             const field_ty = maybe_union_ty.unionFieldType(item_val, mod).?;
             break :blk field_ty.zigTypeTag(mod) != .NoReturn;
         } else true;
@@ -16671,7 +16594,7 @@ fn zirClosureCapture(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
         .zir_index = inst,
         .index = block.wip_capture_scope,
     };
-    if (try sema.resolveMaybeUndefValAllowVariables(operand)) |val| {
+    if (try sema.resolveMaybeUndefVal(operand)) |val| {
         try mod.comptime_capture_scopes.put(gpa, key, try val.intern(ty, mod));
     } else {
         try mod.runtime_capture_scopes.put(gpa, key, ty.toIntern());
@@ -36644,7 +36567,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
             .simple_type, // handled above
             // values, not types
             .undef,
-            .runtime_value,
             .simple_value,
             .ptr_decl,
             .ptr_anon_decl,
src/type.zig
@@ -414,7 +414,6 @@ pub const Type = struct {
 
             // values, not types
             .undef,
-            .runtime_value,
             .simple_value,
             .variable,
             .extern_func,
@@ -633,7 +632,6 @@ pub const Type = struct {
 
                 // values, not types
                 .undef,
-                .runtime_value,
                 .simple_value,
                 .variable,
                 .extern_func,
@@ -741,7 +739,6 @@ pub const Type = struct {
 
             // values, not types
             .undef,
-            .runtime_value,
             .simple_value,
             .variable,
             .extern_func,
@@ -1103,7 +1100,6 @@ pub const Type = struct {
 
                 // values, not types
                 .undef,
-                .runtime_value,
                 .simple_value,
                 .variable,
                 .extern_func,
@@ -1461,7 +1457,6 @@ pub const Type = struct {
 
                 // values, not types
                 .undef,
-                .runtime_value,
                 .simple_value,
                 .variable,
                 .extern_func,
@@ -1681,7 +1676,6 @@ pub const Type = struct {
 
             // values, not types
             .undef,
-            .runtime_value,
             .simple_value,
             .variable,
             .extern_func,
@@ -2217,7 +2211,6 @@ pub const Type = struct {
 
                 // values, not types
                 .undef,
-                .runtime_value,
                 .simple_value,
                 .variable,
                 .extern_func,
@@ -2560,7 +2553,6 @@ pub const Type = struct {
 
                 // values, not types
                 .undef,
-                .runtime_value,
                 .simple_value,
                 .variable,
                 .extern_func,
@@ -2754,7 +2746,6 @@ pub const Type = struct {
 
                 // values, not types
                 .undef,
-                .runtime_value,
                 .simple_value,
                 .variable,
                 .extern_func,
src/TypedValue.zig
@@ -206,7 +206,6 @@ pub fn print(
             .inferred_error_set_type,
             => return Type.print(val.toType(), writer, mod),
             .undef => return writer.writeAll("undefined"),
-            .runtime_value => return writer.writeAll("(runtime value)"),
             .simple_value => |simple_value| switch (simple_value) {
                 .void => return writer.writeAll("{}"),
                 .empty_struct => return printAggregate(ty, val, writer, level, mod),
src/value.zig
@@ -364,7 +364,6 @@ pub const Value = struct {
             .inferred_error_set_type,
 
             .undef,
-            .runtime_value,
             .simple_value,
             .variable,
             .extern_func,
@@ -464,7 +463,6 @@ pub const Value = struct {
             .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),
             .null_value => BigIntMutable.init(&space.limbs, 0).toConst(),
             else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
-                .runtime_value => |runtime_value| runtime_value.val.toValue().toBigIntAdvanced(space, mod, opt_sema),
                 .int => |int| switch (int.storage) {
                     .u64, .i64, .big_int => int.storage.toBigInt(space),
                     .lazy_align, .lazy_size => |ty| {
@@ -1657,10 +1655,6 @@ pub const Value = struct {
         };
     }
 
-    pub fn isRuntimeValue(val: Value, mod: *Module) bool {
-        return mod.intern_pool.isRuntimeValue(val.toIntern());
-    }
-
     /// Returns true if a Value is backed by a variable
     pub fn isVariable(val: Value, mod: *Module) bool {
         return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) {