]> Cypherpunks.ru repositories - gostls13.git/commitdiff
gc: add ... T, rework plain ...
authorRuss Cox <rsc@golang.org>
Mon, 1 Feb 2010 08:25:59 +0000 (00:25 -0800)
committerRuss Cox <rsc@golang.org>
Mon, 1 Feb 2010 08:25:59 +0000 (00:25 -0800)
No longer a distinct type; now a property of func types.

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

21 files changed:
src/cmd/5g/gsubr.c
src/cmd/6g/gsubr.c
src/cmd/8g/gsubr.c
src/cmd/gc/align.c
src/cmd/gc/dcl.c
src/cmd/gc/go.h
src/cmd/gc/go.y
src/cmd/gc/print.c
src/cmd/gc/reflect.c
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
src/pkg/exp/datafmt/datafmt.go
src/pkg/exp/eval/bridge.go
src/pkg/reflect/type.go
src/pkg/runtime/type.go
src/pkg/runtime/type.h
test/ddd.go [new file with mode: 0644]
test/ddd1.go [new file with mode: 0644]
test/ddd2.go [new file with mode: 0644]
test/ddd3.go [new file with mode: 0644]

index 561d2ccceb6f29ab5124888909548b0c36dff486..ad9cad67e05dd2d0c14d7061b83d094279156ecf 100644 (file)
@@ -178,7 +178,6 @@ isfat(Type *t)
        case TARRAY:
        case TSTRING:
        case TINTER:    // maybe remove later
-       case TDDD:      // maybe remove later
                return 1;
        }
        return 0;
index 07471ffa7ce91a9282745294d763e233f1f273b8..5549830e3f1c15624c7557f7dbbc4c239a8c2f4d 100644 (file)
@@ -174,7 +174,6 @@ isfat(Type *t)
        case TARRAY:
        case TSTRING:
        case TINTER:    // maybe remove later
-       case TDDD:      // maybe remove later
                return 1;
        }
        return 0;
index e09ba7b20d279e9f7bc146b235aa33d75fd15d51..07ad153e0c203eba412a9985c985ddd24cf33330 100644 (file)
@@ -176,7 +176,6 @@ isfat(Type *t)
        case TARRAY:
        case TSTRING:
        case TINTER:    // maybe remove later
-       case TDDD:      // maybe remove later
                return 1;
        }
        return 0;
index ba84c4377fca5f8115f8f98047f5af539d61523e..7a27a040c9f88ffe103558dfdbcffe0f619fbd07 100644 (file)
@@ -176,9 +176,6 @@ dowidth(Type *t)
                w = 8;
                checkwidth(t->type);
                break;
-       case TDDD:
-               w = 2*widthptr;
-               break;
        case TINTER:            // implemented as 2 pointers
                w = 2*widthptr;
                offmod(t);
index 4639eda8d20f25153da3e0724748b3ce4cff9592..aeb3e3916aae0e7fd5c53b248248602553dab128 100644 (file)
@@ -877,6 +877,7 @@ stotype(NodeList *l, int et, Type **t)
                f->type = n->type;
                f->note = note;
                f->width = BADWIDTH;
+               f->isddd = n->isddd;
 
                if(n->left != N && n->left->op == ONAME) {
                        f->nname = n->left;
@@ -1022,11 +1023,23 @@ checkarglist(NodeList *all, int input)
                if(n != N)
                        n = newname(n->sym);
                n = nod(ODCLFIELD, n, t);
-               if(n->right != N && n->right->op == OTYPE && isddd(n->right->type)) {
+               if(n->right != N && n->right->op == ODDD) {
                        if(!input)
                                yyerror("cannot use ... in output argument list");
                        else if(l->next != nil)
                                yyerror("can only use ... as final argument in list");
+                       if(n->right->left == N) {
+                               // TODO(rsc): Delete with DDD cleanup.
+                               n->right->op = OTYPE;
+                               n->right->type = typ(TINTER);
+                       } else {
+                               n->right->op = OTARRAY;
+                               n->right->right = n->right->left;
+                               n->right->left = N;
+                       }
+                       n->isddd = 1;
+                       if(n->left != N)
+                               n->left->isddd = 1;
                }
                l->n = n;
        }
index e5715e895ef950165bcb635f2ed573db775939d2..d634d0d3a9a2f5f01aeea484a8331ce4749e0eab 100644 (file)
@@ -147,6 +147,7 @@ struct      Type
        uchar   local;          // created in this file
        uchar   deferwidth;
        uchar   broke;
+       uchar   isddd;  // TFIELD is ... argument
 
        Node*   nod;            // canonical OTYPE node
        int             lineno;
@@ -205,6 +206,7 @@ struct      Node
        uchar   dodata;         // compile literal assignment as data statement
        uchar   used;
        uchar   oldref;
+       uchar   isddd;
 
        // most nodes
        Node*   left;
@@ -401,6 +403,9 @@ enum
        OTINTER,
        OTFUNC,
        OTARRAY,
+       
+       // misc
+       ODDD,
 
        // for back ends
        OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
@@ -425,21 +430,20 @@ enum
 
        TPTR32, TPTR64,         // 16
 
-       TDDD,                   // 18
-       TFUNC,
+       TFUNC,          // 18
        TARRAY,
        T_old_DARRAY,
-       TSTRUCT,                // 22
+       TSTRUCT,                // 21
        TCHAN,
        TMAP,
-       TINTER,                 // 25
+       TINTER,                 // 24
        TFORW,
        TFIELD,
        TANY,
        TSTRING,
 
        // pseudo-types for literals
-       TIDEAL,                 // 30
+       TIDEAL,                 // 29
        TNIL,
        TBLANK,
        
@@ -844,7 +848,6 @@ int isfixedarray(Type*);
 int    isslice(Type*);
 int    isinter(Type*);
 int    isnilinter(Type*);
-int    isddd(Type*);
 int    isideal(Type*);
 int    isblank(Node*);
 Type*  maptype(Type*, Type*);
index c309d0d01762c6747e29dcba956dc17aa7276e72..f2a037710bcd53f41114110a4b259ac25ccb36c0 100644 (file)
@@ -76,7 +76,7 @@
 
 %type  <sym>   hidden_importsym hidden_pkg_importsym
 
-%type  <node>  hidden_constant hidden_dcl hidden_interfacedcl hidden_structdcl
+%type  <node>  hidden_constant hidden_dcl hidden_interfacedcl hidden_structdcl hidden_opt_sym
 
 %type  <list>  hidden_funres
 %type  <list>  ohidden_funres
@@ -896,10 +896,10 @@ convtype:
                // array literal
                $$ = nod(OTARRAY, $2, $4);
        }
-|      '[' dotdotdot ']' ntype
+|      '[' LDDD ']' ntype
        {
                // array literal of nelem
-               $$ = nod(OTARRAY, $2, $4);
+               $$ = nod(OTARRAY, nod(ODDD, N, N), $4);
        }
 |      LMAP '[' ntype ']' ntype
        {
@@ -920,7 +920,11 @@ convtype:
 dotdotdot:
        LDDD
        {
-               $$ = typenod(typ(TDDD));
+               $$ = nod(ODDD, N, N);
+       }
+|      LDDD ntype
+       {
+               $$ = nod(ODDD, $2, N);
        }
 
 ntype:
@@ -979,10 +983,10 @@ othertype:
        {
                $$ = nod(OTARRAY, $2, $4);
        }
-|      '[' dotdotdot ']' ntype
+|      '[' LDDD ']' ntype
        {
                // array literal of nelem
-               $$ = nod(OTARRAY, $2, $4);
+               $$ = nod(OTARRAY, nod(ODDD, N, N), $4);
        }
 |      LCHAN non_recvchantype
        {
@@ -1651,10 +1655,6 @@ hidden_type_misc:
                $$->type = $3;
                $$->chan = Csend;
        }
-|      LDDD
-       {
-               $$ = typ(TDDD);
-       }
 
 hidden_type_recv_chan:
        LCOMM LCHAN hidden_type
@@ -1670,14 +1670,35 @@ hidden_type_func:
                $$ = functype(nil, $3, $5);
        }
 
+hidden_opt_sym:
+       sym
+       {
+               $$ = newname($1);
+       }
+|      '?'
+       {
+               $$ = N;
+       }
+
 hidden_dcl:
-       sym hidden_type
+       hidden_opt_sym hidden_type
        {
-               $$ = nod(ODCLFIELD, newname($1), typenod($2));
+               $$ = nod(ODCLFIELD, $1, typenod($2));
+       }
+|      hidden_opt_sym LDDD
+       {
+               $$ = nod(ODCLFIELD, $1, typenod(typ(TINTER)));
+               $$->isddd = 1;
        }
-|      '?' hidden_type
+|      hidden_opt_sym LDDD hidden_type
        {
-               $$ = nod(ODCLFIELD, N, typenod($2));
+               Type *t;
+               
+               t = typ(TARRAY);
+               t->bound = -1;
+               t->type = $3;
+               $$ = nod(ODCLFIELD, $1, typenod(t));
+               $$->isddd = 1;
        }
 
 hidden_structdcl:
index 91f012d8b877d6ea2cfa151303e66fde0c8b177d..57ebe3f1cfa9189df753a8330d2697e1362ec354 100644 (file)
@@ -243,7 +243,19 @@ exprfmt(Fmt *f, Node *n, int prec)
                break;
 
        case OCOMPLIT:
-               fmtprint(f, "<compos>");
+               fmtprint(f, "composite literal");
+               break;
+       
+       case OARRAYLIT:
+               fmtprint(f, "slice literal");
+               break;
+       
+       case OMAPLIT:
+               fmtprint(f, "map literal");
+               break;
+       
+       case OSTRUCTLIT:
+               fmtprint(f, "struct literal");
                break;
 
        case ODOT:
@@ -338,9 +350,6 @@ exprfmt(Fmt *f, Node *n, int prec)
        case OMAKEMAP:
                fmtprint(f, "make(%#T)", n->type);
                break;
-
-       case OMAPLIT:
-               fmtprint(f, "map literal");
        }
 
        if(prec > nprec)
index e1dba06b8cfabe11e3cdb82b252876c13e28900c..3f90f68e93e43d088195ac1bb909ca90cf688dfd 100644 (file)
@@ -391,7 +391,6 @@ enum {
        KindFloat64,
        KindArray,
        KindChan,
-       KindDotDotDot,
        KindFunc,
        KindInterface,
        KindMap,
@@ -423,7 +422,6 @@ kinds[] =
        [TFLOAT64]      = KindFloat64,
        [TBOOL]         = KindBool,
        [TSTRING]               = KindString,
-       [TDDD]          = KindDotDotDot,
        [TPTR32]                = KindPtr,
        [TPTR64]                = KindPtr,
        [TSTRUCT]       = KindStruct,
@@ -453,7 +451,6 @@ structnames[] =
        [TFLOAT64]      = "*runtime.Float64Type",
        [TBOOL]         = "*runtime.BoolType",
        [TSTRING]               = "*runtime.StringType",
-       [TDDD]          = "*runtime.DotDotDotType",
 
        [TPTR32]                = "*runtime.PtrType",
        [TPTR64]                = "*runtime.PtrType",
@@ -518,7 +515,6 @@ haspointers(Type *t)
                                return 1;
                return 0;
        case TSTRING:
-       case TDDD:
        case TPTR32:
        case TPTR64:
        case TINTER:
@@ -637,7 +633,7 @@ typename(Type *t)
 static Sym*
 dtypesym(Type *t)
 {
-       int ot, n;
+       int ot, n, isddd;
        Sym *s, *s1, *s2;
        Sig *a, *m;
        Type *t1;
@@ -709,14 +705,19 @@ ok:
        case TFUNC:
                for(t1=getthisx(t)->type; t1; t1=t1->down)
                        dtypesym(t1->type);
-               for(t1=getinargx(t)->type; t1; t1=t1->down)
+               isddd = 0;
+               for(t1=getinargx(t)->type; t1; t1=t1->down) {
+                       isddd = t1->isddd;
                        dtypesym(t1->type);
+               }
                for(t1=getoutargx(t)->type; t1; t1=t1->down)
                        dtypesym(t1->type);
 
                ot = dcommontype(s, ot, t);
+               ot = duint8(s, ot, isddd);
 
                // two slice headers: in and out.
+               ot = rnd(ot, widthptr);
                ot = dsymptr(s, ot, s, ot+2*(widthptr+2*4));
                n = t->thistuple + t->intuple;
                ot = duint32(s, ot, n);
@@ -855,7 +856,6 @@ dumptypestructs(void)
                for(i=1; i<=TBOOL; i++)
                        dtypesym(ptrto(types[i]));
                dtypesym(ptrto(types[TSTRING]));
-               dtypesym(typ(TDDD));
                dtypesym(ptrto(pkglookup("Pointer", unsafepkg)->def->type));
                
                // add paths for runtime and main, which 6l imports implicitly.
index 9d0c84ac419469f06fa490bce86bb5befa8e81c7..a9384247040642e093e9ae46a9b4747fba9eb08b 100644 (file)
@@ -941,7 +941,6 @@ etnames[] =
        [TBOOL]         = "BOOL",
        [TPTR32]        = "PTR32",
        [TPTR64]        = "PTR64",
-       [TDDD]          = "DDD",
        [TFUNC]         = "FUNC",
        [TARRAY]        = "ARRAY",
        [TSTRUCT]       = "STRUCT",
@@ -1088,7 +1087,6 @@ basicnames[] =
        [TFLOAT64]      = "float64",
        [TBOOL]         = "bool",
        [TANY]          = "any",
-       [TDDD]          = "...",
        [TSTRING]               = "string",
        [TNIL]          = "nil",
        [TIDEAL]                = "ideal",
@@ -1166,9 +1164,16 @@ Tpretty(Fmt *fp, Type *t)
                        fmtprint(fp, "func");
                fmtprint(fp, "(");
                for(t1=getinargx(t)->type; t1; t1=t1->down) {
-                       if(noargnames && t1->etype == TFIELD)
-                               fmtprint(fp, "%T", t1->type);
-                       else
+                       if(noargnames && t1->etype == TFIELD) {
+                               if(t1->isddd) {
+                                       // TODO(rsc): Delete with DDD cleanup.
+                                       if(t1->type->etype == TINTER)
+                                               fmtprint(fp, "...");
+                                       else
+                                               fmtprint(fp, "... %T", t1->type->type);
+                               } else
+                                       fmtprint(fp, "%T", t1->type);
+                       } else
                                fmtprint(fp, "%T", t1);
                        if(t1->down)
                                fmtprint(fp, ", ");
@@ -1246,9 +1251,16 @@ Tpretty(Fmt *fp, Type *t)
                if(t->sym == S || t->embedded) {
                        if(exporting)
                                fmtprint(fp, "? ");
-                       fmtprint(fp, "%T", t->type);
                } else
-                       fmtprint(fp, "%hS %T", t->sym, t->type);
+                       fmtprint(fp, "%hS ", t->sym);
+               if(t->isddd) {
+                       // TODO(rsc): delete with DDD cleanup.
+                       if(t->type->etype == TINTER)
+                               fmtprint(fp, "...");
+                       else
+                               fmtprint(fp, "... %T", t->type->type);
+               } else
+                       fmtprint(fp, "%T", t->type);
                if(t->note)
                        fmtprint(fp, " \"%Z\"", t->note);
                return 0;
@@ -1608,13 +1620,7 @@ isselect(Node *n)
 int
 isinter(Type *t)
 {
-       if(t != T) {
-               if(t->etype == TINTER)
-                       return 1;
-               if(t->etype == TDDD)
-                       return 1;
-       }
-       return 0;
+       return t != T && t->etype == TINTER;
 }
 
 int
@@ -1627,14 +1633,6 @@ isnilinter(Type *t)
        return 1;
 }
 
-int
-isddd(Type *t)
-{
-       if(t != T && t->etype == TDDD)
-               return 1;
-       return 0;
-}
-
 int
 isideal(Type *t)
 {
@@ -1756,7 +1754,7 @@ eqtype1(Type *t1, Type *t2, int d, int names)
                        while(ta != tb) {
                                if(ta == T || tb == T)
                                        return 0;
-                               if(ta->etype != TFIELD || tb->etype != TFIELD)
+                               if(ta->etype != TFIELD || tb->etype != TFIELD || ta->isddd != tb->isddd)
                                        return 0;
                                if(!eqtype1(ta->type, tb->type, d+1, names))
                                        return 0;
@@ -2193,19 +2191,24 @@ out:
 void
 badtype(int o, Type *tl, Type *tr)
 {
-       yyerror("illegal types for operand: %O", o);
+       Fmt fmt;
+       char *s;
+       
+       fmtstrinit(&fmt);
        if(tl != T)
-               print(" %T\n", tl);
+               fmtprint(&fmt, "\n      %T", tl);
        if(tr != T)
-               print(" %T\n", tr);
+               fmtprint(&fmt, "\n      %T", tr);
 
        // common mistake: *struct and *interface.
        if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
                if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER)
-                       print(" (*struct vs *interface)\n");
+                       fmtprint(&fmt, "\n      (*struct vs *interface)");
                else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT)
-                       print(" (*interface vs *struct)\n");
+                       fmtprint(&fmt, "\n      (*interface vs *struct)");
        }
+       s = fmtstrflush(&fmt);
+       yyerror("illegal types for operand: %O%s", o, s);
 }
 
 /*
index e8ed1dc941b7a5b038d46cd37622d8e321d9c444..dfd67b71cb1f39538a30728c7a7099ad7f9d449e 100644 (file)
@@ -140,6 +140,9 @@ reswitch:
                        n = n->right;
                goto redo;
 
+       case ODDD:
+               break;
+
        /*
         * types (OIND is with exprs)
         */
@@ -157,7 +160,8 @@ reswitch:
                if(l == nil) {
                        t->bound = -1;
                } else {
-                       typecheck(&l, Erv | Etype);
+                       if(l->op != ODDD)
+                               typecheck(&l, Erv | Etype);
                        switch(l->op) {
                        default:
                                yyerror("invalid array bound %#N", l);
@@ -173,13 +177,7 @@ reswitch:
                                }
                                break;
 
-                       case OTYPE:
-                               if(l->type == T)
-                                       goto error;
-                               if(l->type->etype != TDDD) {
-                                       yyerror("invalid array bound %T", l->type);
-                                       goto error;
-                               }
+                       case ODDD:
                                t->bound = -100;
                                break;
                        }
@@ -1496,12 +1494,18 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
                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);
+                               goto out;
+                       }
                        if(tn == T) {
                                yyerror("not enough arguments to %#O", op);
                                goto out;
                        }
-                       if(isddd(tl->type))
-                               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);
                        tn = tn->down;
@@ -1513,10 +1517,17 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
 
        for(tl=tstruct->type; tl; tl=tl->down) {
                t = tl->type;
-               if(isddd(t)) {
+               if(tl->isddd) {
+                       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);
+                               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);                                       
                        }
                        goto out;
                }
index e142814f7bb76eef43b5927b23179ccf06bbeaaa..9a84acce36832d759799ea18f88a6d63497cfedf 100644 (file)
@@ -1368,6 +1368,31 @@ mkdotargs(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
        return nn;
 }
 
+ /*
+ * package all the arguments that match a ... T parameter into a []T.
+ */
+NodeList*
+mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
+{
+       Node *a, *n;
+       Type *tslice;
+       
+       tslice = typ(TARRAY);
+       tslice->type = l->type->type;
+       tslice->bound = -1;
+       
+       n = nod(OCOMPLIT, N, typenod(tslice));
+       n->list = lr0;
+       typecheck(&n, Erv);
+       if(n->type == T)
+               fatal("mkdotargslice: typecheck failed");
+       walkexpr(&n, init);
+       
+       a = nod(OAS, nodarg(l, fp), n);
+       nn = list(nn, convas(a, init));
+       return nn;
+}
+
 /*
  * helpers for shape errors
  */
@@ -1466,7 +1491,7 @@ ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init)
        }
 
 loop:
-       if(l != T && isddd(l->type)) {
+       if(l != T && l->isddd) {
                // the ddd parameter must be last
                ll = structnext(&savel);
                if(ll != T)
@@ -1476,7 +1501,7 @@ loop:
                // only if we are assigning a single ddd
                // argument to a ddd parameter then it is
                // passed thru unencapsulated
-               if(r != N && lr->next == nil && isddd(r->type)) {
+               if(r != N && lr->next == nil && r->isddd && eqtype(l->type, r->type)) {
                        a = nod(OAS, nodarg(l, fp), r);
                        a = convas(a, init);
                        nn = list(nn, a);
@@ -1486,7 +1511,11 @@ loop:
                // normal case -- make a structure of all
                // remaining arguments and pass a pointer to
                // it to the ddd parameter (empty interface)
-               nn = mkdotargs(lr, nn, l, fp, init);
+               // TODO(rsc): delete in DDD cleanup.
+               if(l->type->etype == TINTER)
+                       nn = mkdotargs(lr, nn, l, fp, init);
+               else
+                       nn = mkdotargslice(lr, nn, l, fp, init);
                goto ret;
        }
 
index 0a2354286b96226fc3491e80e5f74c14a6e7c1f1..cd9af2b6ac540b4410cb23179f7f726266ed7479 100644 (file)
@@ -415,8 +415,6 @@ func typename(typ reflect.Type) string {
                return "array"
        case *reflect.ChanType:
                return "chan"
-       case *reflect.DotDotDotType:
-               return "ellipsis"
        case *reflect.FuncType:
                return "func"
        case *reflect.InterfaceType:
index 43a6fd30d6ff1aaf5fb5d1b3d10fc92e67ff5465..d494421a434df7d8a001afb7a3fe1d3299e29bb2 100644 (file)
@@ -75,12 +75,9 @@ func TypeFromNative(t reflect.Type) Type {
        case *reflect.FuncType:
                nin := t.NumIn()
                // Variadic functions have DotDotDotType at the end
-               varidic := false
-               if nin > 0 {
-                       if _, ok := t.In(nin - 1).(*reflect.DotDotDotType); ok {
-                               varidic = true
-                               nin--
-                       }
+               variadic := t.DotDotDot()
+               if variadic {
+                       nin--
                }
                in := make([]Type, nin)
                for i := range in {
@@ -90,7 +87,7 @@ func TypeFromNative(t reflect.Type) Type {
                for i := range out {
                        out[i] = TypeFromNative(t.Out(i))
                }
-               et = NewFuncType(in, varidic, out)
+               et = NewFuncType(in, variadic, out)
        case *reflect.InterfaceType:
                log.Crashf("%T not implemented", t)
        case *reflect.MapType:
index cd838d7289a151a83d887fb449ae5742f9c6bb22..1e2772f66b7cc20de3b4f2b806018649ea2221de 100644 (file)
@@ -139,12 +139,6 @@ type UintptrType struct {
        commonType
 }
 
-// DotDotDotType represents the ... that can
-// be used as the type of the final function parameter.
-type DotDotDotType struct {
-       commonType
-}
-
 // UnsafePointerType represents an unsafe.Pointer type.
 type UnsafePointerType struct {
        commonType
@@ -176,8 +170,9 @@ type ChanType struct {
 // FuncType represents a function type.
 type FuncType struct {
        commonType
-       in  []*runtime.Type
-       out []*runtime.Type
+       dotdotdot bool
+       in        []*runtime.Type
+       out       []*runtime.Type
 }
 
 // Method on interface type
@@ -377,6 +372,19 @@ func (t *FuncType) In(i int) Type {
        return toType(*t.in[i])
 }
 
+// DotDotDot returns true if the final function input parameter
+// is a "..." parameter.  If so, the parameter's underlying static
+// type - either interface{} or []T - is returned by t.In(t.NumIn() - 1).
+//
+// For concreteness, if t is func(x int, y ... float), then
+//
+//     t.NumIn() == 2
+//     t.In(0) is the reflect.Type for "int"
+//     t.In(1) is the reflect.Type for "[]float"
+//     t.DotDotDot() == true
+//
+func (t *FuncType) DotDotDot() bool { return t.dotdotdot }
+
 // NumIn returns the number of input parameters.
 func (t *FuncType) NumIn() int { return len(t.in) }
 
@@ -571,8 +579,6 @@ func toType(i interface{}) Type {
                return nil
        case *runtime.BoolType:
                return (*BoolType)(unsafe.Pointer(v))
-       case *runtime.DotDotDotType:
-               return (*DotDotDotType)(unsafe.Pointer(v))
        case *runtime.FloatType:
                return (*FloatType)(unsafe.Pointer(v))
        case *runtime.Float32Type:
index bf757c7631d82a3e3db475b0fabe923a2cc8cdf4..d76edeba4bed7d5abf015ee35950f5427187ea82 100644 (file)
@@ -55,7 +55,6 @@ const (
        kindFloat64
        kindArray
        kindChan
-       kindDotDotDot
        kindFunc
        kindInterface
        kindMap
@@ -136,10 +135,6 @@ type StringType commonType
 // UintptrType represents a uintptr type.
 type UintptrType commonType
 
-// DotDotDotType represents the ... that can
-// be used as the type of the final function parameter.
-type DotDotDotType commonType
-
 // UnsafePointerType represents an unsafe.Pointer type.
 type UnsafePointerType commonType
 
@@ -175,8 +170,9 @@ type ChanType struct {
 // FuncType represents a function type.
 type FuncType struct {
        commonType
-       in  []*Type // input parameter types
-       out []*Type // output parameter types
+       dotdotdot bool    // last input parameter is ...
+       in        []*Type // input parameter types
+       out       []*Type // output parameter types
 }
 
 // Method on interface type
index 9dc7881db567f5de894485cef81a06c629b18214..36a3b6acf440e6b21b23b2838695477b64ab78da 100644 (file)
@@ -45,7 +45,6 @@ enum {
        KindFloat64,
        KindArray,
        KindChan,
-       KindDotDotDot,
        KindFunc,
        KindInterface,
        KindMap,
@@ -116,4 +115,3 @@ struct SliceType
        Type;
        Type *elem;
 };
-
diff --git a/test/ddd.go b/test/ddd.go
new file mode 100644 (file)
index 0000000..682f22f
--- /dev/null
@@ -0,0 +1,105 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 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
+
+func sum(args ...int) int {
+       s := 0
+       for _, v := range args {
+               s += v
+       }
+       return s
+}
+
+func sumA(args []int) int {
+       s := 0
+       for _, v := range args {
+               s += v
+       }
+       return s
+}
+
+func sum2(args ...int) int { return 2 * sum(args) }
+
+func sum3(args ...int) int { return 3 * sumA(args) }
+
+func intersum(args ...interface{}) int {
+       s := 0
+       for _, v := range args {
+               s += v.(int)
+       }
+       return s
+}
+
+type T []T
+
+func ln(args ...T) int { return len(args) }
+
+func ln2(args ...T) int { return 2 * ln(args) }
+
+func main() {
+       if x := sum(1, 2, 3); x != 6 {
+               panicln("sum 6", x)
+       }
+       if x := sum(); x != 0 {
+               panicln("sum 0", x)
+       }
+       if x := sum(10); x != 10 {
+               panicln("sum 10", x)
+       }
+       if x := sum(1, 8); x != 9 {
+               panicln("sum 9", x)
+       }
+       if x := sum2(1, 2, 3); x != 2*6 {
+               panicln("sum 6", x)
+       }
+       if x := sum2(); x != 2*0 {
+               panicln("sum 0", x)
+       }
+       if x := sum2(10); x != 2*10 {
+               panicln("sum 10", x)
+       }
+       if x := sum2(1, 8); x != 2*9 {
+               panicln("sum 9", x)
+       }
+       if x := sum3(1, 2, 3); x != 3*6 {
+               panicln("sum 6", x)
+       }
+       if x := sum3(); x != 3*0 {
+               panicln("sum 0", x)
+       }
+       if x := sum3(10); x != 3*10 {
+               panicln("sum 10", x)
+       }
+       if x := sum3(1, 8); x != 3*9 {
+               panicln("sum 9", x)
+       }
+       if x := intersum(1, 2, 3); x != 6 {
+               panicln("intersum 6", x)
+       }
+       if x := intersum(); x != 0 {
+               panicln("intersum 0", x)
+       }
+       if x := intersum(10); x != 10 {
+               panicln("intersum 10", x)
+       }
+       if x := intersum(1, 8); x != 9 {
+               panicln("intersum 9", x)
+       }
+
+       if x := ln(nil, nil, nil); x != 3 {
+               panicln("ln 3", x)
+       }
+       if x := ln([]T{}); x != 1 {
+               panicln("ln 1", x)
+       }
+       if x := ln2(nil, nil, nil); x != 2*3 {
+               panicln("ln2 3", x)
+       }
+       if x := ln2([]T{}); x != 2*1 {
+               panicln("ln2 1", x)
+       }
+}
diff --git a/test/ddd1.go b/test/ddd1.go
new file mode 100644 (file)
index 0000000..da03a70
--- /dev/null
@@ -0,0 +1,28 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 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
+
+func sum(args ...int) int { return 0 }
+
+var (
+       _ = sum(1, 2, 3)
+       _ = sum()
+       _ = sum(1.0, 2.0)
+       _ = sum(1.5)      // ERROR "integer"
+       _ = sum("hello")  // ERROR "convert"
+       _ = sum([]int{1}) // ERROR "slice literal as type int"
+)
+
+type T []T
+
+func funny(args ...T) int { return 0 }
+
+var (
+       _ = funny(nil)
+       _ = funny(nil, nil)
+       _ = funny([]T{}) // ok because []T{} is a T; passes []T{[]T{}}
+)
diff --git a/test/ddd2.go b/test/ddd2.go
new file mode 100644 (file)
index 0000000..a06af0c
--- /dev/null
@@ -0,0 +1,16 @@
+// true
+
+// Copyright 2010 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 ddd
+
+func Sum(args ...int) int {
+       s := 0
+       for _, v := range args {
+               s += v
+       }
+       return s
+}
+
diff --git a/test/ddd3.go b/test/ddd3.go
new file mode 100644 (file)
index 0000000..f5f9952
--- /dev/null
@@ -0,0 +1,24 @@
+// $G $D/ddd2.go && $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 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
+
+import "./ddd2"
+
+func main() {
+       if x := ddd.Sum(1, 2, 3); x != 6 {
+               panicln("ddd.Sum 6", x)
+       }
+       if x := ddd.Sum(); x != 0 {
+               panicln("ddd.Sum 0", x)
+       }
+       if x := ddd.Sum(10); x != 10 {
+               panicln("ddd.Sum 10", x)
+       }
+       if x := ddd.Sum(1, 8); x != 9 {
+               panicln("ddd.Sum 9", x)
+       }
+}