ziglang / zig

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

peer type resolution not coercing properly #12608

Open nektro opened 2 years ago

nektro commented 2 years ago

Zig Version

0.10.0-dev.3672+cd5a9ba1f

Steps to Reproduce

const std = @import("std");

test {
    var a: u32 = 45;
    var b: u8 = 4;

    var runtime = true;
    var other = false;

    const x = if (runtime) blk: {
        break :blk a;
    } else if (other) blk: {
        break :blk b;
    } else null;

    try std.testing.expectEqual(?u32, @TypeOf(x));
    // try std.testing.expect(x == 45); // see #12609
}

Expected Behavior

All 1 tests passed.

Actual Behavior

test.zig:10:15: error: expected type '?u8', found 'u32'
    const x = if (runtime) blk: {
              ^~
test.zig:10:15: note: unsigned 8-bit int cannot represent all possible unsigned 32-bit values
andrewrk commented 2 years ago

I understand that this made it into stage1 however allowing such comparison is problematic and I think self-hosted behavior is better.

nektro commented 2 years ago

removed stage2 from title since stage1 fails too

./test.zig:10:15: error: incompatible types: 'u32' and '?u8'
    const x = if (runtime) blk: {
              ^
./test.zig:11:20: note: type 'u32' here
        break :blk a;
                   ^
./test.zig:10:15: note: type '?u8' here
    const x = if (runtime) blk: {
              ^
mlugg commented 1 year ago

There are two ways this snippet could be expected to work.

The first is if a chain of if / else if / else all did PTR and coercion as a single operation. That way, the resolved type would be ?u32, and all operands can coerce to that. I think this would be a quite reasonable change: it's effectively just order independence in the type resolution of such a chain.

The second, and arguably simpler one, is if we allow the coercion ?u8 -> ?u32 (more generally, ?A -> ?B if A coerces to B). As of my PTR rewrite, the snippet resolves the final type of ?u32 correctly, however it fails to perform the coercion, as the second if (i.e. from the else if to the else) coerces its result to a ?u8, and that can't coerce to the final resolved type of ?u32. If this were allowed, the snippet would work.

@andrewrk, I'm curious to hear why you thought this behavior was problematic. All it's really asking for is order-independence in type resolution of an if chain, which seems to me very reasonable, even if I understand why it doesn't currently happen.