When exactly does it becomes illegal to have fields after decls?

I was looking at the following code:

const std = @import("std");
const builtin = @import("builtin");
const Pool = @This();
const WaitGroup = @import("WaitGroup.zig");

mutex: std.Thread.Mutex = .{},
cond: std.Thread.Condition = .{},
run_queue: RunQueue = .{},
is_running: bool = true,
allocator: std.mem.Allocator,
threads: []std.Thread,

const RunQueue = std.SinglyLinkedList(Runnable);
const Runnable = struct {
    runFn: RunProto,
};

So we have a bunch of decls, followed by a bunch of fields, then more decls. And that’s legal. In the past though, I’ve run into complaints from compiler about fields coming before or after decls. What exactly are the logics?

1 Like

I’m not certain, but I think the rule is that you can’t have declarations between fields, i.e the fields must be grouped together:

const std = @import("std");

foo: i32,
bar: i32,
baz: Baz,

const Baz = enum { a, b };

qux: []const u8,
$ zig build-exe fields.zig
fields.zig:7:1: error: declarations are not allowed between container fields
const Baz = enum { a, b };
^~~~~
fields.zig:5:1: note: field before declarations here
baz: Baz,
^~~
fields.zig:9:1: note: field after declarations here
qux: []const u8,
^~~
8 Likes

Let’s consult the grammar:

ContainerMembers <- ContainerDeclaration* (ContainerField COMMA)* (ContainerField / ContainerDeclaration*)

So @n0s4 is correct: zero or more decls, followed by zero or more fields, followed by zero or more decls, and if there is a decl after the last field, that last field must have a trailing comma. Decls between fields are not allowed.

6 Likes