more on arbitrary receiver types
this CL passes the tests, but should
be considered unstable

R=r
OCL=16390
CL=16390
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 5a45aca..a6b9bca 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -58,7 +58,10 @@
 	char*	name;
 	Sym*	sym;
 	uint32	hash;
+	int32	perm;
 	int32	offset;
+	int32	width;
+	int32	elemalg;
 	Sig*	link;
 };
 
diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c
index 5b16e71..a44ebdf 100644
--- a/src/cmd/6g/obj.c
+++ b/src/cmd/6g/obj.c
@@ -580,10 +580,13 @@
 				a->name = sp+1;
 			
 			a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
-			a->offset = o;
+			a->perm = o;
 			snprint(namebuf, sizeof(namebuf), "%s_%s",
 				at.sym->name+5, f->sym->name);
 			a->sym = lookup(namebuf);
+			a->offset = 0;
+			a->elemalg = 0;
+			a->width = 0;
 
 			o++;
 		}
@@ -660,7 +663,18 @@
 			ot += wi;
 
 			if(et == TINTER) {
-				// sigi[++].offset = offset of method
+				// sigi[++].perm = mapped offset of method
+				ot = rnd(ot, wi);
+				p = pc;
+				gins(ADATA, N, N);
+				p->from = at;
+				p->from.offset = ot;
+				p->from.scale = wi;
+				p->to = ac;
+				p->to.offset = b->perm;
+				ot += wi;
+			} else {
+				// sigt[++].offset = of embeded struct
 				ot = rnd(ot, wi);
 				p = pc;
 				gins(ADATA, N, N);
@@ -670,17 +684,30 @@
 				p->to = ac;
 				p->to.offset = b->offset;
 				ot += wi;
-			} else {
-				// leave space for 3 ints
-				// offset, algorithm and width
+
+				// sigt[++].width = type size
 				ot = rnd(ot, wi);
-				ot += wi;
-				ot = rnd(ot, wi);
-				ot += wi;
-				ot = rnd(ot, wi);
+				p = pc;
+				gins(ADATA, N, N);
+				p->from = at;
+				p->from.offset = ot;
+				p->from.scale = wi;
+				p->to = ac;
+				p->to.offset = b->width;
 				ot += wi;
 
-				// sigs[++].fun = &method
+				// sigt[++].elemalg = type algorithm
+				ot = rnd(ot, wi);
+				p = pc;
+				gins(ADATA, N, N);
+				p->from = at;
+				p->from.offset = ot;
+				p->from.scale = wi;
+				p->to = ac;
+				p->to.offset = b->elemalg;
+				ot += wi;
+
+				// sigt[++].fun = &method
 				ot = rnd(ot, widthptr);
 				p = pc;
 				gins(ADATA, N, N);
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 5839d4a..d6f1b14 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -250,7 +250,6 @@
 {
 	Type *f, *d, *pa;
 	Sym *st, *sf;
-	int ptr;
 
 	// get field sym
 	if(n == N)
@@ -272,29 +271,11 @@
 	if(pa == T)
 		goto bad;
 
-	switch(algtype(pa)) {
-	default:
-		goto bad;
-	case ASIMP:
-	case APTR:
-	case ASTRING:
-		break;
-	}
-
-	// optionally rip off ptr to type
-	ptr = 0;
-	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");
-
 	// and finally the receiver sym
+	f = ismethod(pa);
+	if(f == T)
+		goto bad;
+	pa = f;
 	st = pa->sym;
 	if(st == S)
 		goto bad;
@@ -306,11 +287,6 @@
 	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
 	for(f=pa->method; f!=T; f=f->down) {
 		if(f->etype != TFIELD)
@@ -331,7 +307,7 @@
 		stotype(n, &d->down);
 
 	if(dflag())
-		print("method         %S of type %s%S\n", sf, (ptr? "*":""), st);
+		print("method         %S of type %T\n", sf, pa);
 	return;
 
 bad:
@@ -450,8 +426,10 @@
 			all |= 2;
 		t = structnext(&save);
 	}
+
+	// this test is remarkedly similar to checkarglist
 	if(all == 3)
-		yyerror("output parameters are all named or not named");
+		yyerror("cannot mix anonymous and named output arguments");
 
 	ft->outnamed = 0;
 	if(all == 1)
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index d38c8cb..28a2a62 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -571,7 +571,7 @@
 int	isptrarray(Type*);
 int	isptrdarray(Type*);
 int	isinter(Type*);
-int	ismethod(Type*);
+Type*	ismethod(Type*);
 Sym*	signame(Type*);
 int	bytearraysz(Type*);
 int	eqtype(Type*, Type*, int);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 4514f39..d2c6a13 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -1357,18 +1357,59 @@
 	return 0;
 }
 
-int
+Type*
 ismethod(Type *t)
 {
-	// OLD WAY
-	if(isptrto(t, TSTRUCT))
-		return 1;
-	return 0;
+	int a;
+	Sym *s;
 
-	// NEW WAY - but doesnt work yet
-	if(t != T && t->method != T)
-		return 1;
-	return 0;
+	if(t == T)
+		return T;
+
+	a = algtype(t);
+
+	// direct receiver
+	s = t->sym;
+	if(s != S && s->name[0] != '_') {
+		if(t->methptr == 2)
+			goto both;
+		t->methptr |= 1;
+		goto out;
+	}
+
+	// pointer receiver
+	if(!isptr[t->etype])
+		return T;
+
+	t = t->type;
+	if(t == T)
+		return T;
+
+	s = t->sym;
+	if(s != S && s->name[0] != '_') {
+		if(t->methptr == 1)
+			goto both;
+		t->methptr |= 2;
+		goto out;
+	}
+
+	return T;
+
+both:
+	yyerror("type %T used as both direct and indirect method", t);
+	t->methptr = 3;
+
+out:
+	switch(a) {
+	default:
+		yyerror("type %T cannot be used as a method", t);
+	case ASIMP:
+	case APTR:
+	case ASTRING:
+		break;
+	}
+
+	return t;
 }
 
 Sym*
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index cc06abc..f3aafc4 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -1598,9 +1598,12 @@
 //	if(eqtype(t2, nilptr, 0))
 //		return 1;
 
-	if(isinter(t1))
-		if(ismethod(t2) || isinter(t2))
+	if(isinter(t1)) {
+		if(isinter(t2))
 			return 1;
+		if(ismethod(t2))
+			return 1;
+	}
 
 	if(isinter(t2))
 		if(ismethod(t1))
@@ -2445,15 +2448,20 @@
 
 	rt = r->type;
 	if(isinter(lt)) {
-		if(ismethod(rt))
+		if(isinter(rt)) {
+			if(!eqtype(rt, lt, 0))
+				return I2I;
+			return Inone;
+		}
+		if(ismethod(rt) != T)
 			return T2I;
-		if(isinter(rt) && !eqtype(rt, lt, 0))
-			return I2I;
+		return Inone;
 	}
 
-	if(ismethod(lt)) {
-		if(isinter(rt))
+	if(isinter(rt)) {
+		if(ismethod(lt) != T)
 			return I2T;
+		return Inone;
 	}
 
 	return Inone;