Zig: convoluted usingnamespace bug

Created on 12 Nov 2020  路  6Comments  路  Source: ziglang/zig

Ran into this issue in a bigger project and minified as much as I could to the following 3 files:

lib.zig

const a = @import("./a.zig");
const b = @import("./b.zig");
const ab = struct {
    usingnamespace @import("./a.zig");
    usingnamespace @import("./b.zig");
};
test "" {
    @import("std").testing.refAllDecls(@This());
}

a.zig and b.zig (the same):

usingnamespace struct {
    pub const FOO = 0;
};
$ zig test lib.zig
./lib.zig:5:5: error: import of 'FOO' overrides existing definition
    usingnamespace @import("./b.zig");
    ^
./a.zig:2:9: note: previous definition here
    pub const FOO = 0;
        ^
./b.zig:2:9: note: imported definition here
    pub const FOO = 0;
        ^

So the issue here is that the FOO symbol in both a.zig and b.zig should be private to the file (note: even though it is marked pub, it is only public from the struct, which is private to the file, it would require pub usingnamespace to make it public outside the file). So there should be no conflict in lib.zig where we declare usingnamespace on both modules. In fact, if you replace those files with const FOO = 0; then no conflict occurs, but, this should be equivalent to usingnamespace struct { pub const FOO = 0; };.

Note that the error goes away if you:

  • don't put the FOO definition in separate files (i.e. if you copy/paste the contents of a.zig and b.zig into lib.zig)
  • If you move the const ab definition to appear first in lib.zig, before importing the other files
  • comment out either of the first 2 lines of lib.zig...but these lines should have no affect on the error on line 5.
  • If you just have the usingnamespace's at the top-level of the lib.zig file instead of inside a struct

Most helpful comment

the pub here making it not private

The usingnamespace in a.zig and b.zig is not pub usingnamespace, so they take all the pub symbols in the target and make them non-pub symbols in the outer namespace. No pub symbols are defined in the outer namespace. The expanded form is

const a = struct {
};
const b = struct {
};
const ab = struct {
};

All 6 comments

So the issue here is that the FOO symbol ... should be private

but yet it's defined as pub const FOO = 0;. the pub here making it not private.

expanded, this is what you're trying to compile:

const a = struct {
    pub const FOO = 0;
};
const b = struct {
    pub const FOO = 0;
};
const ab = struct {
    pub const FOO = 0;
    pub const FOO = 0;
};
...

hence the name conflict.

the pub here making it not private

The usingnamespace in a.zig and b.zig is not pub usingnamespace, so they take all the pub symbols in the target and make them non-pub symbols in the outer namespace. No pub symbols are defined in the outer namespace. The expanded form is

const a = struct {
};
const b = struct {
};
const ab = struct {
};

@nektro I had a feeling someone was going to make this mistake, In my post I tried to make it clear this wasn't the case but it looks like I failed. @SpexGuy is correct, you need to have pub usingnamespace to make the symbols you are importing public outside your own scope.

// FOO is not visible outside this file becuse we don't have `pub` on the `usingnamespace`
usingnamespace struct {
    pub const FOO = 0;
};
// This is how you would make FOO public outside this file
pub usingnamespace struct {
    pub const FOO = 0;
};

gotcha, my bad

6445 ?

@LemonBoy yes that looks like the same issue

Was this page helpful?
0 / 5 - 0 ratings