#function called at runtime cannot return value at comptime

1 messages · Page 1 of 1 (latest)

stuck otter
#

I'm not sure how, I'm getting this error:

error: function called at runtime cannot return value at comptime
                return Self{ .fe = baseOne };

What does this mean? Is it complaning that that line isn't deterministic? It shouldn't be the case.

lapis moss
#

im assuming you are trying to get a function pointer if so return Self{ .fe = &baseOne };

#

if not would need to see more code

stuck otter
#

baseOne is a [4]u64

lapis moss
#

can you show the code?

stuck otter
#

Technically "can't" which is annoying... let me see if I can figure out somewhat to extract the gist of it.

#

Could somehow the Self = @This() have some indirect non-determinism? Like something on the type maybe

#

This was actually working yesterday, and I don't see any change in my git repo...
I don't believe in ghosts, but AFAIK my zig version hasn't changed.

#

I'm a bit surprised at the line the error is pointing at... is basically creating a type value with a field which is a [4]u64 🤷

#

(definitely not a pointer, which would be wrong for comptime)

slow panther
#

does the function do anything like print to stderr/stdout or any other such I/O

stuck otter
#

nop

#

let me try something if triggers the same error and is sharable

#

@slow panther , @lapis moss ,

pub fn oneTest() Self {
            return comptime {
                var baseOneTest: [4]u64 = undefined;
                baseOneTest[0] = 0x1fffffffe;
                baseOneTest[1] = 0x5884b7fa00034802;
                baseOneTest[2] = 0x998c4fefecbc4ff5;
                baseOneTest[3] = 0x1824b159acc5056f;

                return Self{ .fe = baseOneTest };
            };
        }

Error:

 error: function called at runtime cannot return value at comptime
                return Self{ .fe = baseOneTest };
lapis moss
#

there only way i can even get that error is by doing exactly what it says, returning at comptime in a runtime call

fn f() u8 {
    comptime return 1;
}
#

at the call site comptime oneTest();

#

function calls are at runtime unless already in a comptime scope

stuck otter
#

You mean that I should always do comptime oneTest() in each caller?

lapis moss
#

or something like this

pub fn oneTest() [4]u64 {
    const baseOneTest: [4]u64 = comptime blk: {
        var baseOneTest: [4]u64 = undefined;
        baseOneTest[0] = 0x1fffffffe;
        baseOneTest[1] = 0x5884b7fa00034802;
        baseOneTest[2] = 0x998c4fefecbc4ff5;
        baseOneTest[3] = 0x1824b159acc5056f;
        break :blk baseOneTest;
    };

    return baseOneTest;
}

#

basically dont return inside comptime scope, unless the function is only called at comptime

stuck otter
#

Interesting... feels I've a mental gap about what it means to return inside a comptime.

#

I'm actually not sure what that means now that I think about it

#

Compared with that break :blk ...

lapis moss
#

it only makes sense if the caller is comptime

stuck otter
#

Very interesting, let me try.

#

@lapis moss, looks like this fixed the error.
I'm a bit surprised how this could have worked and "suddenly" (which of course always have an explanation) stop working.

From what I imagine, in some new caller this methods might be used and wasn't comptime, and this fact of returning inside comptime become relevant? Sounds plausible?

lapis moss
#

might be something like this?

const outside_function = oneTest(); // FINE - outside of function so is comptime

fn func() void {
    const inside_function = oneTest(); // ERROR - inside function which means runtime (unless `func` is called at comptime)
}
grand jolt
#

I think this was you @humble tree, right?

humble tree
#

comptime return is now invalid in a function called at runtime

#

That's because it's trying to do runtime control flow at comptime, which is not possible

#

It didn't used to work, it was just silently equivalent to return comptime (which is what you probably want) due to #7056

#

Yeah, just skimmed the thread, that's exactly what you're running into

#

So @stuck otter your confusion probably comes from the fact that this changed literally yesterday

grand jolt
humble tree
#

comptime blocks and expressions used to be a bit broken: they didn't actually force their contents to be completely comptime-evaluated, only certain things like function calls. That's the only reason comptime return was ever valid (in a function called at runtime)

stuck otter
lapis moss
#

no, the extension only updates zls

stuck otter
#

Ah ok, I think I understand what happened.
I also tried some old git commit which definitely was working some weeks ago, but at that time I was using a different zig compiler.

#

cool

#

Very tricky to test old code when you're changing your compiler often heh

#

So why I would ever want to use comptime { ... return ..; } ?

humble tree
#

In my experience Zig's breaking changes don't tend to be too painful to work around

stuck otter
#

I like that.

#

I mean, I like that I shouldn't

#

It's a bit confusing having that option, so good that isn't allowed/recommended.

humble tree
#

All comptime syntax does is ensures some expression is evaluated at comptime. It can't fundamentally change control flow or anything like that

stuck otter
#

Is basically a funciont returning a constant

lapis moss
#

yea which means just a constant is better than a function call at all

humble tree
#

Yeah, that'd be the idea. Note that you can shorten that:

return comptime blk: {
    ...
    break :blk whatever;
};
stuck otter
#

oh that looks better

humble tree
#

That's what I changed it to wherever the compiler or std was using the old thing

stuck otter
#

Why is "blk :" needed there?

#

Can't the "break" label be infered?

humble tree
#

break without a label breaks to the enclosing loop, not to a block

stuck otter
#

But there's no ambiguity there

humble tree
#

Breaking to a loop always requires a label

lapis moss
#

if you don't need to take an argument don't even bother with the function:

const baseOneTest: [4]u64 = blk: {
    var temp: [4]u64 = undefined;
    temp[0] = 0x1fffffffe;
    temp[1] = 0x5884b7fa00034802;
    temp[2] = 0x998c4fefecbc4ff5;
    temp[3] = 0x1824b159acc5056f;
    break :blk temp;
};

fn func() void {
    var thing = baseOneTest;
}
humble tree
#

But even if that weren't the case, it's also just a clarity thing

#

If you see an unlabelled block, you know it doesn't give a result without having to read it all

grand jolt
humble tree
#

Yes

grand jolt
#

Okay cool 😄

#

Some sense this does make

stuck otter
#

@humble tree , the blk: label... which kind of semantic should have for its name?

#

That's kind of the "annoying" part for me.

grand jolt
#

You can use the name of the target as the label name

stuck otter
#

yeah but sounds redundant

humble tree
#

The name blk is honestly fine in cases like this, but you could also go with result, or a more contextually appropriate name describing what the thing you're returning is

grand jolt
#
const foobar = foobar: {
    break :foobar 5;
};
stuck otter
#

cool, like naming the returned value

#

so the name of the receiving variable can be contextual to the function, and the "break" label maybe more related to the value meaning inside the block

#

kind of naming a return parameter

#

ok, interesting, maybe i'm convinced :P

grand jolt
#

Pretty much yeah

stuck otter
#

still feels like a return

#

i think that's why I was tempted to use that

grand jolt
# grand jolt Pretty much yeah

I tend to do blk: { most of the time, but I may [start using] the target idea more honestly. It's nice if there's a lot going on, or the block is more than a page, or whatever.

stuck otter
#

From my side we can consider this thread solved, thanks everyone.
(Not sure if I can mark this solved or there's an "exit-flow")

grand jolt
#

You can react with a ✅

#

o7 😄

stuck otter
#

done!