Commit 2119294a authored by Ken Thompson's avatar Ken Thompson

methods on any type

-- but only *struct tested

R=r
OCL=15326
CL=15326
parent b9cee1b6
...@@ -306,15 +306,15 @@ loop: ...@@ -306,15 +306,15 @@ loop:
switch(t->etype) { switch(t->etype) {
default: default:
fatal("signame: unknown type %T", t); e = "sigs";
break;
case TPTR32: case TPTR32:
case TPTR64: case TPTR64:
t = t->type; t = t->type;
goto loop; goto loop;
case TSTRUCT: case TSTRUCT:
e = "sigs";
break;
case TINTER: case TINTER:
e = "sigi"; e = "sigi";
break; break;
......
...@@ -566,7 +566,12 @@ dumpsignatures(void) ...@@ -566,7 +566,12 @@ dumpsignatures(void)
a = nil; a = nil;
o = 0; o = 0;
for(f=t->type; f!=T; f=f->down) {
f = t->type;
if(et != TINTER)
f = t->method;
for(; f!=T; f=f->down) {
if(f->type->etype != TFUNC) if(f->type->etype != TFUNC)
continue; continue;
...@@ -589,8 +594,11 @@ dumpsignatures(void) ...@@ -589,8 +594,11 @@ dumpsignatures(void)
a->name = sp+1; a->name = sp+1;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0); a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
a->sym = f->sym;
a->offset = o; a->offset = o;
snprint(namebuf, sizeof(namebuf), "%s_%s",
at.sym->name+5, f->sym->name);
a->sym = lookup(namebuf);
o++; o++;
} }
......
...@@ -219,6 +219,10 @@ methodname(Node *n, Type *t) ...@@ -219,6 +219,10 @@ methodname(Node *n, Type *t)
{ {
Sym *s; Sym *s;
if(t == T)
goto bad;
// method receiver must be typename or *typename
s = S; s = S;
if(t->sym != S) if(t->sym != S)
s = t->sym; s = t->sym;
...@@ -226,12 +230,9 @@ methodname(Node *n, Type *t) ...@@ -226,12 +230,9 @@ methodname(Node *n, Type *t)
t = t->type; t = t->type;
if(t->sym != S) if(t->sym != S)
s = t->sym; s = t->sym;
// if(t->etype != TSTRUCT)
// goto bad;
if(s == S) if(s == S)
goto bad; goto bad;
snprint(namebuf, sizeof(namebuf), "%s_%s", s->name, n->sym->name); snprint(namebuf, sizeof(namebuf), "%s_%s", s->name, n->sym->name);
return newname(lookup(namebuf)); return newname(lookup(namebuf));
...@@ -242,71 +243,85 @@ bad: ...@@ -242,71 +243,85 @@ bad:
/* /*
* add a method, declared as a function, * add a method, declared as a function,
* into the structure * n is fieldname, pa is base type, t is function type
*/ */
void void
addmethod(Node *n, Type *pa, Type *t) addmethod(Node *n, Type *t, int local)
{ {
Type *f, *d, *p; Type *f, *d, *pa;
Sym *s; Sym *st, *sf;
int ptr;
// get field sym
if(n == N)
goto bad;
if(n->op != ONAME) if(n->op != ONAME)
goto bad; goto bad;
s = n->sym; sf = n->sym;
if(s == S) if(sf == S)
goto bad; goto bad;
// get parent type sym
pa = *getthis(t); // ptr to this structure
if(pa == T) if(pa == T)
goto bad; goto bad;
if(!isptr[pa->etype]) pa = pa->type; // ptr to this field
goto bad; if(pa == T)
p = pa->type;
if(p == T)
goto bad;
if(p->etype != TSTRUCT)
goto bad; goto bad;
if(p->sym == S) pa = pa->type; // ptr to this type
if(pa == T)
goto bad; goto bad;
if(p->type == T) { // optionally rip off ptr to type
n = nod(ODCLFIELD, newname(s), N); ptr = 0;
n->type = t; if(isptr[pa->etype]) {
if(pa->sym == S || pa->sym->name[0] == '_') {
ptr = 1;
pa = pa->type;
if(pa == T)
goto bad;
}
}
if(pa->etype == TINTER)
yyerror("no methods on interfaces");
stotype(n, &p->type); // and finally the receiver sym
st = pa->sym;
if(st == S)
goto bad;
if(local && !st->local) {
yyerror("method receiver type must be locally defined: %S", st);
return; return;
} }
n = nod(ODCLFIELD, newname(sf), N);
n->type = t;
if(pa->method == T)
pa->methptr = ptr;
if(pa->methptr != ptr)
yyerror("combination of direct and ptr receivers of: %S", st);
d = T; // last found d = T; // last found
for(f=p->type; f!=T; f=f->down) { for(f=pa->method; f!=T; f=f->down) {
if(f->etype != TFIELD) if(f->etype != TFIELD)
fatal("addmethod: not TFIELD: %N", f); fatal("addmethod: not TFIELD: %N", f);
if(strcmp(s->name, f->sym->name) != 0) { if(strcmp(sf->name, f->sym->name) != 0) {
d = f; d = f;
continue; continue;
} }
// if a field matches a non-this function
// then delete it and let it be redeclared
if(methcmp(t, f->type)) {
if(d == T) {
p->type = f->down;
continue;
}
d->down = f->down;
continue;
}
if(!eqtype(t, f->type, 0)) if(!eqtype(t, f->type, 0))
yyerror("field redeclared as method: %S", s); yyerror("method redeclared: %S of type %S", sf, st);
return;
} }
n = nod(ODCLFIELD, newname(s), N);
n->type = t;
if(d == T) if(d == T)
stotype(n, &p->type); stotype(n, &pa->method);
else else
stotype(n, &d->down); stotype(n, &d->down);
if(dflag())
print("method %S of type %s%S\n", sf, (ptr? "*":""), st);
return; return;
bad: bad:
...@@ -393,11 +408,6 @@ funchdr(Node *n) ...@@ -393,11 +408,6 @@ funchdr(Node *n)
markdcl(); markdcl();
funcargs(n->type); funcargs(n->type);
if(n->type->thistuple > 0) {
Type *t;
t = *getthis(n->type);
addmethod(n->nname, t->type->type, n->type);
}
} }
void void
......
...@@ -233,6 +233,13 @@ dumpexporttype(Sym *s) ...@@ -233,6 +233,13 @@ dumpexporttype(Sym *s)
Bprint(bout, "%lS %d %lS\n", s, t->chan, t->type->sym); Bprint(bout, "%lS %d %lS\n", s, t->chan, t->type->sym);
break; break;
} }
for(f=t->method; f!=T; f=f->down) {
if(f->etype != TFIELD)
fatal("dumpexporttype: method not field: %lT", f);
reexport(f->type);
Bprint(bout, "\tfunc %S %lS\n", f->sym, f->type->sym);
}
} }
void void
...@@ -548,7 +555,6 @@ doimport3(Node *ss, Node *n) ...@@ -548,7 +555,6 @@ doimport3(Node *ss, Node *n)
t->thistuple = importcount(t->type); t->thistuple = importcount(t->type);
t->outtuple = importcount(t->type->down); t->outtuple = importcount(t->type->down);
t->intuple = importcount(t->type->down->down); t->intuple = importcount(t->type->down->down);
dowidth(t); dowidth(t);
importfuncnam(t); importfuncnam(t);
...@@ -648,3 +654,16 @@ doimport8(Node *ss, Val *v, Node *st) ...@@ -648,3 +654,16 @@ doimport8(Node *ss, Val *v, Node *st)
importaddtyp(ss, t); importaddtyp(ss, t);
} }
/*
* LFUNC importsym sym
* method type
*/
void
doimport9(Sym *sf, Node *ss)
{
Sym *sfun;
sfun = getimportsym(ss);
addmethod(newname(sf), sfun->otype, 0);
}
...@@ -115,6 +115,7 @@ struct Type ...@@ -115,6 +115,7 @@ struct Type
uchar chan; uchar chan;
uchar recur; // to detect loops uchar recur; // to detect loops
uchar trecur; // to detect loops uchar trecur; // to detect loops
uchar methptr; // all methods are pointers to this type
// TFUNCT // TFUNCT
uchar thistuple; uchar thistuple;
...@@ -122,9 +123,14 @@ struct Type ...@@ -122,9 +123,14 @@ struct Type
uchar intuple; uchar intuple;
uchar outnamed; uchar outnamed;
Type* method;
Sym* sym; Sym* sym;
int32 vargen; // unique name for OTYPE/ONAME int32 vargen; // unique name for OTYPE/ONAME
Node* nname;
vlong argwid;
// most nodes // most nodes
Type* type; Type* type;
vlong width; // offset in TFIELD, width in all others vlong width; // offset in TFIELD, width in all others
...@@ -135,10 +141,6 @@ struct Type ...@@ -135,10 +141,6 @@ struct Type
// TPTR // TPTR
Type* nforw; Type* nforw;
// TFUNCT
Node* nname;
vlong argwid;
// TARRAY // TARRAY
int32 bound; // negative is dynamic array int32 bound; // negative is dynamic array
}; };
...@@ -609,6 +611,7 @@ void dodcltype(Type*, Type*); ...@@ -609,6 +611,7 @@ void dodcltype(Type*, Type*);
void dodclconst(Node*, Node*); void dodclconst(Node*, Node*);
void defaultlit(Node*); void defaultlit(Node*);
int listcount(Node*); int listcount(Node*);
void addmethod(Node*, Type*, int);
Node* methodname(Node*, Type*); Node* methodname(Node*, Type*);
Type* functype(Node*, Node*, Node*); Type* functype(Node*, Node*, Node*);
char* thistypenam(Node*); char* thistypenam(Node*);
...@@ -658,6 +661,7 @@ void doimport5(Node*, Val*); ...@@ -658,6 +661,7 @@ void doimport5(Node*, Val*);
void doimport6(Node*, Node*); void doimport6(Node*, Node*);
void doimport7(Node*, Node*); void doimport7(Node*, Node*);
void doimport8(Node*, Val*, Node*); void doimport8(Node*, Val*, Node*);
void doimport9(Sym*, Node*);
/* /*
* walk.c * walk.c
...@@ -671,7 +675,7 @@ Type* walkswitch(Node*, Type*(*)(Node*, Type*)); ...@@ -671,7 +675,7 @@ Type* walkswitch(Node*, Type*(*)(Node*, Type*));
int casebody(Node*); int casebody(Node*);
void walkselect(Node*); void walkselect(Node*);
int whatis(Node*); int whatis(Node*);
void walkdot(Node*, int); void walkdot(Node*);
Node* ascompatee(int, Node**, Node**); Node* ascompatee(int, Node**, Node**);
Node* ascompatet(int, Node**, Type**, int); Node* ascompatet(int, Node**, Type**, int);
Node* ascompatte(int, Type**, Node**, int); Node* ascompatte(int, Type**, Node**, int);
......
...@@ -1057,12 +1057,12 @@ fndcl: ...@@ -1057,12 +1057,12 @@ fndcl:
| '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres | '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres
{ {
b0stack = dclstack; // mark base for fn literals b0stack = dclstack; // mark base for fn literals
if($2 == N || $2->op == OLIST)
yyerror("syntax error in method receiver");
$$ = nod(ODCLFUNC, N, N); $$ = nod(ODCLFUNC, N, N);
$$->nname = methodname($4, $2->type); $$->nname = methodname($4, $2->type);
$$->type = functype($2, $6, $8); $$->type = functype($2, $6, $8);
funchdr($$); funchdr($$);
addmethod($4, $$->type, 1);
} }
fntype: fntype:
...@@ -1573,6 +1573,11 @@ hidden_import: ...@@ -1573,6 +1573,11 @@ hidden_import:
// type interface // type interface
doimport8($2, &$3, $4); doimport8($2, &$3, $4);
} }
| LFUNC sym1 hidden_importsym
{
// method
doimport9($2, $3);
}
isym: isym:
sym1 '.' sym2 sym1 '.' sym2
......
...@@ -17,10 +17,6 @@ int ...@@ -17,10 +17,6 @@ int
walkret(Node *n) walkret(Node *n)
{ {
// until gri gets rid
// of the bugs on this
return 0;
loop: loop:
if(n != N) if(n != N)
switch(n->op) { switch(n->op) {
...@@ -866,7 +862,7 @@ loop: ...@@ -866,7 +862,7 @@ loop:
case ODOTINTER: case ODOTINTER:
if(top == Etop) if(top == Etop)
goto nottop; goto nottop;
walkdot(n, top); walkdot(n);
goto ret; goto ret;
case OADDR: case OADDR:
...@@ -1323,17 +1319,15 @@ walkselect(Node *sel) ...@@ -1323,17 +1319,15 @@ walkselect(Node *sel)
* normal binary operations. * normal binary operations.
*/ */
Type* Type*
lookdot(Node *n, Type *t, int d) lookdot(Node *n, Type *f)
{ {
Type *f, *r, *c; Type *r, *c;
Sym *s; Sym *s;
r = T; r = T;
s = n->sym; s = n->sym;
if(d > 0)
goto deep;
for(f=t->type; f!=T; f=f->down) { for(; f!=T; f=f->down) {
if(f->sym == S) if(f->sym == S)
continue; continue;
if(f->sym != s) if(f->sym != s)
...@@ -1345,38 +1339,18 @@ lookdot(Node *n, Type *t, int d) ...@@ -1345,38 +1339,18 @@ lookdot(Node *n, Type *t, int d)
r = f; r = f;
} }
return r; return r;
deep:
/* deeper look after shallow failed */
for(f=t->type; f!=T; f=f->down) {
// only look at unnamed sub-structures
// BOTCH no such thing -- all are assigned temp names
if(f->sym != S)
continue;
c = f->type;
if(c->etype != TSTRUCT)
continue;
c = lookdot(n, c, d-1);
if(c == T)
continue;
if(r != T) {
yyerror("ambiguous unnamed DOT reference %s", s->name);
break;
}
r = c;
}
return r;
} }
void void
walkdot(Node *n, int top) walkdot(Node *n)
{ {
Node *mn; Node *mn;
Type *t, *f; Type *t, *f;
int i;
if(n->left == N || n->right == N) if(n->left == N || n->right == N)
return; return;
if(n->op == ODOTINTER || n->op == ODOTMETH)
return; // already done
walktype(n->left, Erv); walktype(n->left, Erv);
if(n->right->op != ONAME) { if(n->right->op != ONAME) {
...@@ -1395,50 +1369,29 @@ walkdot(Node *n, int top) ...@@ -1395,50 +1369,29 @@ walkdot(Node *n, int top)
n->op = ODOTPTR; n->op = ODOTPTR;
} }
if(n->right->op != ONAME) // as a structure field
fatal("walkdot: not name %O", n->right->op); if(t->etype == TSTRUCT || t->etype == TINTER) {
f = lookdot(n->right, t->type);
switch(t->etype) { if(f != T) {
default: n->xoffset = f->width;
badtype(ODOT, t, T); n->right = f->nname; // substitute real name
return; n->type = f->type;
if(t->etype == TINTER)
case TSTRUCT:
case TINTER:
for(i=0; i<5; i++) {
f = lookdot(n->right, t, i);
if(f != T)
break;
}
// look up the field as TYPE_name
// for a mothod. botch this should
// be done better.
if(f == T && t->etype == TSTRUCT) {
mn = methodname(n->right, t);
for(i=0; i<5; i++) {
f = lookdot(mn, t, i);
if(f != T)
break;
}
}
if(f == T) {
yyerror("undefined DOT reference %N", n->right);
break;
}
n->xoffset = f->width;
n->right = f->nname; // substitute real name
n->type = f->type;
if(n->type->etype == TFUNC) {
n->op = ODOTMETH;
if(t->etype == TINTER) {
n->op = ODOTINTER; n->op = ODOTINTER;
} return;
} }
break;
} }
f = lookdot(n->right, t->method);
if(f == T) {
yyerror("undefined DOT reference %N", n->right);
return;
}
n->xoffset = f->width;
n->right = methodname(n->right, t);
n->type = f->type;
n->op = ODOTMETH;
} }
Node* Node*
...@@ -1841,25 +1794,21 @@ fixmap(Type *tm) ...@@ -1841,25 +1794,21 @@ fixmap(Type *tm)
Type *t; Type *t;
t = tm->type; t = tm->type;
if(t == T) { if(t == T)
fatal("fixmap: t nil"); goto bad;
return T; if(t->etype != TMAP)
} goto bad;
if(t->down == T || t->type == T)
if(t->etype != TMAP) { goto bad;
fatal("fixmap: %lT not map", tm);
return T;
}
if(t->down == T || t->type == T) {
fatal("fixmap: map key/value types are nil");
return T;
}
dowidth(t->down); dowidth(t->down);
dowidth(t->type); dowidth(t->type);
return t; return t;
bad:
yyerror("not a map: %lT", tm);
return T;
} }
Type* Type*
...@@ -1867,25 +1816,23 @@ fixchan(Type *tm) ...@@ -1867,25 +1816,23 @@ fixchan(Type *tm)
{ {
Type *t; Type *t;
if(tm == T)
goto bad;
t = tm->type; t = tm->type;
if(t == T) { if(t == T)
fatal("fixchan: t nil"); goto bad;
return T; if(t->etype != TCHAN)
} goto bad;
if(t->type == T)
if(t->etype != TCHAN) { goto bad;
fatal("fixchan: %lT not chan", tm);
return T;
}
if(t->type == T) {
fatal("fixchan: chan element type is nil");
return T;
}
dowidth(t->type); dowidth(t->type);
return t; return t;
bad:
yyerror("not a channel: %lT", tm);
return T;
} }
static int static int
...@@ -2288,24 +2235,21 @@ fixarray(Type *tm) ...@@ -2288,24 +2235,21 @@ fixarray(Type *tm)
Type *t; Type *t;
t = tm->type; t = tm->type;
if(t == T) { if(t == T)
fatal("fixarray: t nil"); goto bad;
return T; if(t->etype != TARRAY)
} goto bad;
if(t->type == T)
if(t->etype != TARRAY) { goto bad;
fatal("fixarray: %lT not array", tm);
return T;
}
if(t->type == T) {
fatal("fixarray: array element type is nil");
return T;
}
dowidth(t->type); dowidth(t->type);
return t; return t;
bad:
yyerror("not an array: %lT", tm);
return T;
} }
Node* Node*
......
...@@ -96,12 +96,13 @@ sys·printfloat(float64 v) ...@@ -96,12 +96,13 @@ sys·printfloat(float64 v)
buf[1] = buf[2]; buf[1] = buf[2];
buf[2] = '.'; buf[2] = '.';
buf[n+2] = '+'; buf[n+2] = 'e';
buf[n+3] = '+';
if(e < 0) { if(e < 0) {
e = -e; e = -e;
buf[n+2] = '-'; buf[n+3] = '-';
} }
buf[n+3] = 'e';
buf[n+4] = (e/10) + '0'; buf[n+4] = (e/10) + '0';
buf[n+5] = (e%10) + '0'; buf[n+5] = (e%10) + '0';
sys·write(1, buf, n+6); sys·write(1, buf, n+6);
......
...@@ -201,6 +201,7 @@ loop2: ...@@ -201,6 +201,7 @@ loop2:
hash[h] = m; hash[h] = m;
return nil; return nil;
} }
if(ihash != ss[ns].hash || if(ihash != ss[ns].hash ||
strcmp(sname, iname) != 0) { strcmp(sname, iname) != 0) {
ns++; ns++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment