Commit be1b231206

Jacob Young <jacobly0@users.noreply.github.com>
2023-05-21 09:57:12
InternPool: add missing logic
1 parent 9584fea
Changed files (3)
src/InternPool.zig
@@ -1517,6 +1517,8 @@ pub const Tag = enum(u8) {
 /// 0. name: NullTerminatedString for each names_len
 pub const ErrorSet = struct {
     names_len: u32,
+    /// Maps error names to declaration index.
+    names_map: MapIndex,
 };
 
 /// Trailing:
@@ -2024,6 +2026,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
             const names = ip.extra.items[error_set.end..][0..names_len];
             return .{ .error_set_type = .{
                 .names = @ptrCast([]const NullTerminatedString, names),
+                .names_map = error_set.data.names_map.toOptional(),
             } };
         },
         .type_inferred_error_set => .{
@@ -2518,6 +2521,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
                 .tag = .type_error_set,
                 .data = ip.addExtraAssumeCapacity(ErrorSet{
                     .names_len = names_len,
+                    .names_map = names_map,
                 }),
             });
             ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, error_set_type.names));
@@ -3605,15 +3609,34 @@ pub fn sliceLen(ip: InternPool, i: Index) Index {
 /// * int <=> int
 /// * int <=> enum
 /// * ptr <=> ptr
+/// * null_value => opt
+/// * payload => opt
 pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
-    if (ip.typeOf(val) == new_ty) return val;
+    const old_ty = ip.typeOf(val);
+    if (old_ty == new_ty) return val;
     switch (ip.indexToKey(val)) {
         .int => |int| switch (ip.indexToKey(new_ty)) {
+            .simple_type => |simple_type| switch (simple_type) {
+                .usize,
+                .isize,
+                .c_char,
+                .c_short,
+                .c_ushort,
+                .c_int,
+                .c_uint,
+                .c_long,
+                .c_ulong,
+                .c_longlong,
+                .c_ulonglong,
+                => return getCoercedInts(ip, gpa, int, new_ty),
+                else => {},
+            },
+            .int_type => return getCoercedInts(ip, gpa, int, new_ty),
             .enum_type => return ip.get(gpa, .{ .enum_tag = .{
                 .ty = new_ty,
                 .int = val,
             } }),
-            else => return getCoercedInts(ip, gpa, int, new_ty),
+            else => {},
         },
         .enum_tag => |enum_tag| {
             // Assume new_ty is an integer type.
@@ -3624,10 +3647,24 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
                 .ty = new_ty,
                 .addr = ptr.addr,
             } }),
-            else => unreachable,
+            else => {},
         },
-        else => unreachable,
+        else => {},
+    }
+    switch (ip.indexToKey(new_ty)) {
+        .opt_type => |child_ty| switch (val) {
+            .null_value => return ip.get(gpa, .{ .opt = .{
+                .ty = new_ty,
+                .val = .none,
+            } }),
+            else => return ip.get(gpa, .{ .opt = .{
+                .ty = new_ty,
+                .val = try ip.getCoerced(gpa, val, child_ty),
+            } }),
+        },
+        else => {},
     }
+    unreachable;
 }
 
 /// Asserts `val` has an integer type.
src/Sema.zig
@@ -8480,13 +8480,10 @@ fn zirOptionalPayload(
     };
 
     if (try sema.resolveDefinedValue(block, src, operand)) |val| {
-        if (val.isNull(mod)) {
-            return sema.fail(block, src, "unable to unwrap null", .{});
-        }
-        if (val.castTag(.opt_payload)) |payload| {
-            return sema.addConstant(result_ty, payload.data);
-        }
-        return sema.addConstant(result_ty, val);
+        return if (val.optionalValue(mod)) |payload|
+            sema.addConstant(result_ty, payload)
+        else
+            sema.fail(block, src, "unable to unwrap null", .{});
     }
 
     try sema.requireRuntimeBlock(block, src, null);
@@ -18929,7 +18926,7 @@ fn zirReify(
                     if (ptr_size == .One or ptr_size == .C) {
                         return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{});
                     }
-                    const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data;
+                    const sentinel_ptr_val = sentinel_val.optionalValue(mod).?;
                     const ptr_ty = try Type.ptr(sema.arena, mod, .{
                         .@"addrspace" = .generic,
                         .pointee_type = elem_ty,
@@ -28807,7 +28804,11 @@ fn coerceCompatiblePtrs(
             return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)});
         }
         // The comptime Value representation is compatible with both types.
-        return sema.addConstant(dest_ty, val);
+        return sema.addConstant(dest_ty, (try mod.intern_pool.getCoerced(
+            mod.gpa,
+            try val.intern(inst_ty, mod),
+            dest_ty.ip_index,
+        )).toValue());
     }
     try sema.requireRuntimeBlock(block, inst_src, null);
     const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod);
src/value.zig
@@ -718,18 +718,25 @@ pub const Value = struct {
                     },
                     else => unreachable,
                 };
-                const enum_type = ip.indexToKey(ty.ip_index).enum_type;
-                if (enum_type.values.len != 0) {
-                    return enum_type.values[field_index].toValue();
-                } else {
-                    // Field index and integer values are the same.
-                    return mod.intValue(enum_type.tag_ty.toType(), field_index);
-                }
+                return switch (ip.indexToKey(ty.ip_index)) {
+                    // Assume it is already an integer and return it directly.
+                    .simple_type, .int_type => val,
+                    .enum_type => |enum_type| if (enum_type.values.len != 0)
+                        enum_type.values[field_index].toValue()
+                    else // Field index and integer values are the same.
+                        mod.intValue(enum_type.tag_ty.toType(), field_index),
+                    else => unreachable,
+                };
             },
-            else => {
-                const enum_type = ip.indexToKey(ip.typeOf(val.ip_index)).enum_type;
-                const int = try ip.getCoerced(mod.gpa, val.ip_index, enum_type.tag_ty);
-                return int.toValue();
+            else => return switch (ip.indexToKey(ip.typeOf(val.ip_index))) {
+                // Assume it is already an integer and return it directly.
+                .simple_type, .int_type => val,
+                .enum_type => |enum_type| (try ip.getCoerced(
+                    mod.gpa,
+                    val.ip_index,
+                    enum_type.tag_ty,
+                )).toValue(),
+                else => unreachable,
             },
         }
     }
@@ -2906,7 +2913,7 @@ pub const Value = struct {
                     inline .u64, .i64 => |x| x == 0,
                 },
                 .opt => |opt| opt.val == .none,
-                else => unreachable,
+                else => false,
             },
         };
     }
@@ -2949,11 +2956,20 @@ pub const Value = struct {
 
     /// Value of the optional, null if optional has no payload.
     pub fn optionalValue(val: Value, mod: *const Module) ?Value {
-        if (val.isNull(mod)) return null;
-
-        // Valid for optional representation to be the direct value
-        // and not use opt_payload.
-        return if (val.castTag(.opt_payload)) |p| p.data else val;
+        return switch (val.ip_index) {
+            .none => if (val.isNull(mod)) null
+            // Valid for optional representation to be the direct value
+            // and not use opt_payload.
+            else if (val.castTag(.opt_payload)) |p| p.data else val,
+            .null_value => null,
+            else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
+                .opt => |opt| switch (opt.val) {
+                    .none => null,
+                    else => opt.val.toValue(),
+                },
+                else => unreachable,
+            },
+        };
     }
 
     /// Valid for all types. Asserts the value is not undefined.