zig icon indicating copy to clipboard operation
zig copied to clipboard

Function not visible inside itself through generic struct with usingnamespace

Open LordMZTE opened this issue 2 years ago • 3 comments

I apologize in advance for the title of this issue.

Zig Version

0.12.0-dev.1396+f6de3ec96

Steps to Reproduce and Observed Behavior

  1. Create a file bug.zig:
const B = struct {
    pub fn func() void {
        @compileLog(@typeInfo(C).Struct.decls); // .{ .{ .name = "func" } }
        @compileLog(@hasDecl(C, "func")); // false
        _ = C.func; // ERROR: no member named func
    }
};

fn A(comptime T: type) type {
    return struct {
        pub usingnamespace T;
    };
}

const C = A(B);

pub fn main() !void {
    C.func();
}
  1. zig run bug.zig
bug.zig:5:14: error: struct 'bug.A(bug.B)' has no member named 'func'
        _ = C.func; // ERROR: no member named func
            ~^~~~~
bug.zig:10:12: note: struct declared here
    return struct {
           ^~~~~~
referenced by:
    main: bug.zig:18:6
    callMain: /home/lordmzte/.local/share/zupper/installs/master/lib/std/start.zig:581:32
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

Compile Log Output:
@as([]const builtin.Type.Declaration, .{ .{.name = "func"} })
@as(bool, false)

According to @typeInfo, the declaration func is present within C, but according to @hasDecl, it is not. Schrödinger's declaration!

Expected Behavior

The code compiles.

LordMZTE avatar Nov 05 '23 12:11 LordMZTE

Equivalent to

const B = struct {
    pub fn func() void {
        @compileLog(@typeInfo(C).Struct.decls); // .{ .{ .name = "func" } }
        @compileLog(@hasDecl(C, "func")); // false
        _ = C.func; // ERROR: no member named func
    }
};

const C = struct {
    pub usingnamespace B;
};

pub fn main() !void {
    C.func();
}

Is the circular dependency supposed to be allowed here?

expikr avatar Nov 08 '23 03:11 expikr

Dependency loops only happen when analyzing a declaration depends on the declaration already being analyzed. A function referencing itself does not require it to be analyzed.

export fn foo() void {
    foo();
}

Vexu avatar Nov 08 '23 06:11 Vexu

Also encountered this issue on both 0.12.0 and 0.13.0-dev.46+3648d7df1, maybe a simpler reproduction:

const std = @import("std");

pub const Example = struct {
    usingnamespace struct {}; // works without this line

    pub fn foo() void {
        _ = Example.foo;  // error: struct 'main.Example' has no member named 'foo'
    }
};

pub fn main() !void {
    Example.foo();
}

akarpovskii avatar Apr 28 '24 12:04 akarpovskii