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);