gc: method expressions on concrete types
R=ken2
https://golang.org/cl/180092
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index e17ccfb..c9fcb12 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -1048,7 +1048,7 @@
Type *rcvr;
Type *t;
- rcvr = getthisx(f->type)->type;
+ rcvr = getthisx(f)->type;
if(rcvr->sym != S)
return 0;
t = rcvr->type;
@@ -1146,7 +1146,7 @@
return pkglookup(buf, s->package);
bad:
- yyerror("illegal <this> type: %T", t);
+ yyerror("illegal receiver type: %T", t0);
return S;
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 692dc77..01bc756 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -925,6 +925,7 @@
void addmethod(Sym*, Type*, int);
Node* methodname(Node*, Type*);
Node* methodname1(Node*, Node*);
+Type* methodfunc(Type*);
Sym* methodsym(Sym*, Type*);
Type* functype(Node*, NodeList*, NodeList*);
char* thistypenam(Node*);
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 50506b9..03d6f5f 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -88,7 +88,7 @@
* f is method type, with receiver.
* return function type, receiver as first argument.
*/
-static Type*
+Type*
methodfunc(Type *f)
{
NodeList *in, *out;
@@ -98,17 +98,17 @@
in = nil;
if(!isifacemethod(f)) {
d = nod(ODCLFIELD, N, N);
- d->type = getthisx(f->type)->type->type;
+ d->type = getthisx(f)->type->type;
in = list(in, d);
}
- for(t=getinargx(f->type)->type; t; t=t->down) {
+ for(t=getinargx(f)->type; t; t=t->down) {
d = nod(ODCLFIELD, N, N);
d->type = t->type;
in = list(in, d);
}
out = nil;
- for(t=getoutargx(f->type)->type; t; t=t->down) {
+ for(t=getoutargx(f)->type; t; t=t->down) {
d = nod(ODCLFIELD, N, N);
d->type = t->type;
out = list(out, d);
@@ -164,7 +164,7 @@
if(isptr[this->etype] && this->type == t)
continue;
if(isptr[this->etype] && !isptr[t->etype]
- && f->embedded != 2 && !isifacemethod(f))
+ && f->embedded != 2 && !isifacemethod(f->type))
continue;
b = mal(sizeof(*b));
@@ -180,7 +180,7 @@
a->perm = o++;
a->isym = methodsym(method, it);
a->tsym = methodsym(method, t);
- a->type = methodfunc(f);
+ a->type = methodfunc(f->type);
if(!(a->isym->flags & SymSiggen)) {
a->isym->flags |= SymSiggen;
@@ -192,7 +192,7 @@
// using genembedtramp if all that is necessary
// is a pointer adjustment and a JMP.
if(isptr[it->etype] && isptr[this->etype]
- && f->embedded && !isifacemethod(f))
+ && f->embedded && !isifacemethod(f->type))
genembedtramp(it, f, a->isym);
else
genwrapper(it, f, a->isym);
@@ -205,7 +205,7 @@
if(oldlist == nil)
oldlist = pc;
if(isptr[t->etype] && isptr[this->etype]
- && f->embedded && !isifacemethod(f))
+ && f->embedded && !isifacemethod(f->type))
genembedtramp(t, f, a->tsym);
else
genwrapper(t, f, a->tsym);
@@ -255,7 +255,7 @@
}
a->perm = o++;
a->offset = 0;
- a->type = methodfunc(f);
+ a->type = methodfunc(f->type);
}
return lsort(a, sigcmp);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index d79e5b8..5826cd3 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -2531,7 +2531,7 @@
Sym *s;
int c, d;
- typecheck(&n->left, Erv);
+ typecheck(&n->left, Etype|Erv);
t = n->left->type;
if(t == T)
goto ret;
@@ -2913,7 +2913,7 @@
// if pointer receiver in method,
// the method does not exist for value types.
rcvr = getthisx(tm->type)->type->type;
- if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm)) {
+ if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
if(debug['r'])
yyerror("interface pointer mismatch");
*m = im;
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index d0b8fde..08c47d0 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -54,6 +54,7 @@
NodeList *args;
int lno, ok, ntop;
Type *t;
+ Sym *sym;
// cannot type check until all the source has been parsed
if(!typecheckok)
@@ -445,7 +446,7 @@
n->op = ODOT;
// fall through
case ODOT:
- l = typecheck(&n->left, Erv);
+ l = typecheck(&n->left, Erv|Etype);
if((t = l->type) == T)
goto error;
if(n->right->op != ONAME) {
@@ -459,6 +460,7 @@
n->op = ODOTPTR;
checkwidth(t);
}
+ sym = n->right->sym;
if(!lookdot(n, t, 0)) {
if(lookdot(n, t, 1))
yyerror("%#N undefined (cannot refer to unexported field %S)", n, n->right->sym);
@@ -466,6 +468,25 @@
yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym);
goto error;
}
+ if(l->op == OTYPE) {
+ if(n->type->etype != TFUNC || n->type->thistuple != 1) {
+ yyerror("type %T has no method %s", n->left->type, sym);
+ n->type = T;
+ goto error;
+ }
+ if(t->etype == TINTER) {
+ yyerror("method expression on interface not implemented");
+ n->type = T;
+ goto error;
+ }
+ n->op = ONAME;
+ n->sym = methodsym(sym, l->type);
+ n->type = methodfunc(n->type);
+ getinargx(n->type)->type->type = l->type; // fix up receiver
+ n->class = PFUNC;
+ ok = Erv;
+ goto ret;
+ }
switch(n->op) {
case ODOTINTER:
case ODOTMETH:
@@ -1227,16 +1248,15 @@
tt = n->left->type;
dowidth(tt);
rcvr = getthisx(f2->type)->type->type;
- if(!eqtype(rcvr, tt)) {
+ if(n->left->op != OTYPE && !eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
- typecheck(&n->left, Erv);
checklvalue(n->left, "call pointer method on");
addrescapes(n->left);
n->left = nod(OADDR, n->left, N);
- typecheck(&n->left, Erv);
+ typecheck(&n->left, Etype|Erv);
} else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
n->left = nod(OIND, n->left, N);
- typecheck(&n->left, Erv);
+ typecheck(&n->left, Etype|Erv);
} else {
// method is attached to wrong type?
fatal("method mismatch: %T for %T", rcvr, tt);