diff --git a/src/analysis.zig b/src/analysis.zig index e18b438d8..fbfac8d93 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -469,7 +469,7 @@ pub fn firstParamIs( if (resolved_type.isMetaType()) return false; const deref_type = deref: switch (resolved_type.data) { - .pointer => |info| switch (info.size) { + .pointer => |info| switch (info.flags.size) { .one, .c => info.elem_ty.*, .many, .slice => return false, }, @@ -481,7 +481,7 @@ pub fn firstParamIs( }; const deref_expected_type = switch (expected_type.data) { - .pointer => |info| switch (info.size) { + .pointer => |info| switch (info.flags.size) { .one, .c => info.elem_ty.*, .many, .slice => return false, }, @@ -881,7 +881,7 @@ pub fn resolveOptionalUnwrap(analyser: *Analyser, optional: Type) error{OutOfMem switch (optional.data) { .optional => |child_ty| return try child_ty.instanceUnchecked(analyser), .pointer => |ptr| { - if (ptr.size == .c) return optional; + if (ptr.flags.size == .c) return optional; return null; }, .ip_index => |payload| switch (analyser.ip.indexToKey(payload.type)) { @@ -910,7 +910,7 @@ pub fn resolveOrelseType(analyser: *Analyser, lhs: Type, rhs: Type) error{OutOfM pub fn resolveAddressOf(analyser: *Analyser, is_const: bool, ty: Type) error{OutOfMemory}!Type { const elem_ty = try ty.typeOf(analyser); - const pointer_ty = try Type.createPointerType(analyser, .one, .none, is_const, elem_ty); + const pointer_ty = try Type.createPointerType(analyser, elem_ty, .none, .{ .size = .one, .is_const = is_const }); return try pointer_ty.instanceUnchecked(analyser); } @@ -1000,10 +1000,10 @@ pub fn resolveDerefBinding(analyser: *Analyser, pointer: Type) error{OutOfMemory if (pointer.is_type_val) return null; switch (pointer.data) { - .pointer => |info| switch (info.size) { + .pointer => |info| switch (info.flags.size) { .one, .c => return .{ .type = try info.elem_ty.instanceTypeVal(analyser) orelse return null, - .is_const = info.is_const, + .is_const = info.flags.is_const, }, .many, .slice => return null, }, @@ -1120,10 +1120,9 @@ fn bracketAccessTypeFromIPIndex(analyser: *Analyser, ip_index: InternPool.Index) .pointer_type => |info| .{ .data = .{ .pointer = .{ - .size = info.flags.size, - .sentinel = info.sentinel, - .is_const = info.flags.is_const, .elem_ty = try analyser.allocType(try analyser.bracketAccessTypeFromIPIndex(info.elem_type)), + .sentinel = info.sentinel, + .flags = info.flags, }, }, .is_type_val = true, @@ -1137,7 +1136,7 @@ pub fn resolveBracketAccess(analyser: *Analyser, lhs_binding: Binding, rhs: Brac if (lhs.is_type_val) return null; const is_const = switch (lhs.data) { - .pointer => |info| info.is_const, + .pointer => |info| info.flags.is_const, else => lhs_binding.is_const, }; @@ -1185,7 +1184,7 @@ pub fn resolveBracketAccess(analyser: *Analyser, lhs_binding: Binding, rhs: Brac break :elem info.elem_ty; }, }, - .pointer => |info| switch (info.size) { + .pointer => |info| switch (info.flags.size) { .one => switch (info.elem_ty.data) { .tuple, .array => continue :elem info.elem_ty.data, else => switch (rhs) { @@ -1233,12 +1232,12 @@ pub fn resolveBracketAccess(analyser: *Analyser, lhs_binding: Binding, rhs: Brac switch (result) { .array => |elem_count| { const array_ty = try Type.createArrayType(analyser, elem_count, sentinel, elem_ty.*); - const pointer_ty = try Type.createPointerType(analyser, .one, .none, is_const, array_ty); + const pointer_ty = try Type.createPointerType(analyser, array_ty, .none, .{ .size = .one, .is_const = is_const }); const pointer_instance = try pointer_ty.instanceUnchecked(analyser); return .{ .type = pointer_instance, .is_const = true }; }, .slice => { - const slice_ty = try Type.createPointerType(analyser, .slice, sentinel, is_const, elem_ty.*); + const slice_ty = try Type.createPointerType(analyser, elem_ty.*, sentinel, .{ .size = .slice, .is_const = is_const }); const slice_instance = try slice_ty.instanceUnchecked(analyser); return .{ .type = slice_instance, .is_const = true }; }, @@ -1250,7 +1249,7 @@ pub fn resolvePropertyType(analyser: *Analyser, ty: Type, name: []const u8) erro return null; switch (ty.data) { - .pointer => |info| switch (info.size) { + .pointer => |info| switch (info.flags.size) { .one => { if (std.mem.eql(u8, "*", name)) { return info.elem_ty.instanceTypeVal(analyser); @@ -1263,13 +1262,14 @@ pub fn resolvePropertyType(analyser: *Analyser, ty: Type, name: []const u8) erro } if (std.mem.eql(u8, "ptr", name)) { + var flags = info.flags; + flags.size = .many; return .{ .data = .{ .pointer = .{ - .size = .many, - .sentinel = info.sentinel, - .is_const = info.is_const, .elem_ty = info.elem_ty, + .sentinel = info.sentinel, + .flags = flags, }, }, .is_type_val = false, @@ -2157,13 +2157,33 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error const ptr_info = ast.fullPtrType(tree, node).?; const size = ptr_info.size; const is_const = ptr_info.const_token != null; + const is_volatile = ptr_info.volatile_token != null; + const is_allowzero = ptr_info.allowzero_token != null; const sentinel = try analyser.resolveOptionalIPValue(ptr_info.ast.sentinel, handle); + const address_space: std.lang.AddressSpace = if (ptr_info.ast.addrspace_node.unwrap()) |addrspace_node| blk: { + if (tree.nodeTag(addrspace_node) != .enum_literal) break :blk .generic; + const name = offsets.identifierTokenToNameSlice(&handle.tree, tree.nodeMainToken(addrspace_node)); + break :blk std.meta.stringToEnum(std.lang.AddressSpace, name) orelse .generic; + } else .generic; + + const alignment: u16 = if (ptr_info.ast.align_node.unwrap()) |align_node| + try analyser.resolveIntegerLiteral(u16, .of(align_node, handle)) orelse 0 + else + 0; + const elem_ty = try analyser.resolveTypeOfNodeInternal(.of(ptr_info.ast.child_type, handle)) orelse return null; if (!elem_ty.is_type_val) return null; - return try Type.createPointerType(analyser, size, sentinel, is_const, elem_ty); + return try Type.createPointerType(analyser, elem_ty, sentinel, .{ + .size = size, + .is_const = is_const, + .is_volatile = is_volatile, + .is_allowzero = is_allowzero, + .alignment = alignment, + .address_space = address_space, + }); }, .array_type, .array_type_sentinel, @@ -2964,7 +2984,10 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error r_elem_ty = try r_elem_ty.instanceUnchecked(analyser); var elem_ty = try analyser.resolveArrayCat(l_elem_ty, r_elem_ty) orelse return null; elem_ty = try elem_ty.typeOf(analyser); - const pointer_ty = try Type.createPointerType(analyser, .one, .none, true, elem_ty); + const pointer_ty = try Type.createPointerType(analyser, elem_ty, .none, .{ + .size = .one, + .is_const = true, + }); return try pointer_ty.instanceUnchecked(analyser); } @@ -3165,11 +3188,10 @@ pub const Type = struct { /// - `[]const T` /// - `[*c]T` pointer: struct { - size: std.lang.Type.Pointer.Size, + elem_ty: *Type, /// `.none` means no sentinel, `.unknown_unknown` means unknown sentinel sentinel: InternPool.Index, - is_const: bool, - elem_ty: *Type, + flags: InternPool.Key.Pointer.Flags, }, /// `[elem_count :sentinel]elem_ty` @@ -3272,10 +3294,9 @@ pub const Type = struct { fn createPointer( analyser: *Analyser, - size: std.lang.Type.Pointer.Size, - sentinel: InternPool.Index, - is_const: bool, elem_ty: Type, + sentinel: InternPool.Index, + flags: InternPool.Key.Pointer.Flags, ) !Data { std.debug.assert(elem_ty.is_type_val); blk: { @@ -3284,20 +3305,16 @@ pub const Type = struct { .pointer_type = .{ .elem_type = elem_type, .sentinel = try analyser.coerceIP(elem_type, sentinel) orelse break :blk, - .flags = .{ - .size = size, - .is_const = is_const, - }, + .flags = flags, }, }); return .{ .ip_index = .{ .type = .type_type, .index = index } }; } return .{ .pointer = .{ - .size = size, - .sentinel = sentinel, - .is_const = is_const, .elem_ty = try analyser.allocType(elem_ty), + .sentinel = sentinel, + .flags = flags, }, }; } @@ -3393,9 +3410,8 @@ pub const Type = struct { hasher.update(&.{@backingInt(data)}); switch (data) { .pointer => |info| { - std.hash.autoHash(hasher, info.size); + std.hash.autoHash(hasher, info.flags); std.hash.autoHash(hasher, info.sentinel); - std.hash.autoHash(hasher, info.is_const); info.elem_ty.hashWithHasher(hasher); }, .array => |info| { @@ -3461,7 +3477,7 @@ pub const Type = struct { switch (a) { .pointer => |a_type| { const b_type = b.pointer; - if (a_type.size != b_type.size) return false; + if (a_type.flags != b_type.flags) return false; if (a_type.sentinel != b_type.sentinel) return false; if (!a_type.elem_ty.eql(b_type.elem_ty.*)) return false; }, @@ -3651,11 +3667,8 @@ pub const Type = struct { return t.data.resolveGeneric(analyser, bound_params, visiting); }, .pointer => |info| { - const size = info.size; - const sentinel = info.sentinel; - const is_const = info.is_const; const elem_ty = try analyser.resolveGenericTypeInternal(info.elem_ty.*, bound_params, visiting); - return try createPointer(analyser, size, sentinel, is_const, elem_ty); + return try createPointer(analyser, elem_ty, info.sentinel, info.flags); }, .array => |info| { const elem_count = info.elem_count; @@ -3751,13 +3764,12 @@ pub const Type = struct { fn createPointerType( analyser: *Analyser, - size: std.lang.Type.Pointer.Size, - sentinel: InternPool.Index, - is_const: bool, elem_ty: Type, + sentinel: InternPool.Index, + flags: InternPool.Key.Pointer.Flags, ) !Type { return .{ - .data = try Data.createPointer(analyser, size, sentinel, is_const, elem_ty), + .data = try Data.createPointer(analyser, elem_ty, sentinel, flags), .is_type_val = true, }; } @@ -4393,7 +4405,7 @@ pub const Type = struct { fn pointerSize(self: Type, analyser: *Analyser) ?std.lang.Type.Pointer.Size { if (self.is_type_val) return null; return switch (self.data) { - .pointer => |info| info.size, + .pointer => |info| info.flags.size, .ip_index => |payload| switch (analyser.ip.indexToKey(payload.type)) { .pointer_type => |pointer_info| pointer_info.flags.size, else => null, @@ -4410,7 +4422,7 @@ pub const Type = struct { if (self.is_type_val) return null; return switch (self.data) { .pointer => |info| { - if (info.size != size) return null; + if (info.flags.size != size) return null; return info.elem_ty.*; }, .ip_index => |payload| switch (analyser.ip.indexToKey(payload.type)) { @@ -4574,7 +4586,7 @@ pub const Type = struct { switch (ty.data) { .pointer => |info| { - switch (info.size) { + switch (info.flags.size) { .one => try writer.writeByte('*'), .many => { try writer.writeAll("[*"); @@ -4602,7 +4614,11 @@ pub const Type = struct { }, .c => try writer.writeAll("[*c]"), } - if (info.is_const) try writer.writeAll("const "); + if (info.flags.is_allowzero and info.flags.size != .c) try writer.writeAll("allowzero "); + if (info.flags.alignment != 0) try writer.print("align({d}) ", .{info.flags.alignment}); + if (info.flags.address_space != .generic) try writer.print("addrspace(.{t}) ", .{info.flags.address_space}); + if (info.flags.is_const) try writer.writeAll("const "); + if (info.flags.is_volatile) try writer.writeAll("volatile "); try info.elem_ty.rawStringify(writer, analyser, options); }, .array => |info| { @@ -4875,7 +4891,10 @@ fn resolveLangrefType(analyser: *Analyser, type_str: []const u8) Error!?Type { elem_str = elem_str[6..]; const elem_instance = try analyser.resolveLangrefType(elem_str) orelse return null; const elem_ty = try elem_instance.typeOf(analyser); - const pointer_ty = try Type.createPointerType(analyser, .one, .none, is_const, elem_ty); + const pointer_ty = try Type.createPointerType(analyser, elem_ty, .none, .{ + .size = .one, + .is_const = is_const, + }); return try pointer_ty.instanceUnchecked(analyser); } @@ -4911,7 +4930,10 @@ fn resolveLangrefType(analyser: *Analyser, type_str: []const u8) Error!?Type { elem_str = elem_str[6..]; const elem_instance = try analyser.resolveLangrefType(elem_str) orelse return null; const elem_ty = try elem_instance.typeOf(analyser); - const slice_ty = try Type.createPointerType(analyser, .slice, sentinel, is_const, elem_ty); + const slice_ty = try Type.createPointerType(analyser, elem_ty, sentinel, .{ + .size = .slice, + .is_const = is_const, + }); return try slice_ty.instanceUnchecked(analyser); } @@ -6013,7 +6035,7 @@ pub const DeclWithHandle = struct { if (!self.isCaptureByRef()) return resolved_ty; const elem_ty = try resolved_ty.typeOf(analyser); - const pointer_ty = try Type.createPointerType(analyser, .one, .none, false, elem_ty); + const pointer_ty = try Type.createPointerType(analyser, elem_ty, .none, .{ .size = .one }); return try pointer_ty.instanceUnchecked(analyser); } }; @@ -6796,7 +6818,7 @@ pub fn resolveExpressionTypeFromAncestors( } switch (expr_ty.data) { - .pointer => |info| switch (info.size) { + .pointer => |info| switch (info.flags.size) { .slice => { var buffer: [2]Ast.Node.Index = undefined; const array_init = tree.fullArrayInit(&buffer, node) orelse return null; diff --git a/src/features/completions.zig b/src/features/completions.zig index 673d4cf4f..d140aef65 100644 --- a/src/features/completions.zig +++ b/src/features/completions.zig @@ -108,7 +108,7 @@ fn typeToCompletion(builder: *Builder, ty: Analyser.Type) Analyser.Error!void { try builder.completions.ensureUnusedCapacity(builder.arena, 2); switch (ty.data) { - .pointer => |info| switch (info.size) { + .pointer => |info| switch (info.flags.size) { .one, .c => { if (ty.is_type_val) return; @@ -118,7 +118,7 @@ fn typeToCompletion(builder: *Builder, ty: Analyser.Type) Analyser.Error!void { .detail = try info.elem_ty.stringifyTypeVal(builder.analyser, .{ .truncate_container_decls = false }), }); - if (info.size == .c) { + if (info.flags.size == .c) { builder.completions.appendAssumeCapacity(.{ .label = "?", .kind = .Operator, @@ -142,7 +142,7 @@ fn typeToCompletion(builder: *Builder, ty: Analyser.Type) Analyser.Error!void { var many_ptr_ty = ty; many_ptr_ty.is_type_val = true; - many_ptr_ty.data.pointer.size = .many; + many_ptr_ty.data.pointer.flags.size = .many; builder.completions.appendAssumeCapacity(.{ .label = "ptr", .kind = .Field, diff --git a/tests/analysis/pointer.zig b/tests/analysis/pointer.zig index f795f24d7..64706db11 100644 --- a/tests/analysis/pointer.zig +++ b/tests/analysis/pointer.zig @@ -270,6 +270,18 @@ const ManyPointerWithSentinel = [*:.{}]addrspace(.generic) const bitpack struct // ^ (bitpack struct {})() // ^^^^^^^^ (AddressSpace)() +const VolatilePointer = *volatile u32; +// ^^^^^^^^^^^^^^^ (type)(*volatile u32) + +const AlignConstVolatilePointer = *align(8) const volatile u32; +// ^^^^^^^^^^^^^^^^^^^^^^^^^ (type)(*align(8) const volatile u32) + +const AllowZeroConstPointer = *allowzero const u32; +// ^^^^^^^^^^^^^^^^^^^^^ (type)(*allowzero const u32) + +const AddrspacePointer = *addrspace(.uniform) u32; +// ^^^^^^^^^^^^^^^^ (type)(*addrspace(.uniform) u32) + var runtime_index: usize = 5; var runtime_u8: u8 = 1; var runtime_i8: i8 = -1;