Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1 | // 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 | |
| 5 | package gc |
| 6 | |
| 7 | import "cmd/internal/obj" |
| 8 | |
| 9 | /* |
| 10 | * range |
| 11 | */ |
| 12 | func typecheckrange(n *Node) { |
| 13 | var toomany int |
| 14 | var why string |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 15 | var t1 *Type |
| 16 | var t2 *Type |
| 17 | var v1 *Node |
| 18 | var v2 *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 19 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 32 | t := n.Right.Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 33 | if t == nil { |
| 34 | goto out |
| 35 | } |
| 36 | |
| 37 | // delicate little dance. see typecheckas2 |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 38 | for ll := n.List; ll != nil; ll = ll.Next { |
Russ Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 39 | if ll.N.Name == nil || ll.N.Name.Defn != n { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 40 | typecheck(&ll.N, Erv|Easgn) |
| 41 | } |
| 42 | } |
| 43 | |
Josh Bleecher Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 44 | if Isptr[t.Etype] && Isfixedarray(t.Type) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 45 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 64 | if t.Chan&Crecv == 0 { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 65 | Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 66 | 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 Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 105 | if v1.Name != nil && v1.Name.Defn == n { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 106 | v1.Type = t1 |
| 107 | } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 108 | Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, obj.FmtLong), why) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 109 | } |
| 110 | checkassign(n, v1) |
| 111 | } |
| 112 | |
| 113 | if v2 != nil { |
Russ Cox | 4fdd536 | 2015-05-26 22:19:27 -0400 | [diff] [blame] | 114 | if v2.Name != nil && v2.Name.Defn == n { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 115 | v2.Type = t2 |
| 116 | } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 { |
Russ Cox | 17228f4 | 2015-04-17 12:03:22 -0400 | [diff] [blame] | 117 | Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, obj.FmtLong), why) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 118 | } |
| 119 | checkassign(n, v2) |
| 120 | } |
| 121 | |
| 122 | // second half of dance |
| 123 | out: |
| 124 | n.Typecheck = 1 |
| 125 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 126 | for ll := n.List; ll != nil; ll = ll.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 127 | 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 | |
| 137 | func walkrange(n *Node) { |
Russ Cox | cdb7d7d | 2015-03-05 13:57:36 -0500 | [diff] [blame] | 138 | // 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 145 | t := n.Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 146 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 147 | a := n.Right |
| 148 | lno := int(setlineno(a)) |
Russ Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 149 | n.Right = nil |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 150 | |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 151 | var v1 *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 152 | if n.List != nil { |
| 153 | v1 = n.List.N |
| 154 | } |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 155 | var v2 *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 156 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 164 | var body *NodeList |
Russ Cox | 4492811 | 2015-03-02 20:34:22 -0500 | [diff] [blame] | 165 | var init *NodeList |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 166 | switch t.Etype { |
| 167 | default: |
| 168 | Fatal("walkrange") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 169 | |
| 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 180 | if Debug['N'] == 0 { |
| 181 | if flag_race == 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 182 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 187 | tmp := n.Nbody.N // first statement of body |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 188 | if tmp.Op == OAS { |
| 189 | if tmp.Left.Op == OINDEX { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 190 | if samesafeexpr(tmp.Left.Left, a) { |
| 191 | if samesafeexpr(tmp.Left.Right, v1) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 192 | if t.Type.Width > 0 { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 193 | if iszero(tmp.Right) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 194 | // 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 Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 204 | n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 205 | |
| 206 | // hp = &a[0] |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 207 | hp := temp(Ptrto(Types[TUINT8])) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 208 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 209 | tmp := Nod(OINDEX, a, Nodintconst(0)) |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 210 | tmp.Bounded = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 211 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 217 | hn := temp(Types[TUINTPTR]) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 218 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 225 | fn := mkcall("memclr", nil, nil, hp, hn) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 226 | |
| 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 Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 234 | typecheck(&n.Left, Erv) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 235 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 254 | ha := a |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 255 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 256 | hv1 := temp(Types[TINT]) |
| 257 | hn := temp(Types[TINT]) |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 258 | var hp *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 259 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 264 | tmp := Nod(OINDEX, ha, Nodintconst(0)) |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 265 | tmp.Bounded = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 266 | init = list(init, Nod(OAS, hp, Nod(OADDR, tmp, nil))) |
| 267 | } |
| 268 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 269 | n.Left = Nod(OLT, hv1, hn) |
Russ Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 270 | n.Right = Nod(OAS, hv1, Nod(OADD, hv1, Nodintconst(1))) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 271 | if v1 == nil { |
| 272 | body = nil |
| 273 | } else if v2 == nil { |
| 274 | body = list1(Nod(OAS, v1, hv1)) |
| 275 | } else { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 276 | a := Nod(OAS2, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 277 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 289 | tmp := Nod(OADD, hp, Nodintconst(t.Type.Width)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 290 | |
| 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 Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 297 | n.Right.Ninit = list1(a) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 298 | } |
| 299 | |
| 300 | // orderstmt allocated the iterator for us. |
| 301 | // we only use a once, so no copy needed. |
| 302 | case TMAP: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 303 | ha := a |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 304 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 305 | th := hiter(t) |
Russ Cox | 60e5f5b | 2015-05-26 23:05:35 -0400 | [diff] [blame] | 306 | hit := prealloc[n] |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 307 | hit.Type = th |
| 308 | n.Left = nil |
Keith Randall | cd5b144 | 2015-03-11 12:58:47 -0700 | [diff] [blame] | 309 | keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 310 | valname := newname(th.Type.Down.Sym) // ditto |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 311 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 312 | fn := syslook("mapiterinit", 1) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 313 | |
Russ Cox | 13f9c8b | 2015-03-08 13:33:49 -0400 | [diff] [blame] | 314 | substArgTypes(fn, t.Down, t.Type, th) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 315 | init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil))) |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 316 | n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil()) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 317 | |
| 318 | fn = syslook("mapiternext", 1) |
Russ Cox | 13f9c8b | 2015-03-08 13:33:49 -0400 | [diff] [blame] | 319 | substArgTypes(fn, th) |
Russ Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 320 | n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 321 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 322 | key := Nod(ODOT, hit, keyname) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 323 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 329 | val := Nod(ODOT, hit, valname) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 330 | val = Nod(OIND, val, nil) |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 331 | a := Nod(OAS2, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 332 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 339 | ha := a |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 340 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 341 | n.Left = nil |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 342 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 343 | hv1 := temp(t.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 344 | hv1.Typecheck = 1 |
| 345 | if haspointers(t.Type) { |
| 346 | init = list(init, Nod(OAS, hv1, nil)) |
| 347 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 348 | hb := temp(Types[TBOOL]) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 349 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 350 | n.Left = Nod(ONE, hb, Nodbool(false)) |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 351 | a := Nod(OAS2RECV, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 352 | a.Typecheck = 1 |
| 353 | a.List = list(list1(hv1), hb) |
| 354 | a.Rlist = list1(Nod(ORECV, ha, nil)) |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 355 | n.Left.Ninit = list1(a) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 356 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 364 | ha := a |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 365 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 366 | ohv1 := temp(Types[TINT]) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 367 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 368 | hv1 := temp(Types[TINT]) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 369 | init = list(init, Nod(OAS, hv1, nil)) |
| 370 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 371 | var a *Node |
Russ Cox | 4492811 | 2015-03-02 20:34:22 -0500 | [diff] [blame] | 372 | var hv2 *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 373 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 379 | fn := syslook("stringiter2", 0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 380 | a.Rlist = list1(mkcall1(fn, getoutargx(fn.Type), nil, ha, hv1)) |
| 381 | } |
| 382 | |
Russ Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 383 | n.Left = Nod(ONE, hv1, Nodintconst(0)) |
| 384 | n.Left.Ninit = list(list1(Nod(OAS, ohv1, hv1)), a) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 385 | |
| 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 Cox | 66be148 | 2015-05-26 21:30:20 -0400 | [diff] [blame] | 398 | typechecklist(n.Left.Ninit, Etop) |
| 399 | typecheck(&n.Left, Erv) |
Russ Cox | ffef180 | 2015-05-22 01:16:52 -0400 | [diff] [blame] | 400 | typecheck(&n.Right, Etop) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 401 | typechecklist(body, Etop) |
| 402 | n.Nbody = concat(body, n.Nbody) |
| 403 | walkstmt(&n) |
| 404 | |
| 405 | lineno = int32(lno) |
| 406 | } |