Skip to content

Unclear compile time variable scoping rules #6613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lerno opened this issue Oct 8, 2020 · 5 comments
Closed

Unclear compile time variable scoping rules #6613

lerno opened this issue Oct 8, 2020 · 5 comments

Comments

@lerno
Copy link

lerno commented Oct 8, 2020

If we have the following code:

fn foo(num: i32) i32
{
    return num + 1;
}

export fn bar(num: i32) i32 
{
    comptime var i : i32 = 0;
    i = i + 1;
    if (num > 2)
    {
        i = i + 2;
        var x : i32 = foo(i);
    }
    else
    {
        i = i * 2;
        var x : i32 = foo(i);
    }
    i = i + 10;
    return foo(i);
}

Inspecting the LLVM output in 0.6.0, we note that foo is called with values 3, 6 and 16 respectively. There is a certain sense to this. The function will return 17 regardless of input. However if we change the code to this way:

export fn bar(num: i32) i32 
{
    comptime var i : i32 = 0;
    i = i + 1;
    if (false)
    {
        i = i + 2;
        var x : i32 = foo(i);
    }
    else
    {
        i = i * 2;
        var x : i32 = foo(i);
    }
    i = i + 10;
    return foo(i);
}

Suddenly the function returns 13.

This seems like something that could be extremely bug prone.

Possible alternatives:

  1. Make it an error to change a comptime in a deeper scope (i.e. both examples are considered invalid)
  2. Make it an error to change a comptime in a deeper scope if it cannot be flattened to a singly directed graph (makes the first example invalid)
  3. Altering a comp time variable in a deeper scope creates a copy (so in our example the function would return 11 for both examples.
@lerno
Copy link
Author

lerno commented Oct 8, 2020

It seems that this behaviour was documented earlier, for example in #906 and #1470. #1470 appears to suggest (1), but perhaps (2) is more attractive as it would allow more complex uses of compile time variables. (3) produces the best results for some cases, but is more difficult to reason about when there are compile time loops.

@ghost
Copy link

ghost commented Oct 8, 2020

I think it's important to allow branching on compile time conditions. Your second code example should be allowed. But in your first code example, it definitely feels sketchy to allow an outer comptime variable to be mutated in a runtime conditional scope.

@lerno
Copy link
Author

lerno commented Oct 9, 2020

@dbandstra It's slightly working against Zig here that there is no specific code to make the if-statement compile time. If the code had looked like this:

inline if (false)
{
   i = i + 2;
   var x : i32 = foo(i);
}

Then we could contrast that with this:

if (false)
{
   i = i + 2; // Compile time error
   var x : i32 = foo(i);
}

So essentially only allow the modification if it is in a compile time branch.

@andrewrk
Copy link
Member

@lerno
Copy link
Author

lerno commented Oct 13, 2020

@andrewrk Which issue is appropriate to track if I want to see what happens with this particular issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants