From e2cfbe7afe4ad8655bdec22df47fa21e8ea8bd80 Mon Sep 17 00:00:00 2001 From: barry3406 Date: Sat, 11 Apr 2026 01:48:32 -0700 Subject: [PATCH] preserve allowzero, align, volatile, and addrspace on pointer types The `ptr_type` resolver in analysis.zig only read `const_token` from `ptr_info`, and `Data.createPointer` only set `is_const` on the `InternPool.pointer_type` flags. As a result, types like `*allowzero u8`, `*align(4) u8`, `*volatile u8` were collapsed to `*u8` in inlay hints (and any other surface that runs through `stringifyTypeOf`). Read `volatile_token`, `allowzero_token`, and the integer literal in `ast.align_node` from `ptr_info`, plumb them through `createPointerType` / `Data.createPointer` into the IP flags and the `.pointer` Data fallback, and update `rawStringify` so the fallback path matches the InternPool printer. Address-space resolution from arbitrary expressions still defers to `.generic`; only the literal alignment integer is read for now. Fixes #2603. --- src/analysis.zig | 87 +++++++++++++++++++++++++----- tests/lsp_features/inlay_hints.zig | 27 ++++++++++ 2 files changed, 100 insertions(+), 14 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index 3b47508d6..e489654e3 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -908,7 +908,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, .one, .none, is_const, false, false, 0, .generic, elem_ty); return try pointer_ty.instanceUnchecked(analyser); } @@ -1231,12 +1231,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, .one, .none, is_const, false, false, 0, .generic, array_ty); 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, .slice, sentinel, is_const, false, false, 0, .generic, elem_ty.*); const slice_instance = try slice_ty.instanceUnchecked(analyser); return .{ .type = slice_instance, .is_const = true }; }, @@ -2153,13 +2153,30 @@ 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 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, + size, + sentinel, + is_const, + is_volatile, + is_allowzero, + alignment, + .generic, + elem_ty, + ); }, .array_type, .array_type_sentinel, @@ -2957,7 +2974,7 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error elem_ty = try elem_ty.instanceUnchecked(analyser); elem_ty = try analyser.resolveArrayMult(elem_ty, mult_lit) 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, .one, .none, true, false, false, 0, .generic, elem_ty); return try pointer_ty.instanceUnchecked(analyser); } @@ -2979,7 +2996,7 @@ 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, .one, .none, true, false, false, 0, .generic, elem_ty); return try pointer_ty.instanceUnchecked(analyser); } @@ -3184,6 +3201,11 @@ pub const Type = struct { /// `.none` means no sentinel, `.unknown_unknown` means unknown sentinel sentinel: InternPool.Index, is_const: bool, + is_volatile: bool = false, + is_allowzero: bool = false, + /// `0` means default alignment. + alignment: u16 = 0, + address_space: std.builtin.AddressSpace = .generic, elem_ty: *Type, }, @@ -3290,6 +3312,10 @@ pub const Type = struct { size: std.builtin.Type.Pointer.Size, sentinel: InternPool.Index, is_const: bool, + is_volatile: bool, + is_allowzero: bool, + alignment: u16, + address_space: std.builtin.AddressSpace, elem_ty: Type, ) !Data { std.debug.assert(elem_ty.is_type_val); @@ -3302,6 +3328,10 @@ pub const Type = struct { .flags = .{ .size = size, .is_const = is_const, + .is_volatile = is_volatile, + .is_allowzero = is_allowzero, + .alignment = alignment, + .address_space = address_space, }, }, }); @@ -3312,6 +3342,10 @@ pub const Type = struct { .size = size, .sentinel = sentinel, .is_const = is_const, + .is_volatile = is_volatile, + .is_allowzero = is_allowzero, + .alignment = alignment, + .address_space = address_space, .elem_ty = try analyser.allocType(elem_ty), }, }; @@ -3666,11 +3700,18 @@ 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, + info.size, + info.sentinel, + info.is_const, + info.is_volatile, + info.is_allowzero, + info.alignment, + info.address_space, + elem_ty, + ); }, .array => |info| { const elem_count = info.elem_count; @@ -3769,10 +3810,24 @@ pub const Type = struct { size: std.builtin.Type.Pointer.Size, sentinel: InternPool.Index, is_const: bool, + is_volatile: bool, + is_allowzero: bool, + alignment: u16, + address_space: std.builtin.AddressSpace, elem_ty: Type, ) !Type { return .{ - .data = try Data.createPointer(analyser, size, sentinel, is_const, elem_ty), + .data = try Data.createPointer( + analyser, + size, + sentinel, + is_const, + is_volatile, + is_allowzero, + alignment, + address_space, + elem_ty, + ), .is_type_val = true, }; } @@ -4605,7 +4660,11 @@ pub const Type = struct { }, .c => try writer.writeAll("[*c]"), } + if (info.is_allowzero and info.size != .c) try writer.writeAll("allowzero "); + if (info.alignment != 0) try writer.print("align({d}) ", .{info.alignment}); + if (info.address_space != .generic) try writer.print("addrspace(.{t}) ", .{info.address_space}); if (info.is_const) try writer.writeAll("const "); + if (info.is_volatile) try writer.writeAll("volatile "); try info.elem_ty.rawStringify(writer, analyser, options); }, .array => |info| { @@ -4878,7 +4937,7 @@ 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, .one, .none, is_const, false, false, 0, .generic, elem_ty); return try pointer_ty.instanceUnchecked(analyser); } @@ -4914,7 +4973,7 @@ 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, .slice, sentinel, is_const, false, false, 0, .generic, elem_ty); return try slice_ty.instanceUnchecked(analyser); } @@ -6018,7 +6077,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, .one, .none, false, false, false, 0, .generic, elem_ty); return try pointer_ty.instanceUnchecked(analyser); } }; diff --git a/tests/lsp_features/inlay_hints.zig b/tests/lsp_features/inlay_hints.zig index e2d51dcda..f71e15de5 100644 --- a/tests/lsp_features/inlay_hints.zig +++ b/tests/lsp_features/inlay_hints.zig @@ -286,6 +286,33 @@ test "var decl" { , .{ .kind = .Type }); } +test "var decl - pointer modifiers" { + try testInlayHints( + \\const a: *u8 = undefined; + \\const b<*u8> = a; + , .{ .kind = .Type }); + try testInlayHints( + \\const a: *allowzero u8 = undefined; + \\const b<*allowzero u8> = a; + , .{ .kind = .Type }); + try testInlayHints( + \\const a: *align(4) u8 = undefined; + \\const b<*align(4) u8> = a; + , .{ .kind = .Type }); + try testInlayHints( + \\const a: *volatile u8 = undefined; + \\const b<*volatile u8> = a; + , .{ .kind = .Type }); + try testInlayHints( + \\const a: *allowzero align(8) const volatile u8 = undefined; + \\const b<*allowzero align(8) const volatile u8> = a; + , .{ .kind = .Type }); + try testInlayHints( + \\const a: [*]allowzero u8 = undefined; + \\const b<[*]allowzero u8> = a; + , .{ .kind = .Type }); +} + test "comptime return types" { try testInlayHints( \\fn Box(comptime T: type) type {