github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/range.go (about) 1 // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/range.go 2 3 // Copyright 2009 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package gc 8 9 import "rsc.io/tmp/bootstrap/internal/obj" 10 11 /* 12 * range 13 */ 14 func typecheckrange(n *Node) { 15 var toomany int 16 var why string 17 var t1 *Type 18 var t2 *Type 19 var v1 *Node 20 var v2 *Node 21 22 // Typechecking order is important here: 23 // 0. first typecheck range expression (slice/map/chan), 24 // it is evaluated only once and so logically it is not part of the loop. 25 // 1. typcheck produced values, 26 // this part can declare new vars and so it must be typechecked before body, 27 // because body can contain a closure that captures the vars. 28 // 2. decldepth++ to denote loop body. 29 // 3. typecheck body. 30 // 4. decldepth--. 31 32 typecheck(&n.Right, Erv) 33 34 t := n.Right.Type 35 if t == nil { 36 goto out 37 } 38 39 // delicate little dance. see typecheckas2 40 for ll := n.List; ll != nil; ll = ll.Next { 41 if ll.N.Defn != n { 42 typecheck(&ll.N, Erv|Easgn) 43 } 44 } 45 46 if Isptr[t.Etype] && Isfixedarray(t.Type) { 47 t = t.Type 48 } 49 n.Type = t 50 51 toomany = 0 52 switch t.Etype { 53 default: 54 Yyerror("cannot range over %v", Nconv(n.Right, obj.FmtLong)) 55 goto out 56 57 case TARRAY: 58 t1 = Types[TINT] 59 t2 = t.Type 60 61 case TMAP: 62 t1 = t.Down 63 t2 = t.Type 64 65 case TCHAN: 66 if t.Chan&Crecv == 0 { 67 Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type) 68 goto out 69 } 70 71 t1 = t.Type 72 t2 = nil 73 if count(n.List) == 2 { 74 toomany = 1 75 } 76 77 case TSTRING: 78 t1 = Types[TINT] 79 t2 = runetype 80 } 81 82 if count(n.List) > 2 || toomany != 0 { 83 Yyerror("too many variables in range") 84 } 85 86 v1 = nil 87 if n.List != nil { 88 v1 = n.List.N 89 } 90 v2 = nil 91 if n.List != nil && n.List.Next != nil { 92 v2 = n.List.Next.N 93 } 94 95 // this is not only a optimization but also a requirement in the spec. 96 // "if the second iteration variable is the blank identifier, the range 97 // clause is equivalent to the same clause with only the first variable 98 // present." 99 if isblank(v2) { 100 if v1 != nil { 101 n.List = list1(v1) 102 } 103 v2 = nil 104 } 105 106 if v1 != nil { 107 if v1.Defn == n { 108 v1.Type = t1 109 } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 { 110 Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, obj.FmtLong), why) 111 } 112 checkassign(n, v1) 113 } 114 115 if v2 != nil { 116 if v2.Defn == n { 117 v2.Type = t2 118 } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 { 119 Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, obj.FmtLong), why) 120 } 121 checkassign(n, v2) 122 } 123 124 // second half of dance 125 out: 126 n.Typecheck = 1 127 128 for ll := n.List; ll != nil; ll = ll.Next { 129 if ll.N.Typecheck == 0 { 130 typecheck(&ll.N, Erv|Easgn) 131 } 132 } 133 134 decldepth++ 135 typechecklist(n.Nbody, Etop) 136 decldepth-- 137 } 138 139 func walkrange(n *Node) { 140 // variable name conventions: 141 // ohv1, hv1, hv2: hidden (old) val 1, 2 142 // ha, hit: hidden aggregate, iterator 143 // hn, hp: hidden len, pointer 144 // hb: hidden bool 145 // a, v1, v2: not hidden aggregate, val 1, 2 146 147 t := n.Type 148 149 a := n.Right 150 lno := int(setlineno(a)) 151 152 var v1 *Node 153 if n.List != nil { 154 v1 = n.List.N 155 } 156 var v2 *Node 157 if n.List != nil && n.List.Next != nil && !isblank(n.List.Next.N) { 158 v2 = n.List.Next.N 159 } 160 161 // n->list has no meaning anymore, clear it 162 // to avoid erroneous processing by racewalk. 163 n.List = nil 164 165 var body *NodeList 166 var init *NodeList 167 switch t.Etype { 168 default: 169 Fatal("walkrange") 170 171 // Lower n into runtime·memclr if possible, for 172 // fast zeroing of slices and arrays (issue 5373). 173 // Look for instances of 174 // 175 // for i := range a { 176 // a[i] = zero 177 // } 178 // 179 // in which the evaluation of a is side-effect-free. 180 case TARRAY: 181 if Debug['N'] == 0 { 182 if flag_race == 0 { 183 if v1 != nil { 184 if v2 == nil { 185 if n.Nbody != nil { 186 if n.Nbody.N != nil { // at least one statement in body 187 if n.Nbody.Next == nil { // at most one statement in body 188 tmp := n.Nbody.N // first statement of body 189 if tmp.Op == OAS { 190 if tmp.Left.Op == OINDEX { 191 if samesafeexpr(tmp.Left.Left, a) { 192 if samesafeexpr(tmp.Left.Right, v1) { 193 if t.Type.Width > 0 { 194 if iszero(tmp.Right) { 195 // Convert to 196 // if len(a) != 0 { 197 // hp = &a[0] 198 // hn = len(a)*sizeof(elem(a)) 199 // memclr(hp, hn) 200 // i = len(a) - 1 201 // } 202 n.Op = OIF 203 204 n.Nbody = nil 205 n.Ntest = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0)) 206 n.Nincr = nil 207 208 // hp = &a[0] 209 hp := temp(Ptrto(Types[TUINT8])) 210 211 tmp := Nod(OINDEX, a, Nodintconst(0)) 212 tmp.Bounded = true 213 tmp = Nod(OADDR, tmp, nil) 214 tmp = Nod(OCONVNOP, tmp, nil) 215 tmp.Type = Ptrto(Types[TUINT8]) 216 n.Nbody = list(n.Nbody, Nod(OAS, hp, tmp)) 217 218 // hn = len(a) * sizeof(elem(a)) 219 hn := temp(Types[TUINTPTR]) 220 221 tmp = Nod(OLEN, a, nil) 222 tmp = Nod(OMUL, tmp, Nodintconst(t.Type.Width)) 223 tmp = conv(tmp, Types[TUINTPTR]) 224 n.Nbody = list(n.Nbody, Nod(OAS, hn, tmp)) 225 226 // memclr(hp, hn) 227 fn := mkcall("memclr", nil, nil, hp, hn) 228 229 n.Nbody = list(n.Nbody, fn) 230 231 // i = len(a) - 1 232 v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1))) 233 234 n.Nbody = list(n.Nbody, v1) 235 236 typecheck(&n.Ntest, Erv) 237 typechecklist(n.Nbody, Etop) 238 walkstmt(&n) 239 lineno = int32(lno) 240 return 241 } 242 } 243 } 244 } 245 } 246 } 247 } 248 } 249 } 250 } 251 } 252 } 253 } 254 255 // orderstmt arranged for a copy of the array/slice variable if needed. 256 ha := a 257 258 hv1 := temp(Types[TINT]) 259 hn := temp(Types[TINT]) 260 var hp *Node 261 262 init = list(init, Nod(OAS, hv1, nil)) 263 init = list(init, Nod(OAS, hn, Nod(OLEN, ha, nil))) 264 if v2 != nil { 265 hp = temp(Ptrto(n.Type.Type)) 266 tmp := Nod(OINDEX, ha, Nodintconst(0)) 267 tmp.Bounded = true 268 init = list(init, Nod(OAS, hp, Nod(OADDR, tmp, nil))) 269 } 270 271 n.Ntest = Nod(OLT, hv1, hn) 272 n.Nincr = Nod(OAS, hv1, Nod(OADD, hv1, Nodintconst(1))) 273 if v1 == nil { 274 body = nil 275 } else if v2 == nil { 276 body = list1(Nod(OAS, v1, hv1)) 277 } else { 278 a := Nod(OAS2, nil, nil) 279 a.List = list(list1(v1), v2) 280 a.Rlist = list(list1(hv1), Nod(OIND, hp, nil)) 281 body = list1(a) 282 283 // Advance pointer as part of increment. 284 // We used to advance the pointer before executing the loop body, 285 // but doing so would make the pointer point past the end of the 286 // array during the final iteration, possibly causing another unrelated 287 // piece of memory not to be garbage collected until the loop finished. 288 // Advancing during the increment ensures that the pointer p only points 289 // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;", 290 // after which p is dead, so it cannot confuse the collector. 291 tmp := Nod(OADD, hp, Nodintconst(t.Type.Width)) 292 293 tmp.Type = hp.Type 294 tmp.Typecheck = 1 295 tmp.Right.Type = Types[Tptr] 296 tmp.Right.Typecheck = 1 297 a = Nod(OAS, hp, tmp) 298 typecheck(&a, Etop) 299 n.Nincr.Ninit = list1(a) 300 } 301 302 // orderstmt allocated the iterator for us. 303 // we only use a once, so no copy needed. 304 case TMAP: 305 ha := a 306 307 th := hiter(t) 308 hit := n.Alloc 309 hit.Type = th 310 n.Left = nil 311 keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter 312 valname := newname(th.Type.Down.Sym) // ditto 313 314 fn := syslook("mapiterinit", 1) 315 316 substArgTypes(fn, t.Down, t.Type, th) 317 init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil))) 318 n.Ntest = Nod(ONE, Nod(ODOT, hit, keyname), nodnil()) 319 320 fn = syslook("mapiternext", 1) 321 substArgTypes(fn, th) 322 n.Nincr = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil)) 323 324 key := Nod(ODOT, hit, keyname) 325 key = Nod(OIND, key, nil) 326 if v1 == nil { 327 body = nil 328 } else if v2 == nil { 329 body = list1(Nod(OAS, v1, key)) 330 } else { 331 val := Nod(ODOT, hit, valname) 332 val = Nod(OIND, val, nil) 333 a := Nod(OAS2, nil, nil) 334 a.List = list(list1(v1), v2) 335 a.Rlist = list(list1(key), val) 336 body = list1(a) 337 } 338 339 // orderstmt arranged for a copy of the channel variable. 340 case TCHAN: 341 ha := a 342 343 n.Ntest = nil 344 345 hv1 := temp(t.Type) 346 hv1.Typecheck = 1 347 if haspointers(t.Type) { 348 init = list(init, Nod(OAS, hv1, nil)) 349 } 350 hb := temp(Types[TBOOL]) 351 352 n.Ntest = Nod(ONE, hb, Nodbool(false)) 353 a := Nod(OAS2RECV, nil, nil) 354 a.Typecheck = 1 355 a.List = list(list1(hv1), hb) 356 a.Rlist = list1(Nod(ORECV, ha, nil)) 357 n.Ntest.Ninit = list1(a) 358 if v1 == nil { 359 body = nil 360 } else { 361 body = list1(Nod(OAS, v1, hv1)) 362 } 363 364 // orderstmt arranged for a copy of the string variable. 365 case TSTRING: 366 ha := a 367 368 ohv1 := temp(Types[TINT]) 369 370 hv1 := temp(Types[TINT]) 371 init = list(init, Nod(OAS, hv1, nil)) 372 373 var a *Node 374 var hv2 *Node 375 if v2 == nil { 376 a = Nod(OAS, hv1, mkcall("stringiter", Types[TINT], nil, ha, hv1)) 377 } else { 378 hv2 = temp(runetype) 379 a = Nod(OAS2, nil, nil) 380 a.List = list(list1(hv1), hv2) 381 fn := syslook("stringiter2", 0) 382 a.Rlist = list1(mkcall1(fn, getoutargx(fn.Type), nil, ha, hv1)) 383 } 384 385 n.Ntest = Nod(ONE, hv1, Nodintconst(0)) 386 n.Ntest.Ninit = list(list1(Nod(OAS, ohv1, hv1)), a) 387 388 body = nil 389 if v1 != nil { 390 body = list1(Nod(OAS, v1, ohv1)) 391 } 392 if v2 != nil { 393 body = list(body, Nod(OAS, v2, hv2)) 394 } 395 } 396 397 n.Op = OFOR 398 typechecklist(init, Etop) 399 n.Ninit = concat(n.Ninit, init) 400 typechecklist(n.Ntest.Ninit, Etop) 401 typecheck(&n.Ntest, Erv) 402 typecheck(&n.Nincr, Etop) 403 typechecklist(body, Etop) 404 n.Nbody = concat(body, n.Nbody) 405 walkstmt(&n) 406 407 lineno = int32(lno) 408 }