1
0
mirror of https://github.com/golang/go synced 2024-11-25 04:57:56 -07:00

gc: add ... T, rework plain ...

No longer a distinct type; now a property of func types.

R=ken2
CC=golang-dev
https://golang.org/cl/197042
This commit is contained in:
Russ Cox 2010-02-01 00:25:59 -08:00
parent 65e671b903
commit 68796b0270
21 changed files with 361 additions and 110 deletions

View File

@ -178,7 +178,6 @@ isfat(Type *t)
case TARRAY: case TARRAY:
case TSTRING: case TSTRING:
case TINTER: // maybe remove later case TINTER: // maybe remove later
case TDDD: // maybe remove later
return 1; return 1;
} }
return 0; return 0;

View File

@ -174,7 +174,6 @@ isfat(Type *t)
case TARRAY: case TARRAY:
case TSTRING: case TSTRING:
case TINTER: // maybe remove later case TINTER: // maybe remove later
case TDDD: // maybe remove later
return 1; return 1;
} }
return 0; return 0;

View File

@ -176,7 +176,6 @@ isfat(Type *t)
case TARRAY: case TARRAY:
case TSTRING: case TSTRING:
case TINTER: // maybe remove later case TINTER: // maybe remove later
case TDDD: // maybe remove later
return 1; return 1;
} }
return 0; return 0;

View File

@ -176,9 +176,6 @@ dowidth(Type *t)
w = 8; w = 8;
checkwidth(t->type); checkwidth(t->type);
break; break;
case TDDD:
w = 2*widthptr;
break;
case TINTER: // implemented as 2 pointers case TINTER: // implemented as 2 pointers
w = 2*widthptr; w = 2*widthptr;
offmod(t); offmod(t);

View File

@ -877,6 +877,7 @@ stotype(NodeList *l, int et, Type **t)
f->type = n->type; f->type = n->type;
f->note = note; f->note = note;
f->width = BADWIDTH; f->width = BADWIDTH;
f->isddd = n->isddd;
if(n->left != N && n->left->op == ONAME) { if(n->left != N && n->left->op == ONAME) {
f->nname = n->left; f->nname = n->left;
@ -1022,11 +1023,23 @@ checkarglist(NodeList *all, int input)
if(n != N) if(n != N)
n = newname(n->sym); n = newname(n->sym);
n = nod(ODCLFIELD, n, t); 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) if(!input)
yyerror("cannot use ... in output argument list"); yyerror("cannot use ... in output argument list");
else if(l->next != nil) else if(l->next != nil)
yyerror("can only use ... as final argument in list"); 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; l->n = n;
} }

View File

@ -147,6 +147,7 @@ struct Type
uchar local; // created in this file uchar local; // created in this file
uchar deferwidth; uchar deferwidth;
uchar broke; uchar broke;
uchar isddd; // TFIELD is ... argument
Node* nod; // canonical OTYPE node Node* nod; // canonical OTYPE node
int lineno; int lineno;
@ -205,6 +206,7 @@ struct Node
uchar dodata; // compile literal assignment as data statement uchar dodata; // compile literal assignment as data statement
uchar used; uchar used;
uchar oldref; uchar oldref;
uchar isddd;
// most nodes // most nodes
Node* left; Node* left;
@ -402,6 +404,9 @@ enum
OTFUNC, OTFUNC,
OTARRAY, OTARRAY,
// misc
ODDD,
// for back ends // for back ends
OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG, OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
@ -425,21 +430,20 @@ enum
TPTR32, TPTR64, // 16 TPTR32, TPTR64, // 16
TDDD, // 18 TFUNC, // 18
TFUNC,
TARRAY, TARRAY,
T_old_DARRAY, T_old_DARRAY,
TSTRUCT, // 22 TSTRUCT, // 21
TCHAN, TCHAN,
TMAP, TMAP,
TINTER, // 25 TINTER, // 24
TFORW, TFORW,
TFIELD, TFIELD,
TANY, TANY,
TSTRING, TSTRING,
// pseudo-types for literals // pseudo-types for literals
TIDEAL, // 30 TIDEAL, // 29
TNIL, TNIL,
TBLANK, TBLANK,
@ -844,7 +848,6 @@ int isfixedarray(Type*);
int isslice(Type*); int isslice(Type*);
int isinter(Type*); int isinter(Type*);
int isnilinter(Type*); int isnilinter(Type*);
int isddd(Type*);
int isideal(Type*); int isideal(Type*);
int isblank(Node*); int isblank(Node*);
Type* maptype(Type*, Type*); Type* maptype(Type*, Type*);

View File

@ -76,7 +76,7 @@
%type <sym> hidden_importsym hidden_pkg_importsym %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> hidden_funres
%type <list> ohidden_funres %type <list> ohidden_funres
@ -896,10 +896,10 @@ convtype:
// array literal // array literal
$$ = nod(OTARRAY, $2, $4); $$ = nod(OTARRAY, $2, $4);
} }
| '[' dotdotdot ']' ntype | '[' LDDD ']' ntype
{ {
// array literal of nelem // array literal of nelem
$$ = nod(OTARRAY, $2, $4); $$ = nod(OTARRAY, nod(ODDD, N, N), $4);
} }
| LMAP '[' ntype ']' ntype | LMAP '[' ntype ']' ntype
{ {
@ -920,7 +920,11 @@ convtype:
dotdotdot: dotdotdot:
LDDD LDDD
{ {
$$ = typenod(typ(TDDD)); $$ = nod(ODDD, N, N);
}
| LDDD ntype
{
$$ = nod(ODDD, $2, N);
} }
ntype: ntype:
@ -979,10 +983,10 @@ othertype:
{ {
$$ = nod(OTARRAY, $2, $4); $$ = nod(OTARRAY, $2, $4);
} }
| '[' dotdotdot ']' ntype | '[' LDDD ']' ntype
{ {
// array literal of nelem // array literal of nelem
$$ = nod(OTARRAY, $2, $4); $$ = nod(OTARRAY, nod(ODDD, N, N), $4);
} }
| LCHAN non_recvchantype | LCHAN non_recvchantype
{ {
@ -1651,10 +1655,6 @@ hidden_type_misc:
$$->type = $3; $$->type = $3;
$$->chan = Csend; $$->chan = Csend;
} }
| LDDD
{
$$ = typ(TDDD);
}
hidden_type_recv_chan: hidden_type_recv_chan:
LCOMM LCHAN hidden_type LCOMM LCHAN hidden_type
@ -1670,14 +1670,35 @@ hidden_type_func:
$$ = functype(nil, $3, $5); $$ = functype(nil, $3, $5);
} }
hidden_dcl: hidden_opt_sym:
sym hidden_type sym
{ {
$$ = nod(ODCLFIELD, newname($1), typenod($2)); $$ = newname($1);
} }
| '?' hidden_type | '?'
{ {
$$ = nod(ODCLFIELD, N, typenod($2)); $$ = N;
}
hidden_dcl:
hidden_opt_sym hidden_type
{
$$ = nod(ODCLFIELD, $1, typenod($2));
}
| hidden_opt_sym LDDD
{
$$ = nod(ODCLFIELD, $1, typenod(typ(TINTER)));
$$->isddd = 1;
}
| hidden_opt_sym LDDD hidden_type
{
Type *t;
t = typ(TARRAY);
t->bound = -1;
t->type = $3;
$$ = nod(ODCLFIELD, $1, typenod(t));
$$->isddd = 1;
} }
hidden_structdcl: hidden_structdcl:

View File

@ -243,7 +243,19 @@ exprfmt(Fmt *f, Node *n, int prec)
break; break;
case OCOMPLIT: 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; break;
case ODOT: case ODOT:
@ -338,9 +350,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case OMAKEMAP: case OMAKEMAP:
fmtprint(f, "make(%#T)", n->type); fmtprint(f, "make(%#T)", n->type);
break; break;
case OMAPLIT:
fmtprint(f, "map literal");
} }
if(prec > nprec) if(prec > nprec)

View File

@ -391,7 +391,6 @@ enum {
KindFloat64, KindFloat64,
KindArray, KindArray,
KindChan, KindChan,
KindDotDotDot,
KindFunc, KindFunc,
KindInterface, KindInterface,
KindMap, KindMap,
@ -423,7 +422,6 @@ kinds[] =
[TFLOAT64] = KindFloat64, [TFLOAT64] = KindFloat64,
[TBOOL] = KindBool, [TBOOL] = KindBool,
[TSTRING] = KindString, [TSTRING] = KindString,
[TDDD] = KindDotDotDot,
[TPTR32] = KindPtr, [TPTR32] = KindPtr,
[TPTR64] = KindPtr, [TPTR64] = KindPtr,
[TSTRUCT] = KindStruct, [TSTRUCT] = KindStruct,
@ -453,7 +451,6 @@ structnames[] =
[TFLOAT64] = "*runtime.Float64Type", [TFLOAT64] = "*runtime.Float64Type",
[TBOOL] = "*runtime.BoolType", [TBOOL] = "*runtime.BoolType",
[TSTRING] = "*runtime.StringType", [TSTRING] = "*runtime.StringType",
[TDDD] = "*runtime.DotDotDotType",
[TPTR32] = "*runtime.PtrType", [TPTR32] = "*runtime.PtrType",
[TPTR64] = "*runtime.PtrType", [TPTR64] = "*runtime.PtrType",
@ -518,7 +515,6 @@ haspointers(Type *t)
return 1; return 1;
return 0; return 0;
case TSTRING: case TSTRING:
case TDDD:
case TPTR32: case TPTR32:
case TPTR64: case TPTR64:
case TINTER: case TINTER:
@ -637,7 +633,7 @@ typename(Type *t)
static Sym* static Sym*
dtypesym(Type *t) dtypesym(Type *t)
{ {
int ot, n; int ot, n, isddd;
Sym *s, *s1, *s2; Sym *s, *s1, *s2;
Sig *a, *m; Sig *a, *m;
Type *t1; Type *t1;
@ -709,14 +705,19 @@ ok:
case TFUNC: case TFUNC:
for(t1=getthisx(t)->type; t1; t1=t1->down) for(t1=getthisx(t)->type; t1; t1=t1->down)
dtypesym(t1->type); 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); dtypesym(t1->type);
}
for(t1=getoutargx(t)->type; t1; t1=t1->down) for(t1=getoutargx(t)->type; t1; t1=t1->down)
dtypesym(t1->type); dtypesym(t1->type);
ot = dcommontype(s, ot, t); ot = dcommontype(s, ot, t);
ot = duint8(s, ot, isddd);
// two slice headers: in and out. // two slice headers: in and out.
ot = rnd(ot, widthptr);
ot = dsymptr(s, ot, s, ot+2*(widthptr+2*4)); ot = dsymptr(s, ot, s, ot+2*(widthptr+2*4));
n = t->thistuple + t->intuple; n = t->thistuple + t->intuple;
ot = duint32(s, ot, n); ot = duint32(s, ot, n);
@ -855,7 +856,6 @@ dumptypestructs(void)
for(i=1; i<=TBOOL; i++) for(i=1; i<=TBOOL; i++)
dtypesym(ptrto(types[i])); dtypesym(ptrto(types[i]));
dtypesym(ptrto(types[TSTRING])); dtypesym(ptrto(types[TSTRING]));
dtypesym(typ(TDDD));
dtypesym(ptrto(pkglookup("Pointer", unsafepkg)->def->type)); dtypesym(ptrto(pkglookup("Pointer", unsafepkg)->def->type));
// add paths for runtime and main, which 6l imports implicitly. // add paths for runtime and main, which 6l imports implicitly.

View File

@ -941,7 +941,6 @@ etnames[] =
[TBOOL] = "BOOL", [TBOOL] = "BOOL",
[TPTR32] = "PTR32", [TPTR32] = "PTR32",
[TPTR64] = "PTR64", [TPTR64] = "PTR64",
[TDDD] = "DDD",
[TFUNC] = "FUNC", [TFUNC] = "FUNC",
[TARRAY] = "ARRAY", [TARRAY] = "ARRAY",
[TSTRUCT] = "STRUCT", [TSTRUCT] = "STRUCT",
@ -1088,7 +1087,6 @@ basicnames[] =
[TFLOAT64] = "float64", [TFLOAT64] = "float64",
[TBOOL] = "bool", [TBOOL] = "bool",
[TANY] = "any", [TANY] = "any",
[TDDD] = "...",
[TSTRING] = "string", [TSTRING] = "string",
[TNIL] = "nil", [TNIL] = "nil",
[TIDEAL] = "ideal", [TIDEAL] = "ideal",
@ -1166,9 +1164,16 @@ Tpretty(Fmt *fp, Type *t)
fmtprint(fp, "func"); fmtprint(fp, "func");
fmtprint(fp, "("); fmtprint(fp, "(");
for(t1=getinargx(t)->type; t1; t1=t1->down) { for(t1=getinargx(t)->type; t1; t1=t1->down) {
if(noargnames && t1->etype == TFIELD) if(noargnames && t1->etype == TFIELD) {
fmtprint(fp, "%T", t1->type); if(t1->isddd) {
// TODO(rsc): Delete with DDD cleanup.
if(t1->type->etype == TINTER)
fmtprint(fp, "...");
else else
fmtprint(fp, "... %T", t1->type->type);
} else
fmtprint(fp, "%T", t1->type);
} else
fmtprint(fp, "%T", t1); fmtprint(fp, "%T", t1);
if(t1->down) if(t1->down)
fmtprint(fp, ", "); fmtprint(fp, ", ");
@ -1246,9 +1251,16 @@ Tpretty(Fmt *fp, Type *t)
if(t->sym == S || t->embedded) { if(t->sym == S || t->embedded) {
if(exporting) if(exporting)
fmtprint(fp, "? "); fmtprint(fp, "? ");
fmtprint(fp, "%T", t->type);
} else } 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) if(t->note)
fmtprint(fp, " \"%Z\"", t->note); fmtprint(fp, " \"%Z\"", t->note);
return 0; return 0;
@ -1608,13 +1620,7 @@ isselect(Node *n)
int int
isinter(Type *t) isinter(Type *t)
{ {
if(t != T) { return t != T && t->etype == TINTER;
if(t->etype == TINTER)
return 1;
if(t->etype == TDDD)
return 1;
}
return 0;
} }
int int
@ -1627,14 +1633,6 @@ isnilinter(Type *t)
return 1; return 1;
} }
int
isddd(Type *t)
{
if(t != T && t->etype == TDDD)
return 1;
return 0;
}
int int
isideal(Type *t) isideal(Type *t)
{ {
@ -1756,7 +1754,7 @@ eqtype1(Type *t1, Type *t2, int d, int names)
while(ta != tb) { while(ta != tb) {
if(ta == T || tb == T) if(ta == T || tb == T)
return 0; return 0;
if(ta->etype != TFIELD || tb->etype != TFIELD) if(ta->etype != TFIELD || tb->etype != TFIELD || ta->isddd != tb->isddd)
return 0; return 0;
if(!eqtype1(ta->type, tb->type, d+1, names)) if(!eqtype1(ta->type, tb->type, d+1, names))
return 0; return 0;
@ -2193,19 +2191,24 @@ out:
void void
badtype(int o, Type *tl, Type *tr) badtype(int o, Type *tl, Type *tr)
{ {
yyerror("illegal types for operand: %O", o); Fmt fmt;
char *s;
fmtstrinit(&fmt);
if(tl != T) if(tl != T)
print(" %T\n", tl); fmtprint(&fmt, "\n %T", tl);
if(tr != T) if(tr != T)
print(" %T\n", tr); fmtprint(&fmt, "\n %T", tr);
// common mistake: *struct and *interface. // common mistake: *struct and *interface.
if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) { if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER) 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) 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);
} }
/* /*

View File

@ -140,6 +140,9 @@ reswitch:
n = n->right; n = n->right;
goto redo; goto redo;
case ODDD:
break;
/* /*
* types (OIND is with exprs) * types (OIND is with exprs)
*/ */
@ -157,6 +160,7 @@ reswitch:
if(l == nil) { if(l == nil) {
t->bound = -1; t->bound = -1;
} else { } else {
if(l->op != ODDD)
typecheck(&l, Erv | Etype); typecheck(&l, Erv | Etype);
switch(l->op) { switch(l->op) {
default: default:
@ -173,13 +177,7 @@ reswitch:
} }
break; break;
case OTYPE: case ODDD:
if(l->type == T)
goto error;
if(l->type->etype != TDDD) {
yyerror("invalid array bound %T", l->type);
goto error;
}
t->bound = -100; t->bound = -100;
break; break;
} }
@ -1496,12 +1494,18 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
tn = n->type->type; tn = n->type->type;
for(tl=tstruct->type; tl; tl=tl->down) { for(tl=tstruct->type; tl; tl=tl->down) {
int xx, yy; 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) { if(tn == T) {
yyerror("not enough arguments to %#O", op); yyerror("not enough arguments to %#O", op);
goto out; goto out;
} }
if(isddd(tl->type))
goto out;
if(checkconv(tn->type, tl->type, 0, &xx, &yy, desc) < 0) 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); yyerror("cannot use type %T as type %T in %s", tn->type, tl->type, desc);
tn = tn->down; tn = tn->down;
@ -1513,10 +1517,17 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
for(tl=tstruct->type; tl; tl=tl->down) { for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type; t = tl->type;
if(isddd(t)) { if(tl->isddd) {
if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t))
goto out;
for(; nl; nl=nl->next) { for(; nl; nl=nl->next) {
int xx, yy;
setlineno(nl->n); 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; goto out;
} }

View File

@ -1368,6 +1368,31 @@ mkdotargs(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
return nn; 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 * helpers for shape errors
*/ */
@ -1466,7 +1491,7 @@ ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init)
} }
loop: loop:
if(l != T && isddd(l->type)) { if(l != T && l->isddd) {
// the ddd parameter must be last // the ddd parameter must be last
ll = structnext(&savel); ll = structnext(&savel);
if(ll != T) if(ll != T)
@ -1476,7 +1501,7 @@ loop:
// only if we are assigning a single ddd // only if we are assigning a single ddd
// argument to a ddd parameter then it is // argument to a ddd parameter then it is
// passed thru unencapsulated // 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 = nod(OAS, nodarg(l, fp), r);
a = convas(a, init); a = convas(a, init);
nn = list(nn, a); nn = list(nn, a);
@ -1486,7 +1511,11 @@ loop:
// normal case -- make a structure of all // normal case -- make a structure of all
// remaining arguments and pass a pointer to // remaining arguments and pass a pointer to
// it to the ddd parameter (empty interface) // it to the ddd parameter (empty interface)
// TODO(rsc): delete in DDD cleanup.
if(l->type->etype == TINTER)
nn = mkdotargs(lr, nn, l, fp, init); nn = mkdotargs(lr, nn, l, fp, init);
else
nn = mkdotargslice(lr, nn, l, fp, init);
goto ret; goto ret;
} }

View File

@ -415,8 +415,6 @@ func typename(typ reflect.Type) string {
return "array" return "array"
case *reflect.ChanType: case *reflect.ChanType:
return "chan" return "chan"
case *reflect.DotDotDotType:
return "ellipsis"
case *reflect.FuncType: case *reflect.FuncType:
return "func" return "func"
case *reflect.InterfaceType: case *reflect.InterfaceType:

View File

@ -75,13 +75,10 @@ func TypeFromNative(t reflect.Type) Type {
case *reflect.FuncType: case *reflect.FuncType:
nin := t.NumIn() nin := t.NumIn()
// Variadic functions have DotDotDotType at the end // Variadic functions have DotDotDotType at the end
varidic := false variadic := t.DotDotDot()
if nin > 0 { if variadic {
if _, ok := t.In(nin - 1).(*reflect.DotDotDotType); ok {
varidic = true
nin-- nin--
} }
}
in := make([]Type, nin) in := make([]Type, nin)
for i := range in { for i := range in {
in[i] = TypeFromNative(t.In(i)) in[i] = TypeFromNative(t.In(i))
@ -90,7 +87,7 @@ func TypeFromNative(t reflect.Type) Type {
for i := range out { for i := range out {
out[i] = TypeFromNative(t.Out(i)) out[i] = TypeFromNative(t.Out(i))
} }
et = NewFuncType(in, varidic, out) et = NewFuncType(in, variadic, out)
case *reflect.InterfaceType: case *reflect.InterfaceType:
log.Crashf("%T not implemented", t) log.Crashf("%T not implemented", t)
case *reflect.MapType: case *reflect.MapType:

View File

@ -139,12 +139,6 @@ type UintptrType struct {
commonType 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. // UnsafePointerType represents an unsafe.Pointer type.
type UnsafePointerType struct { type UnsafePointerType struct {
commonType commonType
@ -176,6 +170,7 @@ type ChanType struct {
// FuncType represents a function type. // FuncType represents a function type.
type FuncType struct { type FuncType struct {
commonType commonType
dotdotdot bool
in []*runtime.Type in []*runtime.Type
out []*runtime.Type out []*runtime.Type
} }
@ -377,6 +372,19 @@ func (t *FuncType) In(i int) Type {
return toType(*t.in[i]) 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. // NumIn returns the number of input parameters.
func (t *FuncType) NumIn() int { return len(t.in) } func (t *FuncType) NumIn() int { return len(t.in) }
@ -571,8 +579,6 @@ func toType(i interface{}) Type {
return nil return nil
case *runtime.BoolType: case *runtime.BoolType:
return (*BoolType)(unsafe.Pointer(v)) return (*BoolType)(unsafe.Pointer(v))
case *runtime.DotDotDotType:
return (*DotDotDotType)(unsafe.Pointer(v))
case *runtime.FloatType: case *runtime.FloatType:
return (*FloatType)(unsafe.Pointer(v)) return (*FloatType)(unsafe.Pointer(v))
case *runtime.Float32Type: case *runtime.Float32Type:

View File

@ -55,7 +55,6 @@ const (
kindFloat64 kindFloat64
kindArray kindArray
kindChan kindChan
kindDotDotDot
kindFunc kindFunc
kindInterface kindInterface
kindMap kindMap
@ -136,10 +135,6 @@ type StringType commonType
// UintptrType represents a uintptr type. // UintptrType represents a uintptr type.
type UintptrType commonType 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. // UnsafePointerType represents an unsafe.Pointer type.
type UnsafePointerType commonType type UnsafePointerType commonType
@ -175,6 +170,7 @@ type ChanType struct {
// FuncType represents a function type. // FuncType represents a function type.
type FuncType struct { type FuncType struct {
commonType commonType
dotdotdot bool // last input parameter is ...
in []*Type // input parameter types in []*Type // input parameter types
out []*Type // output parameter types out []*Type // output parameter types
} }

View File

@ -45,7 +45,6 @@ enum {
KindFloat64, KindFloat64,
KindArray, KindArray,
KindChan, KindChan,
KindDotDotDot,
KindFunc, KindFunc,
KindInterface, KindInterface,
KindMap, KindMap,
@ -116,4 +115,3 @@ struct SliceType
Type; Type;
Type *elem; Type *elem;
}; };

105
test/ddd.go Normal file
View File

@ -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)
}
}

28
test/ddd1.go Normal file
View File

@ -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{}}
)

16
test/ddd2.go Normal file
View File

@ -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
}

24
test/ddd3.go Normal file
View File

@ -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)
}
}