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 15 var t1 *Type 16 var t2 *Type 17 var v1 *Node 18 var v2 *Node 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 32 t := n.Right.Type 33 if t == nil { 34 goto out 35 } 36 37 // delicate little dance. see typecheckas2 38 for ll := n.List; ll != nil; ll = ll.Next { 39 if ll.N.Name == nil || ll.N.Name.Defn != n { 40 typecheck(&ll.N, Erv|Easgn) 41 } 42 } 43 44 if Isptr[t.Etype] && Isfixedarray(t.Type) { 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: 64 if t.Chan&Crecv == 0 { 65 Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type) 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 { 105 if v1.Name != nil && v1.Name.Defn == n { 106 v1.Type = t1 107 } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 { 108 Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, obj.FmtLong), why) 109 } 110 checkassign(n, v1) 111 } 112 113 if v2 != nil { 114 if v2.Name != nil && v2.Name.Defn == n { 115 v2.Type = t2 116 } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 { 117 Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, obj.FmtLong), why) 118 } 119 checkassign(n, v2) 120 } 121 122 // second half of dance 123 out: 124 n.Typecheck = 1 125 126 for ll := n.List; ll != nil; ll = ll.Next { 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) { 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 145 t := n.Type 146 147 a := n.Right 148 lno := int(setlineno(a)) 149 n.Right = nil 150 151 var v1 *Node 152 if n.List != nil { 153 v1 = n.List.N 154 } 155 var v2 *Node 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 164 var body *NodeList 165 var init *NodeList 166 switch t.Etype { 167 default: 168 Fatal("walkrange") 169 170 // Lower n into runtimememclr 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: 180 if Debug['N'] == 0 { 181 if flag_race == 0 { 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 187 tmp := n.Nbody.N // first statement of body 188 if tmp.Op == OAS { 189 if tmp.Left.Op == OINDEX { 190 if samesafeexpr(tmp.Left.Left, a) { 191 if samesafeexpr(tmp.Left.Right, v1) { 192 if t.Type.Width > 0 { 193 if iszero(tmp.Right) { 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 204 n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0)) 205 206 // hp = &a[0] 207 hp := temp(Ptrto(Types[TUINT8])) 208 209 tmp := Nod(OINDEX, a, Nodintconst(0)) 210 tmp.Bounded = true 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)) 217 hn := temp(Types[TUINTPTR]) 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) 225 fn := mkcall("memclr", nil, nil, hp, hn) 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 234 typecheck(&n.Left, Erv) 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. 254 ha := a 255 256 hv1 := temp(Types[TINT]) 257 hn := temp(Types[TINT]) 258 var hp *Node 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)) 264 tmp := Nod(OINDEX, ha, Nodintconst(0)) 265 tmp.Bounded = true 266 init = list(init, Nod(OAS, hp, Nod(OADDR, tmp, nil))) 267 } 268 269 n.Left = Nod(OLT, hv1, hn) 270 n.Right = Nod(OAS, hv1, Nod(OADD, hv1, Nodintconst(1))) 271 if v1 == nil { 272 body = nil 273 } else if v2 == nil { 274 body = list1(Nod(OAS, v1, hv1)) 275 } else { 276 a := Nod(OAS2, nil, nil) 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. 289 tmp := Nod(OADD, hp, Nodintconst(t.Type.Width)) 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) 297 n.Right.Ninit = list1(a) 298 } 299 300 // orderstmt allocated the iterator for us. 301 // we only use a once, so no copy needed. 302 case TMAP: 303 ha := a 304 305 th := hiter(t) 306 hit := prealloc[n] 307 hit.Type = th 308 n.Left = nil 309 keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter 310 valname := newname(th.Type.Down.Sym) // ditto 311 312 fn := syslook("mapiterinit", 1) 313 314 substArgTypes(fn, t.Down, t.Type, th) 315 init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil))) 316 n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil()) 317 318 fn = syslook("mapiternext", 1) 319 substArgTypes(fn, th) 320 n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil)) 321 322 key := Nod(ODOT, hit, keyname) 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 { 329 val := Nod(ODOT, hit, valname) 330 val = Nod(OIND, val, nil) 331 a := Nod(OAS2, nil, nil) 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: 339 ha := a 340 341 n.Left = nil 342 343 hv1 := temp(t.Type) 344 hv1.Typecheck = 1 345 if haspointers(t.Type) { 346 init = list(init, Nod(OAS, hv1, nil)) 347 } 348 hb := temp(Types[TBOOL]) 349 350 n.Left = Nod(ONE, hb, Nodbool(false)) 351 a := Nod(OAS2RECV, nil, nil) 352 a.Typecheck = 1 353 a.List = list(list1(hv1), hb) 354 a.Rlist = list1(Nod(ORECV, ha, nil)) 355 n.Left.Ninit = list1(a) 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: 364 ha := a 365 366 ohv1 := temp(Types[TINT]) 367 368 hv1 := temp(Types[TINT]) 369 init = list(init, Nod(OAS, hv1, nil)) 370 371 var a *Node 372 var hv2 *Node 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) 379 fn := syslook("stringiter2", 0) 380 a.Rlist = list1(mkcall1(fn, getoutargx(fn.Type), nil, ha, hv1)) 381 } 382 383 n.Left = Nod(ONE, hv1, Nodintconst(0)) 384 n.Left.Ninit = list(list1(Nod(OAS, ohv1, hv1)), a) 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) 398 typechecklist(n.Left.Ninit, Etop) 399 typecheck(&n.Left, Erv) 400 typecheck(&n.Right, Etop) 401 typechecklist(body, Etop) 402 n.Nbody = concat(body, n.Nbody) 403 walkstmt(&n) 404 405 lineno = int32(lno) 406 } 407