From e77dede87e8cff2679485aecf0d3af146595db3a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 May 2023 13:38:59 -0700 Subject: [PATCH] InternPool: implement typePtrOrOptionalPtrTy --- src/Sema.zig | 35 +++++++++++++++++++++++++++++++++-- src/type.zig | 20 ++++++++++++++++---- src/value.zig | 2 ++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index ceaae1fbc8..c39146ca5a 100644 --- a/src/Sema.zig +++ b/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, diff --git a/src/type.zig b/src/type.zig index cafb1beefe..8fd0ea6869 100644 --- a/src/type.zig +++ b/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, } diff --git a/src/value.zig b/src/value.zig index d89be35d85..7f0e6006f0 100644 --- a/src/value.zig +++ b/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.