How to solve error "unable to resolve comptime value"?

Hi, me again, (sorry if I post way too much) This time it’s about an error that I can’t solve, I’ve looked into the documentation on error inference, and comptime, I’ve looked at the std code, but I just can’t find what I’m doing wrong here, so basically when I compile my code I get hit with

main.zig:42:46: error: unable to resolve comptime value
            const list: *Self = try allocator.create(@TypeOf(Self));
                                    ~~~~~~~~~^~~~~~~
main.zig:42:46: note: argument to function being called at comptime must be comptime-known
/Users/plgol/zig/0.12.0-dev.3160+aa7d16aba/files/lib/std/mem/Allocator.zig:103:55: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type
pub fn create(self: Allocator, comptime T: type) Error!*T {
                                                 ~~~~~^~~

But unless I’m missing something very obvious it seems like I’m doing things right (probably not tho I’m just copping) but here is the code :

const std = @import("std");

pub fn ListUnmanaged(comptime T: type) type {
    return struct {
        const Self = @This();
        maybe_head: ?*Node,
        len: usize,

        pub const Node = struct {
            maybe_next: ?*Node,
            data: T,

            pub fn create(allocator: std.mem.Allocator, data: T) !*Node {
                var node: *Node = try allocator.create(@TypeOf(Node));
                node.maybe_next = null;
                node.data = data;
                return (node);
            }

            pub fn destroy(node: *Node, allocator: std.mem.Allocator) void {
                allocator.free(node);
            }

            pub fn insertAfter(node: *Node, next_node: *Node) void {
                next_node.maybe_next = node.maybe_next;
                node.maybe_next = next_node;
            }

            pub fn removeAfter(node: *Node) ?*Node {
                const removed = node.maybe_next orelse return null;
                node.maybe_next = removed.maybe_next;
                removed.maybe_next = null;
                return (removed);
            }

            pub fn next(node: *Node) ?*Node {
                return (node.maybe_next);
            }
        };

        pub fn create(allocator: std.mem.Allocator) !*Self {
            const list: *Self = try allocator.create(@TypeOf(Self));
            list.maybe_head = null;
            list.len = 0;
            return (list);
        }

        pub fn destroy(list: *Self, allocator: std.mem.Allocator) void {
            var temp: *Node = undefined;
            while (list.maybe_head) |node| {
                temp = node;
                list.maybe_head = node.next();
                list.len -= 1;
                temp.destroy(allocator);
            }
            list.destroy(allocator);
        }

        pub fn insertFront(list: *Self, node: *Node) void {
            if (list.maybe_head) |head| {
                node.maybe_next = head;
                list.maybe_head = node;
            } else {
                list.maybe_head = node;
            }
            list.len += 1;
        }

        pub fn print(list: *Self) void {
            while (list.maybe_head) |node| {
                std.debug.print("[{any}]->", .{node.data});
            }
            std.debug.print("\n", .{});
        }
    };
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var list = try ListUnmanaged(usize).create(allocator);
    defer list.destroy(allocator);
}

@TypeOf(Self) is type
You don’t need the @TypeOf, it is already a type.

const list: *Self = try allocator.create(Self);
2 Likes

it’s been an hour and this is just me being desperate I’ve tried so many things like using catch, defining the error explicitly, and yes I’ve tried to use @TypeOf() out of despair but thanks anyway for the suggestion I just can’t get it to compile or give me an error message that I can work with, It’s very obscure right now, and I can’t find answers online or in the doc.

The previous suggestion, remove @TypeOf(.., plus

            pub fn destroy(node: *Node, allocator: std.mem.Allocator) void {
                allocator.destroy(node);
            }
2 Likes

Wait, this was the error ? I mean don’t get me wrong there is a ton of mistake in my implementation because I’m still prototyping and doing weird thing to find how to do things, like the print is wrong too, and a lot is to be desired I’m just exploring, but I want to understand how changing the allocator.free to allocator.destroy, somehow made the original error message disappear ? out of all the solution I was expecting this is the most bizarre one, thanks anyway that’s very nice of you for suggesting the solution,

Allocator.create and Allocator.destroy are for allocating/freeing single items *T.
Allocator.alloc and Allocator.free are for allocating/freeing slices []T.

I don’t think this is related to the original error in the opening post, but it should be one of the compile errors you’re getting.

1 Like

Yes I know about the difference between the two, but I’m unsure as to why this small blunder lead to such a criptic error message. Because I swear once I changed from allocator.free to allocator.destroy, it did compile just fine. That’s why I’m so curious, as to why the allocator.free created such a weird reaction, because as much as I appreciate everyone’s answers and guidance over my posts I’d like to be able to understand such errors to not have to rely so much on Ziggit’s members to solve them.

You are mixing up two passes of errors. Copy-pasting your original code and compiling it the first time, it says:

run.zig:42:46: error: unable to resolve comptime value
            const list: *Self = try allocator.create(@TypeOf(Self));

After changing @TypeOf(Self) to Self and recompiling (with -freference-trace for more info), it now says

C:\zig\lib\std\meta.zig:121:5: error: Expected pointer, slice, array or vector type, found '*run.ListUnmanaged(usize).Node'
    @compileError("Expected pointer, slice, array or vector type, found '" ++ @typeName(T) ++ "'");
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\zig\lib\std\mem.zig:4104:30: note: called from here
    if (@sizeOf(std.meta.Elem(Slice)) == 0) return &[0]u8{};
                ~~~~~~~~~~~~~^~~~~~~
referenced by:
    free__anon_7039: C:\zig\lib\std\mem\Allocator.zig:308:35
    destroy: run.zig:21:31
    destroy: run.zig:54:21

run.zig:21:31 is the first reference that is actually within our own code, specifically this line:

20             pub fn destroy(node: *Node, allocator: std.mem.Allocator) void {
21                 allocator.destroy(node);
22             }

After changing this to allocator.free, the code compiles.

There are still errors in the code, for example another @TypeOf on line 14

13             pub fn create(allocator: std.mem.Allocator, data: T) !*Node {
14                 var node: *Node = try allocator.create(@TypeOf(Node));
15                 node.maybe_next = null;

but because Zig is lazily evaluated and there are no calls to Node.create in the program the compiler won’t analyze this chunk of code.

3 Likes

Thanks for the brilliant explanation and now I see exactly what I’ve missed, I was confused with your error because I didn’t have that in my terminal it turns out that my current color scheme was hiding totally this part of the error message, this is why I was finding that message so unhelpful because there was no clear source or location indication of where the error was coming from.

referenced by:
    free__anon_7039: C:\zig\lib\std\mem\Allocator.zig:308:35
    destroy: run.zig:21:31
    destroy: run.zig:54:21
1 Like