コード例 #1
0
ファイル: swt.c プロジェクト: 8l/go
/*
 * normal (expression) switch.
 * rebulid case statements into if .. goto
 */
static void
exprswitch(Node *sw)
{
	Node *def;
	NodeList *cas;
	Node *a;
	Case *c0, *c, *c1;
	Type *t;
	int arg, ncase;

	casebody(sw, N);

	arg = Snorm;
	if(isconst(sw->ntest, CTBOOL)) {
		arg = Strue;
		if(sw->ntest->val.u.bval == 0)
			arg = Sfalse;
	}
	walkexpr(&sw->ntest, &sw->ninit);
	t = sw->type;
	if(t == T)
		return;

	/*
	 * convert the switch into OIF statements
	 */
	exprname = N;
	cas = nil;
	if(arg != Strue && arg != Sfalse) {
		exprname = temp(sw->ntest->type);
		cas = list1(nod(OAS, exprname, sw->ntest));
		typechecklist(cas, Etop);
	} else {
		exprname = nodbool(arg == Strue);
	}

	c0 = mkcaselist(sw, arg);
	if(c0 != C && c0->type == Tdefault) {
		def = c0->node->right;
		c0 = c0->link;
	} else {
		def = nod(OBREAK, N, N);
	}

loop:
	if(c0 == C) {
		cas = list(cas, def);
		sw->nbody = concat(cas, sw->nbody);
		sw->list = nil;
		walkstmtlist(sw->nbody);
		return;
	}

	// deal with the variables one-at-a-time
	if(!okforcmp[t->etype] || c0->type != Texprconst) {
		a = exprbsw(c0, 1, arg);
		cas = list(cas, a);
		c0 = c0->link;
		goto loop;
	}

	// do binary search on run of constants
	ncase = 1;
	for(c=c0; c->link!=C; c=c->link) {
		if(c->link->type != Texprconst)
			break;
		ncase++;
	}

	// break the chain at the count
	c1 = c->link;
	c->link = C;

	// sort and compile constants
	c0 = csort(c0, exprcmp);
	a = exprbsw(c0, ncase, arg);
	cas = list(cas, a);

	c0 = c1;
	goto loop;

}
コード例 #2
0
ファイル: swt.c プロジェクト: 8l/go
/*
 * type check switch statement
 */
void
typecheckswitch(Node *n)
{
	int top, lno, ptr;
	char *nilonly;
	Type *t, *badtype, *missing, *have;
	NodeList *l, *ll;
	Node *ncase, *nvar;
	Node *def;

	lno = lineno;
	typechecklist(n->ninit, Etop);
	nilonly = nil;

	if(n->ntest != N && n->ntest->op == OTYPESW) {
		// type switch
		top = Etype;
		typecheck(&n->ntest->right, Erv);
		t = n->ntest->right->type;
		if(t != T && t->etype != TINTER)
			yyerror("cannot type switch on non-interface value %lN", n->ntest->right);
	} else {
		// value switch
		top = Erv;
		if(n->ntest) {
			typecheck(&n->ntest, Erv);
			defaultlit(&n->ntest, T);
			t = n->ntest->type;
		} else
			t = types[TBOOL];
		if(t) {
			if(!okforeq[t->etype])
				yyerror("cannot switch on %lN", n->ntest);
			else if(t->etype == TARRAY && !isfixedarray(t))
				nilonly = "slice";
			else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ)
				yyerror("cannot switch on %lN", n->ntest);
			else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ)
				yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype);
			else if(t->etype == TFUNC)
				nilonly = "func";
			else if(t->etype == TMAP)
				nilonly = "map";
		}
	}
	n->type = t;

	def = N;
	for(l=n->list; l; l=l->next) {
		ncase = l->n;
		setlineno(n);
		if(ncase->list == nil) {
			// default
			if(def != N)
				yyerror("multiple defaults in switch (first at %L)", def->lineno);
			else
				def = ncase;
		} else {
			for(ll=ncase->list; ll; ll=ll->next) {
				setlineno(ll->n);
				typecheck(&ll->n, Erv | Etype);
				if(ll->n->type == T || t == T)
					continue;
				setlineno(ncase);
				switch(top) {
				case Erv:	// expression switch
					defaultlit(&ll->n, t);
					if(ll->n->op == OTYPE)
						yyerror("type %T is not an expression", ll->n->type);
					else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) {
						if(n->ntest)
							yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
						else
							yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type);
					} else if(nilonly && !isconst(ll->n, CTNIL)) {
						yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest);
					}
					break;
				case Etype:	// type switch
					if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) {
						;
					} else if(ll->n->op != OTYPE && ll->n->type != T) {  // should this be ||?
						yyerror("%lN is not a type", ll->n);
						// reset to original type
						ll->n = n->ntest->right;
					} else if(ll->n->type->etype != TINTER && t->etype == TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) {
						if(have && !missing->broke && !have->broke)
							yyerror("impossible type switch case: %lN cannot have dynamic type %T"
								" (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT",
								n->ntest->right, ll->n->type, missing->sym, have->sym, have->type,
								missing->sym, missing->type);
						else if(!missing->broke)
							yyerror("impossible type switch case: %lN cannot have dynamic type %T"
								" (missing %S method)", n->ntest->right, ll->n->type, missing->sym);
					}
					break;
				}
			}
		}
		if(top == Etype && n->type != T) {
			ll = ncase->list;
			nvar = ncase->nname;
			if(nvar != N) {
				if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
					// single entry type switch
					nvar->ntype = typenod(ll->n->type);
				} else {
					// multiple entry type switch or default
					nvar->ntype = typenod(n->type);
				}
			}
		}
		typechecklist(ncase->nbody, Etop);
	}

	lineno = lno;
}
コード例 #3
0
ファイル: swt.c プロジェクト: edisonwsk/golang-on-cygwin
/*
 * type check switch statement
 */
void
typecheckswitch(Node *n)
{
	int top, lno;
	Type *t;
	NodeList *l, *ll;
	Node *ncase, *nvar;
	Node *def;

	lno = lineno;
	typechecklist(n->ninit, Etop);

	if(n->ntest != N && n->ntest->op == OTYPESW) {
		// type switch
		top = Etype;
		typecheck(&n->ntest->right, Erv);
		t = n->ntest->right->type;
		if(t != T && t->etype != TINTER)
			yyerror("cannot type switch on non-interface value %+N", n->ntest->right);
	} else {
		// value switch
		top = Erv;
		if(n->ntest) {
			typecheck(&n->ntest, Erv);
			defaultlit(&n->ntest, T);
			t = n->ntest->type;
		} else
			t = types[TBOOL];
	}
	n->type = t;

	def = N;
	for(l=n->list; l; l=l->next) {
		ncase = l->n;
		setlineno(n);
		if(ncase->list == nil) {
			// default
			if(def != N)
				yyerror("multiple defaults in switch (first at %L)", def->lineno);
			else
				def = ncase;
		} else {
			for(ll=ncase->list; ll; ll=ll->next) {
				setlineno(ll->n);
				typecheck(&ll->n, Erv | Etype);
				if(ll->n->type == T || t == T)
					continue;
				switch(top) {
				case Erv:	// expression switch
					defaultlit(&ll->n, t);
					if(ll->n->op == OTYPE)
						yyerror("type %T is not an expression", ll->n->type);
					else if(ll->n->type != T && !eqtype(ll->n->type, t))
						yyerror("case %+N in %T switch", ll->n, t);
					break;
				case Etype:	// type switch
					if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL))
						;
					else if(ll->n->op != OTYPE && ll->n->type != T)
						yyerror("%#N is not a type", ll->n);
					break;
				}
			}
		}
		if(top == Etype && n->type != T) {
			ll = ncase->list;
			nvar = ncase->nname;
			if(nvar != N) {
				if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
					// single entry type switch
					nvar->ntype = typenod(ll->n->type);
				} else {
					// multiple entry type switch or default
					nvar->ntype = typenod(n->type);
				}
			}
		}
		typechecklist(ncase->nbody, Etop);
	}

	lineno = lno;
}
コード例 #4
0
ファイル: swt.c プロジェクト: 8l/go
/*
 * build separate list of statements and cases
 * make labels between cases and statements
 * deal with fallthrough, break, unreachable statements
 */
static void
casebody(Node *sw, Node *typeswvar)
{
	Node *n, *c, *last;
	Node *def;
	NodeList *cas, *stat, *l, *lc;
	Node *go, *br;
	int32 lno, needvar;

	if(sw->list == nil)
		return;

	lno = setlineno(sw);

	cas = nil;	// cases
	stat = nil;	// statements
	def = N;	// defaults
	br = nod(OBREAK, N, N);

	for(l=sw->list; l; l=l->next) {
		n = l->n;
		setlineno(n);
		if(n->op != OXCASE)
			fatal("casebody %O", n->op);
		n->op = OCASE;
		needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;

		go = nod(OGOTO, newlabel(), N);
		if(n->list == nil) {
			if(def != N)
				yyerror("more than one default case");
			// reuse original default case
			n->right = go;
			def = n;
		}

		if(n->list != nil && n->list->next == nil) {
			// one case - reuse OCASE node.
			c = n->list->n;
			n->left = c;
			n->right = go;
			n->list = nil;
			cas = list(cas, n);
		} else {
			// expand multi-valued cases
			for(lc=n->list; lc; lc=lc->next) {
				c = lc->n;
				cas = list(cas, nod(OCASE, c, go));
			}
		}

		stat = list(stat, nod(OLABEL, go->left, N));
		if(typeswvar && needvar && n->nname != N) {
			NodeList *l;

			l = list1(nod(ODCL, n->nname, N));
			l = list(l, nod(OAS, n->nname, typeswvar));
			typechecklist(l, Etop);
			stat = concat(stat, l);
		}
		stat = concat(stat, n->nbody);

		// botch - shouldn't fall thru declaration
		last = stat->end->n;
		if(last->xoffset == n->xoffset && last->op == OXFALL) {
			if(typeswvar) {
				setlineno(last);
				yyerror("cannot fallthrough in type switch");
			}
			if(l->next == nil) {
				setlineno(last);
				yyerror("cannot fallthrough final case in switch");
			}
			last->op = OFALL;
		} else
			stat = list(stat, br);
	}

	stat = list(stat, br);
	if(def)
		cas = list(cas, def);

	sw->list = cas;
	sw->nbody = stat;
	lineno = lno;
}
コード例 #5
0
ファイル: range.c プロジェクト: funkygao/govtil
void
walkrange(Node *n)
{
	Node *ohv1, *hv1, *hv2;	// hidden (old) val 1, 2
	Node *ha, *hit;	// hidden aggregate, iterator
	Node *hn, *hp;	// hidden len, pointer
	Node *hb;  // hidden bool
	Node *a, *v1, *v2;	// not hidden aggregate, val 1, 2
	Node *fn, *tmp;
	NodeList *body, *init;
	Type *th, *t;
	int lno;

	t = n->type;
	init = nil;

	a = n->right;
	lno = setlineno(a);
	if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
		a = nod(OCONV, n->right, N);
		a->type = types[TSTRING];
	}

	v1 = n->list->n;
	v2 = N;
	if(n->list->next)
		v2 = n->list->next->n;
	hv2 = N;

	if(v2 == N && t->etype == TARRAY) {
		// will have just one reference to argument.
		// no need to make a potentially expensive copy.
		ha = a;
	} else {
		ha = temp(a->type);
		init = list(init, nod(OAS, ha, a));
	}

	switch(t->etype) {
	default:
		fatal("walkrange");

	case TARRAY:
		hv1 = temp(types[TINT]);
		hn = temp(types[TINT]);
		hp = nil;

		init = list(init, nod(OAS, hv1, N));
		init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
		if(v2) {
			hp = temp(ptrto(n->type->type));
			tmp = nod(OINDEX, ha, nodintconst(0));
			tmp->etype = 1;	// no bounds check
			init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
		}

		n->ntest = nod(OLT, hv1, hn);
		n->nincr = nod(OASOP, hv1, nodintconst(1));
		n->nincr->etype = OADD;
		if(v2 == N)
			body = list1(nod(OAS, v1, hv1));
		else {
			a = nod(OAS2, N, N);
			a->list = list(list1(v1), v2);
			a->rlist = list(list1(hv1), nod(OIND, hp, N));
			body = list1(a);

			tmp = nod(OADD, hp, nodintconst(t->type->width));
			tmp->type = hp->type;
			tmp->typecheck = 1;
			tmp->right->type = types[tptr];
			tmp->right->typecheck = 1;
			body = list(body, nod(OAS, hp, tmp));
		}
		break;

	case TMAP:
		th = typ(TARRAY);
		th->type = ptrto(types[TUINT8]);
		// see ../../pkg/runtime/hashmap.h:/hash_iter
		// Size in words.
		th->bound = 5 + 4*3 + 4*4/widthptr;
		hit = temp(th);

		fn = syslook("mapiterinit", 1);
		argtype(fn, t->down);
		argtype(fn, t->type);
		argtype(fn, th);
		init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N)));
		n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());

		fn = syslook("mapiternext", 1);
		argtype(fn, th);
		n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));

		if(v2 == N) {
			fn = syslook("mapiter1", 1);
			argtype(fn, th);
			argtype(fn, t->down);
			a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
		} else {
			fn = syslook("mapiter2", 1);
			argtype(fn, th);
			argtype(fn, t->down);
			argtype(fn, t->type);
			a = nod(OAS2, N, N);
			a->list = list(list1(v1), v2);
			a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
		}
		body = list1(a);
		break;

	case TCHAN:
		hv1 = temp(t->type);
		hb = temp(types[TBOOL]);

		n->ntest = nod(ONE, hb, nodbool(0));
		a = nod(OAS2RECV, N, N);
		a->typecheck = 1;
		a->list = list(list1(hv1), hb);
		a->rlist = list1(nod(ORECV, ha, N));
		n->ntest->ninit = list1(a);
		body = list1(nod(OAS, v1, hv1));
		break;

	case TSTRING:
		ohv1 = temp(types[TINT]);

		hv1 = temp(types[TINT]);
		init = list(init, nod(OAS, hv1, N));

		if(v2 == N)
			a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
		else {
			hv2 = temp(runetype);
			a = nod(OAS2, N, N);
			a->list = list(list1(hv1), hv2);
			fn = syslook("stringiter2", 0);
			a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
		}
		n->ntest = nod(ONE, hv1, nodintconst(0));
		n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);

		body = list1(nod(OAS, v1, ohv1));
		if(v2 != N)
			body = list(body, nod(OAS, v2, hv2));
		break;
	}

	n->op = OFOR;
	typechecklist(init, Etop);
	n->ninit = concat(n->ninit, init);
	typechecklist(n->ntest->ninit, Etop);
	typecheck(&n->ntest, Erv);
	typecheck(&n->nincr, Etop);
	typechecklist(body, Etop);
	n->nbody = concat(body, n->nbody);
	walkstmt(&n);
	
	lineno = lno;
}
コード例 #6
0
ファイル: range.c プロジェクト: funkygao/govtil
void
typecheckrange(Node *n)
{
	char *why;
	Type *t, *t1, *t2;
	Node *v1, *v2;
	NodeList *ll;

	// delicate little dance.  see typecheckas2
	for(ll=n->list; ll; ll=ll->next)
		if(ll->n->defn != n)
			typecheck(&ll->n, Erv | Easgn);

	typecheck(&n->right, Erv);
	if((t = n->right->type) == T)
		goto out;
	if(isptr[t->etype] && isfixedarray(t->type))
		t = t->type;
	n->type = t;

	switch(t->etype) {
	default:
		yyerror("cannot range over %lN", n->right);
		goto out;

	case TARRAY:
		t1 = types[TINT];
		t2 = t->type;
		break;

	case TMAP:
		t1 = t->down;
		t2 = t->type;
		break;

	case TCHAN:
		if(!(t->chan & Crecv)) {
			yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type);
			goto out;
		}
		t1 = t->type;
		t2 = nil;
		if(count(n->list) == 2)
			goto toomany;
		break;

	case TSTRING:
		t1 = types[TINT];
		t2 = runetype;
		break;
	}

	if(count(n->list) > 2) {
	toomany:
		yyerror("too many variables in range");
	}

	v1 = n->list->n;
	v2 = N;
	if(n->list->next)
		v2 = n->list->next->n;

	if(v1->defn == n)
		v1->type = t1;
	else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
		yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
	if(v2) {
		if(v2->defn == n)
			v2->type = t2;
		else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
			yyerror("cannot assign type %T to %lN in range%s", t2, v2, why);
	}

out:
	typechecklist(n->nbody, Etop);

	// second half of dance
	n->typecheck = 1;
	for(ll=n->list; ll; ll=ll->next)
		if(ll->n->typecheck == 0)
			typecheck(&ll->n, Erv | Easgn);
}
コード例 #7
0
ファイル: range.c プロジェクト: 8l/go-learn
void
walkrange(Node *n)
{
	Node *ohv1, *hv1, *hv2;	// hidden (old) val 1, 2
	Node *ha, *hit;	// hidden aggregate, iterator
	Node *a, *v1, *v2;	// not hidden aggregate, val 1, 2
	Node *fn;
	NodeList *body, *init;
	Type *th, *t;

	t = n->type;
	init = nil;

	a = n->right;
	if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
		a = nod(OCONV, n->right, N);
		a->type = types[TSTRING];
	}
	ha = nod(OXXX, N, N);
	tempname(ha, a->type);
	init = list(init, nod(OAS, ha, a));

	v1 = n->list->n;
	hv1 = N;

	v2 = N;
	if(n->list->next)
		v2 = n->list->next->n;
	hv2 = N;

	switch(t->etype) {
	default:
		fatal("walkrange");

	case TARRAY:
		hv1 = nod(OXXX, N, n);
		tempname(hv1, types[TINT]);

		init = list(init, nod(OAS, hv1, N));
		n->ntest = nod(OLT, hv1, nod(OLEN, ha, N));
		n->nincr = nod(OASOP, hv1, nodintconst(1));
		n->nincr->etype = OADD;
		body = list1(nod(OAS, v1, hv1));
		if(v2)
			body = list(body, nod(OAS, v2, nod(OINDEX, ha, hv1)));
		break;

	case TMAP:
		th = typ(TARRAY);
		th->type = ptrto(types[TUINT8]);
		th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr;
		hit = nod(OXXX, N, N);
		tempname(hit, th);

		fn = syslook("mapiterinit", 1);
		argtype(fn, t->down);
		argtype(fn, t->type);
		argtype(fn, th);
		init = list(init, mkcall1(fn, T, nil, ha, nod(OADDR, hit, N)));
		n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());

		fn = syslook("mapiternext", 1);
		argtype(fn, th);
		n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));

		if(v2 == N) {
			fn = syslook("mapiter1", 1);
			argtype(fn, th);
			argtype(fn, t->down);
			a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
		} else {
			fn = syslook("mapiter2", 1);
			argtype(fn, th);
			argtype(fn, t->down);
			argtype(fn, t->type);
			a = nod(OAS2, N, N);
			a->list = list(list1(v1), v2);
			a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
		}
		body = list1(a);
		break;

	case TCHAN:
		hv1 = nod(OXXX, N, n);
		tempname(hv1, t->type);

		n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N);
		n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N)));
		body = list1(nod(OAS, v1, hv1));
		break;

	case TSTRING:
		ohv1 = nod(OXXX, N, N);
		tempname(ohv1, types[TINT]);

		hv1 = nod(OXXX, N, N);
		tempname(hv1, types[TINT]);
		init = list(init, nod(OAS, hv1, N));

		if(v2 == N)
			a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
		else {
			hv2 = nod(OXXX, N, N);
			tempname(hv2, types[TINT]);
			a = nod(OAS2, N, N);
			a->list = list(list1(hv1), hv2);
			fn = syslook("stringiter2", 0);
			a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
		}
		n->ntest = nod(ONE, hv1, nodintconst(0));
		n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);

		body = list1(nod(OAS, v1, ohv1));
		if(v2 != N)
			body = list(body, nod(OAS, v2, hv2));
		break;
	}

	n->op = OFOR;
	typechecklist(init, Etop);
	n->ninit = concat(n->ninit, init);
	typechecklist(n->ntest->ninit, Etop);
	typecheck(&n->ntest, Erv);
	typecheck(&n->nincr, Etop);
	typechecklist(body, Etop);
	n->nbody = concat(body, n->nbody);
	walkstmt(&n);
}
コード例 #8
0
ファイル: range.c プロジェクト: 8l/go-learn
void
typecheckrange(Node *n)
{
	int op, et;
	Type *t, *t1, *t2;
	Node *v1, *v2;
	NodeList *ll;

	// delicate little dance.  see typecheckas2
	for(ll=n->list; ll; ll=ll->next)
		if(ll->n->defn != n)
			typecheck(&ll->n, Erv | Easgn);

	typecheck(&n->right, Erv);
	if((t = n->right->type) == T)
		goto out;
	n->type = t;

	switch(t->etype) {
	default:
		yyerror("cannot range over %+N", n->right);
		goto out;

	case TARRAY:
		t1 = types[TINT];
		t2 = t->type;
		break;

	case TMAP:
		t1 = t->down;
		t2 = t->type;
		break;

	case TCHAN:
		t1 = t->type;
		t2 = nil;
		if(count(n->list) == 2)
			goto toomany;
		break;

	case TSTRING:
		t1 = types[TINT];
		t2 = types[TINT];
		break;
	}

	if(count(n->list) > 2) {
	toomany:
		yyerror("too many variables in range");
	}

	v1 = n->list->n;
	v2 = N;
	if(n->list->next)
		v2 = n->list->next->n;

	if(v1->defn == n)
		v1->type = t1;
	else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et) < 0)
		yyerror("cannot assign type %T to %+N", t1, v1);
	if(v2) {
		if(v2->defn == n)
			v2->type = t2;
		else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et) < 0)
			yyerror("cannot assign type %T to %+N", t1, v1);
	}

out:
	typechecklist(n->nbody, Etop);

	// second half of dance
	n->typecheck = 1;
	for(ll=n->list; ll; ll=ll->next)
		if(ll->n->typecheck == 0)
			typecheck(&ll->n, Erv | Easgn);
}
コード例 #9
0
ファイル: init.c プロジェクト: 29decibel/golang
void
fninit(NodeList *n)
{
	int i;
	Node *gatevar;
	Node *a, *b, *fn;
	NodeList *r;
	uint32 h;
	Sym *s, *initsym;

	if(debug['A']) {
		// sys.go or unsafe.go during compiler build
		return;
	}

	n = initfix(n);
	if(!anyinit(n))
		return;

	r = nil;

	// (1)
	snprint(namebuf, sizeof(namebuf), "initdone·");
	gatevar = newname(lookup(namebuf));
	addvar(gatevar, types[TUINT8], PEXTERN);

	// (2)
	maxarg = 0;
	snprint(namebuf, sizeof(namebuf), "init");

	fn = nod(ODCLFUNC, N, N);
	initsym = lookup(namebuf);
	fn->nname = newname(initsym);
	fn->nname->defn = fn;
	fn->nname->ntype = nod(OTFUNC, N, N);
	declare(fn->nname, PFUNC);
	funchdr(fn);

	// (3)
	a = nod(OIF, N, N);
	a->ntest = nod(ONE, gatevar, nodintconst(0));
	r = list(r, a);

	// (4)
	b = nod(OIF, N, N);
	b->ntest = nod(OEQ, gatevar, nodintconst(2));
	b->nbody = list1(nod(ORETURN, N, N));
	a->nbody = list1(b);

	// (5)
	b = syslook("throwinit", 0);
	b = nod(OCALL, b, N);
	a->nbody = list(a->nbody, b);

	// (6)
	a = nod(OAS, gatevar, nodintconst(1));
	r = list(r, a);

	// (7)
	for(h=0; h<NHASH; h++)
	for(s = hash[h]; s != S; s = s->link) {
		if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
			continue;
		if(s->def == N)
			continue;
		if(s == initsym)
			continue;

		// could check that it is fn of no args/returns
		a = nod(OCALL, s->def, N);
		r = list(r, a);
	}

	// (8)
	r = concat(r, n);

	// (9)
	// could check that it is fn of no args/returns
	for(i=1;; i++) {
		snprint(namebuf, sizeof(namebuf), "init·%d", i);
		s = lookup(namebuf);
		if(s->def == N)
			break;
		a = nod(OCALL, s->def, N);
		r = list(r, a);
	}

	// (10)
	a = nod(OAS, gatevar, nodintconst(2));
	r = list(r, a);

	// (11)
	a = nod(ORETURN, N, N);
	r = list(r, a);
	exportsym(fn->nname);

	fn->nbody = r;
	funcbody(fn);

	curfn = fn;
	typecheck(&fn, Etop);
	typechecklist(r, Etop);
	curfn = nil;
	funccompile(fn, 0);
}