Stream: compiler development

Topic: zig 0.14.0


view this post on Zulip Luke Boswell (Mar 05 2025 at 12:12):

https://ziglang.org/download/0.14.0/release-notes.html

view this post on Zulip Luke Boswell (Mar 05 2025 at 12:16):

Roc gets a mention in the LLVM Builder API https://ziglang.org/download/0.14.0/release-notes.html#LLVM-Builder-API

Big thanks to the Zig team for this :heart_eyes:

view this post on Zulip Brendan Hansknecht (Mar 08 2025 at 08:12):

I started looking at zig 0.14.0. Looks like it should mostly be a minor update. Here is the starter list of minor complaints. I think a number of the issues can be fixed on main before even updating to 0.14.0. For example, all of the naming conflicts:

src/base.zig:40:5: error: duplicate union member name 'Int'
    Int: Int,
    ^~~
src/base.zig:48:15: note: duplicate name here
    pub const Int = union(enum) {
              ^~~
src/base.zig:39:21: note: union declared here
pub const Literal = union(enum) {
                    ^~~~~
src/base.zig:41:5: error: duplicate union member name 'Float'
    Float: Float,
    ^~~~~
src/base.zig:62:15: note: duplicate name here
    pub const Float = union(enum) {
              ^~~~~
src/base.zig:39:21: note: union declared here
pub const Literal = union(enum) {
                    ^~~~~
src/types.zig:10:5: error: duplicate union member name 'Int'
    Int: Int,
    ^~~
src/types.zig:17:15: note: duplicate name here
    pub const Int = enum {
              ^~~
src/types.zig:9:23: note: union declared here
pub const Primitive = union(enum) {
                      ^~~~~
src/types.zig:11:5: error: duplicate union member name 'Float'
    Float: Float,
    ^~~~~
src/types.zig:30:15: note: duplicate name here
    pub const Float = enum {
              ^~~~~
src/types.zig:9:23: note: union declared here
pub const Primitive = union(enum) {
                      ^~~~~
src/check/parse/IR.zig:1506:28: error: expected type 'check.parse.IR.NodeStore.TypeAnnoIdx', found 'check.parse.IR.NodeStore.getTypeAnno__struct_27714'
                    .ret = ret,
                           ^~~
src/check/parse/IR.zig:1503:30: note: struct declared here
                const ret = .{ .id = store.extra_data.items[@as(usize, @intCast(node.main_token))] };
                            ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/check/parse/IR.zig:536:29: note: struct declared here
    pub const TypeAnnoIdx = struct { id: u32 };
                            ^~~~~~~~~~~~~~~~~~
src/check/parse/Parser.zig:869:47: error: expected type 'check.parse.IR.NodeStore.Body', found 'check.parse.Parser.parseExprWithBp__struct_29141'
                expr = self.store.addExpr(.{ .block = body });
                                             ~^~~~~~~~~~~~
src/check/parse/Parser.zig:865:31: note: struct declared here
                const body = .{
                             ~^
src/check/parse/IR.zig:1557:22: note: struct declared here
    pub const Body = struct {
                     ^~~~~~
src/check/parse/tokenize.zig:810:17: error: switch on type '?check.parse.tokenize.BraceKind'
        switch (last) {
                ^~~~
src/snapshot.zig:9:16: error: root source file struct 'std' has no member named 'rand'
var prng = std.rand.DefaultPrng.init(1234567890);
               ^~~~
/Users/bren077s/vendor/zig-0.14.0/lib/std/std.zig:1:1: note: struct declared here
pub const ArrayHashMap = array_hash_map.ArrayHashMap;

view this post on Zulip Brendan Hansknecht (Mar 08 2025 at 08:13):

Also, all deps except for zig-bootstrap (for building the new version of musl llvm) are updated. So I think we technically could update now given nothing actually depends on llvm yet.

view this post on Zulip Brendan Hansknecht (Mar 08 2025 at 08:13):

zig-afl-kit 0.14.0: https://github.com/kristoff-it/zig-afl-kit/tree/zig-0.14.0

view this post on Zulip Brendan Hansknecht (Mar 08 2025 at 08:17):

Started a draft PR, but am headed to sleep now. Anyone feel free to push fixes to: https://github.com/roc-lang/roc/pull/7679

view this post on Zulip Brendan Hansknecht (Mar 08 2025 at 08:31):

I think for the first set of errors we just nesd to lowercase the struct field name

view this post on Zulip Brendan Hansknecht (Mar 08 2025 at 18:43):

Hey @Andrew Kelley with the zig 0.14.0 update, is this the expected behaviour and resolution?

I think it is from Remove Anonymous Struct Types, Unify Tuples


Initial code:

const ret = .{ .id = store.extra_data.items[@as(usize, @intCast(node.main_token))] };
return .{ .@"fn" = .{
    .region = emptyRegion(),
    .ret = ret,
    .args = .{ .span = .{
        .start = node.data.lhs,
        .len = node.data.rhs,
    } },
} };

Error:

src/check/parse/IR.zig:1506:28: error: expected type 'check.parse.IR.NodeStore.TypeAnnoIdx', found 'check.parse.IR.NodeStore.getTypeAnno__struct_26120'
                    .ret = ret,
                           ^~~
src/check/parse/IR.zig:1503:30: note: struct declared here
                const ret = .{ .id = store.extra_data.items[@as(usize, @intCast(node.main_token))] };
                            ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/check/parse/IR.zig:536:29: note: struct declared here
    pub const TypeAnnoIdx = struct { id: u32 };

Solution 1:

const ret = TypeAnnoIdx{ .id = store.extra_data.items[@as(usize, @intCast(node.main_token))] };
return .{ .@"fn" = .{
    .region = emptyRegion(),
    .ret = ret,
    .args = .{ .span = .{
        .start = node.data.lhs,
        .len = node.data.rhs,
    } },
} };

Solution 2:

return .{ .@"fn" = .{
    .region = emptyRegion(),
    .ret = .{ .id = store.extra_data.items[@as(usize, @intCast(node.main_token))] },
    .args = .{ .span = .{
        .start = node.data.lhs,
        .len = node.data.rhs,
    } },
} };

This feels like a regression in type inference. Though maybe this is expected with what is linked above (I'm not sure though). Feels odd that I can't pull a struct field into a separate constant without adding a type.

view this post on Zulip Luke Boswell (Mar 08 2025 at 21:55):

Thank you @Brendan Hansknecht for upgrading us. I just updated everything on my system to 14 and it was a smooth experience. :smiley:

view this post on Zulip Brendan Hansknecht (Mar 08 2025 at 21:56):

It nice having essentially no deps

view this post on Zulip Brendan Hansknecht (Mar 08 2025 at 21:56):

makes updates easy

view this post on Zulip Anthony Bullard (Mar 10 2025 at 13:28):

Did they get rid of anonymous struct inference?

view this post on Zulip Anthony Bullard (Mar 10 2025 at 13:29):

I've never had a problem with this code before:

check/parse/IR.zig:1223:24: error: expected type 'check.parse.IR.NodeStore.Statement', found 'check.parse.IR.NodeStore.getStatement__struct_11541'
                return imp;
                       ^~~
check/parse/IR.zig:1222:30: note: struct declared here
                const imp = .{ .import = i };
                            ~^~~~~~~~~~~~~~~
check/parse/IR.zig:1783:27: note: union declared here
    pub const Statement = union(enum) {
                          ^~~~~
check/parse/IR.zig:1184:69: note: function return type declared here
    pub fn getStatement(store: *NodeStore, statement: StatementIdx) Statement {

view this post on Zulip Brendan Hansknecht (Mar 10 2025 at 15:56):

I'm not fully sure, but it seems like it. I made a comment about it above. Feels like an accidental bug, but the release notes suggests that they may have made anonymous structs(not defined inline with use) into structural instead of nominal types.

view this post on Zulip Brendan Hansknecht (Mar 10 2025 at 15:58):

This change reworks how anonymous struct literals and tuples work.

Previously, an untyped anonymous struct literal (e.g. const x = .{ .a = 123 }) was given an "anonymous struct type", which is a special kind of struct which coerces using structural equivalence. This mechanism was a holdover from before we used Result Location Semantics as the primary mechanism of type inference. This change changes the language so that the type assigned here is a "normal" struct type. It uses a form of equivalence based on the AST node and the type's structure, much like a reified (@Type) type.

Additionally, tuples have been simplified. The distinction between "simple" and "complex" tuple types is eliminated. All tuples, even those explicitly declared using struct { ... } syntax, use structural equivalence, and do not undergo staged type resolution. Tuples are very restricted: they cannot have non-auto layouts, cannot have aligned fields, and cannot have default values with the exception of comptime fields. Tuples currently do not have optimized layout, but this can be changed in the future.

This change simplifies the language, and fixes some problematic coercions through pointers which led to unintuitive behavior.

view this post on Zulip Andrew Kelley (Mar 10 2025 at 19:50):

solution 2 looks good

view this post on Zulip Anthony Bullard (Mar 10 2025 at 21:12):

So basically if a struct is anonymous and not assigned to a annotated var, it is giving its own type, so either create it at a usage site where it’s obvious what it’s meant to be? Otherwise you need to be explicit?


Last updated: Jul 06 2025 at 12:14 UTC