xref: /aosp_15_r20/external/starlark-go/starlark/testdata/assign.star (revision 4947cdc739c985f6d86941e22894f5cefe7c9e9a)
1*4947cdc7SCole Faust# Tests of Starlark assignment.
2*4947cdc7SCole Faust
3*4947cdc7SCole Faust# This is a "chunked" file: each "---" effectively starts a new file.
4*4947cdc7SCole Faust
5*4947cdc7SCole Faust# tuple assignment
6*4947cdc7SCole Faustload("assert.star", "assert")
7*4947cdc7SCole Faust
8*4947cdc7SCole Faust() = () # empty ok
9*4947cdc7SCole Faust
10*4947cdc7SCole Fausta, b, c = 1, 2, 3
11*4947cdc7SCole Faustassert.eq(a, 1)
12*4947cdc7SCole Faustassert.eq(b, 2)
13*4947cdc7SCole Faustassert.eq(c, 3)
14*4947cdc7SCole Faust
15*4947cdc7SCole Faust(d, e, f,) = (1, 2, 3) # trailing comma ok
16*4947cdc7SCole Faust---
17*4947cdc7SCole Faust(a, b, c) = 1 ### "got int in sequence assignment"
18*4947cdc7SCole Faust---
19*4947cdc7SCole Faust(a, b) = () ### "too few values to unpack"
20*4947cdc7SCole Faust---
21*4947cdc7SCole Faust(a, b) = (1,) ### "too few values to unpack"
22*4947cdc7SCole Faust---
23*4947cdc7SCole Faust(a, b, c) = (1, 2) ### "too few values to unpack"
24*4947cdc7SCole Faust---
25*4947cdc7SCole Faust(a, b) = (1, 2, 3) ### "too many values to unpack"
26*4947cdc7SCole Faust---
27*4947cdc7SCole Faust() = 1 ### "got int in sequence assignment"
28*4947cdc7SCole Faust---
29*4947cdc7SCole Faust() = (1,) ### "too many values to unpack"
30*4947cdc7SCole Faust---
31*4947cdc7SCole Faust() = (1, 2) ### "too many values to unpack"
32*4947cdc7SCole Faust---
33*4947cdc7SCole Faust# list assignment
34*4947cdc7SCole Faustload("assert.star", "assert")
35*4947cdc7SCole Faust
36*4947cdc7SCole Faust[] = [] # empty ok
37*4947cdc7SCole Faust
38*4947cdc7SCole Faust[a, b, c] = [1, 2, 3]
39*4947cdc7SCole Faustassert.eq(a, 1)
40*4947cdc7SCole Faustassert.eq(b, 2)
41*4947cdc7SCole Faustassert.eq(c, 3)
42*4947cdc7SCole Faust
43*4947cdc7SCole Faust[d, e, f,] = [1, 2, 3] # trailing comma ok
44*4947cdc7SCole Faust---
45*4947cdc7SCole Faust[a, b, c] = 1 ### "got int in sequence assignment"
46*4947cdc7SCole Faust---
47*4947cdc7SCole Faust[a, b] = [] ### "too few values to unpack"
48*4947cdc7SCole Faust---
49*4947cdc7SCole Faust[a, b] = [1] ### "too few values to unpack"
50*4947cdc7SCole Faust---
51*4947cdc7SCole Faust[a, b, c] = [1, 2] ### "too few values to unpack"
52*4947cdc7SCole Faust---
53*4947cdc7SCole Faust[a, b] = [1, 2, 3] ### "too many values to unpack"
54*4947cdc7SCole Faust---
55*4947cdc7SCole Faust[] = 1 ### "got int in sequence assignment"
56*4947cdc7SCole Faust---
57*4947cdc7SCole Faust[] = [1] ### "too many values to unpack"
58*4947cdc7SCole Faust---
59*4947cdc7SCole Faust[] = [1, 2] ### "too many values to unpack"
60*4947cdc7SCole Faust---
61*4947cdc7SCole Faust# list-tuple assignment
62*4947cdc7SCole Faustload("assert.star", "assert")
63*4947cdc7SCole Faust
64*4947cdc7SCole Faust# empty ok
65*4947cdc7SCole Faust[] = ()
66*4947cdc7SCole Faust() = []
67*4947cdc7SCole Faust
68*4947cdc7SCole Faust[a, b, c] = (1, 2, 3)
69*4947cdc7SCole Faustassert.eq(a, 1)
70*4947cdc7SCole Faustassert.eq(b, 2)
71*4947cdc7SCole Faustassert.eq(c, 3)
72*4947cdc7SCole Faust
73*4947cdc7SCole Faust[a2, b2, c2] = 1, 2, 3 # bare tuple ok
74*4947cdc7SCole Faust
75*4947cdc7SCole Faust(d, e, f) = [1, 2, 3]
76*4947cdc7SCole Faustassert.eq(d, 1)
77*4947cdc7SCole Faustassert.eq(e, 2)
78*4947cdc7SCole Faustassert.eq(f, 3)
79*4947cdc7SCole Faust
80*4947cdc7SCole Faust[g, h, (i, j)] = (1, 2, [3, 4])
81*4947cdc7SCole Faustassert.eq(g, 1)
82*4947cdc7SCole Faustassert.eq(h, 2)
83*4947cdc7SCole Faustassert.eq(i, 3)
84*4947cdc7SCole Faustassert.eq(j, 4)
85*4947cdc7SCole Faust
86*4947cdc7SCole Faust(k, l, [m, n]) = [1, 2, (3, 4)]
87*4947cdc7SCole Faustassert.eq(k, 1)
88*4947cdc7SCole Faustassert.eq(l, 2)
89*4947cdc7SCole Faustassert.eq(m, 3)
90*4947cdc7SCole Faustassert.eq(n, 4)
91*4947cdc7SCole Faust
92*4947cdc7SCole Faust---
93*4947cdc7SCole Faust# misc assignment
94*4947cdc7SCole Faustload("assert.star", "assert")
95*4947cdc7SCole Faust
96*4947cdc7SCole Faustdef assignment():
97*4947cdc7SCole Faust  a = [1, 2, 3]
98*4947cdc7SCole Faust  a[1] = 5
99*4947cdc7SCole Faust  assert.eq(a, [1, 5, 3])
100*4947cdc7SCole Faust  a[-2] = 2
101*4947cdc7SCole Faust  assert.eq(a, [1, 2, 3])
102*4947cdc7SCole Faust  assert.eq("%d %d" % (5, 7), "5 7")
103*4947cdc7SCole Faust  x={}
104*4947cdc7SCole Faust  x[1] = 2
105*4947cdc7SCole Faust  x[1] += 3
106*4947cdc7SCole Faust  assert.eq(x[1], 5)
107*4947cdc7SCole Faust  def f12(): x[(1, "abc", {})] = 1
108*4947cdc7SCole Faust  assert.fails(f12, "unhashable type: dict")
109*4947cdc7SCole Faust
110*4947cdc7SCole Faustassignment()
111*4947cdc7SCole Faust
112*4947cdc7SCole Faust---
113*4947cdc7SCole Faust# augmented assignment
114*4947cdc7SCole Faust
115*4947cdc7SCole Faustload("assert.star", "assert")
116*4947cdc7SCole Faust
117*4947cdc7SCole Faustdef f():
118*4947cdc7SCole Faust  x = 1
119*4947cdc7SCole Faust  x += 1
120*4947cdc7SCole Faust  assert.eq(x, 2)
121*4947cdc7SCole Faust  x *= 3
122*4947cdc7SCole Faust  assert.eq(x, 6)
123*4947cdc7SCole Faustf()
124*4947cdc7SCole Faust
125*4947cdc7SCole Faust---
126*4947cdc7SCole Faust# effects of evaluating LHS occur only once
127*4947cdc7SCole Faust
128*4947cdc7SCole Faustload("assert.star", "assert")
129*4947cdc7SCole Faust
130*4947cdc7SCole Faustcount = [0] # count[0] is the number of calls to f
131*4947cdc7SCole Faust
132*4947cdc7SCole Faustdef f():
133*4947cdc7SCole Faust  count[0] += 1
134*4947cdc7SCole Faust  return count[0]
135*4947cdc7SCole Faust
136*4947cdc7SCole Faustx = [1, 2, 3]
137*4947cdc7SCole Faustx[f()] += 1
138*4947cdc7SCole Faust
139*4947cdc7SCole Faustassert.eq(x, [1, 3, 3]) # sole call to f returned 1
140*4947cdc7SCole Faustassert.eq(count[0], 1) # f was called only once
141*4947cdc7SCole Faust
142*4947cdc7SCole Faust---
143*4947cdc7SCole Faust# Order of evaluation.
144*4947cdc7SCole Faust
145*4947cdc7SCole Faustload("assert.star", "assert")
146*4947cdc7SCole Faust
147*4947cdc7SCole Faustcalls = []
148*4947cdc7SCole Faust
149*4947cdc7SCole Faustdef f(name, result):
150*4947cdc7SCole Faust  calls.append(name)
151*4947cdc7SCole Faust  return result
152*4947cdc7SCole Faust
153*4947cdc7SCole Faust# The right side is evaluated before the left in an ordinary assignment.
154*4947cdc7SCole Faustcalls.clear()
155*4947cdc7SCole Faustf("array", [0])[f("index", 0)] = f("rhs", 0)
156*4947cdc7SCole Faustassert.eq(calls, ["rhs", "array", "index"])
157*4947cdc7SCole Faust
158*4947cdc7SCole Faustcalls.clear()
159*4947cdc7SCole Faustf("lhs1", [0])[0], f("lhs2", [0])[0] = f("rhs1", 0), f("rhs2", 0)
160*4947cdc7SCole Faustassert.eq(calls, ["rhs1", "rhs2", "lhs1", "lhs2"])
161*4947cdc7SCole Faust
162*4947cdc7SCole Faust# Left side is evaluated first (and only once) in an augmented assignment.
163*4947cdc7SCole Faustcalls.clear()
164*4947cdc7SCole Faustf("array", [0])[f("index", 0)] += f("addend", 1)
165*4947cdc7SCole Faustassert.eq(calls, ["array", "index", "addend"])
166*4947cdc7SCole Faust
167*4947cdc7SCole Faust---
168*4947cdc7SCole Faust# global referenced before assignment
169*4947cdc7SCole Faust
170*4947cdc7SCole Faustdef f():
171*4947cdc7SCole Faust   return g ### "global variable g referenced before assignment"
172*4947cdc7SCole Faust
173*4947cdc7SCole Faustf()
174*4947cdc7SCole Faust
175*4947cdc7SCole Faustg = 1
176*4947cdc7SCole Faust
177*4947cdc7SCole Faust---
178*4947cdc7SCole Faust# Free variables are captured by reference, so this is ok.
179*4947cdc7SCole Faustload("assert.star", "assert")
180*4947cdc7SCole Faust
181*4947cdc7SCole Faustdef f():
182*4947cdc7SCole Faust   def g():
183*4947cdc7SCole Faust     return outer
184*4947cdc7SCole Faust   outer = 1
185*4947cdc7SCole Faust   return g()
186*4947cdc7SCole Faust
187*4947cdc7SCole Faustassert.eq(f(), 1)
188*4947cdc7SCole Faust
189*4947cdc7SCole Faust---
190*4947cdc7SCole Faustload("assert.star", "assert")
191*4947cdc7SCole Faust
192*4947cdc7SCole Faustprintok = [False]
193*4947cdc7SCole Faust
194*4947cdc7SCole Faust# This program should resolve successfully but fail dynamically.
195*4947cdc7SCole Faust# However, the Java implementation currently reports the dynamic
196*4947cdc7SCole Faust# error at the x=1 statement (b/33975425).  I think we need to simplify
197*4947cdc7SCole Faust# the resolver algorithm to what we have implemented.
198*4947cdc7SCole Faustdef use_before_def():
199*4947cdc7SCole Faust  print(x) # dynamic error: local var referenced before assignment
200*4947cdc7SCole Faust  printok[0] = True
201*4947cdc7SCole Faust  x = 1  # makes 'x' local
202*4947cdc7SCole Faust
203*4947cdc7SCole Faustassert.fails(use_before_def, 'local variable x referenced before assignment')
204*4947cdc7SCole Faustassert.true(not printok[0]) # execution of print statement failed
205*4947cdc7SCole Faust
206*4947cdc7SCole Faust---
207*4947cdc7SCole Faustx = [1]
208*4947cdc7SCole Faustx.extend([2]) # ok
209*4947cdc7SCole Faust
210*4947cdc7SCole Faustdef f():
211*4947cdc7SCole Faust   x += [4] ### "local variable x referenced before assignment"
212*4947cdc7SCole Faust
213*4947cdc7SCole Faustf()
214*4947cdc7SCole Faust
215*4947cdc7SCole Faust---
216*4947cdc7SCole Faust
217*4947cdc7SCole Faustz += 3 ### "global variable z referenced before assignment"
218*4947cdc7SCole Faust
219*4947cdc7SCole Faust---
220*4947cdc7SCole Faustload("assert.star", "assert")
221*4947cdc7SCole Faust
222*4947cdc7SCole Faust# It's ok to define a global that shadows a built-in...
223*4947cdc7SCole Faustlist = []
224*4947cdc7SCole Faustassert.eq(type(list), "list")
225*4947cdc7SCole Faust
226*4947cdc7SCole Faust# ...but then all uses refer to the global,
227*4947cdc7SCole Faust# even if they occur before the binding use.
228*4947cdc7SCole Faust# See github.com/google/skylark/issues/116.
229*4947cdc7SCole Faustassert.fails(lambda: tuple, "global variable tuple referenced before assignment")
230*4947cdc7SCole Fausttuple = ()
231*4947cdc7SCole Faust
232*4947cdc7SCole Faust---
233*4947cdc7SCole Faust# option:set
234*4947cdc7SCole Faust# Same as above, but set is dialect-specific;
235*4947cdc7SCole Faust# we shouldn't notice any difference.
236*4947cdc7SCole Faustload("assert.star", "assert")
237*4947cdc7SCole Faust
238*4947cdc7SCole Faustset = [1, 2, 3]
239*4947cdc7SCole Faustassert.eq(type(set), "list")
240*4947cdc7SCole Faust
241*4947cdc7SCole Faust# As in Python 2 and Python 3,
242*4947cdc7SCole Faust# all 'in x' expressions in a comprehension are evaluated
243*4947cdc7SCole Faust# in the comprehension's lexical block, except the first,
244*4947cdc7SCole Faust# which is resolved in the outer block.
245*4947cdc7SCole Faustx = [[1, 2]]
246*4947cdc7SCole Faustassert.eq([x for x in x for y in x],
247*4947cdc7SCole Faust          [[1, 2], [1, 2]])
248*4947cdc7SCole Faust
249*4947cdc7SCole Faust---
250*4947cdc7SCole Faust# A comprehension establishes a single new lexical block,
251*4947cdc7SCole Faust# not one per 'for' clause.
252*4947cdc7SCole Faustx = [1, 2]
253*4947cdc7SCole Faust_ = [x for _ in [3] for x in x] ### "local variable x referenced before assignment"
254*4947cdc7SCole Faust
255*4947cdc7SCole Faust---
256*4947cdc7SCole Faustload("assert.star", "assert")
257*4947cdc7SCole Faust
258*4947cdc7SCole Faust# assign singleton sequence to 1-tuple
259*4947cdc7SCole Faust(x,) = (1,)
260*4947cdc7SCole Faustassert.eq(x, 1)
261*4947cdc7SCole Faust(y,) = [1]
262*4947cdc7SCole Faustassert.eq(y, 1)
263*4947cdc7SCole Faust
264*4947cdc7SCole Faust# assign 1-tuple to variable
265*4947cdc7SCole Faustz = (1,)
266*4947cdc7SCole Faustassert.eq(type(z), "tuple")
267*4947cdc7SCole Faustassert.eq(len(z), 1)
268*4947cdc7SCole Faustassert.eq(z[0], 1)
269*4947cdc7SCole Faust
270*4947cdc7SCole Faust# assign value to parenthesized variable
271*4947cdc7SCole Faust(a) = 1
272*4947cdc7SCole Faustassert.eq(a, 1)
273*4947cdc7SCole Faust
274*4947cdc7SCole Faust---
275*4947cdc7SCole Faust# assignment to/from fields.
276*4947cdc7SCole Faustload("assert.star", "assert", "freeze")
277*4947cdc7SCole Faust
278*4947cdc7SCole Fausthf = hasfields()
279*4947cdc7SCole Fausthf.x = 1
280*4947cdc7SCole Faustassert.eq(hf.x, 1)
281*4947cdc7SCole Fausthf.x = [1, 2]
282*4947cdc7SCole Fausthf.x += [3, 4]
283*4947cdc7SCole Faustassert.eq(hf.x, [1, 2, 3, 4])
284*4947cdc7SCole Faustfreeze(hf)
285*4947cdc7SCole Faustdef setX(hf):
286*4947cdc7SCole Faust  hf.x = 2
287*4947cdc7SCole Faustdef setY(hf):
288*4947cdc7SCole Faust  hf.y = 3
289*4947cdc7SCole Faustassert.fails(lambda: setX(hf), "cannot set field on a frozen hasfields")
290*4947cdc7SCole Faustassert.fails(lambda: setY(hf), "cannot set field on a frozen hasfields")
291*4947cdc7SCole Faust
292*4947cdc7SCole Faust---
293*4947cdc7SCole Faust# destucturing assignment in a for loop.
294*4947cdc7SCole Faustload("assert.star", "assert")
295*4947cdc7SCole Faust
296*4947cdc7SCole Faustdef f():
297*4947cdc7SCole Faust  res = []
298*4947cdc7SCole Faust  for (x, y), z in [(["a", "b"], 3), (["c", "d"], 4)]:
299*4947cdc7SCole Faust    res.append((x, y, z))
300*4947cdc7SCole Faust  return res
301*4947cdc7SCole Faustassert.eq(f(), [("a", "b", 3), ("c", "d", 4)])
302*4947cdc7SCole Faust
303*4947cdc7SCole Faustdef g():
304*4947cdc7SCole Faust  a = {}
305*4947cdc7SCole Faust  for i, a[i] in [("one", 1), ("two", 2)]:
306*4947cdc7SCole Faust    pass
307*4947cdc7SCole Faust  return a
308*4947cdc7SCole Faustassert.eq(g(), {"one": 1, "two": 2})
309*4947cdc7SCole Faust
310*4947cdc7SCole Faust---
311*4947cdc7SCole Faust# parenthesized LHS in augmented assignment (success)
312*4947cdc7SCole Faust# option:globalreassign
313*4947cdc7SCole Faustload("assert.star", "assert")
314*4947cdc7SCole Faust
315*4947cdc7SCole Fausta = 5
316*4947cdc7SCole Faust(a) += 3
317*4947cdc7SCole Faustassert.eq(a, 8)
318*4947cdc7SCole Faust
319*4947cdc7SCole Faust---
320*4947cdc7SCole Faust# parenthesized LHS in augmented assignment (error)
321*4947cdc7SCole Faust
322*4947cdc7SCole Faust(a) += 5 ### "global variable a referenced before assignment"
323*4947cdc7SCole Faust
324*4947cdc7SCole Faust---
325*4947cdc7SCole Faust# option:globalreassign
326*4947cdc7SCole Faustload("assert.star", "assert")
327*4947cdc7SCole Faustassert = 1
328*4947cdc7SCole Faustload("assert.star", "assert")
329*4947cdc7SCole Faust
330*4947cdc7SCole Faust---
331*4947cdc7SCole Faust# option:globalreassign option:loadbindsglobally
332*4947cdc7SCole Faustload("assert.star", "assert")
333*4947cdc7SCole Faustassert = 1
334*4947cdc7SCole Faustload("assert.star", "assert")
335*4947cdc7SCole Faust
336*4947cdc7SCole Faust---
337*4947cdc7SCole Faust# option:loadbindsglobally
338*4947cdc7SCole Faust_ = assert ### "global variable assert referenced before assignment"
339*4947cdc7SCole Faustload("assert.star", "assert")
340*4947cdc7SCole Faust
341*4947cdc7SCole Faust---
342*4947cdc7SCole Faust_ = assert ### "local variable assert referenced before assignment"
343*4947cdc7SCole Faustload("assert.star", "assert")
344*4947cdc7SCole Faust
345*4947cdc7SCole Faust---
346*4947cdc7SCole Faustdef f(): assert.eq(1, 1) # forward ref OK
347*4947cdc7SCole Faustload("assert.star", "assert")
348*4947cdc7SCole Faustf()
349*4947cdc7SCole Faust
350*4947cdc7SCole Faust---
351*4947cdc7SCole Faust# option:loadbindsglobally
352*4947cdc7SCole Faustdef f(): assert.eq(1, 1) # forward ref OK
353*4947cdc7SCole Faustload("assert.star", "assert")
354*4947cdc7SCole Faustf()
355