github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/gc/range.c (about) 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 /* 6 * range 7 */ 8 9 #include <u.h> 10 #include <libc.h> 11 #include "go.h" 12 13 void 14 typecheckrange(Node *n) 15 { 16 char *why; 17 Type *t, *t1, *t2; 18 Node *v1, *v2; 19 NodeList *ll; 20 21 // delicate little dance. see typecheckas2 22 for(ll=n->list; ll; ll=ll->next) 23 if(ll->n->defn != n) 24 typecheck(&ll->n, Erv | Easgn); 25 26 typecheck(&n->right, Erv); 27 if((t = n->right->type) == T) 28 goto out; 29 if(isptr[t->etype] && isfixedarray(t->type)) 30 t = t->type; 31 n->type = t; 32 33 switch(t->etype) { 34 default: 35 yyerror("cannot range over %lN", n->right); 36 goto out; 37 38 case TARRAY: 39 t1 = types[TINT]; 40 t2 = t->type; 41 break; 42 43 case TMAP: 44 t1 = t->down; 45 t2 = t->type; 46 break; 47 48 case TCHAN: 49 if(!(t->chan & Crecv)) { 50 yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type); 51 goto out; 52 } 53 t1 = t->type; 54 t2 = nil; 55 if(count(n->list) == 2) 56 goto toomany; 57 break; 58 59 case TSTRING: 60 t1 = types[TINT]; 61 t2 = runetype; 62 break; 63 } 64 65 if(count(n->list) > 2) { 66 toomany: 67 yyerror("too many variables in range"); 68 } 69 70 v1 = n->list->n; 71 v2 = N; 72 if(n->list->next) 73 v2 = n->list->next->n; 74 75 // this is not only a optimization but also a requirement in the spec. 76 // "if the second iteration variable is the blank identifier, the range 77 // clause is equivalent to the same clause with only the first variable 78 // present." 79 if(isblank(v2)) { 80 n->list = list1(v1); 81 v2 = N; 82 } 83 84 if(v1->defn == n) 85 v1->type = t1; 86 else if(v1->type != T && assignop(t1, v1->type, &why) == 0) 87 yyerror("cannot assign type %T to %lN in range%s", t1, v1, why); 88 if(v2) { 89 if(v2->defn == n) 90 v2->type = t2; 91 else if(v2->type != T && assignop(t2, v2->type, &why) == 0) 92 yyerror("cannot assign type %T to %lN in range%s", t2, v2, why); 93 } 94 95 out: 96 typechecklist(n->nbody, Etop); 97 98 // second half of dance 99 n->typecheck = 1; 100 for(ll=n->list; ll; ll=ll->next) 101 if(ll->n->typecheck == 0) 102 typecheck(&ll->n, Erv | Easgn); 103 } 104 105 void 106 walkrange(Node *n) 107 { 108 Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2 109 Node *ha, *hit; // hidden aggregate, iterator 110 Node *hn, *hp; // hidden len, pointer 111 Node *hb; // hidden bool 112 Node *a, *v1, *v2; // not hidden aggregate, val 1, 2 113 Node *fn, *tmp; 114 Node *keyname, *valname; 115 Node *key, *val; 116 NodeList *body, *init; 117 Type *th, *t; 118 int lno; 119 120 t = n->type; 121 init = nil; 122 123 a = n->right; 124 lno = setlineno(a); 125 126 v1 = n->list->n; 127 v2 = N; 128 if(n->list->next && !isblank(n->list->next->n)) 129 v2 = n->list->next->n; 130 // n->list has no meaning anymore, clear it 131 // to avoid erroneous processing by racewalk. 132 n->list = nil; 133 hv2 = N; 134 135 switch(t->etype) { 136 default: 137 fatal("walkrange"); 138 139 case TARRAY: 140 // orderstmt arranged for a copy of the array/slice variable if needed. 141 ha = a; 142 hv1 = temp(types[TINT]); 143 hn = temp(types[TINT]); 144 hp = nil; 145 146 init = list(init, nod(OAS, hv1, N)); 147 init = list(init, nod(OAS, hn, nod(OLEN, ha, N))); 148 if(v2) { 149 hp = temp(ptrto(n->type->type)); 150 tmp = nod(OINDEX, ha, nodintconst(0)); 151 tmp->bounded = 1; 152 init = list(init, nod(OAS, hp, nod(OADDR, tmp, N))); 153 } 154 155 n->ntest = nod(OLT, hv1, hn); 156 n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))); 157 if(v2 == N) 158 body = list1(nod(OAS, v1, hv1)); 159 else { 160 a = nod(OAS2, N, N); 161 a->list = list(list1(v1), v2); 162 a->rlist = list(list1(hv1), nod(OIND, hp, N)); 163 body = list1(a); 164 165 // Advance pointer as part of increment. 166 // We used to advance the pointer before executing the loop body, 167 // but doing so would make the pointer point past the end of the 168 // array during the final iteration, possibly causing another unrelated 169 // piece of memory not to be garbage collected until the loop finished. 170 // Advancing during the increment ensures that the pointer p only points 171 // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;", 172 // after which p is dead, so it cannot confuse the collector. 173 tmp = nod(OADD, hp, nodintconst(t->type->width)); 174 tmp->type = hp->type; 175 tmp->typecheck = 1; 176 tmp->right->type = types[tptr]; 177 tmp->right->typecheck = 1; 178 a = nod(OAS, hp, tmp); 179 typecheck(&a, Etop); 180 n->nincr->ninit = list1(a); 181 } 182 break; 183 184 case TMAP: 185 // orderstmt allocated the iterator for us. 186 // we only use a once, so no copy needed. 187 ha = a; 188 th = hiter(t); 189 hit = n->alloc; 190 hit->type = th; 191 n->left = N; 192 keyname = newname(th->type->sym); // depends on layout of iterator struct. See reflect.c:hiter 193 valname = newname(th->type->down->sym); // ditto 194 195 fn = syslook("mapiterinit", 1); 196 argtype(fn, t->down); 197 argtype(fn, t->type); 198 argtype(fn, th); 199 init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N))); 200 n->ntest = nod(ONE, nod(ODOT, hit, keyname), nodnil()); 201 202 fn = syslook("mapiternext", 1); 203 argtype(fn, th); 204 n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N)); 205 206 key = nod(ODOT, hit, keyname); 207 key = nod(OIND, key, N); 208 if(v2 == N) { 209 a = nod(OAS, v1, key); 210 } else { 211 val = nod(ODOT, hit, valname); 212 val = nod(OIND, val, N); 213 a = nod(OAS2, N, N); 214 a->list = list(list1(v1), v2); 215 a->rlist = list(list1(key), val); 216 } 217 body = list1(a); 218 break; 219 220 case TCHAN: 221 // orderstmt arranged for a copy of the channel variable. 222 ha = a; 223 n->ntest = N; 224 225 hv1 = temp(t->type); 226 if(haspointers(t->type)) 227 init = list(init, nod(OAS, hv1, N)); 228 hb = temp(types[TBOOL]); 229 230 n->ntest = nod(ONE, hb, nodbool(0)); 231 a = nod(OAS2RECV, N, N); 232 a->typecheck = 1; 233 a->list = list(list1(hv1), hb); 234 a->rlist = list1(nod(ORECV, ha, N)); 235 n->ntest->ninit = list1(a); 236 body = list1(nod(OAS, v1, hv1)); 237 break; 238 239 case TSTRING: 240 // orderstmt arranged for a copy of the string variable. 241 ha = a; 242 243 ohv1 = temp(types[TINT]); 244 245 hv1 = temp(types[TINT]); 246 init = list(init, nod(OAS, hv1, N)); 247 248 if(v2 == N) 249 a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1)); 250 else { 251 hv2 = temp(runetype); 252 a = nod(OAS2, N, N); 253 a->list = list(list1(hv1), hv2); 254 fn = syslook("stringiter2", 0); 255 a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1)); 256 } 257 n->ntest = nod(ONE, hv1, nodintconst(0)); 258 n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a); 259 260 body = list1(nod(OAS, v1, ohv1)); 261 if(v2 != N) 262 body = list(body, nod(OAS, v2, hv2)); 263 break; 264 } 265 266 n->op = OFOR; 267 typechecklist(init, Etop); 268 n->ninit = concat(n->ninit, init); 269 typechecklist(n->ntest->ninit, Etop); 270 typecheck(&n->ntest, Erv); 271 typecheck(&n->nincr, Etop); 272 typechecklist(body, Etop); 273 n->nbody = concat(body, n->nbody); 274 walkstmt(&n); 275 276 lineno = lno; 277 } 278