ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.59k stars 2.53k forks source link

`*[1]T` doesn't coerce to `*T` but `*T` coerces to `*[1]T` #19806

Open Trevor-Strong opened 5 months ago

Trevor-Strong commented 5 months ago

Zig Version

0.12.0

Steps to Reproduce and Observed Behavior

run zig test on the following file

fn coerce(comptime From: type, comptime To: type) To {
    return @as(From, undefined);
}

test {
    _ = coerce(*u8, *[1]u8);
    _ = coerce(*[1]u8, *u8); // Causes Compile Error
}

Produces the compile error:

x.zig:3:12: error: expected type '*u8', found '*[1]u8'
    return @as(From, undefined);
           ^~~~~~~~~~~~~~~~~~~~
x.zig:3:12: note: pointer type child '[1]u8' cannot cast into pointer type child 'u8'
x.zig:2:51: note: function return type declared here
fn coerce(comptime From: type, comptime To: type) To {

Expected Behavior

Either both lines should cause a compile error, or neither of them should. Seeing how #3156 was accepted, it should be that both of these pass.

Status quo way to resolve this is &array_pointer[0]. This isn't much typing, but the real issue I have with the status quo is that it is unintuitive to require different syntax depending on the direction the conversion is going.

All other conversions in I know of are either only 1000% known to be safe in one direction (i.e. i8 to i32, *T to *const T), or use the same syntax for both directions (uN to iN and iN to uN are both done with @bitCast).

mlugg commented 5 months ago

This is not a bug, but it's worded reasonably enough for a proposal, so I will label it as such.

FWIW, I personally want to go the other way, by eliminating the coercion *T -> *[1]T. This coercion is a pain for RLS, because it makes it far more difficult to provide an appropriate result type to the sub-expression x in &x.