Injecting new values into a comptime tuple

Modify the code somewhat, though, and it stops working (below).

The error is a bit more descriptive, though.

main.zig:130:18: error: expected type 'main.Concat(struct { comptime main.Empty = .{}, comptime main.One = .{}, main.Many, comptime main.One = .{}, comptime main.One = .{} })', found 'main.Concat(.{ undefined, undefined, .{ ... }, undefined, undefined })'
    return concat(makesep(sep, printers));
           ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
main.zig:45:12: note: struct declared here (2 times)
    return struct {
           ^~~~~~
main.zig:129:76: note: function return type declared here
pub fn separate(comptime sep: anytype, comptime printers: anytype) Separate(sep, printers) {
                                                                   ~~~~~~~~^~~~~~~~~~~~~~~

Why would I get undefined as a type when assigning to my newly created tuple?

const std = @import("std");

const io = std.io;
const mem = std.mem;
const meta = std.meta;
const testing = std.testing;

pub const Error = error{InvalidNewline} || mem.Allocator.Error;

const Empty = struct {
    const Self = @This();

    fn width(_: Self) usize {
        return 0;
    }
};

pub const empty = Empty{};

const One = struct {
    const Self = @This();

    fn width(_: Self) usize {
        return 1;
    }
};

pub const one = One{};

const Many = struct {
    n: usize,

    const Self = @This();

    fn width(self: Self) usize {
        return self.n;
    }
};

pub fn many(comptime n: usize) Many {
    return Many{ .n = n };
}

pub fn Concat(comptime printers: anytype) type {
    return struct {
        pub const T = @TypeOf(printers);

        const Self = @This();

        fn width(_: Self) usize {
            var w: usize = 0;
            inline for (printers) |p| {
                w += p.width();
            }
            return w;
        }
    };
}

pub fn concat(comptime printers: anytype) Concat(printers) {
    return Concat(printers){};
}

test "concat" {
    const pp = concat(.{ empty, one, many(3) });
    std.debug.print("concat: pp = {any}\n", .{@TypeOf(pp)});
    try testing.expectEqual(4, pp.width());
}

fn sepTypes(comptime sep: anytype, comptime printers: anytype) type {
    const info = switch (@typeInfo(@TypeOf(printers))) {
        .@"struct" => |s| s,
        else => @compileError("Not a tuple!"),
    };
    const len = info.fields.len;

    if (len == 0)
        @compileError("No printers to separate!");

    var a: []const type = &[_]type{};

    if (len > 1) {
        const TS = @TypeOf(sep);

        for (0..len - 1) |i| {
            const T = @TypeOf(printers[i]);
            a = a ++ [_]type{T};
            a = a ++ [_]type{TS};
        }
    }

    const T = @TypeOf(printers[len - 1]);
    a = a ++ [_]type{T};

    return meta.Tuple(a);
}

pub fn makesep(comptime sep: anytype, comptime printers: anytype) sepTypes(sep, printers) {
    const info = switch (@typeInfo(@TypeOf(printers))) {
        .@"struct" => |s| s,
        else => @compileError("Not a tuple!"),
    };
    const len = info.fields.len;
    //const len = printers.len;
    const n = comptime if (len == 1) 1 else (len * 2 - 1);
    comptime var a: sepTypes(sep, printers) = undefined;

    if (len > 1) {
        inline for (0..len - 1) |i| {
            a[i * 2] = printers[i];
            a[i * 2 + 1] = sep;
        }
    }

    a[n - 1] = printers[len - 1];

    return a;
}

test "makesep" {
    const pp = makesep(10, .{ 20, 30, 40 });
    try testing.expectEqual(.{ 10, 10, 30, 10, 40 }, pp);
}

pub fn Separate(comptime sep: anytype, comptime printers: anytype) type {
    return Concat(sepTypes(sep, printers));
}

pub fn separate(comptime sep: anytype, comptime printers: anytype) Separate(sep, printers) {
    return concat(makesep(sep, printers));
}

test "separate" {
    const pp = separate(one, .{ empty, many(3), one });
    try testing.expectEqual(5, pp.width());
}

pub fn main() !void {}