Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 67 additions & 51 deletions src/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand All @@ -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,
},
Expand Down Expand Up @@ -892,7 +892,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)) {
Expand Down Expand Up @@ -921,7 +921,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);
}

Expand Down Expand Up @@ -1011,10 +1011,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,
},
Expand Down Expand Up @@ -1131,10 +1131,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,
Expand All @@ -1148,7 +1147,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,
};

Expand Down Expand Up @@ -1196,7 +1195,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) {
Expand Down Expand Up @@ -1244,12 +1243,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 };
},
Expand All @@ -1261,7 +1260,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);
Expand All @@ -1274,13 +1273,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,
Expand Down Expand Up @@ -2168,13 +2168,27 @@ 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, elem_ty, sentinel, .{
.size = size,
.is_const = is_const,
.is_volatile = is_volatile,
.is_allowzero = is_allowzero,
.alignment = alignment,
.address_space = .generic,
});
},
.array_type,
.array_type_sentinel,
Expand Down Expand Up @@ -2975,7 +2989,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);
}

Expand Down Expand Up @@ -3176,11 +3193,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`
Expand Down Expand Up @@ -3283,10 +3299,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: {
Expand All @@ -3295,20 +3310,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,
},
};
}
Expand Down Expand Up @@ -3404,9 +3415,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| {
Expand Down Expand Up @@ -3472,7 +3482,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;
},
Expand Down Expand Up @@ -3662,11 +3672,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;
Expand Down Expand Up @@ -3762,13 +3769,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,
};
}
Expand Down Expand Up @@ -4394,7 +4400,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,
Expand All @@ -4411,7 +4417,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)) {
Expand Down Expand Up @@ -4573,7 +4579,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("[*");
Expand Down Expand Up @@ -4601,7 +4607,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| {
Expand Down Expand Up @@ -4874,7 +4884,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);
}

Expand Down Expand Up @@ -4910,7 +4923,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);
}

Expand Down Expand Up @@ -6012,7 +6028,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);
}
};
Expand Down Expand Up @@ -6795,7 +6811,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;
Expand Down
6 changes: 3 additions & 3 deletions src/features/completions.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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,
Expand All @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions tests/analysis/pointer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,18 @@ const ManyPointerWithSentinel = [*:.{}]addrspace(.generic) const packed struct {
// ^ (packed 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)(*u32)

var runtime_index: usize = 5;
var runtime_u8: u8 = 1;
var runtime_i8: i8 = -1;
Expand Down
Loading