]> Cypherpunks repositories - gostls13.git/commitdiff
gc: method expressions on concrete types
authorRuss Cox <rsc@golang.org>
Sat, 19 Dec 2009 01:24:58 +0000 (17:24 -0800)
committerRuss Cox <rsc@golang.org>
Sat, 19 Dec 2009 01:24:58 +0000 (17:24 -0800)
R=ken2
https://golang.org/cl/180092

src/cmd/gc/dcl.c
src/cmd/gc/go.h
src/cmd/gc/reflect.c
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
test/method.go
test/method3.go

index e17ccfb22eb939670a85f09a802d6ac68586a396..c9fcb1204a6b210c10871354f5ba88da6d8611d2 100644 (file)
@@ -1048,7 +1048,7 @@ isifacemethod(Type *f)
        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 @@ methodsym(Sym *nsym, Type *t0)
        return pkglookup(buf, s->package);
 
 bad:
-       yyerror("illegal <this> type: %T", t);
+       yyerror("illegal receiver type: %T", t0);
        return S;
 }
 
index 692dc77bfc3557aa32c36e7a685f753b8e22ebf3..01bc7568aea7a5471f3a10503fb0b2668eb396f1 100644 (file)
@@ -925,6 +925,7 @@ int structcount(Type*);
 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*);
index 50506b955104c2f196def20af58e5f84ce975690..03d6f5f5a652f0b72f2f9b336eead13fe3e1a8aa 100644 (file)
@@ -88,7 +88,7 @@ lsort(Sig *l, int(*f)(Sig*, Sig*))
  * 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 @@ methodfunc(Type *f)
        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 @@ methods(Type *t)
                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 @@ methods(Type *t)
                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 @@ methods(Type *t)
                                // 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 @@ methods(Type *t)
                                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 @@ imethods(Type *t)
                }
                a->perm = o++;
                a->offset = 0;
-               a->type = methodfunc(f);
+               a->type = methodfunc(f->type);
        }
 
        return lsort(a, sigcmp);
index d79e5b88c90dbc7e371418631f43728b5f212a82..5826cd3a0164bc071e0e120cb148bb2f9bcb1487 100644 (file)
@@ -2531,7 +2531,7 @@ adddot(Node *n)
        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 @@ ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename)
                // 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;
index d0b8fde89c67e2affff5a62d3923347d1ade17d1..08c47d07f83e122bed5bdbe9636c248bfda35b38 100644 (file)
@@ -54,6 +54,7 @@ typecheck(Node **np, int top)
        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 @@ reswitch:
                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 @@ reswitch:
                        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 @@ reswitch:
                                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 @@ lookdot(Node *n, Type *t, int dostrcmp)
                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);
index 43408fef94a81e8653f9b12e40ce449db5722769..4d58a5de66a250b3282a12b8e1656c9ee95d6ceb 100644 (file)
@@ -36,11 +36,18 @@ func main() {
        var pt *T1;
 
        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 (*S1).val(ps) != 2 { panicln("(*S1).val(ps):", (*S1).val(ps)) }
        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 (*I1).val(pi) != 4 { panicln("(*I1).val(pi):", (*I1).val(pi)) }
 //     if t.val() != 7 { panicln("t.val:", t.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(ps) != 2 { panicln("ps.val:", val(ps)) }
@@ -48,5 +55,6 @@ func main() {
        if val(pi) != 4 { panicln("pi.val:", val(pi)) }
 //     if val(t) != 7 { panicln("t.val:", val(t)) }
        if val(pt) != 8 { panicln("pt.val:", val(pt)) }
-
+       
+//     if Val.val(i) != 3 { panicln("Val.val(i):", Val.val(i)) }
 }
index 491bcdad33e298fd1d8371343bf2e8a66077ee7e..20ced1eb23ab12a824d8f24d1994fe468a14723b 100644 (file)
@@ -20,6 +20,12 @@ func main() {
        var i I;
        i = t;
        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));
        }
 }