1
0
mirror of https://github.com/golang/go synced 2024-11-25 21:47:59 -07:00

type checking of assignments, switch, if, for

R=ken
OCL=32716
CL=32720
This commit is contained in:
Russ Cox 2009-08-04 10:26:29 -07:00
parent 417683c3d3
commit d8c19c80dc
6 changed files with 412 additions and 644 deletions

View File

@ -704,6 +704,7 @@ nodlit(Val v)
return n; return n;
} }
// TODO(rsc): combine with convlit
void void
defaultlit(Node **np, Type *t) defaultlit(Node **np, Type *t)
{ {
@ -713,7 +714,7 @@ defaultlit(Node **np, Type *t)
n = *np; n = *np;
if(n == N) if(n == N)
return; return;
if(n->type == T || n->type->etype != TIDEAL) if(n->type == T || (n->type->etype != TIDEAL && n->type->etype != TNIL))
return; return;
switch(n->op) { switch(n->op) {
@ -739,6 +740,16 @@ defaultlit(Node **np, Type *t)
lineno = n->lineno; lineno = n->lineno;
switch(n->val.ctype) { switch(n->val.ctype) {
default: 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); yyerror("defaultlit: unknown literal: %#N", n);
break; break;
case CTINT: case CTINT:

View File

@ -334,7 +334,7 @@ enum
OAPPENDSTR, OAPPENDSTR,
OARRAY, OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR, OARRAYBYTESTR, OARRAYRUNESTR,
OAS, OAS2, OASOP, OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD, OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP, OCAP,
@ -952,18 +952,6 @@ void dumpexport(void);
void dumpexporttype(Sym*); void dumpexporttype(Sym*);
void dumpexportvar(Sym*); void dumpexportvar(Sym*);
void dumpexportconst(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 importconst(Sym *s, Type *t, Node *v);
void importmethod(Sym *s, Type *t); void importmethod(Sym *s, Type *t);
void importtype(Sym *s, Type *t); void importtype(Sym *s, Type *t);
@ -981,7 +969,6 @@ void walkexprlist(NodeList*, NodeList**);
void walkconv(Node**, NodeList**); void walkconv(Node**, NodeList**);
void walkdottype(Node*, NodeList**); void walkdottype(Node*, NodeList**);
void walkas(Node*); void walkas(Node*);
void walkbool(Node**);
void walkswitch(Node*); void walkswitch(Node*);
void walkselect(Node*); void walkselect(Node*);
void walkdot(Node*, NodeList**); void walkdot(Node*, NodeList**);
@ -990,21 +977,14 @@ Node* ascompatee1(int, Node*, Node*, NodeList**);
NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**); NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
NodeList* ascompatte(int, Type**, NodeList*, 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**); Node* mapop(Node*, NodeList**);
Type* fixchan(Type*); Type* fixchan(Type*);
Node* chanop(Node*, NodeList**);
Node* ifacecvt(Type*, Node*, int, NodeList**); Node* ifacecvt(Type*, Node*, int, NodeList**);
Node* ifaceop(Node*);
int ifaceas(Type*, Type*, int); int ifaceas(Type*, Type*, int);
int ifaceas1(Type*, Type*, int); int ifaceas1(Type*, Type*, int);
void ifacecheck(Type*, Type*, int, int); void ifacecheck(Type*, Type*, int, int);
void runifacechecks(void); void runifacechecks(void);
Node* convas(Node*, NodeList**); Node* convas(Node*, NodeList**);
void arrayconv(Type*, Node*);
Node* colas(NodeList*, NodeList*); Node* colas(NodeList*, NodeList*);
Node* dorange(Node*); Node* dorange(Node*);
NodeList* reorder1(NodeList*); NodeList* reorder1(NodeList*);
@ -1019,6 +999,7 @@ void heapmoves(void);
void walkdeflist(NodeList*); void walkdeflist(NodeList*);
void walkdef(Node*); void walkdef(Node*);
void typechecklist(NodeList*, int); void typechecklist(NodeList*, int);
void typecheckswitch(Node*);
Node* typecheckconv(Node*, Node*, Type*, int); Node* typecheckconv(Node*, Node*, Type*, int);
Node* typecheck(Node**, int); Node* typecheck(Node**, int);

View File

@ -231,6 +231,7 @@ exprfmt(Fmt *f, Node *n, int prec)
break; break;
case OINDEX: case OINDEX:
case OINDEXMAP:
exprfmt(f, n->left, 7); exprfmt(f, n->left, 7);
fmtprint(f, "["); fmtprint(f, "[");
exprfmt(f, n->right, 0); exprfmt(f, n->right, 0);

View File

@ -233,112 +233,6 @@ csort(Case *l, int(*f)(Case*, Case*))
return l; 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* Node*
newlabel(void) newlabel(void)
{ {
@ -597,22 +491,9 @@ exprswitch(Node *sw)
arg = Sfalse; arg = Sfalse;
} }
walkexpr(&sw->ntest, &sw->ninit); walkexpr(&sw->ntest, &sw->ninit);
t = sw->type;
/*
* 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);
if(t == T) if(t == T)
return; return;
walkcases(sw, sw3, arg);
convlit(&sw->ntest, t);
/* /*
* convert the switch into OIF statements * convert the switch into OIF statements
@ -785,7 +666,6 @@ typeswitch(Node *sw)
yyerror("type switch must be on an interface"); yyerror("type switch must be on an interface");
return; return;
} }
walkcases(sw, sw0, Stype);
cas = nil; cas = nil;
/* /*
@ -886,3 +766,64 @@ walkswitch(Node *sw)
} }
exprswitch(sw); 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;
}

View File

@ -12,7 +12,8 @@
* *
* TODO: * TODO:
* trailing ... section of function calls * trailing ... section of function calls
* statements * select
* range
*/ */
#include "go.h" #include "go.h"
@ -26,7 +27,7 @@ static Type* lookdot1(Sym *s, Type *t, Type *f);
static int nokeys(NodeList*); static int nokeys(NodeList*);
static void typecheckcomplit(Node**); static void typecheckcomplit(Node**);
static void addrescapes(Node*); static void addrescapes(Node*);
static void typecheckas2(Node*);
static void checklvalue(Node*, char*); static void checklvalue(Node*, char*);
static void checkassign(Node*); static void checkassign(Node*);
static void checkassignlist(NodeList*); static void checkassignlist(NodeList*);
@ -815,9 +816,7 @@ reswitch:
goto ret; goto ret;
case OAS2: case OAS2:
typechecklist(n->list, Erv); typecheckas2(n);
checkassignlist(n->list);
typechecklist(n->rlist, Erv);
goto ret; goto ret;
case OBREAK: case OBREAK:
@ -836,14 +835,18 @@ reswitch:
case OFOR: case OFOR:
typechecklist(n->ninit, Etop); 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); typecheck(&n->nincr, Etop);
typechecklist(n->nbody, Etop); typechecklist(n->nbody, Etop);
goto ret; goto ret;
case OIF: case OIF:
typechecklist(n->ninit, Etop); 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->nbody, Etop);
typechecklist(n->nelse, Etop); typechecklist(n->nelse, Etop);
goto ret; goto ret;
@ -862,13 +865,12 @@ reswitch:
goto ret; goto ret;
case OSWITCH: case OSWITCH:
typechecklist(n->ninit, Etop); typecheckswitch(n);
typecheck(&n->ntest, Erv);
typechecklist(n->list, Etop);
goto ret; goto ret;
case OTYPECASE: case OTYPECASE:
typecheck(&n->left, Erv); typecheck(&n->left, Erv);
ok |= Erv;
goto ret; goto ret;
case OTYPESW: case OTYPESW:
@ -888,7 +890,7 @@ ret:
goto error; goto error;
} }
if((top & (Erv|Etype)) == Etype && n->op != OTYPE) { 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; goto error;
} }
if((ok & Ecall) && !(top & Ecall)) { if((ok & Ecall) && !(top & Ecall)) {
@ -1043,183 +1045,163 @@ nokeys(NodeList *l)
return 1; return 1;
} }
Node* static int
typecheckconv(Node *nconv, Node *n, Type *t, int explicit) checkconv(Type *nt, Type *t, int explicit, int *op, int *et)
{ {
int et, op; *op = OCONV;
Node *n1; *et = 0;
op = OCONV;
et = 0;
// preexisting error // preexisting error
if(t == T || t->etype == TFORW) if(t == T || t->etype == TFORW)
return n; return 0;
/* /*
* implicit conversions * implicit conversions
*/ */
if(nt == T)
return 0;
convlit1(&n, t, explicit); if(eqtype(t, nt)) {
if(n->type == T)
return n;
if(eqtype(t, n->type)) {
exportassignok(t); exportassignok(t);
op = OCONVNOP; *op = OCONVNOP;
if(!explicit || t == n->type) if(!explicit || t == nt)
return n; return 0;
goto conv; return 1;
} }
// interfaces are not subject to the name restrictions below. // 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 // generate a good message. some messages have to be
// delayed anyway. // delayed anyway.
if(isnilinter(t) || isnilinter(n->type) || isinter(t) || isinter(n->type)) { if(isnilinter(t) || isnilinter(nt) || isinter(t) || isinter(nt)) {
et = ifaceas1(t, n->type, 0); *et = ifaceas1(t, nt, 0);
op = OCONVIFACE; *op = OCONVIFACE;
goto conv; return 1;
} }
// otherwise, if concrete types have names, they must match. // otherwise, if concrete types have names, they must match.
if(!explicit && t->sym && n->type->sym && t != n->type) if(!explicit && t->sym && nt->sym && t != nt)
goto badimplicit; return -1;
// channel must not lose directionality // channel must not lose directionality
if(t->etype == TCHAN && n->type->etype == TCHAN) { if(t->etype == TCHAN && nt->etype == TCHAN) {
if(t->chan & ~n->type->chan) { if(t->chan & ~nt->chan)
if(!explicit) return -1;
goto badimplicit; if(eqtype(t->type, nt->type)) {
goto badexplicit; *op = OCONVNOP;
} return 1;
if(eqtype(t->type, n->type->type)) {
op = OCONVNOP;
goto conv;
} }
} }
// array to slice // array to slice
if(isslice(t) && isptr[n->type->etype] && isfixedarray(n->type->type) if(isslice(t) && isptr[nt->etype] && isfixedarray(nt->type)
&& eqtype(t->type, n->type->type->type)) { && eqtype(t->type, nt->type->type)) {
op = OCONVSLICE; *op = OCONVSLICE;
goto conv; return 1;
}
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;
} }
/* /*
* explicit conversions * explicit conversions
*/ */
if(!explicit)
return -1;
// same representation // same representation
if(cvttype(t, n->type)) { if(cvttype(t, nt)) {
if(n->op == OLITERAL) { *op = OCONVNOP;
// can convert literal in place return 1;
n1 = nod(OXXX, N, N);
*n1 = *n;
n1->type = t;
return n1;
}
op = OCONVNOP;
goto conv;
} }
// simple fix-float // simple fix-float
if(isint[t->etype] || isfloat[t->etype]) if(isint[t->etype] || isfloat[t->etype])
if(isint[n->type->etype] || isfloat[n->type->etype]) { if(isint[nt->etype] || isfloat[nt->etype])
// evconst(n); // XXX is this needed? return 1;
goto conv;
}
// to string // to string
if(istype(t, TSTRING)) { if(istype(t, TSTRING)) {
// integer rune // integer rune
if(isint[n->type->etype]) { if(isint[nt->etype]) {
op = ORUNESTR; *op = ORUNESTR;
goto conv; return 1;
} }
// *[10]byte -> string? convert *[10]byte -> []byte // *[10]byte -> string
// in preparation for next step // in preparation for next step
if(isptr[n->type->etype] && isfixedarray(n->type->type)) { if(isptr[nt->etype] && isfixedarray(nt->type)) {
switch(n->type->type->type->etype) { switch(nt->type->type->etype) {
case TUINT8: case TUINT8:
*op = OARRAYBYTESTR;
return 1;
case TINT: case TINT:
n1 = nod(OCONV, n, N); *op = OARRAYRUNESTR;
n1->type = typ(TARRAY); return 1;
n1->type->bound = -1;
n1->type->type = n->type->type->type;
dowidth(n1->type);
typecheck(&n1, Erv);
walkexpr(&n1, nil);
n = n1;
break;
} }
} }
// []byte -> string // []byte -> string
if(isslice(n->type)) { if(isslice(nt)) {
switch(n->type->type->etype) { switch(nt->type->etype) {
case TUINT8: case TUINT8:
op = OARRAYBYTESTR; *op = OARRAYBYTESTR;
goto conv; return 1;
case TINT: case TINT:
op = OARRAYRUNESTR; *op = OARRAYRUNESTR;
goto conv; return 1;
} }
} }
} }
// convert to unsafe pointer // convert to unsafe pointer
if(isptrto(t, TANY) if(isptrto(t, TANY)
&& (isptr[n->type->etype] || n->type->etype == TUINTPTR)) && (isptr[nt->etype] || nt->etype == TUINTPTR))
goto conv; return 1;
// convert from unsafe pointer // convert from unsafe pointer
if(isptrto(n->type, TANY) if(isptrto(nt, TANY)
&& (isptr[t->etype] || t->etype == TUINTPTR)) && (isptr[t->etype] || t->etype == TUINTPTR))
goto conv; return 1;
badexplicit: return -1;
yyerror("cannot convert %+N to type %T", n, t);
nconv->type = T;
return nconv;
conv:
if(nconv == nil) {
nconv = nod(OXXX, n, N);
nconv->type = t;
nconv->typecheck = 1;
}
nconv->etype = et;
nconv->op = op;
return nconv;
} }
/* Node*
* typecheck assignment: type list = type list typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
*/
static void
typecheckastt(int op, Type *t1, Type *t2)
{ {
for(t1=t1->type, t2=t2->type; t1; t1=t1->down, t2=t2->down) { int et, op;
if(t2 == nil) { Node *n1;
yyerror("too few");
return; convlit1(&n, t, explicit);
} if(n->type == T)
if(!eqtype(t1->type, t2->type)) { return n;
yyerror("wrong");
} 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;
} }
/* /*
@ -1228,34 +1210,57 @@ typecheckastt(int op, Type *t1, Type *t2)
static void static void
typecheckaste(int op, Type *tstruct, NodeList *nl) typecheckaste(int op, Type *tstruct, NodeList *nl)
{ {
Type *t, *tl; Type *t, *tl, *tn;
Node *n; Node *n;
int lno;
if(nl != nil && nl->next == nil && nl->n->type != T && nl->n->type->etype == TSTRUCT && nl->n->type->funarg) { lno = lineno;
typecheckastt(op, tstruct, nl->n->type);
return; 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) { for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type; t = tl->type;
if(isddd(t)) { if(isddd(t)) {
for(; nl; nl=nl->next) for(; nl; nl=nl->next) {
setlineno(nl->n);
defaultlit(&nl->n, T); defaultlit(&nl->n, T);
return; }
goto out;
} }
if(nl == nil) { if(nl == nil) {
yyerror("not enough arguments to %#O", op); yyerror("not enough arguments to %#O", op);
return; goto out;
} }
n = nl->n; n = nl->n;
setlineno(nl->n);
if(n->type != T) if(n->type != T)
nl->n = typecheckconv(nil, n, t, 0); nl->n = typecheckconv(nil, n, t, 0);
nl = nl->next; nl = nl->next;
} }
if(nl != nil) { if(nl != nil) {
yyerror("too many arguments to %#O", op); yyerror("too many arguments to %#O", op);
return; goto out;
} }
out:
lineno = lno;
} }
/* /*
@ -1612,6 +1617,9 @@ addrescapes(Node *n)
} }
} }
/*
* lvalue etc
*/
static int static int
islvalue(Node *n) islvalue(Node *n)
{ {
@ -1655,3 +1663,98 @@ checkassignlist(NodeList *l)
for(; l; l=l->next) for(; l; l=l->next)
checkassign(l->n); 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);
}

View File

@ -221,6 +221,11 @@ walkstmt(Node **np)
case OASOP: case OASOP:
case OAS: case OAS:
case OAS2: case OAS2:
case OAS2DOTTYPE:
case OAS2RECV:
case OAS2FUNC:
case OAS2MAPW:
case OAS2MAPR:
case OCLOSE: case OCLOSE:
case OCLOSED: case OCLOSED:
case OCALLMETH: case OCALLMETH:
@ -234,6 +239,8 @@ walkstmt(Node **np)
case OPANIC: case OPANIC:
case OPANICN: case OPANICN:
case OEMPTY: case OEMPTY:
if(n->typecheck == 0)
fatal("missing typecheck");
init = n->ninit; init = n->ninit;
n->ninit = nil; n->ninit = nil;
walkexpr(&n, &init); walkexpr(&n, &init);
@ -266,14 +273,14 @@ walkstmt(Node **np)
case OFOR: case OFOR:
walkstmtlist(n->ninit); walkstmtlist(n->ninit);
walkbool(&n->ntest); walkexpr(&n->ntest, &n->ntest->ninit);
walkstmt(&n->nincr); walkstmt(&n->nincr);
walkstmtlist(n->nbody); walkstmtlist(n->nbody);
break; break;
case OIF: case OIF:
walkstmtlist(n->ninit); walkstmtlist(n->ninit);
walkbool(&n->ntest); walkexpr(&n->ntest, &n->ntest->ninit);
walkstmtlist(n->nbody); walkstmtlist(n->nbody);
walkstmtlist(n->nelse); walkstmtlist(n->nelse);
break; break;
@ -331,7 +338,7 @@ walkexpr(Node **np, NodeList **init)
Node *r, *l; Node *r, *l;
NodeList *ll, *lr; NodeList *ll, *lr;
Type *t; Type *t;
int et, cl, cr; int et;
int32 lno; int32 lno;
Node *n, *fn; Node *n, *fn;
@ -482,127 +489,104 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OAS2: case OAS2:
as2:
*init = concat(*init, n->ninit); *init = concat(*init, n->ninit);
n->ninit = nil; n->ninit = nil;
walkexprlist(n->list, init); walkexprlist(n->list, init);
walkexprlist(n->rlist, init);
ll = ascompatee(OAS, n->list, n->rlist, init);
ll = reorder3(ll);
n = liststmt(ll);
goto ret;
cl = count(n->list); case OAS2FUNC:
cr = count(n->rlist); as2func:
if(cl == cr) { // a,b,... = fn()
multias: *init = concat(*init, n->ninit);
walkexprlist(n->rlist, init); n->ninit = nil;
ll = ascompatee(OAS, n->list, n->rlist, init);
ll = reorder3(ll);
n = liststmt(ll);
goto ret;
}
l = n->list->n;
r = n->rlist->n; 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;
// count mismatch - special cases case OAS2RECV:
switch(r->op) { // a,b = <-c
case OCALLMETH: *init = concat(*init, n->ninit);
case OCALLINTER: n->ninit = nil;
case OCALLFUNC: r = n->rlist->n;
case OCALL: walkexprlist(n->list, init);
if(cr == 1) { walkexpr(&r->left, init);
// a,b,... = fn() fn = chanfn("chanrecv2", 2, r->left->type);
walkexpr(&r, init); r = mkcall1(fn, getoutargx(fn->type), init, r->left);
if(r->type == T || r->type->etype != TSTRUCT) n->rlist->n = r;
break; n->op = OAS2FUNC;
ll = ascompatet(n->op, n->list, &r->type, 0, init); goto as2func;
n = liststmt(concat(list1(r), ll));
goto ret; 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;
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; break;
case I2Ix:
case OINDEXMAP: et = I2I2;
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;
}
break; break;
case E2I:
case ORECV: et = E2I2;
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;
}
break; break;
case E2T:
case ODOTTYPE: et = E2T2;
walkdottype(r, init); break;
if(cl == 2 && cr == 1) { default:
// a,b = i.(T) et = Inone;
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;
}
break; break;
} }
if(et == Inone)
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;
}
break; break;
} r = ifacecvt(r->type, r->left, et, init);
if(l->diag == 0) { ll = ascompatet(n->op, n->list, &r->type, 0, init);
l->diag = 1; n = liststmt(concat(list1(r), ll));
yyerror("assignment count mismatch: %d = %d", cl, cr);
}
goto ret; goto ret;
case ODOTTYPE: case ODOTTYPE:
@ -945,21 +929,6 @@ makenewvar(Type *t, NodeList **init, Node **nstar)
return nvar; 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 void
walkdottype(Node *n, NodeList **init) walkdottype(Node *n, NodeList **init)
{ {
@ -1047,10 +1016,6 @@ selcase(Node *n, Node *var, NodeList **init)
} }
convlit(&c->right, t->type); 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); // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
a = mkcall1(chanfn("selectsend", 2, t), types[TBOOL], init, var, c->left, c->right); a = mkcall1(chanfn("selectsend", 2, t), types[TBOOL], init, var, c->left, c->right);
@ -1255,25 +1220,7 @@ walkselect(Node *sel)
Node* Node*
ascompatee1(int op, Node *l, Node *r, NodeList **init) ascompatee1(int op, Node *l, Node *r, NodeList **init)
{ {
Node *a; return convas(nod(OAS, l, r), init);
/*
* 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;
} }
NodeList* NodeList*
@ -1335,10 +1282,6 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
if(r == T) if(r == T)
break; break;
l = ll->n; 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 // any lv that causes a fn call must be
// deferred until all the return arguments // deferred until all the return arguments
@ -1592,11 +1535,6 @@ loop:
goto ret; goto ret;
} }
if(!ascompat(l->type, r->type)) {
badtype(op, l->type, r->type);
return nil;
}
a = nod(OAS, nodarg(l, fp), r); a = nod(OAS, nodarg(l, fp), r);
a = convas(a, init); a = convas(a, init);
nn = list(nn, a); nn = list(nn, a);
@ -1614,58 +1552,6 @@ ret:
return nn; 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 // generate code for print
static Node* static Node*
walkprint(Node *nn, NodeList **init) walkprint(Node *nn, NodeList **init)
@ -1776,26 +1662,6 @@ callnew(Type *t)
return mkcall1(fn, ptrto(t), nil, nodintconst(t->width)); 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* Type*
fixchan(Type *t) fixchan(Type *t)
{ {
@ -1818,75 +1684,13 @@ bad:
Node* Node*
mapop(Node *n, NodeList **init) mapop(Node *n, NodeList **init)
{ {
Node *r, *a, *l; Node *r, *a;
Type *t; Type *t;
Node *fn;
int cl, cr;
NodeList *args;
r = n; r = n;
switch(n->op) { switch(n->op) {
default: default:
fatal("mapop: unknown op %O", n->op); 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: case OASOP:
// rewrite map[index] op= right // rewrite map[index] op= right
// into tmpi := index; map[tmpi] = map[tmpi] op right // into tmpi := index; map[tmpi] = map[tmpi] op right
@ -1911,75 +1715,6 @@ mapop(Node *n, NodeList **init)
break; break;
} }
return r; 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;
} }
/* /*
@ -2160,7 +1895,8 @@ convas(Node *n, NodeList **init)
goto out; goto out;
if(n->left->op == OINDEXMAP) { 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;
} }
@ -2173,11 +1909,6 @@ convas(Node *n, NodeList **init)
goto out; goto out;
} }
if(ascompat(lt, rt))
goto out;
badtype(n->op, lt, rt);
out: out:
ullmancalc(n); ullmancalc(n);
return n; return n;