Error: Incompatible Types, but Why?

I’m working on a falling tetromino game, and I got a compile error which is kind of confusing me:

minimal-example.zig:16:21: error: incompatible types: 'minimal-example.Piece' and 'minimal-example.main__struct_35611'
    const rotated = switch (pieceIndex) {
                    ^~~~~~
minimal-example.zig:17:14: note: type 'minimal-example.Piece' here
        0 => piece,
             ^~~~~
minimal-example.zig:18:15: note: type 'minimal-example.main__struct_35611' here
        1 => .{ .xs = threes - piece.ys, .ys = threes - piece.xs },
             ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is a sort of reduced example:

const std = @import("std");

pub fn main(init: std.process.Init) void {
    var buffer: [8]u8 = undefined;
    init.io.random(&buffer);
    var prng = std.Random.DefaultPrng.init(@bitCast(buffer));
    const random = prng.random();

    const pieceIndex = random.uintLessThan(usize, pieces.len);
    var piece = pieces[pieceIndex];

    const ones: V4u2 = @splat(1);
    const twos: V4u2 = @splat(2);
    const threes: V4u2 = @splat(3);

    // rotate counterclockwise
    const rotated = switch (pieceIndex) {
        0 => piece,
        1 => .{ .xs = threes - piece.ys, .ys = threes - piece.xs },
        2, 3 => .{
            .xs = @select(u2, piece.ys == ones, twos - piece.xs, piece.xs),
            .ys = @select(u2, piece.xs == ones, piece.ys, twos - piece.ys),
        },
        4, 5, 6 => .{ .xs = twos - piece.ys, .ys = piece.xs },
        else => unreachable,
    };
    piece = rotated;
}

const V4u2 = @Vector(4, u2);
const Piece = struct { xs: V4u2, ys: V4u2 };
const pieces: [7]Piece = .{ O, I, S, Z, L, J, T };

/// 1 1
/// 1 1
const O: Piece = .{ .xs = .{ 0, 1, 0, 1 }, .ys = .{ 0, 0, 1, 1 } };

/// 0 0 1 0  0 0 0 0
/// 0 0 1 0  0 0 0 0
/// 0 0 1 0  1 1 1 1
/// 0 0 1 0  0 0 0 0
/// initial rotation: 1
const I: Piece = .{ .xs = .{ 0, 1, 2, 3 }, .ys = .{ 1, 1, 1, 1 } };

/// 0 0 0  1 0 0
/// 0 1 1  1 1 0
/// 1 1 0  0 1 0
/// initial rotation: 0
const S: Piece = .{ .xs = .{ 0, 1, 1, 2 }, .ys = .{ 0, 0, 1, 1 } };

/// 0 0 0  0 0 1
/// 1 1 0  0 1 1
/// 0 1 1  0 1 0
/// initial rotation: 0
const Z: Piece = .{ .xs = .{ 1, 2, 0, 1 }, .ys = .{ 0, 0, 1, 1 } };

/// 0 1 0  0 0 0  1 1 0  0 0 1
/// 0 1 0  1 1 1  0 1 0  1 1 1
/// 0 1 1  1 0 0  0 1 0  0 0 0
/// initial rotation: 1
const L: Piece = .{ .xs = .{ 0, 0, 1, 2 }, .ys = .{ 0, 1, 1, 1 } };

/// 0 1 0  1 0 0  0 1 1  0 0 0
/// 0 1 0  1 1 1  0 1 0  1 1 1
/// 1 1 0  0 0 0  0 1 0  0 0 1
/// initial rotation: 3
const J: Piece = .{ .xs = .{ 2, 0, 1, 2 }, .ys = .{ 0, 1, 1, 1 } };

/// 0 0 0  0 1 0  0 1 0  0 1 0
/// 1 1 1  1 1 0  1 1 1  0 1 1
/// 0 1 0  0 1 0  0 0 0  0 1 0
/// initial rotation: 0
const T: Piece = .{ .xs = .{ 1, 0, 1, 2 }, .ys = .{ 0, 1, 1, 1 } };

Using Piece{…} instead of .{…} stops the compiler error, but I think I read somewhere that .{…} is preferred. I’m also not sure why the types are actually incompatible and it’s bugging me. This error even happens if you replace 0 => piece with 0 => .{ .xs = piece.xs, .ys = piece.ys }.

Any wisdom is appreciated.

edit: I forgot to mention, but this is 0.16.0.

Use const rotated: Piece = switch ... that way all the switch prongs will have a result type and thus your .{} struct literals will be coerced to instances of Piece instead of being an anonymous struct type instance.

2 Likes

Thanks! I’ll use this, but I still wonder why the anonymous struct literals were incompatible with piece.

Basically in the past Zig had structs that allow these coercions, but now you have to provide result type so that the struct literal can directly be coerced to the target struct type.

The previous semantics had too many corner cases which weren’t really useful and made the language more difficult to understand. (paraphrased)

0.14.0 Release Notes: Remove Anonymous Struct Types Unify Tuples

1 Like