#error: dependency loop detected

1 messages · Page 1 of 1 (latest)

chilly anchor
#
src/widget.zig:114:5: error: dependency loop detected
pub const Widget = statspatch.StatspatchType(Prototype, WidgetData, &zenolith.widget_impls);
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

How does one debug this? I'm mostly looking for just an appraoch to take here. As for what this function does, it's comptime magic beyond comprehension, and explaining it would be way out of the scope of this question.

It seems to boil down to this: Widget ends up being a type that contains a std.ArrayListUnmanaged(*Widget), but this shouldn't be a problem as that's just a pointer.

#

Would be great if I could get the compiler to tell me more here...

chilly anchor
#

Got a minimal reproduction:

const std = @import("std");

fn Union(comptime T: type) type {
    const enum_fields = &[1]std.builtin.Type.EnumField{.{
        .name = "x",
        .value = 0,
    }};

    const Enum = @Type(.{ .Enum = .{
        .tag_type = u1,
        .fields = enum_fields,
        .decls = &.{},
        .is_exhaustive = true,
    } });

    const union_fields = &[1]std.builtin.Type.UnionField{.{
        .name = "x",
        .type = T,
        .alignment = @alignOf(T),
    }};

    return @Type(.{ .Union = .{
        .layout = .Auto,
        .tag_type = Enum,
        .fields = union_fields,
        .decls = &.{},
    } });
}

test {
    _ = struct {
        const A = struct { b: *B };
        const B = Union(A);
    }.B;
}
#

Hmmm, this goes away if I replace the @alignOf(T) with a 0.

chilly anchor
#

The weird thing is, if I replace the implementation of Union with this:

return union(enum) {
    x: T,
};

the compiler is able to correctly infer the alignment of the x field as 8. Why does this work, and the other implementation doesn't?

brisk grail
#

Did this work for you on older compiler versions? (I'm mostly thinking pre-InternPool)

#

It does makes some sense that @alignOf can't handle this, as its result does depend on what it returned by Union.

gleaming socket
#

If you're using default alignment for a field, you can instead set .alignment = 0 when you reify - that makes this example work

#

When an explicit (non-zero) field alignment is given, rather than storing that lazy value for when we actually resolve the alignment later, the value will be immediately resolved (which in this case triggers resolution of our lazy @alignOf, triggering alignment resolution of A, triggering field type resolution of A, triggering analysis of B, hitting the call to Union, triggering a dependency loop). This could be implemented differently in theory, but it's implementational complexity which may not be practically necessary

chilly anchor
#

...so 0 makes the compiler infer it? I wasn't aware that's valid here

(probably because the only way to know that is to have worked on that specific part of the compiler :P)

copper niche
gleaming socket
#

I'm doing some related compiler work as we speak. The work I'll hopefully manage to push by this evening should make an equivalent thing possible again

gleaming socket
#

That work is pushed to #23733; you can get the old .alignment = 0 behavior by not specifying field alignment when reifying (in other words, leaving std.builtin.Type.UnionField.Attributes.@"align" at its default of null)