return n;
}
+// TODO(rsc): combine with convlit
void
defaultlit(Node **np, Type *t)
{
n = *np;
if(n == N)
return;
- if(n->type == T || n->type->etype != TIDEAL)
+ if(n->type == T || (n->type->etype != TIDEAL && n->type->etype != TNIL))
return;
switch(n->op) {
lineno = n->lineno;
switch(n->val.ctype) {
default:
+ if(t != T) {
+ convlit(np, t);
+ break;
+ }
+ if(n->val.ctype == CTNIL) {
+ lineno = lno;
+ yyerror("use of untyped nil");
+ n->type = T;
+ break;
+ }
yyerror("defaultlit: unknown literal: %#N", n);
break;
case CTINT:
OAPPENDSTR,
OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
- OAS, OAS2, OASOP,
+ OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP,
void dumpexporttype(Sym*);
void dumpexportvar(Sym*);
void dumpexportconst(Sym*);
-void doimportv1(Node*, Node*);
-void doimportc1(Node*, Val*);
-void doimportc2(Node*, Node*, Val*);
-void doimport1(Node*, Node*, Node*);
-void doimport2(Node*, Val*, Node*);
-void doimport3(Node*, Node*);
-void doimport4(Node*, Node*);
-void doimport5(Node*, Val*);
-void doimport6(Node*, Node*);
-void doimport7(Node*, Node*);
-void doimport8(Node*, Val*, Node*);
-void doimport9(Sym*, Node*);
void importconst(Sym *s, Type *t, Node *v);
void importmethod(Sym *s, Type *t);
void importtype(Sym *s, Type *t);
void walkconv(Node**, NodeList**);
void walkdottype(Node*, NodeList**);
void walkas(Node*);
-void walkbool(Node**);
void walkswitch(Node*);
void walkselect(Node*);
void walkdot(Node*, NodeList**);
NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
NodeList* ascompatte(int, Type**, NodeList*, int, NodeList**);
-int ascompat(Type*, Type*);
-Node* newcompat(Node*);
-Node* stringop(Node*, NodeList**);
-Type* fixmap(Type*);
Node* mapop(Node*, NodeList**);
Type* fixchan(Type*);
-Node* chanop(Node*, NodeList**);
Node* ifacecvt(Type*, Node*, int, NodeList**);
-Node* ifaceop(Node*);
int ifaceas(Type*, Type*, int);
int ifaceas1(Type*, Type*, int);
void ifacecheck(Type*, Type*, int, int);
void runifacechecks(void);
Node* convas(Node*, NodeList**);
-void arrayconv(Type*, Node*);
Node* colas(NodeList*, NodeList*);
Node* dorange(Node*);
NodeList* reorder1(NodeList*);
void walkdeflist(NodeList*);
void walkdef(Node*);
void typechecklist(NodeList*, int);
+void typecheckswitch(Node*);
Node* typecheckconv(Node*, Node*, Type*, int);
Node* typecheck(Node**, int);
break;
case OINDEX:
+ case OINDEXMAP:
exprfmt(f, n->left, 7);
fmtprint(f, "[");
exprfmt(f, n->right, 0);
return l;
}
-/*
- * walktype
- */
-Type*
-sw0(Node **cp, Type *place, int arg)
-{
- Node *c;
-
- c = *cp;
- if(c == N)
- return T;
- switch(c->op) {
- default:
- if(arg == Stype) {
- yyerror("expression case in a type switch");
- return T;
- }
- walkexpr(cp, nil);
- break;
- case OTYPESW:
- case OTYPECASE:
- if(arg != Stype)
- yyerror("type case in an expression switch");
- break;
- case OAS:
- yyerror("inappropriate assignment in a case statement");
- break;
- }
- return T;
-}
-
-/*
- * return the first type
- */
-Type*
-sw1(Node **cp, Type *place, int arg)
-{
- Node *c;
-
- c = *cp;
- if(place != T)
- return notideal(c->type);
- return place;
-}
-
-/*
- * return a suitable type
- */
-Type*
-sw2(Node **cp, Type *place, int arg)
-{
- return types[TINT]; // botch
-}
-
-/*
- * check that switch type
- * is compat with all the cases
- */
-Type*
-sw3(Node **cp, Type *place, int arg)
-{
- Node *c;
-
- c = *cp;
- if(place == T)
- return c->type;
- if(c->type == T)
- c->type = place;
- convlit(cp, place);
- c = *cp;
- if(!ascompat(place, c->type))
- badtype(OSWITCH, place, c->type);
- return place;
-}
-
-/*
- * over all cases, call parameter function.
- * four passes of these are used to allocate
- * types to cases and switch
- */
-Type*
-walkcases(Node *sw, Type*(*call)(Node**, Type*, int arg), int arg)
-{
- Node *n;
- NodeList *l;
- Type *place;
- int32 lno;
-
- lno = setlineno(sw);
- place = call(&sw->ntest, T, arg);
-
- for(l=sw->list; l; l=l->next) {
- n = l->n;
-
- if(n->op != OCASE)
- fatal("walkcases: not case %O\n", n->op);
-
- if(n->left != N && !n->diag) {
- setlineno(n);
- place = call(&n->left, place, arg);
- }
- }
- lineno = lno;
- return place;
-}
-
Node*
newlabel(void)
{
arg = Sfalse;
}
walkexpr(&sw->ntest, &sw->ninit);
-
- /*
- * pass 0,1,2,3
- * walk the cases as appropriate for switch type
- */
- walkcases(sw, sw0, arg);
- t = notideal(sw->ntest->type);
- if(t == T)
- t = walkcases(sw, sw1, arg);
- if(t == T)
- t = walkcases(sw, sw2, arg);
+ t = sw->type;
if(t == T)
return;
- walkcases(sw, sw3, arg);
- convlit(&sw->ntest, t);
-
/*
* convert the switch into OIF statements
yyerror("type switch must be on an interface");
return;
}
- walkcases(sw, sw0, Stype);
cas = nil;
/*
}
exprswitch(sw);
}
+
+/*
+ * type check switch statement
+ */
+void
+typecheckswitch(Node *n)
+{
+ int top, lno;
+ Type *t;
+ NodeList *l, *ll;
+ Node *ncase;
+ Node *def;
+
+ lno = lineno;
+ typechecklist(n->ninit, Etop);
+
+ if(n->ntest != N && n->ntest->op == OTYPESW) {
+ // type switch
+ typecheck(&n->ntest, Etop);
+ top = Etype;
+ t = n->ntest->type;
+ if(t != T && t->etype != TINTER)
+ yyerror("cannot type switch on non-interface value %+N", n->ntest);
+ } 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); // TODO(rsc): top
+ if(ll->n->type == T || t == T || top != Erv)
+ continue;
+ defaultlit(&ll->n, t);
+ if(ll->n->type != T && !eqtype(ll->n->type, t))
+ yyerror("case %+N in switch of %+N %#O", ll->n, n->ntest, ll->n->op);
+ }
+ }
+ typechecklist(ncase->nbody, Etop);
+ }
+
+ lineno = lno;
+}
*
* TODO:
* trailing ... section of function calls
- * statements
+ * select
+ * range
*/
#include "go.h"
static int nokeys(NodeList*);
static void typecheckcomplit(Node**);
static void addrescapes(Node*);
-
+static void typecheckas2(Node*);
static void checklvalue(Node*, char*);
static void checkassign(Node*);
static void checkassignlist(NodeList*);
goto ret;
case OAS2:
- typechecklist(n->list, Erv);
- checkassignlist(n->list);
- typechecklist(n->rlist, Erv);
+ typecheckas2(n);
goto ret;
case OBREAK:
case OFOR:
typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv); // TODO Ebool
+ typecheck(&n->ntest, Erv);
+ if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
+ yyerror("non-bool %+N used as for condition");
typecheck(&n->nincr, Etop);
typechecklist(n->nbody, Etop);
goto ret;
case OIF:
typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv); // TODO Ebool
+ typecheck(&n->ntest, Erv);
+ if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
+ yyerror("non-bool %+N used as if condition");
typechecklist(n->nbody, Etop);
typechecklist(n->nelse, Etop);
goto ret;
goto ret;
case OSWITCH:
- typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv);
- typechecklist(n->list, Etop);
+ typecheckswitch(n);
goto ret;
case OTYPECASE:
typecheck(&n->left, Erv);
+ ok |= Erv;
goto ret;
case OTYPESW:
goto error;
}
if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
- yyerror("%O is not a type", n->op);
+ yyerror("%#N is not a type", n);
goto error;
}
if((ok & Ecall) && !(top & Ecall)) {
return 1;
}
-Node*
-typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
+static int
+checkconv(Type *nt, Type *t, int explicit, int *op, int *et)
{
- int et, op;
- Node *n1;
-
- op = OCONV;
- et = 0;
+ *op = OCONV;
+ *et = 0;
// preexisting error
if(t == T || t->etype == TFORW)
- return n;
+ return 0;
/*
* implicit conversions
*/
+ if(nt == T)
+ return 0;
- convlit1(&n, t, explicit);
- if(n->type == T)
- return n;
-
- if(eqtype(t, n->type)) {
+ if(eqtype(t, nt)) {
exportassignok(t);
- op = OCONVNOP;
- if(!explicit || t == n->type)
- return n;
- goto conv;
+ *op = OCONVNOP;
+ if(!explicit || t == nt)
+ return 0;
+ return 1;
}
// interfaces are not subject to the name restrictions below.
- // accept anything involving interfaces and let walkiface
+ // accept anything involving interfaces and let ifacecvt
// generate a good message. some messages have to be
// delayed anyway.
- if(isnilinter(t) || isnilinter(n->type) || isinter(t) || isinter(n->type)) {
- et = ifaceas1(t, n->type, 0);
- op = OCONVIFACE;
- goto conv;
+ if(isnilinter(t) || isnilinter(nt) || isinter(t) || isinter(nt)) {
+ *et = ifaceas1(t, nt, 0);
+ *op = OCONVIFACE;
+ return 1;
}
// otherwise, if concrete types have names, they must match.
- if(!explicit && t->sym && n->type->sym && t != n->type)
- goto badimplicit;
+ if(!explicit && t->sym && nt->sym && t != nt)
+ return -1;
// channel must not lose directionality
- if(t->etype == TCHAN && n->type->etype == TCHAN) {
- if(t->chan & ~n->type->chan) {
- if(!explicit)
- goto badimplicit;
- goto badexplicit;
- }
- if(eqtype(t->type, n->type->type)) {
- op = OCONVNOP;
- goto conv;
+ if(t->etype == TCHAN && nt->etype == TCHAN) {
+ if(t->chan & ~nt->chan)
+ return -1;
+ if(eqtype(t->type, nt->type)) {
+ *op = OCONVNOP;
+ return 1;
}
}
// array to slice
- if(isslice(t) && isptr[n->type->etype] && isfixedarray(n->type->type)
- && eqtype(t->type, n->type->type->type)) {
- op = OCONVSLICE;
- goto conv;
- }
-
- if(!explicit) {
- badimplicit:
- yyerror("cannot use %+N as type %T", n, t);
- n = nod(OCONV, n, N); // leave type == T
- n->typecheck = 1;
- return n;
+ if(isslice(t) && isptr[nt->etype] && isfixedarray(nt->type)
+ && eqtype(t->type, nt->type->type)) {
+ *op = OCONVSLICE;
+ return 1;
}
/*
* explicit conversions
*/
+ if(!explicit)
+ return -1;
// same representation
- if(cvttype(t, n->type)) {
- if(n->op == OLITERAL) {
- // can convert literal in place
- n1 = nod(OXXX, N, N);
- *n1 = *n;
- n1->type = t;
- return n1;
- }
- op = OCONVNOP;
- goto conv;
+ if(cvttype(t, nt)) {
+ *op = OCONVNOP;
+ return 1;
}
// simple fix-float
if(isint[t->etype] || isfloat[t->etype])
- if(isint[n->type->etype] || isfloat[n->type->etype]) {
- // evconst(n); // XXX is this needed?
- goto conv;
- }
+ if(isint[nt->etype] || isfloat[nt->etype])
+ return 1;
// to string
if(istype(t, TSTRING)) {
// integer rune
- if(isint[n->type->etype]) {
- op = ORUNESTR;
- goto conv;
+ if(isint[nt->etype]) {
+ *op = ORUNESTR;
+ return 1;
}
- // *[10]byte -> string? convert *[10]byte -> []byte
+ // *[10]byte -> string
// in preparation for next step
- if(isptr[n->type->etype] && isfixedarray(n->type->type)) {
- switch(n->type->type->type->etype) {
+ if(isptr[nt->etype] && isfixedarray(nt->type)) {
+ switch(nt->type->type->etype) {
case TUINT8:
+ *op = OARRAYBYTESTR;
+ return 1;
case TINT:
- n1 = nod(OCONV, n, N);
- n1->type = typ(TARRAY);
- n1->type->bound = -1;
- n1->type->type = n->type->type->type;
- dowidth(n1->type);
- typecheck(&n1, Erv);
- walkexpr(&n1, nil);
- n = n1;
- break;
+ *op = OARRAYRUNESTR;
+ return 1;
}
}
// []byte -> string
- if(isslice(n->type)) {
- switch(n->type->type->etype) {
+ if(isslice(nt)) {
+ switch(nt->type->etype) {
case TUINT8:
- op = OARRAYBYTESTR;
- goto conv;
+ *op = OARRAYBYTESTR;
+ return 1;
case TINT:
- op = OARRAYRUNESTR;
- goto conv;
+ *op = OARRAYRUNESTR;
+ return 1;
}
}
}
// convert to unsafe pointer
if(isptrto(t, TANY)
- && (isptr[n->type->etype] || n->type->etype == TUINTPTR))
- goto conv;
+ && (isptr[nt->etype] || nt->etype == TUINTPTR))
+ return 1;
// convert from unsafe pointer
- if(isptrto(n->type, TANY)
+ if(isptrto(nt, TANY)
&& (isptr[t->etype] || t->etype == TUINTPTR))
- goto conv;
-
-badexplicit:
- yyerror("cannot convert %+N to type %T", n, t);
- nconv->type = T;
- return nconv;
+ return 1;
-conv:
- if(nconv == nil) {
- nconv = nod(OXXX, n, N);
- nconv->type = t;
- nconv->typecheck = 1;
- }
- nconv->etype = et;
- nconv->op = op;
- return nconv;
+ return -1;
}
-/*
- * typecheck assignment: type list = type list
- */
-static void
-typecheckastt(int op, Type *t1, Type *t2)
+Node*
+typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
{
- for(t1=t1->type, t2=t2->type; t1; t1=t1->down, t2=t2->down) {
- if(t2 == nil) {
- yyerror("too few");
- return;
- }
- if(!eqtype(t1->type, t2->type)) {
- yyerror("wrong");
- }
+ int et, op;
+ Node *n1;
+
+ convlit1(&n, t, explicit);
+ if(n->type == T)
+ return n;
+
+ if(cvttype(t, n->type) && n->op == OLITERAL) {
+ // can convert literal in place
+ // TODO(rsc) is this needed?
+ n1 = nod(OXXX, N, N);
+ *n1 = *n;
+ n1->type = t;
+ return n1;
}
- if(t2 != nil)
- yyerror("too many");
+
+ switch(checkconv(n->type, t, explicit, &op, &et)) {
+ case -1:
+ if(explicit)
+ yyerror("cannot convert %+N to type %T", n, t);
+ else
+ yyerror("cannot use %+N as type %T", n, t);
+ return n;
+
+ case 0:
+ return n;
+ }
+
+ if(nconv == N)
+ nconv = nod(OCONV, n, N);
+ nconv->op = op;
+ nconv->etype = et;
+ nconv->type = t;
+ nconv->typecheck = 1;
+ return nconv;
}
/*
static void
typecheckaste(int op, Type *tstruct, NodeList *nl)
{
- Type *t, *tl;
+ Type *t, *tl, *tn;
Node *n;
-
- if(nl != nil && nl->next == nil && nl->n->type != T && nl->n->type->etype == TSTRUCT && nl->n->type->funarg) {
- typecheckastt(op, tstruct, nl->n->type);
- return;
+ int lno;
+
+ lno = lineno;
+
+ if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
+ if(n->type->etype == TSTRUCT && n->type->funarg) {
+ setlineno(n);
+ tn = n->type->type;
+ for(tl=tstruct->type; tl; tl=tl->down) {
+ int xx, yy;
+ if(tn == T) {
+ yyerror("not enough arguments to %#O", op);
+ goto out;
+ }
+ if(checkconv(tn->type, tl->type, 0, &xx, &yy) < 0)
+ yyerror("cannot use type %T as type %T", tn->type, tl->type);
+ tn = tn->down;
+ }
+ if(tn != T)
+ yyerror("too many arguments to %#O", op);
+ goto out;
}
for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type;
if(isddd(t)) {
- for(; nl; nl=nl->next)
+ for(; nl; nl=nl->next) {
+ setlineno(nl->n);
defaultlit(&nl->n, T);
- return;
+ }
+ goto out;
}
if(nl == nil) {
yyerror("not enough arguments to %#O", op);
- return;
+ goto out;
}
n = nl->n;
+ setlineno(nl->n);
if(n->type != T)
nl->n = typecheckconv(nil, n, t, 0);
nl = nl->next;
}
if(nl != nil) {
yyerror("too many arguments to %#O", op);
- return;
+ goto out;
}
+
+out:
+ lineno = lno;
}
/*
}
}
+/*
+ * lvalue etc
+ */
static int
islvalue(Node *n)
{
for(; l; l=l->next)
checkassign(l->n);
}
+
+/*
+ * multiple assignment
+ */
+static void
+typecheckas2(Node *n)
+{
+ int cl, cr, op, et;
+ NodeList *ll, *lr;
+ Node *l, *r;
+ Iter s;
+ Type *t;
+
+ typechecklist(n->list, Erv);
+ checkassignlist(n->list);
+ typechecklist(n->rlist, Erv);
+
+ cl = count(n->list);
+ cr = count(n->rlist);
+
+ if(cl == cr) {
+ // easy
+ for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next)
+ if(ll->n->type != T && lr->n->type != T)
+ lr->n = typecheckconv(nil, lr->n, ll->n->type, 0);
+ return;
+ }
+
+
+ l = n->list->n;
+ r = n->rlist->n;
+
+ // m[i] = x, ok
+ if(cl == 1 && cr == 2 && l->op == OINDEXMAP) {
+ if(l->type == T)
+ return;
+ n->op = OAS2MAPW;
+ n->rlist->n = typecheckconv(nil, r, l->type->down, 0);
+ r = n->rlist->next->n;
+ n->rlist->next->n = typecheckconv(nil, r, types[TBOOL], 0);
+ return;
+ }
+
+ // x,y,z = f()
+ if(cr == 1) {
+ if(r->type == T)
+ return;
+ switch(r->op) {
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ if(r->type->etype != TSTRUCT || r->type->funarg == 0)
+ break;
+ cr = structcount(r->type);
+ if(cr != cl)
+ goto mismatch;
+ n->op = OAS2FUNC;
+ t = structfirst(&s, &r->type);
+ for(ll=n->list; ll; ll=ll->next) {
+ if(ll->n->type != T)
+ if(checkconv(t->type, ll->n->type, 0, &op, &et) < 0)
+ yyerror("cannot assign type %T to %+N", t->type, ll->n);
+ t = structnext(&s);
+ }
+ return;
+ }
+ }
+
+ // x, ok = y
+ if(cl == 2 && cr == 1) {
+ if(r->type == T)
+ return;
+ switch(r->op) {
+ case OINDEXMAP:
+ n->op = OAS2MAPR;
+ goto common;
+ case ORECV:
+ n->op = OAS2RECV;
+ goto common;
+ case ODOTTYPE:
+ n->op = OAS2DOTTYPE;
+ common:
+ if(l->type != T && checkconv(r->type, l->type, 0, &op, &et) < 0)
+ yyerror("cannot assign %+N to %+N", r, l);
+ l = n->list->next->n;
+ if(l->type != T && checkconv(types[TBOOL], l->type, 0, &op, &et) < 0)
+ yyerror("cannot assign bool value to %+N", l);
+ return;
+ }
+ }
+
+mismatch:
+ yyerror("assignment count mismatch: %d = %d", cl, cr);
+}
+
case OASOP:
case OAS:
case OAS2:
+ case OAS2DOTTYPE:
+ case OAS2RECV:
+ case OAS2FUNC:
+ case OAS2MAPW:
+ case OAS2MAPR:
case OCLOSE:
case OCLOSED:
case OCALLMETH:
case OPANIC:
case OPANICN:
case OEMPTY:
+ if(n->typecheck == 0)
+ fatal("missing typecheck");
init = n->ninit;
n->ninit = nil;
walkexpr(&n, &init);
case OFOR:
walkstmtlist(n->ninit);
- walkbool(&n->ntest);
+ walkexpr(&n->ntest, &n->ntest->ninit);
walkstmt(&n->nincr);
walkstmtlist(n->nbody);
break;
case OIF:
walkstmtlist(n->ninit);
- walkbool(&n->ntest);
+ walkexpr(&n->ntest, &n->ntest->ninit);
walkstmtlist(n->nbody);
walkstmtlist(n->nelse);
break;
Node *r, *l;
NodeList *ll, *lr;
Type *t;
- int et, cl, cr;
+ int et;
int32 lno;
Node *n, *fn;
goto ret;
case OAS2:
+ as2:
*init = concat(*init, n->ninit);
n->ninit = nil;
+ walkexprlist(n->list, init);
+ walkexprlist(n->rlist, init);
+ ll = ascompatee(OAS, n->list, n->rlist, init);
+ ll = reorder3(ll);
+ n = liststmt(ll);
+ goto ret;
+ case OAS2FUNC:
+ as2func:
+ // a,b,... = fn()
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ r = n->rlist->n;
walkexprlist(n->list, init);
+ walkexpr(&r, init);
+ ll = ascompatet(n->op, n->list, &r->type, 0, init);
+ n = liststmt(concat(list1(r), ll));
+ goto ret;
- cl = count(n->list);
- cr = count(n->rlist);
- if(cl == cr) {
- multias:
- walkexprlist(n->rlist, init);
- ll = ascompatee(OAS, n->list, n->rlist, init);
- ll = reorder3(ll);
- n = liststmt(ll);
- goto ret;
- }
+ case OAS2RECV:
+ // a,b = <-c
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ r = n->rlist->n;
+ walkexprlist(n->list, init);
+ walkexpr(&r->left, init);
+ fn = chanfn("chanrecv2", 2, r->left->type);
+ r = mkcall1(fn, getoutargx(fn->type), init, r->left);
+ n->rlist->n = r;
+ n->op = OAS2FUNC;
+ goto as2func;
- l = n->list->n;
+ case OAS2MAPR:
+ // a,b = m[i];
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
r = n->rlist->n;
+ walkexprlist(n->list, init);
+ walkexpr(&r->left, init);
+ fn = mapfn("mapaccess2", r->left->type);
+ r = mkcall1(fn, getoutargx(fn->type), init, r->left, r->right);
+ n->rlist = list1(r);
+ n->op = OAS2FUNC;
+ goto as2func;
+
+ case OAS2MAPW:
+ // map[] = a,b - mapassign2
+ // a,b = m[i];
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ walkexprlist(n->list, init);
+ l = n->list->n;
+ t = l->left->type;
+ n = mkcall1(mapfn("mapassign2", t), T, init, l->left, l->right, n->rlist->n, n->rlist->next->n);
+ goto ret;
- // count mismatch - special cases
- switch(r->op) {
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- case OCALL:
- if(cr == 1) {
- // a,b,... = fn()
- walkexpr(&r, init);
- if(r->type == T || r->type->etype != TSTRUCT)
- break;
- ll = ascompatet(n->op, n->list, &r->type, 0, init);
- n = liststmt(concat(list1(r), ll));
- goto ret;
- }
+ case OAS2DOTTYPE:
+ // a,b = i.(T)
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ r = n->rlist->n;
+ walkexprlist(n->list, init);
+ walkdottype(r, init);
+ et = ifaceas1(r->type, r->left->type, 1);
+ switch(et) {
+ case I2Isame:
+ case E2Esame:
+ n->rlist = list(list1(r->left), nodbool(1));
+ typechecklist(n->rlist, Erv);
+ goto as2;
+ case I2E:
+ n->list = list(list1(n->right), nodbool(1));
+ typechecklist(n->rlist, Erv);
+ goto as2;
+ case I2T:
+ et = I2T2;
break;
-
- case OINDEXMAP:
- if(cl == 2 && cr == 1) {
- // a,b = map[] - mapaccess2
- walkexpr(&r->left, init);
- l = mapop(n, init);
- if(l == N)
- break;
- n = l;
- goto ret;
- }
+ case I2Ix:
+ et = I2I2;
break;
-
- case ORECV:
- if(cl == 2 && cr == 1) {
- // a,b = <chan - chanrecv2
- walkexpr(&r->left, init);
- if(!istype(r->left->type, TCHAN))
- break;
- l = chanop(n, init);
- if(l == N)
- break;
- n = l;
- goto ret;
- }
+ case E2I:
+ et = E2I2;
break;
-
- case ODOTTYPE:
- walkdottype(r, init);
- if(cl == 2 && cr == 1) {
- // a,b = i.(T)
- if(r->left == N)
- break;
- et = ifaceas1(r->type, r->left->type, 1);
- switch(et) {
- case I2Isame:
- case E2Esame:
- n->rlist = list(list1(r->left), nodbool(1));
- typechecklist(n->rlist, Erv);
- goto multias;
- case I2E:
- n->list = list(list1(n->right), nodbool(1));
- typechecklist(n->rlist, Erv);
- goto multias;
- case I2T:
- et = I2T2;
- break;
- case I2Ix:
- et = I2I2;
- break;
- case E2I:
- et = E2I2;
- break;
- case E2T:
- et = E2T2;
- break;
- default:
- et = Inone;
- break;
- }
- if(et == Inone)
- break;
- r = ifacecvt(r->type, r->left, et, init);
- ll = ascompatet(n->op, n->list, &r->type, 0, init);
- n = liststmt(concat(list1(r), ll));
- goto ret;
- }
+ case E2T:
+ et = E2T2;
break;
- }
-
- switch(l->op) {
- case OINDEXMAP:
- if(cl == 1 && cr == 2) {
- // map[] = a,b - mapassign2
- l = mapop(n, init);
- if(l == N)
- break;
- n = l;
- goto ret;
- }
+ default:
+ et = Inone;
break;
}
- if(l->diag == 0) {
- l->diag = 1;
- yyerror("assignment count mismatch: %d = %d", cl, cr);
- }
+ if(et == Inone)
+ break;
+ r = ifacecvt(r->type, r->left, et, init);
+ ll = ascompatet(n->op, n->list, &r->type, 0, init);
+ n = liststmt(concat(list1(r), ll));
goto ret;
case ODOTTYPE:
return nvar;
}
-void
-walkbool(Node **np)
-{
- Node *n;
-
- n = *np;
- if(n == N)
- return;
- walkexpr(np, &n->ninit);
- defaultlit(np, T);
- n = *np;
- if(n->type != T && !eqtype(n->type, types[TBOOL]))
- yyerror("IF and FOR require a boolean type");
-}
-
void
walkdottype(Node *n, NodeList **init)
{
}
convlit(&c->right, t->type);
- if(!ascompat(t->type, c->right->type)) {
- badtype(c->op, t->type, c->right->type);
- return N;
- }
// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
a = mkcall1(chanfn("selectsend", 2, t), types[TBOOL], init, var, c->left, c->right);
Node*
ascompatee1(int op, Node *l, Node *r, NodeList **init)
{
- Node *a;
-
- /*
- * check assign expression to
- * a expression. called in
- * expr = expr
- */
- if(l->type != T && l->type->etype == TFORW)
- return N;
- if(r->type != T && r->type->etype ==TFORW)
- return N;
- convlit(&r, l->type);
- if(!ascompat(l->type, r->type)) {
- badtype(op, l->type, r->type);
- return N;
- }
- a = nod(OAS, l, r);
- a = convas(a, init);
- return a;
+ return convas(nod(OAS, l, r), init);
}
NodeList*
if(r == T)
break;
l = ll->n;
- if(!ascompat(l->type, r->type)) {
- badtype(op, l->type, r->type);
- return nil;
- }
// any lv that causes a fn call must be
// deferred until all the return arguments
goto ret;
}
- if(!ascompat(l->type, r->type)) {
- badtype(op, l->type, r->type);
- return nil;
- }
-
a = nod(OAS, nodarg(l, fp), r);
a = convas(a, init);
nn = list(nn, a);
return nn;
}
-/*
- * can we assign var of type src to var of type dst?
- * return 0 if not, 1 if conversion is trivial, 2 if conversion is non-trivial.
- */
-int
-ascompat(Type *dst, Type *src)
-{
- if(eqtype(dst, src))
- return 1;
-
- if(dst == T || src == T)
- return 0;
-
- if(dst->etype == TFORWINTER || dst->etype == TFORWSTRUCT || dst->etype == TFORW)
- return 0;
- if(src->etype == TFORWINTER || src->etype == TFORWSTRUCT || src->etype == TFORW)
- return 0;
-
- // interfaces go through even if names don't match
- if(isnilinter(dst) || isnilinter(src))
- return 2;
-
- if(isinter(dst) && isinter(src))
- return 2;
-
- if(isinter(dst) && methtype(src))
- return 2;
-
- if(isinter(src) && methtype(dst))
- return 2;
-
- // otherwise, if concrete types have names, they must match
- if(dst->sym && src->sym && dst != src)
- return 0;
-
- if(dst->etype == TCHAN && src->etype == TCHAN) {
- if(!eqtype(dst->type, src->type))
- return 0;
- if(dst->chan & ~src->chan)
- return 0;
- return 1;
- }
-
- if(isslice(dst)
- && isptr[src->etype]
- && isfixedarray(src->type)
- && eqtype(dst->type, src->type->type))
- return 2;
-
- return 0;
-}
-
// generate code for print
static Node*
walkprint(Node *nn, NodeList **init)
return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
}
-Type*
-fixmap(Type *t)
-{
- if(t == T)
- goto bad;
- if(t->etype != TMAP)
- goto bad;
- if(t->down == T || t->type == T)
- goto bad;
-
- dowidth(t->down);
- dowidth(t->type);
-
- return t;
-
-bad:
- yyerror("not a map: %lT", t);
- return T;
-}
-
Type*
fixchan(Type *t)
{
Node*
mapop(Node *n, NodeList **init)
{
- Node *r, *a, *l;
+ Node *r, *a;
Type *t;
- Node *fn;
- int cl, cr;
- NodeList *args;
r = n;
switch(n->op) {
default:
fatal("mapop: unknown op %O", n->op);
-
- case OAS:
- // mapassign1(hmap map[any-1]any-2, key any-3, val any-4);
- if(n->left->op != OINDEXMAP)
- goto shape;
-
- t = fixmap(n->left->left->type);
- if(t == T)
- break;
-
- r = mkcall1(mapfn("mapassign1", t), T, init, n->left->left, n->left->right, n->right);
- break;
-
- case OAS2:
- cl = count(n->list);
- cr = count(n->rlist);
-
- if(cl == 1 && cr == 2)
- goto assign2;
- if(cl == 2 && cr == 1)
- goto access2;
- goto shape;
-
- assign2:
- // mapassign2(hmap map[any]any, key any, val any, pres bool);
- l = n->list->n;
- if(l->op != OINDEXMAP)
- goto shape;
-
- t = fixmap(l->left->type);
- if(t == T)
- break;
-
- r = mkcall1(mapfn("mapassign2", t), T, init, l->left, l->right, n->rlist->n, n->rlist->next->n);
- break;
-
- access2:
- // mapaccess2(hmap map[any-1]any-2, key any-3) (val-4 any, pres bool);
-
-//dump("access2", n);
- r = n->rlist->n;
- if(r->op != OINDEXMAP)
- goto shape;
-
- t = fixmap(r->left->type);
- if(t == T)
- break;
-
- args = list1(r->left); // map
- args = list(args, r->right); // key
-
- fn = mapfn("mapaccess2", t);
- a = mkcall1(fn, getoutargx(fn->type), init, r->left, r->right);
- n->rlist = list1(a);
- typecheck(&n, Etop);
- walkexpr(&n, init);
- r = n;
- break;
-
case OASOP:
// rewrite map[index] op= right
// into tmpi := index; map[tmpi] = map[tmpi] op right
break;
}
return r;
-
-shape:
- dump("shape", n);
- fatal("mapop: %O", n->op);
- return N;
-}
-
-Node*
-chanop(Node *n, NodeList **init)
-{
- Node *r, *fn;
- Type *t;
- int cl, cr;
-
- r = n;
- switch(n->op) {
- default:
- fatal("chanop: unknown op %O", n->op);
-
- case OAS2:
- cl = count(n->list);
- cr = count(n->rlist);
-
- if(cl != 2 || cr != 1 || n->rlist->n->op != ORECV)
- goto shape;
-
- // chanrecv2(hchan *chan any) (elem any, pres bool);
- r = n->rlist->n;
- defaultlit(&r->left, T);
- t = fixchan(r->left->type);
- if(t == T)
- break;
- if(!(t->chan & Crecv)) {
- yyerror("cannot receive from %T", t);
- break;
- }
-
- fn = chanfn("chanrecv2", 2, t);
- r = mkcall1(fn, getoutargx(fn->type), init, r->left);
- n->rlist->n = r;
- r = n;
- walkexpr(&r, init);
- break;
- }
- return r;
-
-shape:
- fatal("chanop: %O", n->op);
- return N;
-}
-
-
-Type*
-fixarray(Type *t)
-{
-
- if(t == T)
- goto bad;
- if(t->etype != TARRAY)
- goto bad;
- if(t->type == T)
- goto bad;
- dowidth(t);
- return t;
-
-bad:
- yyerror("not an array: %lT", t);
- return T;
-
}
/*
goto out;
if(n->left->op == OINDEXMAP) {
- n = mapop(n, init);
+ n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init,
+ n->left->left, n->left->right, n->right);
goto out;
}
goto out;
}
- if(ascompat(lt, rt))
- goto out;
-
- badtype(n->op, lt, rt);
-
out:
ullmancalc(n);
return n;