]> Cypherpunks.ru repositories - gostls13.git/commitdiff
gc: new typechecking rules
authorRuss Cox <rsc@golang.org>
Wed, 9 Jun 2010 01:50:02 +0000 (18:50 -0700)
committerRuss Cox <rsc@golang.org>
Wed, 9 Jun 2010 01:50:02 +0000 (18:50 -0700)
* Code for assignment, conversions now mirrors spec.
* Changed some snprint -> smprint.
* Renamed runtime functions to separate
  interface conversions from type assertions:
  convT2I, assertI2T, etc.
* Correct checking of \U sequences.

Fixes #840.
Fixes #830.
Fixes #778.

R=ken2
CC=golang-dev
https://golang.org/cl/1303042

29 files changed:
src/cmd/6g/cgen.c
src/cmd/gc/bits.c
src/cmd/gc/builtin.c.boot
src/cmd/gc/closure.c
src/cmd/gc/const.c
src/cmd/gc/dcl.c
src/cmd/gc/export.c
src/cmd/gc/go.h
src/cmd/gc/lex.c
src/cmd/gc/print.c
src/cmd/gc/range.c
src/cmd/gc/runtime.go
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
src/pkg/math/fltasm_amd64.s [new file with mode: 0644]
src/pkg/runtime/iface.c
test/assign1.go [new file with mode: 0644]
test/convert3.go
test/fixedbugs/bug248.dir/bug3.go
test/fixedbugs/bug251.go
test/fixedbugs/bug284.go [moved from test/bugs/bug284.go with 100% similarity]
test/fixedbugs/bug285.go [moved from test/bugs/bug285.go with 98% similarity]
test/golden.out
test/interface/explicit.go
test/interface/pointer.go
test/interface/receiver1.go
test/named.go
test/named1.go

index 282f6d7be7b8375b03bbd5cf7b8f2eec35eb5040..aacc0d06f0d78bf8bba5f74233305f737797fde1 100644 (file)
@@ -431,7 +431,7 @@ agen(Node *n, Node *res)
        if(n == N || n->type == T)
                return;
 
-       if(!isptr[res->type->etype])
+       if(!isptr[res->type->etype] && res->type->etype != TUINTPTR)
                fatal("agen: not tptr: %T", res->type);
 
        while(n->op == OCONVNOP)
index 57caf58dc0ff152335d36c5e2a590fb488d4b99d..59a8e04efbb62c3c9023350a0c60e974faaa7623 100644 (file)
@@ -133,25 +133,22 @@ bitno(int32 b)
 int
 Qconv(Fmt *fp)
 {
-       char str[STRINGSZ], ss[STRINGSZ], *s;
        Bits bits;
-       int i;
+       int i, first;
 
-       str[0] = 0;
+       first = 1;
        bits = va_arg(fp->args, Bits);
        while(bany(&bits)) {
                i = bnum(bits);
-               if(str[0])
-                       strcat(str, " ");
-               if(var[i].sym == S) {
-                       sprint(ss, "$%lld", var[i].offset);
-                       s = ss;
-               } else
-                       s = var[i].sym->name;
-               if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
-                       break;
-               strcat(str, s);
+               if(first)
+                       first = 0;
+               else
+                       fmtprint(fp, " ");
+               if(var[i].sym == S)
+                       fmtprint(fp, "$%lld", var[i].offset);
+               else
+                       fmtprint(fp, var[i].sym->name);
                bits.b[i/32] &= ~(1L << (i%32));
        }
-       return fmtstrcpy(fp, str);
+       return 0;
 }
index 1e7a14947b6f3ba1961ae866dddf780faf752356..3e2d98872589aa30859a986ea1102f25c8aabc62 100644 (file)
@@ -33,18 +33,22 @@ char *runtimeimport =
        "func \"\".stringiter (? string, ? int) int\n"
        "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
        "func \"\".slicecopy (to any, fr any, wid uint32) int\n"
-       "func \"\".ifaceI2E (iface any) any\n"
-       "func \"\".ifaceE2I (typ *uint8, iface any) any\n"
-       "func \"\".ifaceT2E (typ *uint8, elem any) any\n"
-       "func \"\".ifaceE2T (typ *uint8, elem any) any\n"
-       "func \"\".ifaceE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
-       "func \"\".ifaceE2T2 (typ *uint8, elem any) (ret any, ok bool)\n"
-       "func \"\".ifaceT2I (typ1 *uint8, typ2 *uint8, elem any) any\n"
-       "func \"\".ifaceI2T (typ *uint8, iface any) any\n"
-       "func \"\".ifaceI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
-       "func \"\".ifaceI2I (typ *uint8, iface any) any\n"
-       "func \"\".ifaceI2Ix (typ *uint8, iface any) any\n"
-       "func \"\".ifaceI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
+       "func \"\".convI2E (elem any) any\n"
+       "func \"\".convI2I (typ *uint8, elem any) any\n"
+       "func \"\".convT2E (typ *uint8, elem any) any\n"
+       "func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n"
+       "func \"\".assertE2E (typ *uint8, iface any) any\n"
+       "func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
+       "func \"\".assertE2I (typ *uint8, iface any) any\n"
+       "func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
+       "func \"\".assertE2T (typ *uint8, iface any) any\n"
+       "func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
+       "func \"\".assertI2E (typ *uint8, iface any) any\n"
+       "func \"\".assertI2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
+       "func \"\".assertI2I (typ *uint8, iface any) any\n"
+       "func \"\".assertI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
+       "func \"\".assertI2T (typ *uint8, iface any) any\n"
+       "func \"\".assertI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
        "func \"\".ifaceeq (i1 any, i2 any) bool\n"
        "func \"\".efaceeq (i1 any, i2 any) bool\n"
        "func \"\".ifacethash (i1 any) uint32\n"
index c194a0df324968841b8f24cc622ec9d19a84caa5..a24a03a496cbcfa4f4bfd6b863b22110e916b5d5 100644 (file)
@@ -119,6 +119,7 @@ walkclosure(Node *func, NodeList **init)
        Node *xtype, *v, *addr, *xfunc, *call, *clos;
        NodeList *l, *in;
        static int closgen;
+       char *p;
 
        /*
         * wrap body in external function
@@ -134,8 +135,9 @@ walkclosure(Node *func, NodeList **init)
                if(v->op == 0)
                        continue;
                addr = nod(ONAME, N, N);
-               snprint(namebuf, sizeof namebuf, "&%s", v->sym->name);
-               addr->sym = lookup(namebuf);
+               p = smprint("&%s", v->sym->name);
+               addr->sym = lookup(p);
+               free(p);
                addr->ntype = nod(OIND, typenod(v->type), N);
                addr->class = PPARAM;
                addr->addable = 1;
index be351def652d88ea945e63183cf69c6010826cc6..c33d4d3a70b72a4bedd456212475bae9b6e4ab0c 100644 (file)
@@ -93,8 +93,11 @@ convlit1(Node **np, Type *t, int explicit)
                return;
        case OLITERAL:
                // target is invalid type for a constant?  leave alone.
-               if(!okforconst[t->etype] && n->type->etype != TNIL)
+               if(!okforconst[t->etype] && n->type->etype != TNIL) {
+                       defaultlit(&n, T);
+                       *np = n;
                        return;
+               }
                break;
        case OLSH:
        case ORSH:
@@ -109,10 +112,8 @@ convlit1(Node **np, Type *t, int explicit)
        }
 
        // avoided repeated calculations, errors
-       if(cvttype(n->type, t) == 1) {
-               n->type = t;
+       if(eqtype(n->type, t))
                return;
-       }
 
        ct = consttype(n);
        if(ct < 0)
@@ -968,6 +969,8 @@ defaultlit(Node **np, Type *t)
                break;
        case CTBOOL:
                n->type = types[TBOOL];
+               if(t != T && t->etype == TBOOL)
+                       n->type = t;
                break;
        case CTINT:
                n->type = types[TINT];
index bb81d2a2225b278552b9fef72ee19549c1acf585..48391d510a13a4c6851c1e1f0cfd7347d741cb39 100644 (file)
@@ -281,6 +281,7 @@ updatetype(Type *n, Type *t)
        local = n->local;
        vargen = n->vargen;
        *n = *t;
+       n->orig = t->orig;
        n->sym = s;
        n->local = local;
        n->siggen = 0;
@@ -759,7 +760,7 @@ typedcl2(Type *pt, Type *t)
 
        if(pt->etype == TFORW)
                goto ok;
-       if(!cvttype(pt, t))
+       if(!eqtype(pt->orig, t))
                yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
        return;
 
@@ -1154,7 +1155,7 @@ Sym*
 methodsym(Sym *nsym, Type *t0)
 {
        Sym *s;
-       char buf[NSYMB];
+       char *p;
        Type *t;
 
        t = t0;
@@ -1177,8 +1178,10 @@ methodsym(Sym *nsym, Type *t0)
        if(t != t0 && t0->sym)
                t0 = ptrto(t);
 
-       snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name);
-       return pkglookup(buf, s->pkg);
+       p = smprint("%#hT·%s", t0, nsym->name);
+       s = pkglookup(p, s->pkg);
+       free(p);
+       return s;
 
 bad:
        yyerror("illegal receiver type: %T", t0);
@@ -1200,7 +1203,7 @@ Node*
 methodname1(Node *n, Node *t)
 {
        char *star;
-       char buf[NSYMB];
+       char *p;
 
        star = "";
        if(t->op == OIND) {
@@ -1209,8 +1212,10 @@ methodname1(Node *n, Node *t)
        }
        if(t->sym == S || isblank(n))
                return newname(n->sym);
-       snprint(buf, sizeof(buf), "%s%S·%S", star, t->sym, n->sym);
-       return newname(pkglookup(buf, t->sym->pkg));
+       p = smprint("%s%S·%S", star, t->sym, n->sym);
+       n = newname(pkglookup(p, t->sym->pkg));
+       free(p);
+       return n;
 }
 
 /*
index d11ddf2ea86bcc9fefe66a47dc9d2c1d5e1c2f4d..9992c5219e8afacb09b40dff94c66035fd125cb9 100644 (file)
@@ -182,10 +182,22 @@ dumpexporttype(Sym *s)
        Bprint(bout, "type %#T %l#T\n",  t, t);
 }
 
+static int
+methcmp(const void *va, const void *vb)
+{
+       Type *a, *b;
+       
+       a = *(Type**)va;
+       b = *(Type**)vb;
+       return strcmp(a->sym->name, b->sym->name);
+}
+
 void
 dumpsym(Sym *s)
 {
        Type *f, *t;
+       Type **m;
+       int i, n;
 
        if(s->flags & SymExported)
                return;
@@ -207,14 +219,23 @@ dumpsym(Sym *s)
                break;
        case OTYPE:
                t = s->def->type;
-               // TODO(rsc): sort methods by name
-               for(f=t->method; f!=T; f=f->down)
+               n = 0;
+               for(f=t->method; f!=T; f=f->down) {     
                        dumpprereq(f);
+                       n++;
+               }
+               m = mal(n*sizeof m[0]);
+               i = 0;
+               for(f=t->method; f!=T; f=f->down)
+                       m[i++] = f;
+               qsort(m, n, sizeof m[0], methcmp);
 
                dumpexporttype(s);
-               for(f=t->method; f!=T; f=f->down)
+               for(i=0; i<n; i++) {
+                       f = m[i];
                        Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
                                f->type->type->type, f->sym, f->type);
+               }
                break;
        case ONAME:
                dumpexportvar(s);
@@ -357,7 +378,7 @@ importvar(Sym *s, Type *t, int ctxt)
 
        importsym(s, ONAME);
        if(s->def != N && s->def->op == ONAME) {
-               if(cvttype(t, s->def->type))
+               if(eqtype(t, s->def->type))
                        return;
                yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
                        s, s->def->type, t);
index 5aa95eee3b5e73e0aed5e653960535668bc07273..18e87f0cadf460a44396a86d7664b29d97dd35d6 100644 (file)
@@ -158,6 +158,7 @@ struct      Type
        uchar   isddd;  // TFIELD is ... argument
 
        Node*   nod;            // canonical OTYPE node
+       Type*   orig;           // original type (type literal or predefined type)
        int             lineno;
 
        // TFUNCT
@@ -361,11 +362,12 @@ enum
        OCLOSURE,
        OCMPIFACE, OCMPSTR,
        OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
-       OCONV, OCONVNOP, OCONVIFACE, OCONVSLICE,
+       OCONV, OCONVIFACE, OCONVNOP, OCONVSLICE,
        OCOPY,
        ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
        ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
        ODOTTYPE,
+       ODOTTYPE2,
        OEQ, ONE, OLT, OLE, OGE, OGT,
        OIND,
        OINDEX, OINDEXSTR, OINDEXMAP,
@@ -904,26 +906,21 @@ NodeList* list(NodeList*, Node*);
 NodeList*      concat(NodeList*, NodeList*);
 int            count(NodeList*);
 Node*  liststmt(NodeList*);
-
 Type** getthis(Type*);
 Type** getoutarg(Type*);
 Type** getinarg(Type*);
-
 Type*  getthisx(Type*);
 Type*  getoutargx(Type*);
 Type*  getinargx(Type*);
-
 Type*  structfirst(Iter*, Type**);
 Type*  structnext(Iter*);
 Type*  funcfirst(Iter*, Type*);
 Type*  funcnext(Iter*);
-
 int    brcom(int);
 int    brrev(int);
 void   setmaxarg(Type*);
 int    dotoffset(Node*, int*, Node**);
 void   tempname(Node*, Type*);
-
 int    Econv(Fmt*);
 int    Jconv(Fmt*);
 int    Lconv(Fmt*);
@@ -934,23 +931,22 @@ int       Nconv(Fmt*);
 void   exprfmt(Fmt*, Node*, int);
 int    Wconv(Fmt*);
 int    Zconv(Fmt*);
-
 int    lookdot0(Sym*, Type*, Type**);
 int    adddot1(Sym*, Type*, int, Type**);
 Node*  adddot(Node*);
 void   expandmeth(Sym*, Type*);
 void   genwrapper(Type*, Type*, Sym*);
-
 int    simsimtype(Type*);
-
 int    powtwo(Node*);
 Type*  tounsigned(Type*);
 void   smagic(Magic*);
 void   umagic(Magic*);
-
 void   redeclare(Sym*, char*);
 Sym*   ngotype(Node*);
-
+int    convertop(Type*, Type*, char**);
+int    assignop(Type*, Type*, char**);
+Node*  assignconv(Node*, Type*, char*);
+int    implements(Type*, Type*, Type**, Type**);
 
 /*
  *     dcl.c
@@ -1053,7 +1049,6 @@ void      walkstmt(Node**);
 void   walkstmtlist(NodeList*);
 void   walkexprlist(NodeList*, NodeList**);
 void   walkconv(Node**, NodeList**);
-void   walkdottype(Node*, NodeList**);
 void   walkas(Node*);
 void   walkswitch(Node*);
 void   walkrange(Node*);
@@ -1071,8 +1066,6 @@ Type*     fixchan(Type*);
 Node*  ifacecvt(Type*, Node*, int, NodeList**);
 int    ifaceas(Type*, Type*, int);
 int    ifaceas1(Type*, Type*, int);
-void   ifacecheck(Type*, Type*, int, int);
-void   runifacechecks(void);
 Node*  convas(Node*, NodeList**);
 Node*  colas(NodeList*, NodeList*);
 void   colasdefn(NodeList*, Node*);
@@ -1090,10 +1083,10 @@ void    typecheckswitch(Node*);
 void   typecheckselect(Node*);
 void   typecheckrange(Node*);
 Node*  typecheckconv(Node*, Node*, Type*, int, char*);
-int    checkconv(Type*, Type*, int, int*, int*, char*);
 Node*  typecheck(Node**, int);
 int    islvalue(Node*);
 void   queuemethod(Node*);
+int    exportassignok(Type*, char*);
 
 /*
  *     const.c
@@ -1242,4 +1235,4 @@ int       duintptr(Sym *s, int off, uint64 v);
 int    duintxx(Sym *s, int off, uint64 v, int wid);
 void   genembedtramp(Type*, Type*, Sym*);
 int    gen_as_init(Node*);
-int    anyregalloc();
+int    anyregalloc(void);
index f50c857a6641a8b991af958783103487949183ed..7f85271749a7532e78d4f169968cd6409f0e7a7a 100644 (file)
@@ -148,8 +148,21 @@ main(int argc, char *argv[])
        typecheckok = 1;
        if(debug['f'])
                frame(1);
+
+       // Process top-level declarations in three phases.
+       // Phase 1: const, type, and names and types of funcs.
+       //   This will gather all the information about types
+       //   and methods but doesn't depend on any of it.
+       // Phase 2: Variable assignments.
+       //   To check interface assignments, depends on phase 1.
+       // Phase 3: Function bodies.
        defercheckwidth();
-       typechecklist(xtop, Etop);
+       for(l=xtop; l; l=l->next)
+               if(l->n->op != ODCL && l->n->op != OAS)
+                       typecheck(&l->n, Etop);
+       for(l=xtop; l; l=l->next)
+               if(l->n->op == ODCL || l->n->op == OAS)
+                       typecheck(&l->n, Etop);
        resumecheckwidth();
        for(l=xtop; l; l=l->next)
                if(l->n->op == ODCLFUNC)
@@ -164,7 +177,6 @@ main(int argc, char *argv[])
        }
        dclchecks();
 
-       runifacechecks();
        if(nerrors)
                errorexit();
 
@@ -1155,7 +1167,7 @@ loop:
 int
 escchar(int e, int *escflg, vlong *val)
 {
-       int i, c;
+       int i, u, c;
        vlong l;
 
        *escflg = 0;
@@ -1177,6 +1189,7 @@ escchar(int e, int *escflg, vlong *val)
                return 0;
        }
 
+       u = 0;
        c = getr();
        switch(c) {
        case 'x':
@@ -1186,10 +1199,12 @@ escchar(int e, int *escflg, vlong *val)
 
        case 'u':
                i = 4;
+               u = 1;
                goto hex;
 
        case 'U':
                i = 8;
+               u = 1;
                goto hex;
 
        case '0':
@@ -1239,6 +1254,10 @@ hex:
                ungetc(c);
                break;
        }
+       if(u && l > Runemax) {
+               yyerror("invalid Unicode code point in escape sequence: %#llx", l);
+               l = Runeerror;
+       }
        *val = l;
        return 0;
 
@@ -1388,7 +1407,6 @@ lexinit(void)
        // (the type of x in var x string or var x = "hello").
        // this is the ideal form
        // (the type of x in const x = "hello").
-       // TODO(rsc): this may need some more thought.
        idealstring = typ(TSTRING);
        idealbool = typ(TBOOL);
 
index 83ab1cb86ca64f89a0a013bce6fa97837a16c477..97d92e1dc659cf2d8d0da7466d5e37e6c06b2c32 100644 (file)
@@ -39,6 +39,8 @@ exprfmt(Fmt *f, Node *n, int prec)
        case ODOTPTR:
        case ODOTINTER:
        case ODOTMETH:
+       case ODOTTYPE:
+       case ODOTTYPE2:
        case OARRAYBYTESTR:
        case OCAP:
        case OCLOSE:
@@ -54,7 +56,6 @@ exprfmt(Fmt *f, Node *n, int prec)
        case OCONV:
        case OCONVNOP:
        case OCONVSLICE:
-       case OCONVIFACE:
        case OMAKESLICE:
        case ORUNESTR:
        case OADDR:
@@ -64,6 +65,7 @@ exprfmt(Fmt *f, Node *n, int prec)
        case ONOT:
        case OPLUS:
        case ORECV:
+       case OCONVIFACE:
                nprec = 7;
                break;
 
@@ -277,6 +279,7 @@ exprfmt(Fmt *f, Node *n, int prec)
                break;
 
        case ODOTTYPE:
+       case ODOTTYPE2:
                exprfmt(f, n->left, 7);
                fmtprint(f, ".(");
                if(n->right != N)
@@ -336,9 +339,9 @@ exprfmt(Fmt *f, Node *n, int prec)
                break;
 
        case OCONV:
+       case OCONVIFACE:
        case OCONVNOP:
        case OCONVSLICE:
-       case OCONVIFACE:
        case OARRAYBYTESTR:
        case ORUNESTR:
                if(n->type == T || n->type->sym == S)
index 2794504d2c013a93d9d1999f7807609c91ac6d4e..09d54b3ee661c02d55c190b6dfd55f109e2d1ec2 100644 (file)
@@ -11,7 +11,7 @@
 void
 typecheckrange(Node *n)
 {
-       int op, et;
+       char *why;
        Type *t, *t1, *t2;
        Node *v1, *v2;
        NodeList *ll;
@@ -66,13 +66,13 @@ typecheckrange(Node *n)
 
        if(v1->defn == n)
                v1->type = t1;
-       else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et, "range") < 0)
-               yyerror("cannot assign type %T to %+N", t1, v1);
+       else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
+               yyerror("cannot assign type %T to %+N in range%s", t1, v1, why);
        if(v2) {
                if(v2->defn == n)
                        v2->type = t2;
-               else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et, "range") < 0)
-                       yyerror("cannot assign type %T to %+N", t1, v1);
+               else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
+                       yyerror("cannot assign type %T to %+N in range%s", t2, v2, why);
        }
 
 out:
index 392de17a00ac99cbea0276359ded0b27c8a613a4..5783faafda21a1cd436acfbdff0be3c8648729a7 100644 (file)
@@ -47,18 +47,26 @@ func stringiter(string, int) int
 func stringiter2(string, int) (retk int, retv int)
 func slicecopy(to any, fr any, wid uint32) int
 
-func ifaceI2E(iface any) (ret any)
-func ifaceE2I(typ *byte, iface any) (ret any)
-func ifaceT2E(typ *byte, elem any) (ret any)
-func ifaceE2T(typ *byte, elem any) (ret any)
-func ifaceE2I2(typ *byte, iface any) (ret any, ok bool)
-func ifaceE2T2(typ *byte, elem any) (ret any, ok bool)
-func ifaceT2I(typ1 *byte, typ2 *byte, elem any) (ret any)
-func ifaceI2T(typ *byte, iface any) (ret any)
-func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
-func ifaceI2I(typ *byte, iface any) (ret any)
-func ifaceI2Ix(typ *byte, iface any) (ret any)
-func ifaceI2I2(typ *byte, iface any) (ret any, ok bool)
+// interface conversions
+func convI2E(elem any) (ret any)
+func convI2I(typ *byte, elem any) (ret any)
+func convT2E(typ *byte, elem any) (ret any)
+func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
+
+// interface type assertions  x.(T)
+func assertE2E(typ *byte, iface any) (ret any)
+func assertE2E2(typ *byte, iface any) (ret any, ok bool)
+func assertE2I(typ *byte, iface any) (ret any)
+func assertE2I2(typ *byte, iface any) (ret any, ok bool)
+func assertE2T(typ *byte, iface any) (ret any)
+func assertE2T2(typ *byte, iface any) (ret any, ok bool)
+func assertI2E(typ *byte, iface any) (ret any)
+func assertI2E2(typ *byte, iface any) (ret any, ok bool)
+func assertI2I(typ *byte, iface any) (ret any)
+func assertI2I2(typ *byte, iface any) (ret any, ok bool)
+func assertI2T(typ *byte, iface any) (ret any)
+func assertI2T2(typ *byte, iface any) (ret any, ok bool)
+
 func ifaceeq(i1 any, i2 any) (ret bool)
 func efaceeq(i1 any, i2 any) (ret bool)
 func ifacethash(i1 any) (ret uint32)
index ac700b4c0eb9ae2c174ce4c05d529f5a75614aba..96d03617ceac2f7abe9a689d5932a327733da11a 100644 (file)
@@ -524,6 +524,7 @@ typ(int et)
        t->etype = et;
        t->width = BADWIDTH;
        t->lineno = lineno;
+       t->orig = t;
        return t;
 }
 
@@ -863,16 +864,13 @@ goopnames[] =
 int
 Oconv(Fmt *fp)
 {
-       char buf[500];
        int o;
 
        o = va_arg(fp->args, int);
        if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
                return fmtstrcpy(fp, goopnames[o]);
-       if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) {
-               snprint(buf, sizeof(buf), "O-%d", o);
-               return fmtstrcpy(fp, buf);
-       }
+       if(o < 0 || o >= nelem(opnames) || opnames[o] == nil)
+               return fmtprint(fp, "O-%d", o);
        return fmtstrcpy(fp, opnames[o]);
 }
 
@@ -992,14 +990,11 @@ etnames[] =
 int
 Econv(Fmt *fp)
 {
-       char buf[500];
        int et;
 
        et = va_arg(fp->args, int);
-       if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) {
-               snprint(buf, sizeof(buf), "E-%d", et);
-               return fmtstrcpy(fp, buf);
-       }
+       if(et < 0 || et >= nelem(etnames) || etnames[et] == nil)
+               return fmtprint(fp, "E-%d", et);
        return fmtstrcpy(fp, etnames[et]);
 }
 
@@ -1139,6 +1134,13 @@ Tpretty(Fmt *fp, Type *t)
 {
        Type *t1;
        Sym *s;
+       
+       if(debug['U']) {
+               debug['U'] = 0;
+               fmtprint(fp, "%T (orig=%T)", t, t->orig);
+               debug['U'] = 1;
+               return 0;
+       }
 
        if(t->etype != TFIELD
        && t->sym != S
@@ -1775,113 +1777,73 @@ iscomposite(Type *t)
        return 0;
 }
 
+// Return 1 if t1 and t2 are identical, following the spec rules.
+//
+// Any cyclic type must go through a named type, and if one is
+// named, it is only identical to the other if they are the same
+// pointer (t1 == t2), so there's no chance of chasing cycles
+// ad infinitum, so no need for a depth counter.
 int
-eqtype1(Type *t1, Type *t2, int d, int names)
+eqtype(Type *t1, Type *t2)
 {
-       if(d >= 20)
-               return 1;
        if(t1 == t2)
                return 1;
-       if(t1 == T || t2 == T)
-               return 0;
-       if(t1->etype != t2->etype)
-               return 0;
-       if(names && t1->etype != TFIELD && t1->sym && t2->sym && t1 != t2)
+       if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym)
                return 0;
+
        switch(t1->etype) {
        case TINTER:
        case TSTRUCT:
-               t1 = t1->type;
-               t2 = t2->type;
-               for(;;) {
-                       if(!eqtype1(t1, t2, d+1, names))
+               for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
+                       if(t1->etype != TFIELD || t2->etype != TFIELD)
+                               fatal("struct/interface missing field: %T %T", t1, t2);
+                       if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type))
                                return 0;
-                       if(t1 == T)
-                               return 1;
-                       if(t1->embedded != t2->embedded)
-                               return 0;
-                       if(t1->nname != N && t1->nname->sym != S) {
-                               if(t2->nname == N || t2->nname->sym == S)
-                                       return 0;
-                               if(strcmp(t1->nname->sym->name, t2->nname->sym->name) != 0)
-                                       return 0;
-                       }
-                       t1 = t1->down;
-                       t2 = t2->down;
                }
-               return 1;
+               return t1 == T && t2 == T;
 
        case TFUNC:
                // Loop over structs: receiver, in, out.
-               t1 = t1->type;
-               t2 = t2->type;
-               for(;;) {
+               for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
                        Type *ta, *tb;
-                       if(t1 == t2)
-                               break;
-                       if(t1 == T || t2 == T)
-                               return 0;
+
                        if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
-                               return 0;
+                               fatal("func missing struct: %T %T", t1, t2);
 
-                       // Loop over fields in structs, checking type only.
-                       ta = t1->type;
-                       tb = t2->type;
-                       while(ta != tb) {
-                               if(ta == T || tb == T)
+                       // Loop over fields in structs, ignoring argument names.
+                       for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
+                               if(ta->etype != TFIELD || tb->etype != TFIELD)
+                                       fatal("func struct missing field: %T %T", ta, tb);
+                               if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
                                        return 0;
-                               if(ta->etype != TFIELD || tb->etype != TFIELD || ta->isddd != tb->isddd)
-                                       return 0;
-                               if(!eqtype1(ta->type, tb->type, d+1, names))
-                                       return 0;
-                               ta = ta->down;
-                               tb = tb->down;
                        }
-
-                       t1 = t1->down;
-                       t2 = t2->down;
+                       if(ta != T || tb != T)
+                               return 0;
                }
-               return 1;
-
+               return t1 == T && t2 == T;
+       
        case TARRAY:
                if(t1->bound != t2->bound)
                        return 0;
                break;
-
+       
        case TCHAN:
                if(t1->chan != t2->chan)
                        return 0;
                break;
-
-       case TMAP:
-               if(!eqtype1(t1->down, t2->down, d+1, names))
-                       return 0;
-               break;
        }
-       return eqtype1(t1->type, t2->type, d+1, names);
-}
 
-int
-eqtype(Type *t1, Type *t2)
-{
-       return eqtype1(t1, t2, 0, 1);
-}
-
-/*
- * can we convert from type src to dst with
- * a trivial conversion (no bits changing)?
- */
-int
-cvttype(Type *dst, Type *src)
-{
-       return eqtype1(dst, src, 0, 0);
+       return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
 }
 
+// Are t1 and t2 equal struct types when field names are ignored?
+// For deciding whether the result struct from g can be copied
+// directly when compiling f(g()).
 int
 eqtypenoname(Type *t1, Type *t2)
 {
        if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
-               return eqtype(t1, t2);
+               return 0;
 
        t1 = t1->type;
        t2 = t2->type;
@@ -1895,6 +1857,216 @@ eqtypenoname(Type *t1, Type *t2)
        }
 }
 
+// Is type src assignment compatible to type dst?
+// If so, return op code to use in conversion.
+// If not, return 0.
+//
+// It is the caller's responsibility to call exportassignok
+// to check for assignments to other packages' unexported fields,
+int
+assignop(Type *src, Type *dst, char **why)
+{
+       Type *missing, *have;
+
+       if(why != nil)
+               *why = "";
+
+       if(src == dst)
+               return OCONVNOP;
+       if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
+               return 0;
+
+       // 1. src type is identical to dst.
+       if(eqtype(src, dst))
+               return OCONVNOP;
+       
+       // 2. src and dst have identical underlying types
+       // and either src or dst is not a named type.
+       if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S))
+               return OCONVNOP;
+
+       // 3. dst is an interface type and src implements dst.
+       if(dst->etype == TINTER && src->etype != TNIL) {
+               if(implements(src, dst, &missing, &have))
+                       return OCONVIFACE;
+               if(why != nil) {
+                       if(isptrto(src, TINTER))
+                               *why = smprint(": %T is pointer to interface, not interface", src);
+                       else if(have)
+                               *why = smprint(": %T does not implement %T (wrong type for %S method)\n"
+                                       "\thave %T\n\twant %T", src, dst, missing->sym, have->type, missing->type);
+                       else
+                               *why = smprint(": %T does not implement %T (missing %S method)",
+                                       src, dst, missing->sym);
+               }
+               return 0;
+       }
+       if(src->etype == TINTER && dst->etype != TBLANK) {
+               if(why != nil)
+                       *why = ": need type assertion";
+               return 0;
+       }
+
+       // 4. src is a bidirectional channel value, dst is a channel type,
+       // src and dst have identical element types, and
+       // either src or dst is not a named type.
+       if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
+       if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
+               return OCONVNOP;
+
+       // 5. src is the predeclared identifier nil and dst is a nillable type.
+       if(src->etype == TNIL) {
+               switch(dst->etype) {
+               case TARRAY:
+                       if(dst->bound != -100)  // not slice
+                               break;
+               case TPTR32:
+               case TPTR64:
+               case TFUNC:
+               case TMAP:
+               case TCHAN:
+               case TINTER:
+                       return OCONVNOP;
+               }
+       }
+
+       // 6. rule about untyped constants - already converted by defaultlit.
+       
+       // 7. Any typed value can be assigned to the blank identifier.
+       if(dst->etype == TBLANK)
+               return OCONVNOP;
+       
+       // 8. Array to slice.
+       // TODO(rsc): Not for long.
+       if(!src->sym || !dst->sym)
+       if(isptr[src->etype] && isfixedarray(src->type) && isslice(dst))
+       if(eqtype(src->type->type, dst->type))
+               return OCONVSLICE;
+
+       return 0;
+}
+
+// Can we convert a value of type src to a value of type dst?
+// If so, return op code to use in conversion (maybe OCONVNOP).
+// If not, return 0.
+int
+convertop(Type *src, Type *dst, char **why)
+{
+       int op;
+       
+       if(why != nil)
+               *why = "";
+
+       if(src == dst)
+               return OCONVNOP;
+       if(src == T || dst == T)
+               return 0;
+       
+       // 1. src can be assigned to dst.
+       if((op = assignop(src, dst, why)) != 0)
+               return op;
+
+       // The rules for interfaces are no different in conversions
+       // than assignments.  If interfaces are involved, stop now
+       // with the good message from assignop.
+       // Otherwise clear the error.
+       if(src->etype == TINTER || dst->etype == TINTER)
+               return 0;
+       if(why != nil)
+               *why = "";
+
+       // 2. src and dst have identical underlying types.
+       if(eqtype(src->orig, dst->orig))
+               return OCONVNOP;
+       
+       // 3. src and dst are unnamed pointer types 
+       // and their base types have identical underlying types.
+       if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
+       if(eqtype(src->type->orig, dst->type->orig))
+               return OCONVNOP;
+
+       // 4. src and dst are both integer or floating point types.
+       if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
+               if(simtype[src->etype] == simtype[dst->etype])
+                       return OCONVNOP;
+               return OCONV;
+       }
+
+       // 5. src and dst are both complex types.
+       if(iscomplex[src->etype] && iscomplex[dst->etype]) {
+               if(simtype[src->etype] == simtype[dst->etype])
+                       return OCONVNOP;
+               return OCONV;
+       }
+
+       // 6. src is an integer or has type []byte or []int
+       // and dst is a string type.
+       if(isint[src->etype] && dst->etype == TSTRING)
+               return ORUNESTR;
+
+       if(isslice(src) && src->sym == nil &&  src->type == types[src->type->etype] && dst->etype == TSTRING) {
+               switch(src->type->etype) {
+               case TUINT8:
+                       return OARRAYBYTESTR;
+               case TINT:
+                       return OARRAYRUNESTR;
+               }
+       }
+       
+       // 7. src is a string and dst is []byte or []int.
+       // String to slice.
+       if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) {
+               switch(dst->type->etype) {
+               case TUINT8:
+                       return OSTRARRAYBYTE;
+               case TINT:
+                       return OSTRARRAYRUNE;
+               }
+       }
+       
+       // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
+       if((isptr[src->etype] || src->etype == TUINTPTR) && isptrto(dst, TANY))
+               return OCONVNOP;
+
+       // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
+       if(isptrto(src, TANY) && (isptr[dst->etype] || dst->etype == TUINTPTR))
+               return OCONVNOP;
+               
+
+       return 0;
+}
+
+// Convert node n for assignment to type t.
+Node*
+assignconv(Node *n, Type *t, char *context)
+{
+       int op;
+       Node *r;
+       char *why;
+       
+       if(n == N || n->type == T)
+               return n;
+
+       defaultlit(&n, t);
+       if(t->etype == TBLANK)
+               return n;
+
+       exportassignok(n->type, context);
+       if(eqtype(n->type, t))
+               return n;
+
+       op = assignop(n->type, t, &why);
+       if(op == 0) {
+               yyerror("cannot use %+N as type %T in %s%s", n, t, context, why);
+               op = OCONV;
+       }
+
+       r = nod(op, n, N);
+       r->type = t;
+       r->typecheck = 1;
+       return r;
+}
+
 static int
 subtype(Type **stp, Type *t, int d)
 {
@@ -2026,6 +2198,8 @@ shallow(Type *t)
                return T;
        nt = typ(0);
        *nt = *t;
+       if(t->orig == t)
+               nt->orig = nt;
        return nt;
 }
 
@@ -2941,43 +3115,6 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
        funccompile(fn, 0);
 }
 
-/*
- * delayed interface type check.
- * remember that there is an interface conversion
- * on the given line.  once the file is completely read
- * and all methods are known, we can check that
- * the conversions are valid.
- */
-
-typedef struct Icheck Icheck;
-struct Icheck
-{
-       Icheck *next;
-       Type *dst;
-       Type *src;
-       int lineno;
-       int explicit;
-};
-Icheck *icheck;
-Icheck *ichecktail;
-
-void
-ifacecheck(Type *dst, Type *src, int lineno, int explicit)
-{
-       Icheck *p;
-
-       p = mal(sizeof *p);
-       if(ichecktail)
-               ichecktail->next = p;
-       else
-               icheck = p;
-       p->dst = dst;
-       p->src = src;
-       p->lineno = lineno;
-       p->explicit = explicit;
-       ichecktail = p;
-}
-
 Type*
 ifacelookdot(Sym *s, Type *t, int *followptr)
 {
@@ -3012,20 +3149,42 @@ ifacelookdot(Sym *s, Type *t, int *followptr)
        return T;
 }
 
-// check whether non-interface type t
-// satisifes inteface type iface.
 int
-ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename)
+implements(Type *t, Type *iface, Type **m, Type **samename)
 {
-       Type *t, *im, *tm, *rcvr, *imtype;
+       Type *t0, *im, *tm, *rcvr, *imtype;
        int followptr;
 
-       t = methtype(t0);
+       t0 = t;
+       if(t == T)
+               return 0;
 
        // if this is too slow,
        // could sort these first
        // and then do one loop.
 
+       if(t->etype == TINTER) {
+               for(im=iface->type; im; im=im->down) {
+                       for(tm=t->type; tm; tm=tm->down) {
+                               if(tm->sym == im->sym) {
+                                       if(eqtype(tm->type, im->type))
+                                               goto found;
+                                       *m = im;
+                                       *samename = tm;
+                                       return 0;
+                               }
+                       }
+                       *m = im;
+                       *samename = nil;
+                       return 0;
+               found:;
+               }
+               return 1;
+       }
+
+       t = methtype(t);
+       if(t != T)
+               expandmeth(t->sym, t);
        for(im=iface->type; im; im=im->down) {
                imtype = methodfunc(im->type, 0);
                tm = ifacelookdot(im->sym, t, &followptr);
@@ -3048,87 +3207,6 @@ ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename)
        return 1;
 }
 
-// check whether interface type i1 satisifes interface type i2.
-int
-ifaceokI2I(Type *i1, Type *i2, Type **m)
-{
-       Type *m1, *m2;
-
-       // if this is too slow,
-       // could sort these first
-       // and then do one loop.
-
-       for(m2=i2->type; m2; m2=m2->down) {
-               for(m1=i1->type; m1; m1=m1->down)
-                       if(m1->sym == m2->sym && eqtype(m1, m2))
-                               goto found;
-               *m = m2;
-               return 0;
-       found:;
-       }
-       return 1;
-}
-
-void
-runifacechecks(void)
-{
-       Icheck *p;
-       int lno, wrong, needexplicit;
-       Type *m, *t, *iface, *samename;
-
-       lno = lineno;
-       for(p=icheck; p; p=p->next) {
-               lineno = p->lineno;
-               wrong = 0;
-               needexplicit = 0;
-               m = nil;
-               samename = nil;
-               if(isinter(p->dst) && isinter(p->src)) {
-                       iface = p->dst;
-                       t = p->src;
-                       needexplicit = !ifaceokI2I(t, iface, &m);
-               }
-               else if(isinter(p->dst)) {
-                       t = p->src;
-                       iface = p->dst;
-                       wrong = !ifaceokT2I(t, iface, &m, &samename);
-               } else {
-                       t = p->dst;
-                       iface = p->src;
-                       wrong = !ifaceokT2I(t, iface, &m, &samename);
-                       needexplicit = 1;
-               }
-               if(wrong) {
-                       if(p->explicit) {
-                               if(samename)
-                                       yyerror("%T cannot contain %T\n\tmissing %S%hhT\n\tdo have %S%hhT",
-                                               iface, t, m->sym, m->type, samename->sym, samename->type);
-                               else
-                                       yyerror("%T cannot contain %T\n\tmissing %S%hhT", iface, t, m->sym, m->type);
-                       } else {
-                               if(samename)
-                                       yyerror("%T is not %T\n\tmissing %S%hhT\n\tdo have %S%hhT",
-                                               t, iface, m->sym, m->type, samename->sym, samename->type);
-                               else
-                                       yyerror("%T is not %T\n\tmissing %S%hhT", t, iface, m->sym, m->type);
-                       }
-               }
-               else if(!p->explicit && needexplicit) {
-                       if(m) {
-                               if(samename)
-                                       yyerror("need type assertion to use %T as %T\n\tmissing %S %hhT\n\tdo have %S%hhT",
-                                               p->src, p->dst, m->sym, m->type, samename->sym, samename->type);
-                               else
-                                       yyerror("need type assertion to use %T as %T\n\tmissing %S%hhT",
-                                               p->src, p->dst, m->sym, m->type);
-                       } else
-                               yyerror("need type assertion to use %T as %T",
-                                       p->src, p->dst);
-               }
-       }
-       lineno = lno;
-}
-
 /*
  * even simpler simtype; get rid of ptr, bool.
  * assuming that the front end has rejected
index 19155f07ba0153201d6c3730b3f58286028fafe7..d285ad0a766ef73d2a333f81b278e0081170d540 100644 (file)
@@ -21,7 +21,6 @@ static int    onearg(Node*);
 static int     twoarg(Node*);
 static int     lookdot(Node*, Type*, int);
 static void    typecheckaste(int, Type*, NodeList*, char*);
-static int     exportassignok(Type*, char*);
 static Type*   lookdot1(Sym *s, Type *t, Type *f, int);
 static int     nokeys(NodeList*);
 static void    typecheckcomplit(Node**);
@@ -32,7 +31,6 @@ static void   typecheckfunc(Node*);
 static void    checklvalue(Node*, char*);
 static void    checkassign(Node*);
 static void    checkassignlist(NodeList*);
-static void    toslice(Node**);
 static void stringtoarraylit(Node**);
 
 void
@@ -57,6 +55,7 @@ typecheck(Node **np, int top)
        Type *t;
        Sym *sym;
        Val v;
+       char *why;
 
        // cannot type check until all the source has been parsed
        if(!typecheckok)
@@ -549,8 +548,8 @@ reswitch:
                case TMAP:
                        n->etype = 0;
                        defaultlit(&n->right, t->down);
-                       if(n->right->type != T && !eqtype(n->right->type, t->down))
-                               yyerror("invalid map index %#N - need type %T", n->right, t->down);
+                       if(n->right->type != T)
+                               n->right = assignconv(n->right, t->down, "map index");
                        n->type = t->type;
                        n->op = OINDEXMAP;
                        break;
@@ -644,8 +643,6 @@ reswitch:
                l = n->left;
                if((t = l->type) == T)
                        goto error;
-               // TODO(rsc): 64-bit slice index needs to be checked
-               // for overflow in generated code
                if(istype(t, TSTRING)) {
                        n->type = t;
                        n->op = OSLICESTR;
@@ -866,21 +863,19 @@ reswitch:
                typecheck(&n->right, Erv);
                if(n->left->type == T || n->right->type == T)
                        goto error;
-               toslice(&n->left);
-               toslice(&n->right);
                defaultlit(&n->left, T);
                defaultlit(&n->right, T);
                if(!isslice(n->left->type) || !isslice(n->right->type)) {
                        if(!isslice(n->left->type) && !isslice(n->right->type))
-                               yyerror("arguments to copy must be array pointer or slice; have %lT, %lT", n->left->type, n->right->type);
+                               yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
                        else if(!isslice(n->left->type))
-                               yyerror("first argument to copy should be array pointer or slice; have %lT", n->left->type);
+                               yyerror("first argument to copy should be slice; have %lT", n->left->type);
                        else
-                               yyerror("second argument to copy should be array pointer or slice; have %lT", n->right->type);
+                               yyerror("second argument to copy should be slice; have %lT", n->right->type);
                        goto error;
                }
-               if(!eqtype(n->left->type, n->right->type)) {
-                       yyerror("arguments to copy have different element types %lT and %lT", n->left->type, n->right->type);
+               if(!eqtype(n->left->type->type, n->right->type->type)) {
+                       yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
                        goto error;
                }
                goto ret;
@@ -892,10 +887,17 @@ reswitch:
                convlit1(&n->left, n->type, 1);
                if((t = n->left->type) == T || n->type == T)
                        goto error;
-               n = typecheckconv(n, n->left, n->type, 1, "conversion");
-               if(n->type == T)
-                       goto error;
+               if((n->op = convertop(t, n->type, &why)) == 0) {
+                       yyerror("cannot convert %+N to type %T%s", n->left, n->type, why);
+                       op = OCONV;
+               }
                switch(n->op) {
+               case OCONVNOP:
+                       if(n->left->op == OLITERAL) {
+                               n->op = OLITERAL;
+                               n->val = n->left->val;
+                       }
+                       break;
                case OSTRARRAYBYTE:
                case OSTRARRAYRUNE:
                        if(n->left->op == OLITERAL)
@@ -1031,7 +1033,7 @@ reswitch:
                if(onearg(n) < 0)
                        goto error;
                typecheck(&n->left, Erv);
-               defaultlit(&n->left, types[TINTER]);
+               defaultlit(&n->left, T);
                if(n->left->type == T)
                        goto error;
                goto ret;
@@ -1242,25 +1244,6 @@ implicitstar(Node **nn)
        *nn = n;
 }
 
-static void
-toslice(Node **nn)
-{
-       Node *n;
-       Type *t;
-
-       n = *nn;
-       if(n->type == T)
-               return;
-       if(isptr[n->type->etype] && isfixedarray(n->type->type)) {
-               // convert to slice
-               t = typ(TARRAY);
-               t->bound = -1;
-               t->type = n->type->type->type;
-               n = typecheckconv(nil, n, t, 0, "conversion of array pointer to slice");
-               *nn = n;
-       }
-}
-
 static int
 onearg(Node *n)
 {
@@ -1397,208 +1380,6 @@ nokeys(NodeList *l)
        return 1;
 }
 
-/*
- * check implicit or explicit conversion from node type nt to type t.
- */
-int
-checkconv(Type *nt, Type *t, int explicit, int *op, int *et, char *desc)
-{
-       *op = OCONV;
-       *et = 0;
-
-       // preexisting error
-       if(t == T || t->etype == TFORW)
-               return 0;
-
-       /*
-        * implicit conversions
-        */
-       if(nt == T)
-               return 0;
-
-       if(t->etype == TBLANK) {
-               *op = OCONVNOP;
-               return 0;
-       }
-
-       if(eqtype(t, nt)) {
-               exportassignok(t, desc);
-               *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 ifacecvt
-       // generate a good message.  some messages have to be
-       // delayed anyway.
-       // TODO(rsc): now that everything is delayed for whole-package
-       // compilation, the messages could be generated right here.
-       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 && nt->sym && t != nt)
-               return -1;
-
-       // channel must not lose directionality
-       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[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, nt)) {
-               *op = OCONVNOP;
-               return 1;
-       }
-
-       // simple fix-float
-       if(isint[t->etype] || isfloat[t->etype])
-       if(isint[nt->etype] || isfloat[nt->etype])
-               return 1;
-
-       // simple complex-complex
-       if(iscomplex[t->etype])
-       if(iscomplex[nt->etype])
-               return 1;
-
-       // to string
-       if(istype(t, TSTRING)) {
-               // integer rune
-               if(isint[nt->etype]) {
-                       *op = ORUNESTR;
-                       return 1;
-               }
-
-               // *[10]byte -> string
-               // in preparation for next step
-               if(isptr[nt->etype] && isfixedarray(nt->type)) {
-                       switch(nt->type->type->etype) {
-                       case TUINT8:
-                               *op = OARRAYBYTESTR;
-                               return 1;
-                       case TINT:
-                               *op = OARRAYRUNESTR;
-                               return 1;
-                       }
-               }
-
-               // []byte -> string
-               if(isslice(nt)) {
-                       switch(nt->type->etype) {
-                       case TUINT8:
-                               *op = OARRAYBYTESTR;
-                               return 1;
-                       case TINT:
-                               *op = OARRAYRUNESTR;
-                               return 1;
-                       }
-               }
-       }
-
-       // from string
-       if(istype(nt, TSTRING) && isslice(t) && t->sym == S) {
-               switch(t->type->etype) {
-               case TUINT8:
-                       *op = OSTRARRAYBYTE;
-                       return 1;
-               case TINT:
-                       *op = OSTRARRAYRUNE;
-                       return 1;
-               }
-       }
-
-       // convert to unsafe pointer
-       if(isptrto(t, TANY)
-       && (isptr[nt->etype] || nt->etype == TUINTPTR))
-               return 1;
-
-       // convert from unsafe pointer
-       if(isptrto(nt, TANY)
-       && (isptr[t->etype] || t->etype == TUINTPTR))
-               return 1;
-
-       return -1;
-}
-
-Node*
-typecheckconv(Node *nconv, Node *n, Type *t, int explicit, char *desc)
-{
-       int et, op;
-       Node *n1;
-       char *prefix;
-
-       convlit1(&n, t, explicit);
-       if(n->type == T)
-               return n;
-
-
-       if(n->op == OLITERAL)
-       if(explicit || isideal(n->type))
-       if(cvttype(t, n->type)) {
-               // can convert literal in place
-               // TODO(rsc) is this needed?
-               n1 = nod(OXXX, N, N);
-               *n1 = *n;
-               n1->type = t;
-               return n1;
-       }
-
-       prefix = "";
-       if(desc != nil)
-               prefix = " in ";
-       else
-               desc = "";
-       switch(checkconv(n->type, t, explicit, &op, &et, desc)) {
-       case -1:
-               if(explicit)
-                       yyerror("cannot convert %+N to type %T%s%s", n, t, prefix, desc);
-               else
-                       yyerror("cannot use %+N as type %T%s%s", n, t, prefix, desc);
-               return n;
-
-       case 0:
-               if(nconv) {
-                       nconv->op = OCONVNOP;
-                       return nconv;
-               }
-               return n;
-       }
-
-       if(op == OCONVIFACE)
-               defaultlit(&n, T);
-
-       if(nconv == N)
-               nconv = nod(OCONV, n, N);
-       nconv->op = op;
-       nconv->etype = et;
-       nconv->type = t;
-       nconv->typecheck = 1;
-       return nconv;
-}
-
 /*
  * typecheck assignment: type list = expression list
  */
@@ -1608,6 +1389,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
        Type *t, *tl, *tn;
        Node *n;
        int lno;
+       char *why;
 
        lno = lineno;
 
@@ -1619,21 +1401,20 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
                setlineno(n);
                tn = n->type->type;
                for(tl=tstruct->type; tl; tl=tl->down) {
-                       int xx, yy;
                        if(tl->isddd) {
                                // TODO(rsc): delete if (but not body) in DDD cleanup.
                                if(tl->type->etype != TINTER)
-                                       for(; tn; tn=tn->down)
-                                               if(checkconv(tn->type, tl->type->type, 0, &xx, &yy, desc) < 0)
-                                                       yyerror("cannot use %T as type %T in %s", tn->type, tl->type->type, desc);
+                               for(; tn; tn=tn->down)
+                                       if(assignop(tn->type, tl->type->type, &why) == 0)
+                                               yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
                                goto out;
                        }
                        if(tn == T) {
                                yyerror("not enough arguments to %#O", op);
                                goto out;
                        }
-                       if(checkconv(tn->type, tl->type, 0, &xx, &yy, desc) < 0)
-                               yyerror("cannot use type %T as type %T in %s", tn->type, tl->type, desc);
+                       if(assignop(tn->type, tl->type, &why) == 0)
+                               yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
                        tn = tn->down;
                }
                if(tn != T)
@@ -1652,13 +1433,12 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
                        if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t))
                                goto out;
                        for(; nl; nl=nl->next) {
-                               int xx, yy;
                                setlineno(nl->n);
                                defaultlit(&nl->n, t->type);
                                // TODO(rsc): drop first if in DDD cleanup
                                if(t->etype != TINTER)
-                               if(checkconv(nl->n->type, t->type, 0, &xx, &yy, desc) < 0)
-                                       yyerror("cannot use %+N as type %T in %s", nl->n, t->type, desc);
+                               if(assignop(nl->n->type, t->type, &why) == 0)
+                                       yyerror("cannot use %+N as type %T in %s%s", nl->n, t->type, desc, why);
                        }
                        goto out;
                }
@@ -1669,7 +1449,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
                n = nl->n;
                setlineno(nl->n);
                if(n->type != T)
-                       nl->n = typecheckconv(nil, n, t, 0, desc);
+                       nl->n = assignconv(n, t, desc);
                nl = nl->next;
        }
        if(nl != nil) {
@@ -1686,7 +1466,7 @@ out:
  * cannot be implicitly assigning to any type with
  * an unavailable field.
  */
-static int
+int
 exportassignok(Type *t, char *desc)
 {
        Type *f;
@@ -1882,11 +1662,11 @@ typecheckcomplit(Node **np)
                                }
                                typecheck(&l->right, Erv);
                                defaultlit(&l->right, t->type);
-                               l->right = typecheckconv(nil, l->right, t->type, 0, "array index");
+                               l->right = assignconv(l->right, t->type, "array index");
                        } else {
                                typecheck(&ll->n, Erv);
                                defaultlit(&ll->n, t->type);
-                               ll->n = typecheckconv(nil, ll->n, t->type, 0, "array index");
+                               ll->n = assignconv(ll->n, t->type, "array index");
                                ll->n = nod(OKEY, nodintconst(i), ll->n);
                                ll->n->left->type = types[TINT];
                                ll->n->left->typecheck = 1;
@@ -1922,8 +1702,8 @@ typecheckcomplit(Node **np)
                        typecheck(&l->right, Erv);
                        defaultlit(&l->left, t->down);
                        defaultlit(&l->right, t->type);
-                       l->left = typecheckconv(nil, l->left, t->down, 0, "map key");
-                       l->right = typecheckconv(nil, l->right, t->type, 0, "map value");
+                       l->left = assignconv(l->left, t->down, "map key");
+                       l->right = assignconv(l->right, t->type, "map value");
                        keydup(l->left, hash, nelem(hash));
                }
                n->op = OMAPLIT;
@@ -1944,7 +1724,7 @@ typecheckcomplit(Node **np)
                                s = f->sym;
                                if(s != nil && !exportname(s->name) && s->pkg != localpkg)
                                        yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
-                               ll->n = typecheckconv(nil, ll->n, f->type, 0, "field value");
+                               ll->n = assignconv(ll->n, f->type, "field value");
                                ll->n = nod(OKEY, newname(f->sym), ll->n);
                                ll->n->left->typecheck = 1;
                                f = f->down;
@@ -1977,7 +1757,7 @@ typecheckcomplit(Node **np)
                                }
                                s = f->sym;
                                fielddup(newname(s), hash, nelem(hash));
-                               l->right = typecheckconv(nil, l->right, f->type, 0, "field value");
+                               l->right = assignconv(l->right, f->type, "field value");
                        }
                }
                n->op = OSTRUCTLIT;
@@ -2139,8 +1919,8 @@ typecheckas(Node *n)
        typecheck(&n->right, Erv);
        if(n->right && n->right->type != T) {
                if(n->left->type != T)
-                       n->right = typecheckconv(nil, n->right, n->left->type, 0, "assignment");
-               else
+                       n->right = assignconv(n->right, n->left->type, "assignment");
+               else if(!isblank(n->left))
                        exportassignok(n->right->type, "assignment");
        }
        if(n->left->defn == n && n->left->ntype == N) {
@@ -2156,10 +1936,22 @@ typecheckas(Node *n)
                typecheck(&n->left, Erv | Easgn);
 }
 
+static void
+checkassignto(Type *src, Node *dst)
+{
+       char *why;
+
+       if(assignop(src, dst->type, &why) == 0) {
+               yyerror("cannot assign %T to %+N in multiple assignment%s", src, dst, why);
+               return;
+       }
+       exportassignok(dst->type, "multiple assignment");
+}
+
 static void
 typecheckas2(Node *n)
 {
-       int cl, cr, op, et;
+       int cl, cr;
        NodeList *ll, *lr;
        Node *l, *r;
        Iter s;
@@ -2182,7 +1974,7 @@ typecheckas2(Node *n)
                // 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, nil);
+                               lr->n = assignconv(lr->n, ll->n->type, "assignment");
                        if(ll->n->defn == n && ll->n->ntype == N) {
                                defaultlit(&lr->n, T);
                                ll->n->type = lr->n->type;
@@ -2200,9 +1992,9 @@ typecheckas2(Node *n)
                if(l->type == T)
                        goto out;
                n->op = OAS2MAPW;
-               n->rlist->n = typecheckconv(nil, r, l->type, 0, nil);
+               n->rlist->n = assignconv(r, l->type, "assignment");
                r = n->rlist->next->n;
-               n->rlist->next->n = typecheckconv(nil, r, types[TBOOL], 0, nil);
+               n->rlist->next->n = assignconv(r, types[TBOOL], "assignment");
                goto out;
        }
 
@@ -2223,8 +2015,7 @@ typecheckas2(Node *n)
                        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, nil) < 0)
-                                               yyerror("cannot assign type %T to %+N", t->type, ll->n);
+                                       checkassignto(t->type, ll->n);
                                if(ll->n->defn == n && ll->n->ntype == N)
                                        ll->n->type = t->type;
                                t = structnext(&s);
@@ -2246,14 +2037,15 @@ typecheckas2(Node *n)
                        goto common;
                case ODOTTYPE:
                        n->op = OAS2DOTTYPE;
+                       r->op = ODOTTYPE2;
                common:
-                       if(l->type != T && checkconv(r->type, l->type, 0, &op, &et, nil) < 0)
-                               yyerror("cannot assign %+N to %+N", r, l);
+                       if(l->type != T)
+                               checkassignto(r->type, l);
                        if(l->defn == n)
                                l->type = r->type;
                        l = n->list->next->n;
-                       if(l->type != T && checkconv(types[TBOOL], l->type, 0, &op, &et, nil) < 0)
-                               yyerror("cannot assign bool value to %+N", l);
+                       if(l->type != T)
+                               checkassignto(types[TBOOL], l);
                        if(l->defn == n && l->ntype == N)
                                l->type = types[TBOOL];
                        goto out;
index 21bd0b56ea143d6d2f524edf66cd9bf65ae4951d..a4e509650785d0f1b7435223b7dde272c7e78965 100644 (file)
@@ -9,26 +9,6 @@ static Node*   conv(Node*, Type*);
 static Node*   mapfn(char*, Type*);
 static Node*   makenewvar(Type*, NodeList**, Node**);
 
-enum
-{
-       Inone,
-       I2T,
-       I2T2,
-       I2I,
-       I2Ix,
-       I2I2,
-       T2I,
-       I2Isame,
-       E2T,
-       E2T2,
-       E2I,
-       E2I2,
-       I2E,
-       I2E2,
-       T2E,
-       E2Esame,
-};
-
 // can this code branch reach the end
 // without an undcontitional RETURN
 // this is hard, so it is conservative
@@ -169,8 +149,7 @@ walkdeftype(Node *n)
        t->printed = 0;
        t->deferwidth = 0;
 
-       // double-check use of type as map key
-       // TODO(rsc): also use of type as receiver?
+       // double-check use of type as map key.
        if(maplineno) {
                lineno = maplineno;
                maptype(n->type, types[TBOOL]);
@@ -441,7 +420,10 @@ walkstmt(Node **np)
                walkstmtlist(n->ninit);
                if(n->ntest != N) {
                        walkstmtlist(n->ntest->ninit);
-                       walkexpr(&n->ntest, &n->ninit);
+                       init = n->ntest->ninit;
+                       n->ntest->ninit = nil;
+                       walkexpr(&n->ntest, &init);
+                       n->ntest->ninit = concat(init, n->ntest->ninit);
                }
                walkstmt(&n->nincr);
                walkstmtlist(n->nbody);
@@ -483,7 +465,7 @@ walkstmt(Node **np)
                        break;
                }
                ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit);
-               n->list = reorder4(ll);
+               n->list = ll;
                break;
 
        case OSELECT:
@@ -541,6 +523,7 @@ walkexpr(Node **np, NodeList **init)
        int et;
        int32 lno;
        Node *n, *fn;
+       char buf[100], *p;
 
        n = *np;
 
@@ -671,6 +654,7 @@ walkexpr(Node **np, NodeList **init)
                        // the output bool, so we clear it before the call.
                        Node *b;
                        b = nodbool(0);
+                       typecheck(&b, Erv);
                        lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
                        n->list = concat(n->list, lr);
                }
@@ -710,7 +694,6 @@ walkexpr(Node **np, NodeList **init)
                goto ret;
 
        case OAS2:
-       as2:
                *init = concat(*init, n->ninit);
                n->ninit = nil;
                walkexprlistsafe(n->list, init);
@@ -802,41 +785,77 @@ walkexpr(Node **np, NodeList **init)
                n->ninit = nil;
                r = n->rlist->n;
                walkexprlistsafe(n->list, init);
-               walkdottype(r, init);
-               et = ifaceas1(r->type, r->left->type, 1);
-               switch(et) {
-               case I2Isame:
-               case E2Esame:
-               case I2E:
-                       n->rlist = list(list1(r->left), nodbool(1));
-                       typechecklist(n->rlist, Erv);
-                       goto as2;
-               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);
+               r->op = ODOTTYPE2;
+               walkexpr(&r, init);
                ll = ascompatet(n->op, n->list, &r->type, 0, init);
                n = liststmt(concat(list1(r), ll));
                goto ret;
 
        case ODOTTYPE:
-               walkdottype(n, init);
-               walkconv(&n, init);
+       case ODOTTYPE2:         
+               // Build name of function: assertI2E2 etc.
+               strcpy(buf, "assert");
+               p = buf+strlen(buf);
+               if(isnilinter(n->left->type))
+                       *p++ = 'E';
+               else
+                       *p++ = 'I';
+               *p++ = '2';
+               if(isnilinter(n->type))
+                       *p++ = 'E';
+               else if(isinter(n->type))
+                       *p++ = 'I';
+               else
+                       *p++ = 'T';
+               if(n->op == ODOTTYPE2)
+                       *p++ = '2';
+               *p = '\0';
+       
+               fn = syslook(buf, 1);
+               ll = list1(typename(n->type));
+               ll = list(ll, n->left);
+               argtype(fn, n->left->type);
+               argtype(fn, n->type);
+               n = nod(OCALL, fn, N);
+               n->list = ll;
+               typecheck(&n, Erv | Efnstruct);
+               walkexpr(&n, init);
+               goto ret;
+
+       case OCONVIFACE:
+               // Build name of function: convI2E etc.
+               // Not all names are possible
+               // (e.g., we'll never generate convE2E or convE2I).
+               walkexpr(&n->left, init);
+               strcpy(buf, "conv");
+               p = buf+strlen(buf);
+               if(isnilinter(n->left->type))
+                       *p++ = 'E';
+               else if(isinter(n->left->type))
+                       *p++ = 'I';
+               else
+                       *p++ = 'T';
+               *p++ = '2';
+               if(isnilinter(n->type))
+                       *p++ = 'E';
+               else
+                       *p++ = 'I';
+               *p = '\0';
+               
+               fn = syslook(buf, 1);
+               ll = nil;
+               if(!isinter(n->left->type))
+                       ll = list(ll, typename(n->left->type));
+               if(!isnilinter(n->type))
+                       ll = list(ll, typename(n->type));
+               ll = list(ll, n->left);
+               argtype(fn, n->left->type);
+               argtype(fn, n->type);
+               dowidth(fn->type);
+               n = nod(OCALL, fn, N);
+               n->list = ll;
+               typecheck(&n, Erv);
+               walkexpr(&n, init);
                goto ret;
 
        case OCONV:
@@ -1176,7 +1195,7 @@ walkexpr(Node **np, NodeList **init)
        case ORUNESTR:
                // sys_intstring(v)
                n = mkcall("intstring", n->type, init,
-                       conv(n->left, types[TINT64]));  // TODO(rsc): int64?!
+                       conv(n->left, types[TINT64]));
                goto ret;
 
        case OARRAYBYTESTR:
@@ -1234,11 +1253,6 @@ walkexpr(Node **np, NodeList **init)
                n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right);
                goto ret;
 
-       case OCONVIFACE:
-               walkexpr(&n->left, init);
-               n = ifacecvt(n->type, n->left, n->etype, init);
-               goto ret;
-
        case OCLOSURE:
                n = walkclosure(n, init);
                goto ret;
@@ -1271,70 +1285,6 @@ makenewvar(Type *t, NodeList **init, Node **nstar)
        return nvar;
 }
 
-// TODO(rsc): cut
-void
-walkdottype(Node *n, NodeList **init)
-{
-       walkexpr(&n->left, init);
-       if(n->left == N)
-               return;
-       if(n->right != N) {
-               walkexpr(&n->right, init);
-               n->type = n->right->type;
-               n->right = N;
-       }
-}
-
-// TODO(rsc): cut
-void
-walkconv(Node **np, NodeList **init)
-{
-       int et;
-       char *what;
-       Type *t;
-       Node *l;
-       Node *n;
-
-       n = *np;
-       t = n->type;
-       if(t == T)
-               return;
-       walkexpr(&n->left, init);
-       l = n->left;
-       if(l == N)
-               return;
-       if(l->type == T)
-               return;
-
-       // if using .(T), interface assertion.
-       if(n->op == ODOTTYPE) {
-               et = ifaceas1(t, l->type, 1);
-               if(et == I2Isame || et == E2Esame) {
-                       n->op = OCONVNOP;
-                       return;
-               }
-               if(et != Inone) {
-                       n = ifacecvt(t, l, et, init);
-                       *np = n;
-                       return;
-               }
-               goto bad;
-       }
-
-       fatal("walkconv");
-
-bad:
-       if(n->diag)
-               return;
-       n->diag = 1;
-       if(n->op == ODOTTYPE)
-               what = "type assertion";
-       else
-               what = "conversion";
-       if(l->type != T)
-               yyerror("invalid %s: %T to %T", what, l->type, t);
-}
-
 Node*
 ascompatee1(int op, Node *l, Node *r, NodeList **init)
 {
@@ -1418,6 +1368,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
                if(fncall(l, r->type)) {
                        tmp = nod(OXXX, N, N);
                        tempname(tmp, r->type);
+                       typecheck(&tmp, Erv);
                        a = nod(OAS, l, tmp);
                        a = convas(a, init);
                        mm = list(mm, a);
@@ -1517,6 +1468,7 @@ mkdotargs(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
        var = nod(OXXX, N, N);
        tempname(var, st);
        var->sym = lookup(".ddd");
+       typecheck(&var, Erv);
 
        // assign the fields to the struct.
        // use the init list so that reorder1 doesn't reorder
@@ -1927,166 +1879,11 @@ bad:
        return T;
 }
 
-/*
- * assigning src to dst involving interfaces?
- * return op to use.
- */
-int
-ifaceas1(Type *dst, Type *src, int explicit)
-{
-       if(src == T || dst == T)
-               return Inone;
-
-       if(explicit && !isinter(src))
-               yyerror("cannot use .(T) on non-interface type %T", src);
-
-       if(isinter(dst)) {
-               if(isinter(src)) {
-                       if(isnilinter(dst)) {
-                               if(isnilinter(src))
-                                       return E2Esame;
-                               return I2E;
-                       }
-                       if(eqtype(dst, src))
-                               return I2Isame;
-                       ifacecheck(dst, src, lineno, explicit);
-                       if(isnilinter(src))
-                               return E2I;
-                       if(explicit)
-                               return I2Ix;
-                       return I2I;
-               }
-               if(isnilinter(dst))
-                       return T2E;
-               ifacecheck(dst, src, lineno, explicit);
-               return T2I;
-       }
-       if(isinter(src)) {
-               ifacecheck(dst, src, lineno, explicit);
-               if(isnilinter(src))
-                       return E2T;
-               return I2T;
-       }
-       return Inone;
-}
-
-/*
- * treat convert T to T as noop
- */
-int
-ifaceas(Type *dst, Type *src, int explicit)
-{
-       int et;
-
-       et = ifaceas1(dst, src, explicit);
-       if(et == I2Isame || et == E2Esame)
-               et = Inone;
-       return et;
-}
-
-static char*
-ifacename[] =
-{
-       [I2T]           = "ifaceI2T",
-       [I2T2]          = "ifaceI2T2",
-       [I2I]           = "ifaceI2I",
-       [I2Ix]          = "ifaceI2Ix",
-       [I2I2]          = "ifaceI2I2",
-       [I2Isame]       = "ifaceI2Isame",
-       [E2T]           = "ifaceE2T",
-       [E2T2]          = "ifaceE2T2",
-       [E2I]           = "ifaceE2I",
-       [E2I2]          = "ifaceE2I2",
-       [I2E]           = "ifaceI2E",
-       [I2E2]          = "ifaceI2E2",
-       [T2I]           = "ifaceT2I",
-       [T2E]           = "ifaceT2E",
-       [E2Esame]       = "ifaceE2Esame",
-};
-
-Node*
-ifacecvt(Type *tl, Node *n, int et, NodeList **init)
-{
-       Type *tr;
-       Node *r, *on;
-       NodeList *args;
-
-       tr = n->type;
-
-       switch(et) {
-       default:
-               fatal("ifacecvt: unknown op %d\n", et);
-
-       case I2Isame:
-       case E2Esame:
-               return n;
-
-       case T2I:
-               // ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
-               args = list1(typename(tl));     // sigi
-               args = list(args, typename(tr));        // sigt
-               args = list(args, n);   // elem
-
-               on = syslook("ifaceT2I", 1);
-               argtype(on, tr);
-               argtype(on, tl);
-               dowidth(on->type);
-               break;
-
-       case I2T:
-       case I2T2:
-       case I2I:
-       case I2Ix:
-       case I2I2:
-       case E2T:
-       case E2T2:
-       case E2I:
-       case E2I2:
-               // iface[IT]2[IT][2](sigt *byte, iface any) (ret any[, ok bool]);
-               args = list1(typename(tl));     // sigi or sigt
-               args = list(args, n);           // iface
-
-               on = syslook(ifacename[et], 1);
-               argtype(on, tr);
-               argtype(on, tl);
-               break;
-
-       case I2E:
-               // TODO(rsc): Should do this in back end, without a call.
-               // ifaceI2E(elem any) (ret any);
-               args = list1(n);        // elem
-
-               on = syslook("ifaceI2E", 1);
-               argtype(on, tr);
-               argtype(on, tl);
-               break;
-
-       case T2E:
-               // TODO(rsc): Should do this in back end for pointer case, without a call.
-               // ifaceT2E(sigt *byte, elem any) (ret any);
-               args = list1(typename(tr));     // sigt
-               args = list(args, n);           // elem
-
-               on = syslook("ifaceT2E", 1);
-               argtype(on, tr);
-               argtype(on, tl);
-               break;
-       }
-
-       dowidth(on->type);
-       r = nod(OCALL, on, N);
-       r->list = args;
-       typecheck(&r, Erv | Efnstruct);
-       walkexpr(&r, init);
-       return r;
-}
-
 Node*
 convas(Node *n, NodeList **init)
 {
        Node *l, *r;
        Type *lt, *rt;
-       int et;
 
        if(n->op != OAS)
                fatal("convas: not OAS %O", n->op);
@@ -2115,15 +1912,12 @@ convas(Node *n, NodeList **init)
                        n->left->left, n->left->right, n->right);
                goto out;
        }
-
+       
        if(eqtype(lt, rt))
                goto out;
-
-       et = ifaceas(lt, rt, 0);
-       if(et != Inone) {
-               n->right = ifacecvt(lt, r, et, init);
-               goto out;
-       }
+       
+       n->right = assignconv(r, lt, "assignment");
+       walkexpr(&n->right, init);
 
 out:
        ullmancalc(n);
@@ -2292,24 +2086,6 @@ reorder3(NodeList *all)
        return concat(all, r);
 }
 
-NodeList*
-reorder4(NodeList *ll)
-{
-       /*
-        * from ascompat[te]
-        *      return c,d
-        * return expression assigned to output
-        * parameters. there may be no problems.
-        *
-        * TODO(rsc): i don't believe that.
-        *      func f() (a, b int) {
-        *              a, b = 1, 2;
-        *              return b, a;
-        *      }
-        */
-       return ll;
-}
-
 /*
  * walk through argin parameters.
  * generate and return code to allocate
diff --git a/src/pkg/math/fltasm_amd64.s b/src/pkg/math/fltasm_amd64.s
new file mode 100644 (file)
index 0000000..66442cd
--- /dev/null
@@ -0,0 +1,67 @@
+// Derived from Inferno's libkern/getfcr-amd64.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/getfcr-amd64.s
+//
+//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+//         Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+TEXT   ·SetFPControl(SB), 7, $8
+       // Set new
+       MOVL    p+0(FP), DI
+       XORL    $(0x3F<<7), DI
+       ANDL    $0xFFC0, DI
+       WAIT
+       STMXCSR 0(SP)
+       MOVL    0(SP), AX
+       ANDL    $~0x3F, AX
+       ORL     DI, AX
+       MOVL    AX, 0(SP)
+       LDMXCSR 0(SP)
+       RET
+
+TEXT   ·GetFPControl(SB), 7, $0
+       WAIT
+       STMXCSR 0(SP)
+       MOVWLZX 0(SP), AX
+       ANDL    $0xFFC0, AX
+       XORL    $(0x3F<<7), AX
+       MOVL    AX, ret+0(FP)
+       RET
+
+TEXT   ·SetFPStatus(SB), $0
+       MOVL    p+0(FP), DI
+       ANDL    $0x3F, DI
+       WAIT
+       STMXCSR 0(SP)
+       MOVL    0(SP), AX
+       ANDL    $~0x3F, AX
+       ORL     DI, AX
+       MOVL    AX, 0(SP)
+       LDMXCSR 0(SP)
+       RET
+
+TEXT   ·GetFPStatus(SB), $0
+       WAIT
+       STMXCSR 0(SP)
+       MOVL    0(SP), AX
+       ANDL    $0x3F, AX
+       MOVL    AX, ret+0(FP)
+       RET
index 55a1362c6135ce035be05a13c8118ece62dec24e..35a710eca37da17a27cde863953bc09f0c6e42cb 100644 (file)
@@ -177,26 +177,26 @@ copyout(Type *t, void **src, void *dst)
                algarray[alg].copy(wid, dst, *src);
 }
 
-// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret Iface);
+// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
 #pragma textflag 7
 void
ifaceT2I(InterfaceType *inter, Type *t, ...)
convT2I(Type *t, InterfaceType *inter, ...)
 {
        byte *elem;
        Iface *ret;
        int32 wid;
 
-       elem = (byte*)(&t+1);
+       elem = (byte*)(&inter+1);
        wid = t->size;
        ret = (Iface*)(elem + rnd(wid, Structrnd));
        ret->tab = itab(inter, t, 0);
        copyin(t, elem, &ret->data);
 }
 
-// ifaceT2E(sigt *byte, elem any) (ret Eface);
+// func convT2E(typ *byte, elem any) (ret any)
 #pragma textflag 7
 void
ifaceT2E(Type *t, ...)
convT2E(Type *t, ...)
 {
        byte *elem;
        Eface *ret;
@@ -205,15 +205,14 @@ void
        elem = (byte*)(&t+1);
        wid = t->size;
        ret = (Eface*)(elem + rnd(wid, Structrnd));
-
        ret->type = t;
        copyin(t, elem, &ret->data);
 }
 
-// ifaceI2T(sigt *byte, iface any) (ret any);
+// func ifaceI2T(typ *byte, iface any) (ret any)
 #pragma textflag 7
 void
ifaceI2T(Type *t, Iface i, ...)
assertI2T(Type *t, Iface i, ...)
 {
        Itab *tab;
        byte *ret;
@@ -236,10 +235,10 @@ void
        copyout(t, &i.data, ret);
 }
 
-// ifaceI2T2(sigt *byte, i Iface) (ret any, ok bool);
+// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
 #pragma textflag 7
 void
ifaceI2T2(Type *t, Iface i, ...)
assertI2T2(Type *t, Iface i, ...)
 {
        byte *ret;
        bool *ok;
@@ -259,10 +258,10 @@ void
        copyout(t, &i.data, ret);
 }
 
-// ifaceE2T(sigt *byte, e Eface) (ret any);
+// func ifaceE2T(typ *byte, iface any) (ret any)
 #pragma textflag 7
 void
ifaceE2T(Type *t, Eface e, ...)
assertE2T(Type *t, Eface e, ...)
 {
        byte *ret;
        Eface err;
@@ -284,10 +283,10 @@ void
        copyout(t, &e.data, ret);
 }
 
-// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
+// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
 #pragma textflag 7
 void
ifaceE2T2(Type *t, Eface e, ...)
assertE2T2(Type *t, Eface e, ...)
 {
        byte *ret;
        bool *ok;
@@ -307,50 +306,82 @@ void
        copyout(t, &e.data, ret);
 }
 
-// ifaceI2E(sigi *byte, iface any) (ret any);
-// TODO(rsc): Move to back end, throw away function.
+// func convI2E(elem any) (ret any)
+#pragma textflag 7
 void
ifaceI2E(Iface i, Eface ret)
convI2E(Iface i, Eface ret)
 {
        Itab *tab;
 
        ret.data = i.data;
-       tab = i.tab;
-       if(tab == nil)
+       if((tab = i.tab) == nil)
                ret.type = nil;
        else
                ret.type = tab->type;
        FLUSH(&ret);
 }
 
-// ifaceI2I(sigi *byte, iface any) (ret any);
-// called only for implicit (no type assertion) conversions.
-// converting nil is okay.
+// func ifaceI2E(typ *byte, iface any) (ret any)
+#pragma textflag 7
 void
ifaceI2I(InterfaceType *inter, Iface i, Iface ret)
assertI2E(InterfaceType* inter, Iface i, Eface ret)
 {
        Itab *tab;
+       Eface err;
 
        tab = i.tab;
        if(tab == nil) {
-               // If incoming interface is uninitialized (zeroed)
-               // make the outgoing interface zeroed as well.
-               ret.tab = nil;
-               ret.data = nil;
+               // explicit conversions require non-nil interface value.
+               ·newTypeAssertionError(nil, nil, inter,
+                       nil, nil, inter->string,
+                       nil, &err);
+               ·panic(err);
+       }
+       ret.data = i.data;
+       ret.type = tab->type;
+       FLUSH(&ret);
+}
+
+// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
+#pragma textflag 7
+void
+·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
+{
+       Itab *tab;
+
+       USED(inter);
+       tab = i.tab;
+       if(tab == nil) {
+               ret.type = nil;
+               ok = 0;
        } else {
-               ret = i;
-               if(tab->inter != inter)
-                       ret.tab = itab(inter, tab->type, 0);
+               ret.type = tab->type;
+               ok = 1;
        }
+       ret.data = i.data;
+       FLUSH(&ret);
+       FLUSH(&ok);
+}
 
+// func convI2I(typ *byte, elem any) (ret any)
+#pragma textflag 7
+void
+·convI2I(InterfaceType* inter, Iface i, Iface ret)
+{
+       Itab *tab;
+       
+       ret.data = i.data;
+       if((tab = i.tab) == nil)
+               ret.tab = nil;
+       else if(tab->inter == inter)
+               ret.tab = tab;
+       else
+               ret.tab = itab(inter, tab->type, 0);
        FLUSH(&ret);
 }
 
-// ifaceI2Ix(sigi *byte, iface any) (ret any);
-// called only for explicit conversions (with type assertion).
-// converting nil is not okay.
 void
-·ifaceI2Ix(InterfaceType *inter, Iface i, Iface ret)
+ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
 {
        Itab *tab;
        Eface err;
@@ -362,45 +393,40 @@ void
                        nil, nil, inter->string,
                        nil, &err);
                ·panic(err);
-       } else {
-               ret = i;
-               if(tab->inter != inter)
-                       ret.tab = itab(inter, tab->type, 0);
        }
+       ret->data = i.data;
+       ret->tab = itab(inter, tab->type, 0);
+}
 
-       FLUSH(&ret);
+// func ifaceI2I(sigi *byte, iface any) (ret any)
+#pragma textflag 7
+void
+·assertI2I(InterfaceType* inter, Iface i, Iface ret)
+{
+       ifaceI2I(inter, i, &ret);
 }
 
-// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
+// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
+#pragma textflag 7
 void
ifaceI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
 {
        Itab *tab;
 
        tab = i.tab;
-       if(tab == nil) {
-               // If incoming interface is nil, the conversion fails.
-               ret.tab = nil;
-               ret.data = nil;
-               ok = false;
+       if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) {
+               ret.data = i.data;
+               ret.tab = tab;
+               ok = 1;
        } else {
-               ret = i;
-               ok = true;
-               if(tab->inter != inter) {
-                       ret.tab = itab(inter, tab->type, 1);
-                       if(ret.tab == nil) {
-                               ret.data = nil;
-                               ok = false;
-                       }
-               }
+               ret.data = 0;
+               ret.tab = 0;
+               ok = 0;
        }
-
        FLUSH(&ret);
        FLUSH(&ok);
 }
 
-// ifaceE2I(sigi *byte, iface any) (ret any);
-// Called only for explicit conversions (with type assertion).
 void
 ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
 {
@@ -414,45 +440,71 @@ ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
                        nil, nil, inter->string,
                        nil, &err);
                ·panic(err);
-       } else {
-               ret->data = e.data;
-               ret->tab = itab(inter, t, 0);
        }
+       ret->data = e.data;
+       ret->tab = itab(inter, t, 0);
 }
 
-// ifaceE2I(sigi *byte, iface any) (ret any);
-// Called only for explicit conversions (with type assertion).
+// func ifaceE2I(sigi *byte, iface any) (ret any)
+#pragma textflag 7
 void
ifaceE2I(InterfaceType *inter, Eface e, Iface ret)
assertE2I(InterfaceType* inter, Eface e, Iface ret)
 {
        ifaceE2I(inter, e, &ret);
 }
 
-// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool);
+// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
+#pragma textflag 7
 void
ifaceE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
 {
-       Type *t;
-
-       t = e.type;
-       ok = true;
-       if(t == nil) {
-               // If incoming interface is nil, the conversion fails.
+       if(e.type == nil) {
+               ok = 0;
                ret.data = nil;
                ret.tab = nil;
-               ok = false;
+       } else if((ret.tab = itab(inter, e.type, 1)) == nil) {
+               ok = 0;
+               ret.data = nil;
        } else {
+               ok = 1;
                ret.data = e.data;
-               ret.tab = itab(inter, t, 1);
-               if(ret.tab == nil) {
-                       ret.data = nil;
-                       ok = false;
-               }
        }
        FLUSH(&ret);
        FLUSH(&ok);
 }
 
+// func ifaceE2E(typ *byte, iface any) (ret any)
+#pragma textflag 7
+void
+·assertE2E(InterfaceType* inter, Eface e, Eface ret)
+{
+       Type *t;
+       Eface err;
+
+       t = e.type;
+       if(t == nil) {
+               // explicit conversions require non-nil interface value.
+               ·newTypeAssertionError(nil, nil, inter,
+                       nil, nil, inter->string,
+                       nil, &err);
+               ·panic(err);
+       }
+       ret = e;
+       FLUSH(&ret);
+}
+
+// func ifaceE2E2(iface any) (ret any, ok bool)
+#pragma textflag 7
+void
+·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
+{
+       USED(inter);
+       ret = e;
+       ok = e.type != nil;
+       FLUSH(&ret);
+       FLUSH(&ok);
+}
+
 static uintptr
 ifacehash1(void *data, Type *t)
 {
diff --git a/test/assign1.go b/test/assign1.go
new file mode 100644 (file)
index 0000000..452f90f
--- /dev/null
@@ -0,0 +1,343 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type (
+       A [10]int
+       B []int
+       C chan int
+       F func() int
+       I interface {
+               m() int
+       }
+       M map[int]int
+       P *int
+       S struct {
+               X int
+       }
+
+       A1 [10]int
+       B1 []int
+       C1 chan int
+       F1 func() int
+       I1 interface {
+               m() int
+       }
+       M1 map[int]int
+       P1 *int
+       S1 struct {
+               X int
+       }
+)
+
+var (
+       a0 [10]int
+       b0 []int
+       c0 chan int
+       f0 func() int
+       i0 interface {
+               m() int
+       }
+       m0 map[int]int
+       p0 *int
+       s0 struct {
+               X int
+       }
+
+       a A
+       b B
+       c C
+       f F
+       i I
+       m M
+       p P
+       s S
+
+       a1 A1
+       b1 B1
+       c1 C1
+       f1 F1
+       i1 I1
+       m1 M1
+       p1 P1
+       s1 S1
+
+       pa0 *[10]int
+       pb0 *[]int
+       pc0 *chan int
+       pf0 *func() int
+       pi0 *interface {
+               m() int
+       }
+       pm0 *map[int]int
+       pp0 **int
+       ps0 *struct {
+               X int
+       }
+
+       pa *A
+       pb *B
+       pc *C
+       pf *F
+       pi *I
+       pm *M
+       pp *P
+       ps *S
+
+       pa1 *A1
+       pb1 *B1
+       pc1 *C1
+       pf1 *F1
+       pi1 *I1
+       pm1 *M1
+       pp1 *P1
+       ps1 *S1
+)
+
+func main() {
+       a0 = a
+       a0 = a1
+       a = a0
+       a = a1 // ERROR "cannot use"
+       a1 = a0
+       a1 = a // ERROR "cannot use"
+
+       b0 = b
+       b0 = b1
+       b = b0
+       b = b1 // ERROR "cannot use"
+       b1 = b0
+       b1 = b // ERROR "cannot use"
+
+       c0 = c
+       c0 = c1
+       c = c0
+       c = c1 // ERROR "cannot use"
+       c1 = c0
+       c1 = c // ERROR "cannot use"
+
+       f0 = f
+       f0 = f1
+       f = f0
+       f = f1 // ERROR "cannot use"
+       f1 = f0
+       f1 = f // ERROR "cannot use"
+
+       i0 = i
+       i0 = i1
+       i = i0
+       i = i1
+       i1 = i0
+       i1 = i
+
+       m0 = m
+       m0 = m1
+       m = m0
+       m = m1 // ERROR "cannot use"
+       m1 = m0
+       m1 = m // ERROR "cannot use"
+
+       p0 = p
+       p0 = p1
+       p = p0
+       p = p1 // ERROR "cannot use"
+       p1 = p0
+       p1 = p // ERROR "cannot use"
+
+       s0 = s
+       s0 = s1
+       s = s0
+       s = s1 // ERROR "cannot use"
+       s1 = s0
+       s1 = s // ERROR "cannot use"
+
+       pa0 = pa  // ERROR "cannot use"
+       pa0 = pa1 // ERROR "cannot use"
+       pa = pa0  // ERROR "cannot use"
+       pa = pa1  // ERROR "cannot use"
+       pa1 = pa0 // ERROR "cannot use"
+       pa1 = pa  // ERROR "cannot use"
+
+       pb0 = pb  // ERROR "cannot use"
+       pb0 = pb1 // ERROR "cannot use"
+       pb = pb0  // ERROR "cannot use"
+       pb = pb1  // ERROR "cannot use"
+       pb1 = pb0 // ERROR "cannot use"
+       pb1 = pb  // ERROR "cannot use"
+
+       pc0 = pc  // ERROR "cannot use"
+       pc0 = pc1 // ERROR "cannot use"
+       pc = pc0  // ERROR "cannot use"
+       pc = pc1  // ERROR "cannot use"
+       pc1 = pc0 // ERROR "cannot use"
+       pc1 = pc  // ERROR "cannot use"
+
+       pf0 = pf  // ERROR "cannot use"
+       pf0 = pf1 // ERROR "cannot use"
+       pf = pf0  // ERROR "cannot use"
+       pf = pf1  // ERROR "cannot use"
+       pf1 = pf0 // ERROR "cannot use"
+       pf1 = pf  // ERROR "cannot use"
+
+       pi0 = pi  // ERROR "cannot use"
+       pi0 = pi1 // ERROR "cannot use"
+       pi = pi0  // ERROR "cannot use"
+       pi = pi1  // ERROR "cannot use"
+       pi1 = pi0 // ERROR "cannot use"
+       pi1 = pi  // ERROR "cannot use"
+
+       pm0 = pm  // ERROR "cannot use"
+       pm0 = pm1 // ERROR "cannot use"
+       pm = pm0  // ERROR "cannot use"
+       pm = pm1  // ERROR "cannot use"
+       pm1 = pm0 // ERROR "cannot use"
+       pm1 = pm  // ERROR "cannot use"
+
+       pp0 = pp  // ERROR "cannot use"
+       pp0 = pp1 // ERROR "cannot use"
+       pp = pp0  // ERROR "cannot use"
+       pp = pp1  // ERROR "cannot use"
+       pp1 = pp0 // ERROR "cannot use"
+       pp1 = pp  // ERROR "cannot use"
+
+       ps0 = ps  // ERROR "cannot use"
+       ps0 = ps1 // ERROR "cannot use"
+       ps = ps0  // ERROR "cannot use"
+       ps = ps1  // ERROR "cannot use"
+       ps1 = ps0 // ERROR "cannot use"
+       ps1 = ps  // ERROR "cannot use"
+
+
+       a0 = [10]int(a)
+       a0 = [10]int(a1)
+       a = A(a0)
+       a = A(a1)
+       a1 = A1(a0)
+       a1 = A1(a)
+
+       b0 = []int(b)
+       b0 = []int(b1)
+       b = B(b0)
+       b = B(b1)
+       b1 = B1(b0)
+       b1 = B1(b)
+
+       c0 = chan int(c)
+       c0 = chan int(c1)
+       c = C(c0)
+       c = C(c1)
+       c1 = C1(c0)
+       c1 = C1(c)
+
+       f0 = func() int(f)
+       f0 = func() int(f1)
+       f = F(f0)
+       f = F(f1)
+       f1 = F1(f0)
+       f1 = F1(f)
+
+       i0 = interface {
+               m() int
+       }(i)
+       i0 = interface {
+               m() int
+       }(i1)
+       i = I(i0)
+       i = I(i1)
+       i1 = I1(i0)
+       i1 = I1(i)
+
+       m0 = map[int]int(m)
+       m0 = map[int]int(m1)
+       m = M(m0)
+       m = M(m1)
+       m1 = M1(m0)
+       m1 = M1(m)
+
+       p0 = (*int)(p)
+       p0 = (*int)(p1)
+       p = P(p0)
+       p = P(p1)
+       p1 = P1(p0)
+       p1 = P1(p)
+
+       s0 = struct {
+               X int
+       }(s)
+       s0 = struct {
+               X int
+       }(s1)
+       s = S(s0)
+       s = S(s1)
+       s1 = S1(s0)
+       s1 = S1(s)
+
+       pa0 = (*[10]int)(pa)
+       pa0 = (*[10]int)(pa1)
+       pa = (*A)(pa0)
+       pa = (*A)(pa1)
+       pa1 = (*A1)(pa0)
+       pa1 = (*A1)(pa)
+
+       pb0 = (*[]int)(pb)
+       pb0 = (*[]int)(pb1)
+       pb = (*B)(pb0)
+       pb = (*B)(pb1)
+       pb1 = (*B1)(pb0)
+       pb1 = (*B1)(pb)
+
+       pc0 = (*chan int)(pc)
+       pc0 = (*chan int)(pc1)
+       pc = (*C)(pc0)
+       pc = (*C)(pc1)
+       pc1 = (*C1)(pc0)
+       pc1 = (*C1)(pc)
+
+       pf0 = (*func() int)(pf)
+       pf0 = (*func() int)(pf1)
+       pf = (*F)(pf0)
+       pf = (*F)(pf1)
+       pf1 = (*F1)(pf0)
+       pf1 = (*F1)(pf)
+
+       pi0 = (*interface {
+               m() int
+       })(pi)
+       pi0 = (*interface {
+               m() int
+       })(pi1)
+       pi = (*I)(pi0)
+       pi = (*I)(pi1)
+       pi1 = (*I1)(pi0)
+       pi1 = (*I1)(pi)
+
+       pm0 = (*map[int]int)(pm)
+       pm0 = (*map[int]int)(pm1)
+       pm = (*M)(pm0)
+       pm = (*M)(pm1)
+       pm1 = (*M1)(pm0)
+       pm1 = (*M1)(pm)
+
+       pp0 = (**int)(pp)
+       pp0 = (**int)(pp1)
+       pp = (*P)(pp0)
+       pp = (*P)(pp1)
+       pp1 = (*P1)(pp0)
+       pp1 = (*P1)(pp)
+
+       ps0 = (*struct {
+               X int
+       })(ps)
+       ps0 = (*struct {
+               X int
+       })(ps1)
+       ps = (*S)(ps0)
+       ps = (*S)(ps1)
+       ps1 = (*S1)(ps0)
+       ps1 = (*S1)(ps)
+
+}
index cb05000128f365ee878d5ebeacb4e5a34cca36c8..5f1f0dd94e68f06c5923b03cf157d42d29dae809 100644 (file)
@@ -18,8 +18,9 @@ var f2 = []int(e)
 
 var g = []int(nil)
 
-type H *[4]int
+type H []int
 type J []int
+
 var h H
-var j1 J = h   // ERROR "compat|illegal|cannot|cannot"
+var j1 J = h // ERROR "compat|illegal|cannot"
 var j2 = J(h)
index 41f559b5261819d90e59048824285e2ccf9e154b..c96bf16768a43d9296ae94ef0252f18ae32dc9cf 100644 (file)
@@ -34,14 +34,14 @@ func (t1) M(p1.T) {}
 var i0 I0 = t0(0) // ok
 var i1 I1 = t1(0) // ok
 
-var i2 I0 = t1(0) // ERROR "is not|incompatible"
-var i3 I1 = t0(0) // ERROR "is not|incompatible"
+var i2 I0 = t1(0) // ERROR "does not implement|incompatible"
+var i3 I1 = t0(0) // ERROR "does not implement|incompatible"
 
 var p0i p0.I = t0(0) // ok
 var p1i p1.I = t1(0) // ok
 
-var p0i1 p0.I = t1(0) // ERROR "is not|incompatible"
-var p0i2 p1.I = t0(0) // ERROR "is not|incompatible"
+var p0i1 p0.I = t1(0) // ERROR "does not implement|incompatible"
+var p0i2 p1.I = t0(0) // ERROR "does not implement|incompatible"
 
 func main() {
        // check that cannot assign one to the other,
@@ -52,14 +52,14 @@ func main() {
        v0 = p0.T(v1)
        v1 = p1.T(v0)
 
-       i0 = i1   // ERROR "need type assertion|incompatible"
-       i1 = i0   // ERROR "need type assertion|incompatible"
-       p0i = i1  // ERROR "need type assertion|incompatible"
-       p1i = i0  // ERROR "need type assertion|incompatible"
-       i0 = p1i  // ERROR "need type assertion|incompatible"
-       i1 = p0i  // ERROR "need type assertion|incompatible"
-       p0i = p1i // ERROR "need type assertion|incompatible"
-       p1i = p0i // ERROR "need type assertion|incompatible"
+       i0 = i1   // ERROR "cannot use|incompatible"
+       i1 = i0   // ERROR "cannot use|incompatible"
+       p0i = i1  // ERROR "cannot use|incompatible"
+       p1i = i0  // ERROR "cannot use|incompatible"
+       i0 = p1i  // ERROR "cannot use|incompatible"
+       i1 = p0i  // ERROR "cannot use|incompatible"
+       p0i = p1i // ERROR "cannot use|incompatible"
+       p1i = p0i // ERROR "cannot use|incompatible"
 
        i0 = p0i
        p0i = i0
index 6ddc4a5a65788896a8ea635f8b1a3e951ba2e6fe..37dec905595cecb23531719cb36fbb1b052a6e15 100644 (file)
@@ -12,10 +12,10 @@ type I1 interface {
 }
 
 type I2 interface {
-       I1      // ERROR "loop|interface"
+       I1 // ERROR "loop|interface"
 }
 
 
-var i1 I1 = i2 // ERROR "need type assertion"
+var i1 I1 = i2 // ERROR "missing m method|need type assertion"
 var i2 I2
 var i2a I2 = i1
similarity index 100%
rename from test/bugs/bug284.go
rename to test/fixedbugs/bug284.go
similarity index 98%
rename from test/bugs/bug285.go
rename to test/fixedbugs/bug285.go
index 59499c983cecc25393112418f4a5a025214c6677..544d3487eff5c66adc99f3063afcf29cc3b390db 100644 (file)
@@ -1,4 +1,4 @@
-// $G $D/$F.go && $L $F.go && ./$A.out || echo BUG: bug285
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug285
 
 // Copyright 2010 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
index cda1ec412be69ea338420f65fff6f2c0ccbd9377..1bed6599a8d27bb8726e78d03c8984bef1bfd9da 100644 (file)
@@ -180,58 +180,3 @@ BUG: bug260 failed
 
 =========== bugs/bug274.go
 BUG: errchk: command succeeded unexpectedly
-
-=========== bugs/bug284.go
-BUG: errchk: bugs/bug284.go:33: missing expected error: 'cannot'
-errchk: bugs/bug284.go:36: missing expected error: 'cannot'
-errchk: bugs/bug284.go:37: missing expected error: 'cannot'
-errchk: bugs/bug284.go:38: missing expected error: 'cannot'
-errchk: bugs/bug284.go:56: missing expected error: 'cannot'
-errchk: bugs/bug284.go:59: missing expected error: 'cannot'
-errchk: bugs/bug284.go:60: missing expected error: 'cannot'
-errchk: bugs/bug284.go:61: missing expected error: 'cannot'
-errchk: bugs/bug284.go:71: missing expected error: 'cannot'
-errchk: bugs/bug284.go:74: missing expected error: 'cannot'
-errchk: bugs/bug284.go:75: missing expected error: 'cannot'
-errchk: bugs/bug284.go:76: missing expected error: 'cannot'
-errchk: bugs/bug284.go:96: missing expected error: 'cannot'
-errchk: bugs/bug284.go:99: missing expected error: 'cannot'
-errchk: bugs/bug284.go:101: missing expected error: 'cannot'
-errchk: bugs/bug284.go:111: missing expected error: 'cannot'
-errchk: bugs/bug284.go:114: missing expected error: 'cannot'
-errchk: bugs/bug284.go:115: missing expected error: 'cannot'
-errchk: bugs/bug284.go:116: missing expected error: 'cannot'
-errchk: bugs/bug284.go:134: missing expected error: 'cannot|need type assertion'
-errchk: bugs/bug284.go:137: missing expected error: 'cannot|need type assertion'
-errchk: bugs/bug284.go:138: missing expected error: 'cannot|need type assertion'
-errchk: bugs/bug284.go:139: missing expected error: 'cannot|need type assertion'
-errchk: bugs/bug284.go:149: missing expected error: 'cannot'
-errchk: bugs/bug284.go:152: missing expected error: 'cannot'
-errchk: bugs/bug284.go:153: missing expected error: 'cannot'
-errchk: bugs/bug284.go:154: missing expected error: 'cannot'
-errchk: bugs/bug284.go:164: missing expected error: 'cannot'
-errchk: bugs/bug284.go:167: missing expected error: 'cannot'
-errchk: bugs/bug284.go:168: missing expected error: 'cannot'
-errchk: bugs/bug284.go:169: missing expected error: 'cannot'
-errchk: bugs/bug284.go:179: missing expected error: 'cannot'
-errchk: bugs/bug284.go:182: missing expected error: 'cannot'
-errchk: bugs/bug284.go:183: missing expected error: 'cannot'
-errchk: bugs/bug284.go:184: missing expected error: 'cannot'
-errchk: bugs/bug284.go: unmatched error messages:
-==================================================
-bugs/bug284.go:190: internal compiler error: typename ideal
-==================================================
-
-=========== bugs/bug285.go
-bugs/bug285.go:23: invalid map index false - need type B
-bugs/bug285.go:80: invalid map index z - need type interface { }
-bugs/bug285.go:83: invalid map index new(struct { x int }) - need type interface { }
-bugs/bug285.go:84: invalid map index p - need type interface { }
-bugs/bug285.go:85: invalid map index false - need type interface { }
-bugs/bug285.go:86: invalid map index 17 - need type interface { }
-bugs/bug285.go:87: invalid map index "foo" - need type interface { }
-bugs/bug285.go:93: invalid map index new(struct { x int }) - need type I1
-bugs/bug285.go:94: invalid map index false - need type I1
-bugs/bug285.go:95: invalid map index 17 - need type I1
-bugs/bug285.go:95: too many errors
-BUG: bug285
index bd1bd19a9663d1b864a1876aae31456998e5129c..797cec80e4ed483051d019c59b6959ebd917c513 100644 (file)
@@ -8,34 +8,45 @@
 
 package main
 
-type T struct { a int }
+type T struct {
+       a int
+}
+
 var t *T
 
-type I interface { M() }
+type I interface {
+       M()
+}
+
 var i I
 
-type I2 interface { M(); N(); }
+type I2 interface {
+       M()
+       N()
+}
+
 var i2 I2
 
-type E interface { }
+type E interface{}
+
 var e E
 
 func main() {
-       e = t // ok
-       t = e // ERROR "need explicit|need type assertion"
+       e = t // ok
+       t = e // ERROR "need explicit|need type assertion"
 
        // neither of these can work,
        // because i has an extra method
        // that t does not, so i cannot contain a t.
-       i = t;  // ERROR "missing|incompatible|is not"
-       t = i;  // ERROR "missing|incompatible|is not"
+       i = t // ERROR "incompatible|missing M method"
+       t = i // ERROR "incompatible|need type assertion"
+
+       i = i2 // ok
+       i2 = i // ERROR "missing N method"
 
-       i = i2; // ok
-       i2 = i; // ERROR "need explicit|need type assertion"
-       
-       i = I(i2);      // ok
-       i2 = I2(i);     // ERROR "need explicit|need type assertion"
+       i = I(i2)  // ok
+       i2 = I2(i) // ERROR "missing N method"
 
-       e = E(t);       // ok
-       t = T(e);       // ERROR "need explicit|need type assertion|incompatible"
+       e = E(t) // ok
+       t = T(e) // ERROR "need explicit|need type assertion|incompatible"
 }
index be24952ffb2689dbfbcaf3dcd3518f89efe1699c..e628b558eaa70b9b2ed60af0adf551ab1a4d7df2 100644 (file)
@@ -9,28 +9,28 @@
 package main
 
 type Inst interface {
-       Next()  *Inst;
+       Next() *Inst
 }
 
 type Regexp struct {
-       code []Inst;
-       start   Inst;
+       code  []Inst
+       start Inst
 }
 
 type Start struct {
-       foo     *Inst;
+       foo *Inst
 }
 
 func (start *Start) Next() *Inst { return nil }
 
 
 func AddInst(Inst) *Inst {
-       print("ok in addinst\n");
+       print("ok in addinst\n")
        return nil
 }
 
 func main() {
-       print("call addinst\n");
-       var x Inst = AddInst(new(Start));       // ERROR "illegal|incompatible|is not"
-       print("return from  addinst\n");
+       print("call addinst\n")
+       var x Inst = AddInst(new(Start)) // ERROR "pointer to interface"
+       print("return from  addinst\n")
 }
index 8ce96424e3b554d6d06e5307fb4919b8d6b39e27..51312d00025e1297000f0f332d04d0b1b1d2ccb7 100644 (file)
@@ -9,41 +9,50 @@
 package main
 
 type T int
+
 func (t T) V()
 func (t *T) P()
 
-type V interface { V() }
-type P interface { P(); V() }
+type V interface {
+       V()
+}
+type P interface {
+       P()
+       V()
+}
 
-type S struct { T; }
-type SP struct { *T; }
+type S struct {
+       T
+}
+type SP struct {
+       *T
+}
 
 func main() {
-       var t T;
-       var v V;
-       var p P;
-       var s S;
-       var sp SP;
-
-       v = t;
-       p = t;  // ERROR "is not|requires a pointer"
-       _, _= v, p;
-       v = &t;
-       p = &t;
-       _, _= v, p;
-
-       v = s;
-       p = s;  // ERROR "is not|requires a pointer"
-       _, _= v, p;
-       v = &s;
-       p = &s;
-       _, _= v, p;
-
-       v = sp;
-       p = sp; // no error!
-       _, _= v, p;
-       v = &sp;
-       p = &sp;
-       _, _= v, p;
+       var t T
+       var v V
+       var p P
+       var s S
+       var sp SP
+
+       v = t
+       p = t // ERROR "does not implement|requires a pointer"
+       _, _ = v, p
+       v = &t
+       p = &t
+       _, _ = v, p
+
+       v = s
+       p = s // ERROR "does not implement|requires a pointer"
+       _, _ = v, p
+       v = &s
+       p = &s
+       _, _ = v, p
+
+       v = sp
+       p = sp // no error!
+       _, _ = v, p
+       v = &sp
+       p = &sp
+       _, _ = v, p
 }
-
index a52490215b9fb96b796926d1127a733544f3e04f..d2039bab4d4deed5b6f30ebee027bf62ea7a52b2 100644 (file)
@@ -20,13 +20,13 @@ type String string
 
 // Calling these functions checks at compile time that the argument
 // can be converted implicitly to (used as) the given type.
-func asArray(Array) {}
-func asBool(Bool) {}
-func asChan(Chan) {}
-func asFloat(Float) {}
-func asInt(Int) {}
-func asMap(Map) {}
-func asSlice(Slice) {}
+func asArray(Array)   {}
+func asBool(Bool)     {}
+func asChan(Chan)     {}
+func asFloat(Float)   {}
+func asInt(Int)       {}
+func asMap(Map)       {}
+func asSlice(Slice)   {}
 func asString(String) {}
 
 func (Map) M() {}
@@ -35,247 +35,247 @@ func (Map) M() {}
 // These functions check at run time that the default type
 // (in the absence of any implicit conversion hints)
 // is the given type.
-func isArray(x interface{}) { _ = x.(Array) }
-func isBool(x interface{}) { _ = x.(Bool) }
-func isChan(x interface{}) { _ = x.(Chan) }
-func isFloat(x interface{}) { _ = x.(Float) }
-func isInt(x interface{}) { _ = x.(Int) }
-func isMap(x interface{}) { _ = x.(Map) }
-func isSlice(x interface{}) { _ = x.(Slice) }
+func isArray(x interface{})  { _ = x.(Array) }
+func isBool(x interface{})   { _ = x.(Bool) }
+func isChan(x interface{})   { _ = x.(Chan) }
+func isFloat(x interface{})  { _ = x.(Float) }
+func isInt(x interface{})    { _ = x.(Int) }
+func isMap(x interface{})    { _ = x.(Map) }
+func isSlice(x interface{})  { _ = x.(Slice) }
 func isString(x interface{}) { _ = x.(String) }
 
 func main() {
        var (
-               a Array;
-               b Bool = true;
-               c Chan = make(Chan);
-               f Float = 1;
-               i Int = 1;
-               m Map = make(Map);
-               slice Slice = make(Slice, 10);
-               str String = "hello";
+               a     Array
+               b     Bool   = true
+               c     Chan   = make(Chan)
+               f     Float  = 1
+               i     Int    = 1
+               m     Map    = make(Map)
+               slice Slice  = make(Slice, 10)
+               str   String = "hello"
        )
 
-       asArray(a);
-       isArray(a);
-       asArray(*&a);
-       isArray(*&a);
-       asArray(Array{});
-       isArray(Array{});
+       asArray(a)
+       isArray(a)
+       asArray(*&a)
+       isArray(*&a)
+       asArray(Array{})
+       isArray(Array{})
 
-       asBool(b);
-       isBool(b);
-       asBool(!b);
-       isBool(!b);
-       asBool(true);
-       asBool(*&b);
-       isBool(*&b);
-       asBool(Bool(true));
-       isBool(Bool(true));
+       asBool(b)
+       isBool(b)
+       asBool(!b)
+       isBool(!b)
+       asBool(true)
+       asBool(*&b)
+       isBool(*&b)
+       asBool(Bool(true))
+       isBool(Bool(true))
 
-       asChan(c);
-       isChan(c);
-       asChan(make(Chan));
-       isChan(make(Chan));
-       asChan(*&c);
-       isChan(*&c);
-       asChan(Chan(nil));
-       isChan(Chan(nil));
+       asChan(c)
+       isChan(c)
+       asChan(make(Chan))
+       isChan(make(Chan))
+       asChan(*&c)
+       isChan(*&c)
+       asChan(Chan(nil))
+       isChan(Chan(nil))
 
-       asFloat(f);
-       isFloat(f);
-       asFloat(-f);
-       isFloat(-f);
-       asFloat(+f);
-       isFloat(+f);
-       asFloat(f+1);
-       isFloat(f+1);
-       asFloat(1+f);
-       isFloat(1+f);
-       asFloat(f+f);
-       isFloat(f+f);
-       f++;
-       f+=2;
-       asFloat(f-1);
-       isFloat(f-1);
-       asFloat(1-f);
-       isFloat(1-f);
-       asFloat(f-f);
-       isFloat(f-f);
-       f--;
-       f-=2;
-       asFloat(f*2.5);
-       isFloat(f*2.5);
-       asFloat(2.5*f);
-       isFloat(2.5*f);
-       asFloat(f*f);
-       isFloat(f*f);
-       f*=4;
-       asFloat(f/2.5);
-       isFloat(f/2.5);
-       asFloat(2.5/f);
-       isFloat(2.5/f);
-       asFloat(f/f);
-       isFloat(f/f);
-       f/=4;
-       asFloat(f);
-       isFloat(f);
-       f = 5;
-       asFloat(*&f);
-       isFloat(*&f);
-       asFloat(234);
-       asFloat(Float(234));
-       isFloat(Float(234));
-       asFloat(1.2);
-       asFloat(Float(i));
-       isFloat(Float(i));
+       asFloat(f)
+       isFloat(f)
+       asFloat(-f)
+       isFloat(-f)
+       asFloat(+f)
+       isFloat(+f)
+       asFloat(f + 1)
+       isFloat(f + 1)
+       asFloat(1 + f)
+       isFloat(1 + f)
+       asFloat(f + f)
+       isFloat(f + f)
+       f++
+       f += 2
+       asFloat(f - 1)
+       isFloat(f - 1)
+       asFloat(1 - f)
+       isFloat(1 - f)
+       asFloat(f - f)
+       isFloat(f - f)
+       f--
+       f -= 2
+       asFloat(f * 2.5)
+       isFloat(f * 2.5)
+       asFloat(2.5 * f)
+       isFloat(2.5 * f)
+       asFloat(f * f)
+       isFloat(f * f)
+       f *= 4
+       asFloat(f / 2.5)
+       isFloat(f / 2.5)
+       asFloat(2.5 / f)
+       isFloat(2.5 / f)
+       asFloat(f / f)
+       isFloat(f / f)
+       f /= 4
+       asFloat(f)
+       isFloat(f)
+       f = 5
+       asFloat(*&f)
+       isFloat(*&f)
+       asFloat(234)
+       asFloat(Float(234))
+       isFloat(Float(234))
+       asFloat(1.2)
+       asFloat(Float(i))
+       isFloat(Float(i))
 
-       asInt(i);
-       isInt(i);
-       asInt(-i);
-       isInt(-i);
-       asInt(^i);
-       isInt(^i);
-       asInt(+i);
-       isInt(+i);
-       asInt(i+1);
-       isInt(i+1);
-       asInt(1+i);
-       isInt(1+i);
-       asInt(i+i);
-       isInt(i+i);
-       i++;
-       i+=1;
-       asInt(i-1);
-       isInt(i-1);
-       asInt(1-i);
-       isInt(1-i);
-       asInt(i-i);
-       isInt(i-i);
-       i--;
-       i-=1;
-       asInt(i*2);
-       isInt(i*2);
-       asInt(2*i);
-       isInt(2*i);
-       asInt(i*i);
-       isInt(i*i);
-       i*=2;
-       asInt(i/5);
-       isInt(i/5);
-       asInt(5/i);
-       isInt(5/i);
-       asInt(i/i);
-       isInt(i/i);
-       i/=2;
-       asInt(i%5);
-       isInt(i%5);
-       asInt(5%i);
-       isInt(5%i);
-       asInt(i%i);
-       isInt(i%i);
-       i%=2;
-       asInt(i&5);
-       isInt(i&5);
-       asInt(5&i);
-       isInt(5&i);
-       asInt(i&i);
-       isInt(i&i);
-       i&=2;
-       asInt(i&^5);
-       isInt(i&^5);
-       asInt(5&^i);
-       isInt(5&^i);
-       asInt(i&^i);
-       isInt(i&^i);
-       i&^=2;
-       asInt(i|5);
-       isInt(i|5);
-       asInt(5|i);
-       isInt(5|i);
-       asInt(i|i);
-       isInt(i|i);
-       i|=2;
-       asInt(i^5);
-       isInt(i^5);
-       asInt(5^i);
-       isInt(5^i);
-       asInt(i^i);
-       isInt(i^i);
-       i^=2;
-       asInt(i<<4);
-       isInt(i<<4);
-       i<<=2;
-       asInt(i>>4);
-       isInt(i>>4);
-       i>>=2;
-       asInt(i);
-       isInt(i);
-       asInt(0);
-       asInt(Int(0));
-       isInt(Int(0));
-       i = 10;
-       asInt(*&i);
-       isInt(*&i);
-       asInt(23);
-       asInt(Int(f));
-       isInt(Int(f));
+       asInt(i)
+       isInt(i)
+       asInt(-i)
+       isInt(-i)
+       asInt(^i)
+       isInt(^i)
+       asInt(+i)
+       isInt(+i)
+       asInt(i + 1)
+       isInt(i + 1)
+       asInt(1 + i)
+       isInt(1 + i)
+       asInt(i + i)
+       isInt(i + i)
+       i++
+       i += 1
+       asInt(i - 1)
+       isInt(i - 1)
+       asInt(1 - i)
+       isInt(1 - i)
+       asInt(i - i)
+       isInt(i - i)
+       i--
+       i -= 1
+       asInt(i * 2)
+       isInt(i * 2)
+       asInt(2 * i)
+       isInt(2 * i)
+       asInt(i * i)
+       isInt(i * i)
+       i *= 2
+       asInt(i / 5)
+       isInt(i / 5)
+       asInt(5 / i)
+       isInt(5 / i)
+       asInt(i / i)
+       isInt(i / i)
+       i /= 2
+       asInt(i % 5)
+       isInt(i % 5)
+       asInt(5 % i)
+       isInt(5 % i)
+       asInt(i % i)
+       isInt(i % i)
+       i %= 2
+       asInt(i & 5)
+       isInt(i & 5)
+       asInt(5 & i)
+       isInt(5 & i)
+       asInt(i & i)
+       isInt(i & i)
+       i &= 2
+       asInt(i &^ 5)
+       isInt(i &^ 5)
+       asInt(5 &^ i)
+       isInt(5 &^ i)
+       asInt(i &^ i)
+       isInt(i &^ i)
+       i &^= 2
+       asInt(i | 5)
+       isInt(i | 5)
+       asInt(5 | i)
+       isInt(5 | i)
+       asInt(i | i)
+       isInt(i | i)
+       i |= 2
+       asInt(i ^ 5)
+       isInt(i ^ 5)
+       asInt(5 ^ i)
+       isInt(5 ^ i)
+       asInt(i ^ i)
+       isInt(i ^ i)
+       i ^= 2
+       asInt(i << 4)
+       isInt(i << 4)
+       i <<= 2
+       asInt(i >> 4)
+       isInt(i >> 4)
+       i >>= 2
+       asInt(i)
+       isInt(i)
+       asInt(0)
+       asInt(Int(0))
+       isInt(Int(0))
+       i = 10
+       asInt(*&i)
+       isInt(*&i)
+       asInt(23)
+       asInt(Int(f))
+       isInt(Int(f))
 
-       asMap(m);
-       isMap(m);
-       asMap(nil);
-       m = nil;
-       asMap(make(Map));
-       isMap(make(Map));
-       asMap(*&m);
-       isMap(*&m);
-       asMap(Map(nil));
-       isMap(Map(nil));
-       asMap(Map{});
-       isMap(Map{});
+       asMap(m)
+       isMap(m)
+       asMap(nil)
+       m = nil
+       asMap(make(Map))
+       isMap(make(Map))
+       asMap(*&m)
+       isMap(*&m)
+       asMap(Map(nil))
+       isMap(Map(nil))
+       asMap(Map{})
+       isMap(Map{})
 
-       asSlice(slice);
-       isSlice(slice);
-       asSlice(make(Slice, 5));
-       isSlice(make(Slice, 5));
-       asSlice([]byte{1,2,3});
-       asSlice([]byte{1,2,3}[0:2]);
-       asSlice(slice[0:4]);
-       isSlice(slice[0:4]);
-       asSlice(slice[3:8]);
-       isSlice(slice[3:8]);
-       asSlice(nil);
-       asSlice(Slice(nil));
-       isSlice(Slice(nil));
-       slice = nil;
-       asSlice(Slice{1,2,3});
-       isSlice(Slice{1,2,3});
-       asSlice(Slice{});
-       isSlice(Slice{});
-       asSlice(*&slice);
-       isSlice(*&slice);
+       asSlice(slice)
+       isSlice(slice)
+       asSlice(make(Slice, 5))
+       isSlice(make(Slice, 5))
+       asSlice([]byte{1, 2, 3})
+       asSlice([]byte{1, 2, 3}[0:2])
+       asSlice(slice[0:4])
+       isSlice(slice[0:4])
+       asSlice(slice[3:8])
+       isSlice(slice[3:8])
+       asSlice(nil)
+       asSlice(Slice(nil))
+       isSlice(Slice(nil))
+       slice = nil
+       asSlice(Slice{1, 2, 3})
+       isSlice(Slice{1, 2, 3})
+       asSlice(Slice{})
+       isSlice(Slice{})
+       asSlice(*&slice)
+       isSlice(*&slice)
 
-       asString(str);
-       isString(str);
-       asString(str+"a");
-       isString(str+"a");
-       asString("a"+str);
-       isString("a"+str);
-       asString(str+str);
-       isString(str+str);
-       str += "a";
-       str += str;
-       asString(String('a'));
-       isString(String('a'));
-       asString(String(slice));
-       isString(String(slice));
-       asString(String([]byte(nil)));
-       isString(String([]byte(nil)));
-       asString("hello");
-       asString(String("hello"));
-       isString(String("hello"));
-       str = "hello";
-       isString(str);
-       asString(*&str);
-       isString(*&str);
+       asString(str)
+       isString(str)
+       asString(str + "a")
+       isString(str + "a")
+       asString("a" + str)
+       isString("a" + str)
+       asString(str + str)
+       isString(str + str)
+       str += "a"
+       str += str
+       asString(String('a'))
+       isString(String('a'))
+       asString(String([]byte(slice)))
+       isString(String([]byte(slice)))
+       asString(String([]byte(nil)))
+       isString(String([]byte(nil)))
+       asString("hello")
+       asString(String("hello"))
+       isString(String("hello"))
+       str = "hello"
+       isString(str)
+       asString(*&str)
+       isString(*&str)
 }
index 21019533cebafc0b4dba8a4ffb16c199ccdeb20f..241697d5c0eafce33ecc471754b1e5a9bbe767c0 100644 (file)
@@ -12,46 +12,57 @@ package main
 type Bool bool
 
 type Map map[int]int
+
 func (Map) M() {}
 
-func asBool(Bool) {}
+type Slice []byte
+
+var slice Slice
+
+func asBool(Bool)     {}
+func asString(String) {}
+
+type String string
 
 func main() {
        var (
-               b Bool = true;
-               i, j int;
-               c = make(chan int);
-               m = make(Map);
+               b    Bool = true
+               i, j int
+               c    = make(chan int)
+               m    = make(Map)
        )
 
-       asBool(b);
-       asBool(!b);
-       asBool(true);
-       asBool(*&b);
-       asBool(Bool(true));
-       asBool(1!=2);   // ERROR "cannot use.*type bool.*as type Bool"
-       asBool(i < j);  // ERROR "cannot use.*type bool.*as type Bool"
+       asBool(b)
+       asBool(!b)
+       asBool(true)
+       asBool(*&b)
+       asBool(Bool(true))
+       asBool(1 != 2) // ERROR "cannot use.*type bool.*as type Bool"
+       asBool(i < j)  // ERROR "cannot use.*type bool.*as type Bool"
 
-       _, b = m[2];    // ERROR "cannot .* bool.*type Bool"
-       m[2] = 1, b;    // ERROR "cannot use.*type Bool.*as type bool"
+       _, b = m[2] // ERROR "cannot .* bool.*type Bool"
+       m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool"
 
-       b = c<-1;       // ERROR "cannot use.*type bool.*type Bool"
-       _ = b;
-       asBool(c<-1);   // ERROR "cannot use.*type bool.*as type Bool"
+       b = c <- 1 // ERROR "cannot use.*type bool.*type Bool"
+       _ = b
+       asBool(c <- 1) // ERROR "cannot use.*type bool.*as type Bool"
 
-       _, b = <-c;     // ERROR "cannot .* bool.*type Bool"
-       _ = b;
+       _, b = <-c // ERROR "cannot .* bool.*type Bool"
+       _ = b
 
-       var inter interface{};
-       _, b = inter.(Map);     // ERROR "cannot .* bool.*type Bool"
-       _ = b;
+       var inter interface{}
+       _, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
+       _ = b
 
-       var minter interface{M()};
-       _, b = minter.(Map);    // ERROR "cannot .* bool.*type Bool"
-       _ = b;
+       var minter interface {
+               M()
+       }
+       _, b = minter.(Map) // ERROR "cannot .* bool.*type Bool"
+       _ = b
 
-       asBool(closed(c));      // ERROR "cannot use.*type bool.*as type Bool"
-       b = closed(c);          // ERROR "cannot use.*type bool.*type Bool"
-       _ = b;
-}
+       asBool(closed(c)) // ERROR "cannot use.*type bool.*as type Bool"
+       b = closed(c)     // ERROR "cannot use.*type bool.*type Bool"
+       _ = b
 
+       asString(String(slice)) // ERROR "cannot convert slice"
+}