Skip to content

Conversation

SeanTheGleaming
Copy link
Contributor

@SeanTheGleaming SeanTheGleaming commented Sep 13, 2025

Addresses multiple bugs in Sema/Value/Type.
To be specific:

Peer @TypeOf in a @cImport block

In a unary @TypeOf block, the current behavior regarding @cImport statements is that operands are treated as if they are outside of a @cImport block; If you use @TypeOf(@cInclude(...)) even inside of a @cImport block, this is a compile error. It seems that peer @TypeOf did not agree with this implementation. Or any implementation for that matter. It crashed the compiler by attempting to write to a @cImport buffer that didn't exist. Now

In practice, this turns the following code from a crash into a compile error:

const c = @cImport({
    _ = @TypeOf(@cInclude("stdlib.h"), @cInclude("stdio.h"));
});

Pass an optional sema parameter to print_value and Type.print

Some API changes were made to Value, Type, and print_value to allow for semantic analysis during the formatting of Value and Type. Resolves the TODO above Type.print.

  • Functions in print_value now take an opt_sema: ?*Sema parameter
  • Added new formatting functions to Value
    • Value.fmtValueOptSema
      • Similar to Value.fmtSema , except the sema parameter is now optional.
      • For use when Sema may or may not be available
    • Explicit depth formatting functions
      • Value.fmtDepth
        • Identical to Value.fmt, but takes an additional depth parameter
      • Value.fmtSemaDepth
        • Identical to Value.fmtSema, but takes an additional depth parameter
      • Value.fmtOptSemaDepth
        • Identical to Value.fmtOptSema, but takes an additional depth parameter
  • Type.print now takes an ?*Sema parameter
    • When provided with a nonnull value, this makes semantic analysis during the printing of types possible.
  • Added new formatting functions to Type
    • Type.fmt remains unchanged
      • Never performs semantic analysis
      • Symmetrical to Value.printValue
    • Type.fmtSema
      • Similar to Type.fmt, but accepts an additional *Sema parameter
      • May perform semantic analysis
      • For use whenever Sema is available
      • Symmetrical to Value.printValueSema
    • Type.fmtOptSema
      • Similar to Type.fmt, but accepts an additional ?*Sema parameter
      • May perform semantic analysis if the ?*Sema parameter is nonnull
      • For use when Sema may or may not be available
      • Symmetrical to Value.printValueOptSema

These changes fix the following compiler crash (and many similar crashes in the same vain):

comptime {
    var mutable: u8 = 0;
    @compileLog(@TypeOf(.{&mutable}));
}

And speaking of capturing comptime variables as default field values in anonymous struct literals...

Better checks for capturing comptime-mutable references

Previously, it was relatively simple to "hide" a comptime-mutable reference inside of a type. If you stored a comptime-mutable reference in the sentinel of an array or the default field of a struct, it was possible to create a type which contained a comptime-mutable reference. Building on that, it was possible to create structs containing these types, pointers pointing to these types, arrays with these types as children, and so on. After a thorough rework of the relevant code, this is no more!

In practice, the following code contains multiple parts that used to crash the compiler:

const y = blk: {
    // Crazy contrived example of deeply nesting a comptime variable within types
    var x: u8 = 0;
    const z = *[*:.{(&[3]*u8{ undefined, &x, undefined }).ptr[3..4]}]@Vector(1, [*]const *u8);
    const S = anyerror!struct {
        a: u8,
        b: type,
    };
    const s: S = .{
        .a = 4,
        .b = z,
    };
    break :blk &(s catch unreachable).a;
};

comptime {
    _ = y;
}

And now, as ridiculous as that code was, we get a proper error message:

/abc/example.zig:1:16: error: global variable contains reference to comptime var
const y = blk: {
          ~~~~~^
/abc/example.zig:1:16: note: 'y' points to '(v0 catch unreachable).a', where
/abc/example.zig:1:16: note: '@typeInfo(@typeInfo((v0 catch unreachable).b).pointer.child).pointer.sentinel().?[0]' points to '@as([*]const *u8, @ptrCast(&v1[3])).*', where
/abc/example.zig:4:17: note: 'v1[1]' points to comptime var declared here
    var x: u8 = 0;

SeanTheGleaming and others added 13 commits September 11, 2025 00:00
Previously, any expression which writes to the C Import buffer
(@Cinclude, @cdefine, @dUndef) inside of a peer @typeof call within a
@cImport block would cause illegal behavior and crash. Additionally,
peer @typeof and unary @typeof were inconsistent in their treatment of C
Import statements (Unary @typeof disallowed these expressions even when
inside a @cImport statement, and peer @typeof would have allowed this if
the illegal behavior did not occur). The new behavior is that when
inside of a @cImport statement, @typeof(@c[Define|Undef|Include}(...)) returns the void
type and does not append to the C Import buffer. When outside of a
@cImport statement, this is still a compile error. This applies to both
peer @typeof and unary @typeof.
Adds an optional sema parameter to Type.print,
print_value.printPtrDeviation, and other related functions. Resolves the
TODO above Type.print. Additionally, fixed a crash with
`@compileLog(@typeof(.{&[comptime_var]}))`, although this case allows
for the capturing of a comptime variable pointer in a type via the default
field in a tuple, which should not be allowed (see ziglang#5718) and should be
rectified.
Checks default values of tuple fields being able to store references
to comptime vars (eg. @typeof(.{&[comptime variable]}). This behavior is
now checked when mutable comptime allocations are disallowed.
This is my penance for baiting andrew into deleting the existing generic
queue data structures with my talk of "too many ring buffers".

The new Reader and Writer interfaces are excellent ring buffers for many
use cases, but a generic queue container type is now missing.

This new double-ended queue, known more succinctly as a deque, is
implemented from scratch based on the API design lessons learned from
ArrayList over the years.

The API is not yet as featureful as ArrayList, but the core
functionality is in place and I will be using this in my personal
projects shortly. I think it makes sense to add further functions as
needed based on real-world use-cases.
And delete DeprecatedLinearFifo from the source tree.
…ang#25188)

* Make cat in test/standalone/simple working again

- Fixes:
    zig/0.15.1/lib/zig/std/Io/Writer.zig:939:11: 0x1049aef63 in sendFileAll (nclip)
        assert(w.buffer.len > 0);
- because we are no using non zero buffers for stdout - "do not forget to flush"

* replace std.fs with fs because we are already importing it
Previously, if you "hid" a comptime-mutable reference somewhere sneaky
in a type, such as in the sentinel of a pointer, the child of an array,
or the default field of a struct, it would not be detected. This allowed
for comptime-mutable references to be captured and escape to a container
  level. No more with that!
After further consideration, I have reverted my change in behavior for
@cImport-only expressions within @typeof. My reasoning is that the old
code for the unary @typeof was explicit enough that it could be
reasonably assumed that the old behavior was the intended behavior. With
this in mind, I applied the fix, but kept the old behavior.
Previously, comptime vars could slip under the radar as sentinel values
in pointer types, or default fields in structs. This commit fixes that.
It also correctly handles self-referential types (eg. a linked list),
and correctly prints the source of the comptime var in error messages.
@SeanTheGleaming
Copy link
Contributor Author

Seeing as this is failing CI checks and I don't have enough time at the moment to rectify this, I will be converting this to a draft for the time being.

@SeanTheGleaming SeanTheGleaming marked this pull request as draft September 13, 2025 04:59
@SeanTheGleaming
Copy link
Contributor Author

Somewhere along the way, I seriously bungled with git. I have recreated my changes and successfully bootstrapped in a separate branch free from my mistakes, thus I will be closing and rebooting this as a separate PR from said branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants