Commit 0d668259 authored by Russ Cox's avatar Russ Cox

gc: method expressions on concrete types

R=ken2
https://golang.org/cl/180092
parent 1f0e6a4c
...@@ -1048,7 +1048,7 @@ isifacemethod(Type *f) ...@@ -1048,7 +1048,7 @@ isifacemethod(Type *f)
Type *rcvr; Type *rcvr;
Type *t; Type *t;
rcvr = getthisx(f->type)->type; rcvr = getthisx(f)->type;
if(rcvr->sym != S) if(rcvr->sym != S)
return 0; return 0;
t = rcvr->type; t = rcvr->type;
...@@ -1146,7 +1146,7 @@ methodsym(Sym *nsym, Type *t0) ...@@ -1146,7 +1146,7 @@ methodsym(Sym *nsym, Type *t0)
return pkglookup(buf, s->package); return pkglookup(buf, s->package);
bad: bad:
yyerror("illegal <this> type: %T", t); yyerror("illegal receiver type: %T", t0);
return S; return S;
} }
......
...@@ -925,6 +925,7 @@ int structcount(Type*); ...@@ -925,6 +925,7 @@ int structcount(Type*);
void addmethod(Sym*, Type*, int); void addmethod(Sym*, Type*, int);
Node* methodname(Node*, Type*); Node* methodname(Node*, Type*);
Node* methodname1(Node*, Node*); Node* methodname1(Node*, Node*);
Type* methodfunc(Type*);
Sym* methodsym(Sym*, Type*); Sym* methodsym(Sym*, Type*);
Type* functype(Node*, NodeList*, NodeList*); Type* functype(Node*, NodeList*, NodeList*);
char* thistypenam(Node*); char* thistypenam(Node*);
......
...@@ -88,7 +88,7 @@ lsort(Sig *l, int(*f)(Sig*, Sig*)) ...@@ -88,7 +88,7 @@ lsort(Sig *l, int(*f)(Sig*, Sig*))
* f is method type, with receiver. * f is method type, with receiver.
* return function type, receiver as first argument. * return function type, receiver as first argument.
*/ */
static Type* Type*
methodfunc(Type *f) methodfunc(Type *f)
{ {
NodeList *in, *out; NodeList *in, *out;
...@@ -98,17 +98,17 @@ methodfunc(Type *f) ...@@ -98,17 +98,17 @@ methodfunc(Type *f)
in = nil; in = nil;
if(!isifacemethod(f)) { if(!isifacemethod(f)) {
d = nod(ODCLFIELD, N, N); d = nod(ODCLFIELD, N, N);
d->type = getthisx(f->type)->type->type; d->type = getthisx(f)->type->type;
in = list(in, d); 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 = nod(ODCLFIELD, N, N);
d->type = t->type; d->type = t->type;
in = list(in, d); in = list(in, d);
} }
out = nil; 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 = nod(ODCLFIELD, N, N);
d->type = t->type; d->type = t->type;
out = list(out, d); out = list(out, d);
...@@ -164,7 +164,7 @@ methods(Type *t) ...@@ -164,7 +164,7 @@ methods(Type *t)
if(isptr[this->etype] && this->type == t) if(isptr[this->etype] && this->type == t)
continue; continue;
if(isptr[this->etype] && !isptr[t->etype] if(isptr[this->etype] && !isptr[t->etype]
&& f->embedded != 2 && !isifacemethod(f)) && f->embedded != 2 && !isifacemethod(f->type))
continue; continue;
b = mal(sizeof(*b)); b = mal(sizeof(*b));
...@@ -180,7 +180,7 @@ methods(Type *t) ...@@ -180,7 +180,7 @@ methods(Type *t)
a->perm = o++; a->perm = o++;
a->isym = methodsym(method, it); a->isym = methodsym(method, it);
a->tsym = methodsym(method, t); a->tsym = methodsym(method, t);
a->type = methodfunc(f); a->type = methodfunc(f->type);
if(!(a->isym->flags & SymSiggen)) { if(!(a->isym->flags & SymSiggen)) {
a->isym->flags |= SymSiggen; a->isym->flags |= SymSiggen;
...@@ -192,7 +192,7 @@ methods(Type *t) ...@@ -192,7 +192,7 @@ methods(Type *t)
// using genembedtramp if all that is necessary // using genembedtramp if all that is necessary
// is a pointer adjustment and a JMP. // is a pointer adjustment and a JMP.
if(isptr[it->etype] && isptr[this->etype] if(isptr[it->etype] && isptr[this->etype]
&& f->embedded && !isifacemethod(f)) && f->embedded && !isifacemethod(f->type))
genembedtramp(it, f, a->isym); genembedtramp(it, f, a->isym);
else else
genwrapper(it, f, a->isym); genwrapper(it, f, a->isym);
...@@ -205,7 +205,7 @@ methods(Type *t) ...@@ -205,7 +205,7 @@ methods(Type *t)
if(oldlist == nil) if(oldlist == nil)
oldlist = pc; oldlist = pc;
if(isptr[t->etype] && isptr[this->etype] if(isptr[t->etype] && isptr[this->etype]
&& f->embedded && !isifacemethod(f)) && f->embedded && !isifacemethod(f->type))
genembedtramp(t, f, a->tsym); genembedtramp(t, f, a->tsym);
else else
genwrapper(t, f, a->tsym); genwrapper(t, f, a->tsym);
...@@ -255,7 +255,7 @@ imethods(Type *t) ...@@ -255,7 +255,7 @@ imethods(Type *t)
} }
a->perm = o++; a->perm = o++;
a->offset = 0; a->offset = 0;
a->type = methodfunc(f); a->type = methodfunc(f->type);
} }
return lsort(a, sigcmp); return lsort(a, sigcmp);
......
...@@ -2531,7 +2531,7 @@ adddot(Node *n) ...@@ -2531,7 +2531,7 @@ adddot(Node *n)
Sym *s; Sym *s;
int c, d; int c, d;
typecheck(&n->left, Erv); typecheck(&n->left, Etype|Erv);
t = n->left->type; t = n->left->type;
if(t == T) if(t == T)
goto ret; goto ret;
...@@ -2913,7 +2913,7 @@ ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename) ...@@ -2913,7 +2913,7 @@ ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename)
// if pointer receiver in method, // if pointer receiver in method,
// the method does not exist for value types. // the method does not exist for value types.
rcvr = getthisx(tm->type)->type->type; 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']) if(debug['r'])
yyerror("interface pointer mismatch"); yyerror("interface pointer mismatch");
*m = im; *m = im;
......
...@@ -54,6 +54,7 @@ typecheck(Node **np, int top) ...@@ -54,6 +54,7 @@ typecheck(Node **np, int top)
NodeList *args; NodeList *args;
int lno, ok, ntop; int lno, ok, ntop;
Type *t; Type *t;
Sym *sym;
// cannot type check until all the source has been parsed // cannot type check until all the source has been parsed
if(!typecheckok) if(!typecheckok)
...@@ -445,7 +446,7 @@ reswitch: ...@@ -445,7 +446,7 @@ reswitch:
n->op = ODOT; n->op = ODOT;
// fall through // fall through
case ODOT: case ODOT:
l = typecheck(&n->left, Erv); l = typecheck(&n->left, Erv|Etype);
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
if(n->right->op != ONAME) { if(n->right->op != ONAME) {
...@@ -459,6 +460,7 @@ reswitch: ...@@ -459,6 +460,7 @@ reswitch:
n->op = ODOTPTR; n->op = ODOTPTR;
checkwidth(t); checkwidth(t);
} }
sym = n->right->sym;
if(!lookdot(n, t, 0)) { if(!lookdot(n, t, 0)) {
if(lookdot(n, t, 1)) if(lookdot(n, t, 1))
yyerror("%#N undefined (cannot refer to unexported field %S)", n, n->right->sym); yyerror("%#N undefined (cannot refer to unexported field %S)", n, n->right->sym);
...@@ -466,6 +468,25 @@ reswitch: ...@@ -466,6 +468,25 @@ reswitch:
yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym); yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym);
goto error; 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) { switch(n->op) {
case ODOTINTER: case ODOTINTER:
case ODOTMETH: case ODOTMETH:
...@@ -1227,16 +1248,15 @@ lookdot(Node *n, Type *t, int dostrcmp) ...@@ -1227,16 +1248,15 @@ lookdot(Node *n, Type *t, int dostrcmp)
tt = n->left->type; tt = n->left->type;
dowidth(tt); dowidth(tt);
rcvr = getthisx(f2->type)->type->type; 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)) { if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
typecheck(&n->left, Erv);
checklvalue(n->left, "call pointer method on"); checklvalue(n->left, "call pointer method on");
addrescapes(n->left); addrescapes(n->left);
n->left = nod(OADDR, n->left, N); 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)) { } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
n->left = nod(OIND, n->left, N); n->left = nod(OIND, n->left, N);
typecheck(&n->left, Erv); typecheck(&n->left, Etype|Erv);
} else { } else {
// method is attached to wrong type? // method is attached to wrong type?
fatal("method mismatch: %T for %T", rcvr, tt); fatal("method mismatch: %T for %T", rcvr, tt);
......
...@@ -36,11 +36,18 @@ func main() { ...@@ -36,11 +36,18 @@ func main() {
var pt *T1; var pt *T1;
if s.val() != 1 { panicln("s.val:", s.val()) } if s.val() != 1 { panicln("s.val:", s.val()) }
if S.val(s) != 1 { panicln("S.val(s):", S.val(s)) }
if (*S).val(&s) != 1 { panicln("(*S).val(s):", (*S).val(&s)) }
if ps.val() != 2 { panicln("ps.val:", ps.val()) } if ps.val() != 2 { panicln("ps.val:", ps.val()) }
if (*S1).val(ps) != 2 { panicln("(*S1).val(ps):", (*S1).val(ps)) }
if i.val() != 3 { panicln("i.val:", i.val()) } if i.val() != 3 { panicln("i.val:", i.val()) }
if I.val(i) != 3 { panicln("I.val(i):", I.val(i)) }
if (*I).val(&i) != 3 { panicln("(*I).val(&i):", (*I).val(&i)) }
if pi.val() != 4 { panicln("pi.val:", pi.val()) } if pi.val() != 4 { panicln("pi.val:", pi.val()) }
if (*I1).val(pi) != 4 { panicln("(*I1).val(pi):", (*I1).val(pi)) }
// if t.val() != 7 { panicln("t.val:", t.val()) } // if t.val() != 7 { panicln("t.val:", t.val()) }
if pt.val() != 8 { panicln("pt.val:", pt.val()) } if pt.val() != 8 { panicln("pt.val:", pt.val()) }
if (*T1).val(pt) != 8 { panicln("(*T1).val(pt):", (*T1).val(pt)) }
if val(s) != 1 { panicln("s.val:", val(s)) } if val(s) != 1 { panicln("s.val:", val(s)) }
if val(ps) != 2 { panicln("ps.val:", val(ps)) } if val(ps) != 2 { panicln("ps.val:", val(ps)) }
...@@ -49,4 +56,5 @@ func main() { ...@@ -49,4 +56,5 @@ func main() {
// if val(t) != 7 { panicln("t.val:", val(t)) } // if val(t) != 7 { panicln("t.val:", val(t)) }
if val(pt) != 8 { panicln("pt.val:", val(pt)) } if val(pt) != 8 { panicln("pt.val:", val(pt)) }
// if Val.val(i) != 3 { panicln("Val.val(i):", Val.val(i)) }
} }
...@@ -20,6 +20,12 @@ func main() { ...@@ -20,6 +20,12 @@ func main() {
var i I; var i I;
i = t; i = t;
if i.Len() != 5 { if i.Len() != 5 {
panicln("length", i.Len()); panicln("i.Len", i.Len());
}
if T.Len(t) != 5 {
panicln("T.Len", T.Len(t));
}
if (*T).Len(&t) != 5 {
panicln("(*T).Len", (*T).Len(&t));
} }
} }
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