blob: 26f05d9d70b89bf5c30f57d63a4a62f7785d9120 [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package gc
6
7import "cmd/internal/obj"
8
9/*
10 * range
11 */
12func typecheckrange(n *Node) {
13 var toomany int
14 var why string
Russ Cox8c195bd2015-02-13 14:40:36 -050015 var t1 *Type
16 var t2 *Type
17 var v1 *Node
18 var v2 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -050019
20 // Typechecking order is important here:
21 // 0. first typecheck range expression (slice/map/chan),
22 // it is evaluated only once and so logically it is not part of the loop.
23 // 1. typcheck produced values,
24 // this part can declare new vars and so it must be typechecked before body,
25 // because body can contain a closure that captures the vars.
26 // 2. decldepth++ to denote loop body.
27 // 3. typecheck body.
28 // 4. decldepth--.
29
30 typecheck(&n.Right, Erv)
31
Russ Cox382b44e2015-02-23 16:07:24 -050032 t := n.Right.Type
Russ Cox8c195bd2015-02-13 14:40:36 -050033 if t == nil {
34 goto out
35 }
36
37 // delicate little dance. see typecheckas2
Russ Cox382b44e2015-02-23 16:07:24 -050038 for ll := n.List; ll != nil; ll = ll.Next {
Russ Cox4fdd5362015-05-26 22:19:27 -040039 if ll.N.Name == nil || ll.N.Name.Defn != n {
Russ Cox8c195bd2015-02-13 14:40:36 -050040 typecheck(&ll.N, Erv|Easgn)
41 }
42 }
43
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +000044 if Isptr[t.Etype] && Isfixedarray(t.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -050045 t = t.Type
46 }
47 n.Type = t
48
49 toomany = 0
50 switch t.Etype {
51 default:
52 Yyerror("cannot range over %v", Nconv(n.Right, obj.FmtLong))
53 goto out
54
55 case TARRAY:
56 t1 = Types[TINT]
57 t2 = t.Type
58
59 case TMAP:
60 t1 = t.Down
61 t2 = t.Type
62
63 case TCHAN:
Russ Coxdc7b54b2015-02-17 22:13:49 -050064 if t.Chan&Crecv == 0 {
Russ Cox17228f42015-04-17 12:03:22 -040065 Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -050066 goto out
67 }
68
69 t1 = t.Type
70 t2 = nil
71 if count(n.List) == 2 {
72 toomany = 1
73 }
74
75 case TSTRING:
76 t1 = Types[TINT]
77 t2 = runetype
78 }
79
80 if count(n.List) > 2 || toomany != 0 {
81 Yyerror("too many variables in range")
82 }
83
84 v1 = nil
85 if n.List != nil {
86 v1 = n.List.N
87 }
88 v2 = nil
89 if n.List != nil && n.List.Next != nil {
90 v2 = n.List.Next.N
91 }
92
93 // this is not only a optimization but also a requirement in the spec.
94 // "if the second iteration variable is the blank identifier, the range
95 // clause is equivalent to the same clause with only the first variable
96 // present."
97 if isblank(v2) {
98 if v1 != nil {
99 n.List = list1(v1)
100 }
101 v2 = nil
102 }
103
104 if v1 != nil {
Russ Cox4fdd5362015-05-26 22:19:27 -0400105 if v1.Name != nil && v1.Name.Defn == n {
Russ Cox8c195bd2015-02-13 14:40:36 -0500106 v1.Type = t1
107 } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
Russ Cox17228f42015-04-17 12:03:22 -0400108 Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, obj.FmtLong), why)
Russ Cox8c195bd2015-02-13 14:40:36 -0500109 }
110 checkassign(n, v1)
111 }
112
113 if v2 != nil {
Russ Cox4fdd5362015-05-26 22:19:27 -0400114 if v2.Name != nil && v2.Name.Defn == n {
Russ Cox8c195bd2015-02-13 14:40:36 -0500115 v2.Type = t2
116 } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
Russ Cox17228f42015-04-17 12:03:22 -0400117 Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, obj.FmtLong), why)
Russ Cox8c195bd2015-02-13 14:40:36 -0500118 }
119 checkassign(n, v2)
120 }
121
122 // second half of dance
123out:
124 n.Typecheck = 1
125
Russ Cox382b44e2015-02-23 16:07:24 -0500126 for ll := n.List; ll != nil; ll = ll.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -0500127 if ll.N.Typecheck == 0 {
128 typecheck(&ll.N, Erv|Easgn)
129 }
130 }
131
132 decldepth++
133 typechecklist(n.Nbody, Etop)
134 decldepth--
135}
136
137func walkrange(n *Node) {
Russ Coxcdb7d7d2015-03-05 13:57:36 -0500138 // variable name conventions:
139 // ohv1, hv1, hv2: hidden (old) val 1, 2
140 // ha, hit: hidden aggregate, iterator
141 // hn, hp: hidden len, pointer
142 // hb: hidden bool
143 // a, v1, v2: not hidden aggregate, val 1, 2
144
Russ Cox382b44e2015-02-23 16:07:24 -0500145 t := n.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500146
Russ Cox382b44e2015-02-23 16:07:24 -0500147 a := n.Right
148 lno := int(setlineno(a))
Russ Coxffef1802015-05-22 01:16:52 -0400149 n.Right = nil
Russ Cox8c195bd2015-02-13 14:40:36 -0500150
Russ Cox175929b2015-03-02 14:22:05 -0500151 var v1 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500152 if n.List != nil {
153 v1 = n.List.N
154 }
Russ Cox175929b2015-03-02 14:22:05 -0500155 var v2 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500156 if n.List != nil && n.List.Next != nil && !isblank(n.List.Next.N) {
157 v2 = n.List.Next.N
158 }
159
160 // n->list has no meaning anymore, clear it
161 // to avoid erroneous processing by racewalk.
162 n.List = nil
163
Russ Cox382b44e2015-02-23 16:07:24 -0500164 var body *NodeList
Russ Cox44928112015-03-02 20:34:22 -0500165 var init *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500166 switch t.Etype {
167 default:
168 Fatal("walkrange")
Russ Cox8c195bd2015-02-13 14:40:36 -0500169
170 // Lower n into runtime·memclr if possible, for
171 // fast zeroing of slices and arrays (issue 5373).
172 // Look for instances of
173 //
174 // for i := range a {
175 // a[i] = zero
176 // }
177 //
178 // in which the evaluation of a is side-effect-free.
179 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500180 if Debug['N'] == 0 {
181 if flag_race == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500182 if v1 != nil {
183 if v2 == nil {
184 if n.Nbody != nil {
185 if n.Nbody.N != nil { // at least one statement in body
186 if n.Nbody.Next == nil { // at most one statement in body
Russ Cox382b44e2015-02-23 16:07:24 -0500187 tmp := n.Nbody.N // first statement of body
Russ Cox8c195bd2015-02-13 14:40:36 -0500188 if tmp.Op == OAS {
189 if tmp.Left.Op == OINDEX {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500190 if samesafeexpr(tmp.Left.Left, a) {
191 if samesafeexpr(tmp.Left.Right, v1) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500192 if t.Type.Width > 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500193 if iszero(tmp.Right) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500194 // Convert to
195 // if len(a) != 0 {
196 // hp = &a[0]
197 // hn = len(a)*sizeof(elem(a))
198 // memclr(hp, hn)
199 // i = len(a) - 1
200 // }
201 n.Op = OIF
202
203 n.Nbody = nil
Russ Cox66be1482015-05-26 21:30:20 -0400204 n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500205
206 // hp = &a[0]
Russ Cox382b44e2015-02-23 16:07:24 -0500207 hp := temp(Ptrto(Types[TUINT8]))
Russ Cox8c195bd2015-02-13 14:40:36 -0500208
Russ Cox382b44e2015-02-23 16:07:24 -0500209 tmp := Nod(OINDEX, a, Nodintconst(0))
Russ Coxdc7b54b2015-02-17 22:13:49 -0500210 tmp.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500211 tmp = Nod(OADDR, tmp, nil)
212 tmp = Nod(OCONVNOP, tmp, nil)
213 tmp.Type = Ptrto(Types[TUINT8])
214 n.Nbody = list(n.Nbody, Nod(OAS, hp, tmp))
215
216 // hn = len(a) * sizeof(elem(a))
Russ Cox382b44e2015-02-23 16:07:24 -0500217 hn := temp(Types[TUINTPTR])
Russ Cox8c195bd2015-02-13 14:40:36 -0500218
219 tmp = Nod(OLEN, a, nil)
220 tmp = Nod(OMUL, tmp, Nodintconst(t.Type.Width))
221 tmp = conv(tmp, Types[TUINTPTR])
222 n.Nbody = list(n.Nbody, Nod(OAS, hn, tmp))
223
224 // memclr(hp, hn)
Russ Cox382b44e2015-02-23 16:07:24 -0500225 fn := mkcall("memclr", nil, nil, hp, hn)
Russ Cox8c195bd2015-02-13 14:40:36 -0500226
227 n.Nbody = list(n.Nbody, fn)
228
229 // i = len(a) - 1
230 v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1)))
231
232 n.Nbody = list(n.Nbody, v1)
233
Russ Cox66be1482015-05-26 21:30:20 -0400234 typecheck(&n.Left, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -0500235 typechecklist(n.Nbody, Etop)
236 walkstmt(&n)
237 lineno = int32(lno)
238 return
239 }
240 }
241 }
242 }
243 }
244 }
245 }
246 }
247 }
248 }
249 }
250 }
251 }
252
253 // orderstmt arranged for a copy of the array/slice variable if needed.
Russ Cox382b44e2015-02-23 16:07:24 -0500254 ha := a
Russ Cox8c195bd2015-02-13 14:40:36 -0500255
Russ Cox382b44e2015-02-23 16:07:24 -0500256 hv1 := temp(Types[TINT])
257 hn := temp(Types[TINT])
Russ Cox175929b2015-03-02 14:22:05 -0500258 var hp *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500259
260 init = list(init, Nod(OAS, hv1, nil))
261 init = list(init, Nod(OAS, hn, Nod(OLEN, ha, nil)))
262 if v2 != nil {
263 hp = temp(Ptrto(n.Type.Type))
Russ Cox382b44e2015-02-23 16:07:24 -0500264 tmp := Nod(OINDEX, ha, Nodintconst(0))
Russ Coxdc7b54b2015-02-17 22:13:49 -0500265 tmp.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500266 init = list(init, Nod(OAS, hp, Nod(OADDR, tmp, nil)))
267 }
268
Russ Cox66be1482015-05-26 21:30:20 -0400269 n.Left = Nod(OLT, hv1, hn)
Russ Coxffef1802015-05-22 01:16:52 -0400270 n.Right = Nod(OAS, hv1, Nod(OADD, hv1, Nodintconst(1)))
Russ Cox8c195bd2015-02-13 14:40:36 -0500271 if v1 == nil {
272 body = nil
273 } else if v2 == nil {
274 body = list1(Nod(OAS, v1, hv1))
275 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500276 a := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500277 a.List = list(list1(v1), v2)
278 a.Rlist = list(list1(hv1), Nod(OIND, hp, nil))
279 body = list1(a)
280
281 // Advance pointer as part of increment.
282 // We used to advance the pointer before executing the loop body,
283 // but doing so would make the pointer point past the end of the
284 // array during the final iteration, possibly causing another unrelated
285 // piece of memory not to be garbage collected until the loop finished.
286 // Advancing during the increment ensures that the pointer p only points
287 // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
288 // after which p is dead, so it cannot confuse the collector.
Russ Cox382b44e2015-02-23 16:07:24 -0500289 tmp := Nod(OADD, hp, Nodintconst(t.Type.Width))
Russ Cox8c195bd2015-02-13 14:40:36 -0500290
291 tmp.Type = hp.Type
292 tmp.Typecheck = 1
293 tmp.Right.Type = Types[Tptr]
294 tmp.Right.Typecheck = 1
295 a = Nod(OAS, hp, tmp)
296 typecheck(&a, Etop)
Russ Coxffef1802015-05-22 01:16:52 -0400297 n.Right.Ninit = list1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500298 }
299
300 // orderstmt allocated the iterator for us.
301 // we only use a once, so no copy needed.
302 case TMAP:
Russ Cox382b44e2015-02-23 16:07:24 -0500303 ha := a
Russ Cox8c195bd2015-02-13 14:40:36 -0500304
Russ Cox382b44e2015-02-23 16:07:24 -0500305 th := hiter(t)
Russ Cox60e5f5b2015-05-26 23:05:35 -0400306 hit := prealloc[n]
Russ Cox8c195bd2015-02-13 14:40:36 -0500307 hit.Type = th
308 n.Left = nil
Keith Randallcd5b1442015-03-11 12:58:47 -0700309 keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter
Russ Cox382b44e2015-02-23 16:07:24 -0500310 valname := newname(th.Type.Down.Sym) // ditto
Russ Cox8c195bd2015-02-13 14:40:36 -0500311
Russ Cox382b44e2015-02-23 16:07:24 -0500312 fn := syslook("mapiterinit", 1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500313
Russ Cox13f9c8b2015-03-08 13:33:49 -0400314 substArgTypes(fn, t.Down, t.Type, th)
Russ Cox8c195bd2015-02-13 14:40:36 -0500315 init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
Russ Cox66be1482015-05-26 21:30:20 -0400316 n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil())
Russ Cox8c195bd2015-02-13 14:40:36 -0500317
318 fn = syslook("mapiternext", 1)
Russ Cox13f9c8b2015-03-08 13:33:49 -0400319 substArgTypes(fn, th)
Russ Coxffef1802015-05-22 01:16:52 -0400320 n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -0500321
Russ Cox382b44e2015-02-23 16:07:24 -0500322 key := Nod(ODOT, hit, keyname)
Russ Cox8c195bd2015-02-13 14:40:36 -0500323 key = Nod(OIND, key, nil)
324 if v1 == nil {
325 body = nil
326 } else if v2 == nil {
327 body = list1(Nod(OAS, v1, key))
328 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500329 val := Nod(ODOT, hit, valname)
Russ Cox8c195bd2015-02-13 14:40:36 -0500330 val = Nod(OIND, val, nil)
Russ Cox382b44e2015-02-23 16:07:24 -0500331 a := Nod(OAS2, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500332 a.List = list(list1(v1), v2)
333 a.Rlist = list(list1(key), val)
334 body = list1(a)
335 }
336
337 // orderstmt arranged for a copy of the channel variable.
338 case TCHAN:
Russ Cox382b44e2015-02-23 16:07:24 -0500339 ha := a
Russ Cox8c195bd2015-02-13 14:40:36 -0500340
Russ Cox66be1482015-05-26 21:30:20 -0400341 n.Left = nil
Russ Cox8c195bd2015-02-13 14:40:36 -0500342
Russ Cox382b44e2015-02-23 16:07:24 -0500343 hv1 := temp(t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500344 hv1.Typecheck = 1
345 if haspointers(t.Type) {
346 init = list(init, Nod(OAS, hv1, nil))
347 }
Russ Cox382b44e2015-02-23 16:07:24 -0500348 hb := temp(Types[TBOOL])
Russ Cox8c195bd2015-02-13 14:40:36 -0500349
Russ Cox66be1482015-05-26 21:30:20 -0400350 n.Left = Nod(ONE, hb, Nodbool(false))
Russ Cox382b44e2015-02-23 16:07:24 -0500351 a := Nod(OAS2RECV, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500352 a.Typecheck = 1
353 a.List = list(list1(hv1), hb)
354 a.Rlist = list1(Nod(ORECV, ha, nil))
Russ Cox66be1482015-05-26 21:30:20 -0400355 n.Left.Ninit = list1(a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500356 if v1 == nil {
357 body = nil
358 } else {
359 body = list1(Nod(OAS, v1, hv1))
360 }
361
362 // orderstmt arranged for a copy of the string variable.
363 case TSTRING:
Russ Cox382b44e2015-02-23 16:07:24 -0500364 ha := a
Russ Cox8c195bd2015-02-13 14:40:36 -0500365
Russ Cox382b44e2015-02-23 16:07:24 -0500366 ohv1 := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -0500367
Russ Cox382b44e2015-02-23 16:07:24 -0500368 hv1 := temp(Types[TINT])
Russ Cox8c195bd2015-02-13 14:40:36 -0500369 init = list(init, Nod(OAS, hv1, nil))
370
Russ Cox382b44e2015-02-23 16:07:24 -0500371 var a *Node
Russ Cox44928112015-03-02 20:34:22 -0500372 var hv2 *Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500373 if v2 == nil {
374 a = Nod(OAS, hv1, mkcall("stringiter", Types[TINT], nil, ha, hv1))
375 } else {
376 hv2 = temp(runetype)
377 a = Nod(OAS2, nil, nil)
378 a.List = list(list1(hv1), hv2)
Russ Cox382b44e2015-02-23 16:07:24 -0500379 fn := syslook("stringiter2", 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500380 a.Rlist = list1(mkcall1(fn, getoutargx(fn.Type), nil, ha, hv1))
381 }
382
Russ Cox66be1482015-05-26 21:30:20 -0400383 n.Left = Nod(ONE, hv1, Nodintconst(0))
384 n.Left.Ninit = list(list1(Nod(OAS, ohv1, hv1)), a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500385
386 body = nil
387 if v1 != nil {
388 body = list1(Nod(OAS, v1, ohv1))
389 }
390 if v2 != nil {
391 body = list(body, Nod(OAS, v2, hv2))
392 }
393 }
394
395 n.Op = OFOR
396 typechecklist(init, Etop)
397 n.Ninit = concat(n.Ninit, init)
Russ Cox66be1482015-05-26 21:30:20 -0400398 typechecklist(n.Left.Ninit, Etop)
399 typecheck(&n.Left, Erv)
Russ Coxffef1802015-05-22 01:16:52 -0400400 typecheck(&n.Right, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -0500401 typechecklist(body, Etop)
402 n.Nbody = concat(body, n.Nbody)
403 walkstmt(&n)
404
405 lineno = int32(lno)
406}