mirror of
https://github.com/golang/go
synced 2024-11-13 17:20:22 -07:00
type checking of assignments, switch, if, for
R=ken OCL=32716 CL=32720
This commit is contained in:
parent
417683c3d3
commit
d8c19c80dc
@ -704,6 +704,7 @@ nodlit(Val v)
|
||||
return n;
|
||||
}
|
||||
|
||||
// TODO(rsc): combine with convlit
|
||||
void
|
||||
defaultlit(Node **np, Type *t)
|
||||
{
|
||||
@ -713,7 +714,7 @@ 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) {
|
||||
@ -739,6 +740,16 @@ defaultlit(Node **np, Type *t)
|
||||
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:
|
||||
|
@ -334,7 +334,7 @@ enum
|
||||
OAPPENDSTR,
|
||||
OARRAY,
|
||||
OARRAYBYTESTR, OARRAYRUNESTR,
|
||||
OAS, OAS2, OASOP,
|
||||
OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
|
||||
OBAD,
|
||||
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
|
||||
OCAP,
|
||||
@ -952,18 +952,6 @@ void dumpexport(void);
|
||||
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);
|
||||
@ -981,7 +969,6 @@ void walkexprlist(NodeList*, NodeList**);
|
||||
void walkconv(Node**, NodeList**);
|
||||
void walkdottype(Node*, NodeList**);
|
||||
void walkas(Node*);
|
||||
void walkbool(Node**);
|
||||
void walkswitch(Node*);
|
||||
void walkselect(Node*);
|
||||
void walkdot(Node*, NodeList**);
|
||||
@ -990,21 +977,14 @@ Node* ascompatee1(int, Node*, 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*);
|
||||
@ -1019,6 +999,7 @@ void heapmoves(void);
|
||||
void walkdeflist(NodeList*);
|
||||
void walkdef(Node*);
|
||||
void typechecklist(NodeList*, int);
|
||||
void typecheckswitch(Node*);
|
||||
Node* typecheckconv(Node*, Node*, Type*, int);
|
||||
Node* typecheck(Node**, int);
|
||||
|
||||
|
@ -231,6 +231,7 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
case OINDEXMAP:
|
||||
exprfmt(f, n->left, 7);
|
||||
fmtprint(f, "[");
|
||||
exprfmt(f, n->right, 0);
|
||||
|
183
src/cmd/gc/swt.c
183
src/cmd/gc/swt.c
@ -233,112 +233,6 @@ csort(Case *l, int(*f)(Case*, Case*))
|
||||
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)
|
||||
{
|
||||
@ -597,22 +491,9 @@ exprswitch(Node *sw)
|
||||
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
|
||||
@ -785,7 +666,6 @@ typeswitch(Node *sw)
|
||||
yyerror("type switch must be on an interface");
|
||||
return;
|
||||
}
|
||||
walkcases(sw, sw0, Stype);
|
||||
cas = nil;
|
||||
|
||||
/*
|
||||
@ -886,3 +766,64 @@ walkswitch(Node *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;
|
||||
}
|
||||
|
@ -12,7 +12,8 @@
|
||||
*
|
||||
* TODO:
|
||||
* trailing ... section of function calls
|
||||
* statements
|
||||
* select
|
||||
* range
|
||||
*/
|
||||
|
||||
#include "go.h"
|
||||
@ -26,7 +27,7 @@ static Type* lookdot1(Sym *s, Type *t, Type *f);
|
||||
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*);
|
||||
@ -815,9 +816,7 @@ reswitch:
|
||||
goto ret;
|
||||
|
||||
case OAS2:
|
||||
typechecklist(n->list, Erv);
|
||||
checkassignlist(n->list);
|
||||
typechecklist(n->rlist, Erv);
|
||||
typecheckas2(n);
|
||||
goto ret;
|
||||
|
||||
case OBREAK:
|
||||
@ -836,14 +835,18 @@ reswitch:
|
||||
|
||||
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;
|
||||
@ -862,13 +865,12 @@ reswitch:
|
||||
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:
|
||||
@ -888,7 +890,7 @@ ret:
|
||||
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)) {
|
||||
@ -1043,219 +1045,222 @@ nokeys(NodeList *l)
|
||||
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;
|
||||
return 1;
|
||||
|
||||
badexplicit:
|
||||
return -1;
|
||||
}
|
||||
|
||||
Node*
|
||||
typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
switch(checkconv(n->type, t, explicit, &op, &et)) {
|
||||
case -1:
|
||||
if(explicit)
|
||||
yyerror("cannot convert %+N to type %T", n, t);
|
||||
nconv->type = T;
|
||||
return nconv;
|
||||
else
|
||||
yyerror("cannot use %+N as type %T", n, t);
|
||||
return n;
|
||||
|
||||
conv:
|
||||
if(nconv == nil) {
|
||||
nconv = nod(OXXX, n, 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;
|
||||
}
|
||||
nconv->etype = et;
|
||||
nconv->op = op;
|
||||
return nconv;
|
||||
}
|
||||
|
||||
/*
|
||||
* typecheck assignment: type list = type list
|
||||
*/
|
||||
static void
|
||||
typecheckastt(int op, Type *t1, Type *t2)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
if(t2 != nil)
|
||||
yyerror("too many");
|
||||
}
|
||||
|
||||
/*
|
||||
* typecheck assignment: type list = expression list
|
||||
*/
|
||||
static void
|
||||
typecheckaste(int op, Type *tstruct, NodeList *nl)
|
||||
{
|
||||
Type *t, *tl;
|
||||
Type *t, *tl, *tn;
|
||||
Node *n;
|
||||
int lno;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1612,6 +1617,9 @@ addrescapes(Node *n)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* lvalue etc
|
||||
*/
|
||||
static int
|
||||
islvalue(Node *n)
|
||||
{
|
||||
@ -1655,3 +1663,98 @@ checkassignlist(NodeList *l)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -221,6 +221,11 @@ walkstmt(Node **np)
|
||||
case OASOP:
|
||||
case OAS:
|
||||
case OAS2:
|
||||
case OAS2DOTTYPE:
|
||||
case OAS2RECV:
|
||||
case OAS2FUNC:
|
||||
case OAS2MAPW:
|
||||
case OAS2MAPR:
|
||||
case OCLOSE:
|
||||
case OCLOSED:
|
||||
case OCALLMETH:
|
||||
@ -234,6 +239,8 @@ walkstmt(Node **np)
|
||||
case OPANIC:
|
||||
case OPANICN:
|
||||
case OEMPTY:
|
||||
if(n->typecheck == 0)
|
||||
fatal("missing typecheck");
|
||||
init = n->ninit;
|
||||
n->ninit = nil;
|
||||
walkexpr(&n, &init);
|
||||
@ -266,14 +273,14 @@ walkstmt(Node **np)
|
||||
|
||||
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;
|
||||
@ -331,7 +338,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
Node *r, *l;
|
||||
NodeList *ll, *lr;
|
||||
Type *t;
|
||||
int et, cl, cr;
|
||||
int et;
|
||||
int32 lno;
|
||||
Node *n, *fn;
|
||||
|
||||
@ -482,85 +489,83 @@ walkexpr(Node **np, NodeList **init)
|
||||
goto ret;
|
||||
|
||||
case OAS2:
|
||||
as2:
|
||||
*init = concat(*init, n->ninit);
|
||||
n->ninit = nil;
|
||||
|
||||
walkexprlist(n->list, init);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
l = n->list->n;
|
||||
r = n->rlist->n;
|
||||
|
||||
// count mismatch - special cases
|
||||
switch(r->op) {
|
||||
case OCALLMETH:
|
||||
case OCALLINTER:
|
||||
case OCALLFUNC:
|
||||
case OCALL:
|
||||
if(cr == 1) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case OINDEXMAP:
|
||||
if(cl == 2 && cr == 1) {
|
||||
// a,b = map[] - mapaccess2
|
||||
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);
|
||||
l = mapop(n, init);
|
||||
if(l == N)
|
||||
break;
|
||||
n = l;
|
||||
goto ret;
|
||||
}
|
||||
break;
|
||||
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;
|
||||
|
||||
case ORECV:
|
||||
if(cl == 2 && cr == 1) {
|
||||
// a,b = <chan - chanrecv2
|
||||
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);
|
||||
if(!istype(r->left->type, TCHAN))
|
||||
break;
|
||||
l = chanop(n, init);
|
||||
if(l == N)
|
||||
break;
|
||||
n = l;
|
||||
goto ret;
|
||||
}
|
||||
break;
|
||||
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 ODOTTYPE:
|
||||
walkdottype(r, init);
|
||||
if(cl == 2 && cr == 1) {
|
||||
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)
|
||||
if(r->left == N)
|
||||
break;
|
||||
*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 multias;
|
||||
goto as2;
|
||||
case I2E:
|
||||
n->list = list(list1(n->right), nodbool(1));
|
||||
typechecklist(n->rlist, Erv);
|
||||
goto multias;
|
||||
goto as2;
|
||||
case I2T:
|
||||
et = I2T2;
|
||||
break;
|
||||
@ -583,27 +588,6 @@ walkexpr(Node **np, NodeList **init)
|
||||
ll = ascompatet(n->op, n->list, &r->type, 0, init);
|
||||
n = liststmt(concat(list1(r), ll));
|
||||
goto ret;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(l->diag == 0) {
|
||||
l->diag = 1;
|
||||
yyerror("assignment count mismatch: %d = %d", cl, cr);
|
||||
}
|
||||
goto ret;
|
||||
|
||||
case ODOTTYPE:
|
||||
walkdottype(n, init);
|
||||
@ -945,21 +929,6 @@ makenewvar(Type *t, NodeList **init, Node **nstar)
|
||||
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)
|
||||
{
|
||||
@ -1047,10 +1016,6 @@ selcase(Node *n, Node *var, 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);
|
||||
@ -1255,25 +1220,7 @@ walkselect(Node *sel)
|
||||
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*
|
||||
@ -1335,10 +1282,6 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
|
||||
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
|
||||
@ -1592,11 +1535,6 @@ loop:
|
||||
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);
|
||||
@ -1614,58 +1552,6 @@ ret:
|
||||
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)
|
||||
@ -1776,26 +1662,6 @@ callnew(Type *t)
|
||||
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)
|
||||
{
|
||||
@ -1818,75 +1684,13 @@ bad:
|
||||
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
|
||||
@ -1911,75 +1715,6 @@ mapop(Node *n, NodeList **init)
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2160,7 +1895,8 @@ convas(Node *n, NodeList **init)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2173,11 +1909,6 @@ convas(Node *n, NodeList **init)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(ascompat(lt, rt))
|
||||
goto out;
|
||||
|
||||
badtype(n->op, lt, rt);
|
||||
|
||||
out:
|
||||
ullmancalc(n);
|
||||
return n;
|
||||
|
Loading…
Reference in New Issue
Block a user