diff options
Diffstat (limited to 'resolve/testdata/resolve.star')
-rw-r--r-- | resolve/testdata/resolve.star | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/resolve/testdata/resolve.star b/resolve/testdata/resolve.star new file mode 100644 index 0000000..ce67110 --- /dev/null +++ b/resolve/testdata/resolve.star @@ -0,0 +1,383 @@ +# Tests of resolver errors. +# +# The initial environment contains the predeclared names "M" +# (module-specific) and "U" (universal). This distinction +# should be unobservable to the Starlark program. + +# use of declared global +x = 1 +_ = x + +--- +# premature use of global is not a static error; +# see github.com/google/skylark/issues/116. +_ = x +x = 1 + +--- +# use of undefined global +_ = x ### "undefined: x" + +--- +# redeclaration of global +x = 1 +x = 2 ### "cannot reassign global x declared at .*resolve.star:23:1" + +--- +# Redeclaration of predeclared names is allowed. +# +# This rule permits tool maintainers to add members to the predeclared +# environment without breaking existing programs. + +# module-specific predeclared name +M = 1 # ok +M = 2 ### "cannot reassign global M declared at .*/resolve.star" + +# universal predeclared name +U = 1 # ok +U = 1 ### "cannot reassign global U declared at .*/resolve.star" + +--- +# A global declaration shadows all references to a predeclared; +# see github.com/google/skylark/issues/116. + +a = U # ok: U is a reference to the global defined on the next line. +U = 1 + +--- +# reference to predeclared name +M() + +--- +# locals may be referenced before they are defined + +def f(): + M(x) # dynamic error + x = 1 + +--- +# Various forms of assignment: + +def f(x): # parameter + M(x) + M(y) ### "undefined: y" + +(a, b) = 1, 2 +M(a) +M(b) +M(c) ### "undefined: c" + +[p, q] = 1, 2 +M(p) +M(q) +M(r) ### "undefined: r" + +--- +# a comprehension introduces a separate lexical block + +_ = [x for x in "abc"] +M(x) ### "undefined: x" + +--- +# Functions may have forward refs. +def f(): + g() + h() ### "undefined: h" + def inner(): + i() + i = lambda: 0 + +def g(): + f() + +--- +# It is not permitted to rebind a global using a += assignment. + +x = [1] +x.extend([2]) # ok +x += [3] ### `cannot reassign global x` + +def f(): + x += [4] # x is local to f + +y = 1 +y += 2 ### `cannot reassign global y` +z += 3 # ok (but fails dynamically because z is undefined) + +--- +def f(a): + if 1==1: + b = 1 + c = 1 + M(a) # ok: param + M(b) # ok: maybe bound local + M(c) # ok: bound local + M(d) # NB: we don't do a use-before-def check on local vars! + M(e) # ok: global + M(f) # ok: global + d = 1 + +e = 1 + +--- +# This program should resolve successfully but fail dynamically. +x = 1 + +def f(): + M(x) # dynamic error: reference to undefined local + x = 2 + +f() + +--- +load("module", "name") # ok + +def f(): + load("foo", "bar") ### "load statement within a function" + +load("foo", + "", ### "load: empty identifier" + "_a", ### "load: names with leading underscores are not exported: _a" + b="", ### "load: empty identifier" + c="_d", ### "load: names with leading underscores are not exported: _d" + _e="f") # ok + +--- +# option:globalreassign +if M: + load("foo", "bar") ### "load statement within a conditional" + +--- +# option:globalreassign +for x in M: + load("foo", "bar") ### "load statement within a loop" + +--- +# option:recursion option:globalreassign +while M: + load("foo", "bar") ### "load statement within a loop" + +--- +# return statements must be within a function + +return ### "return statement not within a function" + +--- +# if-statements and for-loops at top-level are forbidden +# (without globalreassign option) + +for x in "abc": ### "for loop not within a function" + pass + +if x: ### "if statement not within a function" + pass + +--- +# option:globalreassign + +for x in "abc": # ok + pass + +if x: # ok + pass + +--- +# while loops are forbidden (without -recursion option) + +def f(): + while U: ### "dialect does not support while loops" + pass + +--- +# option:recursion + +def f(): + while U: # ok + pass + +while U: ### "while loop not within a function" + pass + +--- +# option:globalreassign option:recursion + +while U: # ok + pass + +--- +# The parser allows any expression on the LHS of an assignment. + +1 = 0 ### "can't assign to literal" +1+2 = 0 ### "can't assign to binaryexpr" +f() = 0 ### "can't assign to callexpr" + +[a, b] = 0 +[c, d] += 0 ### "can't use list expression in augmented assignment" +(e, f) += 0 ### "can't use tuple expression in augmented assignment" + +[] = 0 # ok +() = 0 # ok + +--- +# break and continue statements must appear within a loop + +break ### "break not in a loop" + +continue ### "continue not in a loop" + +pass + +--- +# Positional arguments (and required parameters) +# must appear before named arguments (and optional parameters). + +M(x=1, 2) ### `positional argument may not follow named` + +def f(x=1, y): pass ### `required parameter may not follow optional` +--- +# No parameters may follow **kwargs in a declaration. + +def f(**kwargs, x): ### `parameter may not follow \*\*kwargs` + pass + +def g(**kwargs, *args): ### `\* parameter may not follow \*\*kwargs` + pass + +def h(**kwargs1, **kwargs2): ### `multiple \*\* parameters not allowed` + pass + +--- +# Only keyword-only params and **kwargs may follow *args in a declaration. + +def f(*args, x): # ok + pass + +def g(*args1, *args2): ### `multiple \* parameters not allowed` + pass + +def h(*, ### `bare \* must be followed by keyword-only parameters` + *): ### `multiple \* parameters not allowed` + pass + +def i(*args, *): ### `multiple \* parameters not allowed` + pass + +def j(*, ### `bare \* must be followed by keyword-only parameters` + *args): ### `multiple \* parameters not allowed` + pass + +def k(*, **kwargs): ### `bare \* must be followed by keyword-only parameters` + pass + +def l(*): ### `bare \* must be followed by keyword-only parameters` + pass + +def m(*args, a=1, **kwargs): # ok + pass + +def n(*, a=1, **kwargs): # ok + pass + +--- +# No arguments may follow **kwargs in a call. +def f(*args, **kwargs): + pass + +f(**{}, 1) ### `argument may not follow \*\*kwargs` +f(**{}, x=1) ### `argument may not follow \*\*kwargs` +f(**{}, *[]) ### `\*args may not follow \*\*kwargs` +f(**{}, **{}) ### `multiple \*\*kwargs not allowed` + +--- +# Only **kwargs may follow *args in a call. +def f(*args, **kwargs): + pass + +f(*[], 1) ### `positional argument may not follow \*args` +f(*[], a=1) ### `keyword argument may not follow \*args` +f(*[], *[]) ### `multiple \*args not allowed` +f(*[], **{}) # ok + +--- +# Parameter names must be unique. + +def f(a, b, a): pass ### "duplicate parameter: a" +def g(args, b, *args): pass ### "duplicate parameter: args" +def h(kwargs, a, **kwargs): pass ### "duplicate parameter: kwargs" +def i(*x, **x): pass ### "duplicate parameter: x" + +--- +# Floating-point support is now standard. +a = float("3.141") +b = 1 / 2 +c = 3.141 + +--- +# option:globalreassign +# Legacy Bazel (and Python) semantics: def must precede use even for globals. + +_ = x ### `undefined: x` +x = 1 + +--- +# option:globalreassign +# Legacy Bazel (and Python) semantics: reassignment of globals is allowed. +x = 1 +x = 2 # ok + +--- +# option:globalreassign +# Redeclaration of predeclared names is allowed. + +# module-specific predeclared name +M = 1 # ok +M = 2 # ok (legacy) + +# universal predeclared name +U = 1 # ok +U = 1 # ok (legacy) + +--- +# https://github.com/bazelbuild/starlark/starlark/issues/21 +def f(**kwargs): pass +f(a=1, a=1) ### `keyword argument a repeated` + + +--- +# spelling + +print = U + +hello = 1 +print(hollo) ### `undefined: hollo \(did you mean hello\?\)` + +def f(abc): + print(abd) ### `undefined: abd \(did you mean abc\?\)` + print(goodbye) ### `undefined: goodbye$` + +--- +load("module", "x") # ok +x = 1 ### `cannot reassign local x` +load("module", "x") ### `cannot reassign top-level x` + +--- +# option:loadbindsglobally +load("module", "x") # ok +x = 1 ### `cannot reassign global x` +load("module", "x") ### `cannot reassign global x` + +--- +# option:globalreassign +load("module", "x") # ok +x = 1 # ok +load("module", "x") # ok + +--- +# option:globalreassign option:loadbindsglobally +load("module", "x") # ok +x = 1 +load("module", "x") # ok + +--- +_ = x # forward ref to file-local +load("module", "x") # ok |