google / starlark-go

Starlark in Go: the Starlark configuration language, implemented in Go
BSD 3-Clause "New" or "Revised" License
2.31k stars 210 forks source link

unexpected global variable referenced before assignment #505

Open Pussbebe2103 opened 1 year ago

Pussbebe2103 commented 1 year ago

Here's 2 scripts with -globalassign enabled, run the first one, and use its output as input/predeclared for the second one:

Script 1:

hello = [123, 456]
debug = False

Script 2:

print(hello)

It runs fine, but if you change the second script to:

if debug:
    hello = "hello world"

print(hello)

It will throw an unexpected error: global variable hello referenced before assignment

Why?

adonovan commented 1 year ago

In Starlark and Python, within a function, an assignment statement creates a variable binding in the function, whether or not it is executed:

$ starlark
>>> def f():
...     if False:
...        x = 1
...     print(x)
... 
>>> f()
Traceback (most recent call last):
  <stdin>:1:2: in <expr>
  <stdin>:4:11: in f
Error: local variable x referenced before assignment
$ python3
>>> def f():
...    if False:
...      x = 1
...    print(x)
... 
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in f
UnboundLocalError: cannot access local variable 'x' where it is not associated with a value
>>> 

But Starlark differs from Python in its treatment of the toplevel. The spec disallows loops and conditional assignments at toplevel (conditional assignments are just loops where n < 2!), and the -globalreassign flag in the Go implementation treats the toplevel like any other function.