]> Cypherpunks repositories - gostls13.git/commitdiff
type checking of assignments, switch, if, for
authorRuss Cox <rsc@golang.org>
Tue, 4 Aug 2009 17:26:29 +0000 (10:26 -0700)
committerRuss Cox <rsc@golang.org>
Tue, 4 Aug 2009 17:26:29 +0000 (10:26 -0700)
R=ken
OCL=32716
CL=32720

src/cmd/gc/const.c
src/cmd/gc/go.h
src/cmd/gc/print.c
src/cmd/gc/swt.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c

index bbbc8d7399d12da438a696d81e55a6dead7a9b95..054ce2412113599ac940f5a88221b6a4e32a2901 100644 (file)
@@ -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:
index 7b2776dd76887a7d9b9869139b9325e4b58f9797..4b81dd9599f5f96d2ca117fe72e08fb4a0e0df1f 100644 (file)
@@ -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);
 
index 5792422b4b614e3fe60a0643ef786d3cc75715dc..bb79037258bcbf1662c42e0329aef170dcea058e 100644 (file)
@@ -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);
index a885bb371f1a69d0a42de948efc0bc373c11e191..17a4433489488fb4d226ac5307a986112098560e 100644 (file)
@@ -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;
+}
index 5f82b08eee9fe148e030f0ab444f95325867f62a..b8139c3d8c2bd018c0edd15cb1bcdf4d3d6115be 100644 (file)
@@ -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,183 +1045,163 @@ 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;
-
-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;
 }
 
 /*
@@ -1228,34 +1210,57 @@ typecheckastt(int op, Type *t1, Type *t2)
 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;
 }
 
 /*
@@ -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);
+}
+
index d9f2a9092c937b5d02c976b7263a9628a23a7173..ad7c4254d5c4d538b8ceb83fb0c019ffefdd590a 100644 (file)
@@ -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,127 +489,104 @@ walkexpr(Node **np, NodeList **init)
                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:
@@ -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;