Error: expected type '[]const u8', found '*[]u8'

Here’s the error…

src/utils.zig:8:13: error: expected type '[]const u8', found '*[]u8'
        try std.os.getrandom(std.mem.asBytes(&seed));
            ^~~
referenced by:
    test.crossover: src/utils.zig:93:9

I’ll try to minimize the code here, but it’s happening in this function:

pub fn ourRng() !std.rand.DefaultPrng {
    return std.rand.DefaultPrng.init(blk: {
        var seed: u64 = undefined;
        try std.os.getrandom(std.mem.asBytes(&seed));
        break :blk seed;
    });
}

The 4th time it’s being called, from here:

    try crossover(allocator, &binary_string_1, &binary_string_2, random.random());

That function is called without parameters, so I’m totally lost about what can have happened there. And why it happens only the 4th time it?s called, too…

I have refactored the code, bringing that function out… And this is what I get now:

src/eo.zig:7:16: error: expected type '[]const u8', found '*[]u8'
    var count: u32 = 0;
               ^~~
referenced by:
    test.crossover: src/eo.zig:78:9
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

What am I missing here? Did I commit some bug error somewhere that’s making the compiler go bonkers?

I am not sure what is going on.


I am normally initializing the DefaultPrng using the crypto random interface:

var prng: std.rand.DefaultPrng = undefined;
const seed = std.crypto.random.int(u64);
prng = std.rand.DefaultPrng.init(seed);
1 Like

I don’t think it’s an issue with the Random interface itself. I’ve factored that function to its own file:

const std = @import("std");
const expect = std.testing.expect;
const ourRng = @import("utils.zig").ourRng;

// Crossover operator that combines two strings, cutting them in two random points, interchanging the result
pub fn crossover(allocator: std.mem.Allocator, binary_string_1: *[]u8, binary_string_2: *[]u8, random: std.rand.Random) !void {
    var binary_string_1Clone: []u8 = try allocator.dupeZ(u8, binary_string_1);
    defer allocator.free(binary_string_1Clone);
    var binary_string_2Clone: []u8 = try allocator.dupeZ(u8, binary_string_2);
    defer allocator.free(binary_string_2Clone);

    var index1 = random.int(u32) % binary_string_1.len;
    var index2 = random.int(u32) % binary_string_2.len;

    if (index1 > index2) {
        var temp = index1;
        index1 = index2;
        index2 = temp;
    }

    for (index1..index2) |i| {
        binary_string_2[i] = binary_string_1Clone[i];
        binary_string_1[i] = binary_string_2Clone[i];
    }
}

test "crossover" {
    var prng = try ourRng();
    var allocator = std.heap.page_allocator;

    var binary_string_1 = try allocator.dupeZ(u8, "101010");
    defer allocator.free(binary_string_1);
    const copy_binary_string_1 = try allocator.dupeZ(u8, "101010");
    defer allocator.free(copy_binary_string_1);
    var binary_string_2 = try allocator.dupeZ(u8, "010101");
    defer allocator.free(binary_string_2);
    const copy_binary_string_2 = try allocator.dupeZ(u8, "010101");
    defer allocator.free(copy_binary_string_2);

    try crossover(allocator, &binary_string_1, &binary_string_2, prng.random());

    try expect(copy_binary_string_1.len == binary_string_1.len);
    try expect(copy_binary_string_2.len == binary_string_2.len);
    try expect(!std.mem.eql(u8, copy_binary_string_1, binary_string_1));
    try expect(!std.mem.eql(u8, copy_binary_string_2, binary_string_2));
}

And now it fails here:

src/crossover.zig:2:27: error: expected type '[]const u8', found '*[]u8'
const expect = std.testing.expect;
               ~~~~~~~~~~~^~~~~~~
referenced by:
    test.crossover: src/crossover.zig:40:9
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

The only thing that’s constant is the line where it fails, which is this one:

    try crossover(allocator, &binary_string_1, &binary_string_2, prng.random());

So thanks a lot for the answer, but this smells like a bug, maybe due to the way the parameters are passed to the function? Should value parameters be passed before pointers or something like that?

No, not the parameter order (although it looks more reasonable to do it that way). Passing the prng after the allocator fails in the same place, in the same way.

Changing the content of the line shows the error in the new content of the line. So looks like something is going awry in the compiler, because this does not make any sense.

This error does not make sense.
Looks like a compiler bug.
Which version do you use? (zig version)

Try to reduce the lines that trigger the problem.
Does it compile the 3 first lines? (EDIT: You also need to reference the unused symbols from a dummy test)

const std = @import("std");
const expect = std.testing.expect;
const ourRng = @import("utils.zig").ourRng;

test "bug" {
    _ = expect;
    _ = ourRng;
}
1 Like

0.11.0

Yep, it does work; I’ve finally refactored the big file to many other files and that stanza is at the beginning of every one of them.

I’ve tried to simplify the function (taking out the allocator, for instance) and it disappears… But I don’t have a lot of experience here, I’m afraid…

use testing.allocator when testing.

You don’t need the extra pointer in crossover arguments.
The slice ([]u8) contains a pointer to the string and its length.

pub fn crossover(allocator: std.mem.Allocator, binary_string_1: []u8, binary_string_2: []u8, random: std.rand.Random) !void {

try crossover(allocator, binary_string_1, binary_string_2, prng.random());
3 Likes

That worked, no compiler error, and tests passing. Thanks a lot. I get a new error, I’ll open another topic. Much appreciated.

2 Likes

The problem was here:

binary_string_1 was *[]u8 but dupeZ expects []const u8
after removing the pointer binary_string_1 became []u8 that implicitly casts to []const u8.

A good question is: Why the compiler does not show the correct source position?

3 Likes