Commit e77dede87e

Andrew Kelley <andrew@ziglang.org>
2023-05-03 22:38:59
InternPool: implement typePtrOrOptionalPtrTy
1 parent 264292f
Changed files (3)
src/Sema.zig
@@ -1898,10 +1898,14 @@ fn resolveMaybeUndefVal(
     inst: Air.Inst.Ref,
 ) CompileError!?Value {
     const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
-    switch (val.tag()) {
-        .variable => return null,
+    switch (val.ip_index) {
         .generic_poison => return error.GenericPoison,
         else => return val,
+        .none => switch (val.tag()) {
+            .variable => return null,
+            .generic_poison => return error.GenericPoison,
+            else => return val,
+        },
     }
 }
 
@@ -33497,6 +33501,33 @@ fn typePtrOrOptionalPtrTy(
     buf: *Type.Payload.ElemType,
 ) !?Type {
     const mod = sema.mod;
+
+    if (ty.ip_index != .none) switch (mod.intern_pool.indexToKey(ty.ip_index)) {
+        .ptr_type => |ptr_type| switch (ptr_type.size) {
+            .Slice => return null,
+            .C => return ptr_type.elem_type.toType(),
+            .One, .Many => return ty,
+        },
+        .optional_type => |o| switch (mod.intern_pool.indexToKey(o.payload_type)) {
+            .ptr_type => |ptr_type| switch (ptr_type.size) {
+                .Slice, .C => return null,
+                .Many, .One => {
+                    if (ptr_type.is_allowzero) return null;
+
+                    // optionals of zero sized types behave like bools, not pointers
+                    const payload_ty = o.payload_type.toType();
+                    if ((try sema.typeHasOnePossibleValue(payload_ty)) != null) {
+                        return null;
+                    }
+
+                    return payload_ty;
+                },
+            },
+            else => return null,
+        },
+        else => return null,
+    };
+
     switch (ty.tag()) {
         .optional_single_const_pointer,
         .optional_single_mut_pointer,
src/type.zig
@@ -4319,8 +4319,20 @@ pub const Type = struct {
 
     /// Returns true if the type is optional and would be lowered to a single pointer
     /// address value, using 0 for null. Note that this returns true for C pointers.
-    pub fn isPtrLikeOptional(self: Type, mod: *const Module) bool {
-        switch (self.tag()) {
+    /// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`.
+    pub fn isPtrLikeOptional(ty: Type, mod: *const Module) bool {
+        if (ty.ip_index != .none) return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
+            .ptr_type => |ptr_type| ptr_type.size == .C,
+            .optional_type => |o| switch (mod.intern_pool.indexToKey(o.payload_type)) {
+                .ptr_type => |ptr_type| switch (ptr_type.size) {
+                    .Slice, .C => false,
+                    .Many, .One => !ptr_type.is_allowzero,
+                },
+                else => false,
+            },
+            else => false,
+        };
+        switch (ty.tag()) {
             .optional_single_const_pointer,
             .optional_single_mut_pointer,
             .c_const_pointer,
@@ -4328,7 +4340,7 @@ pub const Type = struct {
             => return true,
 
             .optional => {
-                const child_ty = self.castTag(.optional).?.data;
+                const child_ty = ty.castTag(.optional).?.data;
                 if (child_ty.zigTypeTag(mod) != .Pointer) return false;
                 const info = child_ty.ptrInfo().data;
                 switch (info.size) {
@@ -4337,7 +4349,7 @@ pub const Type = struct {
                 }
             },
 
-            .pointer => return self.castTag(.pointer).?.data.size == .C,
+            .pointer => return ty.castTag(.pointer).?.data.size == .C,
 
             else => return false,
         }
src/value.zig
@@ -117,6 +117,8 @@ pub const Value = struct {
         int_big_negative,
         function,
         extern_fn,
+        /// A comptime-known pointer can point to the address of a global
+        /// variable. The child element value in this case will have this tag.
         variable,
         /// A wrapper for values which are comptime-known but should
         /// semantically be runtime-known.