mirror of
https://github.com/golang/go
synced 2024-11-26 00:38:00 -07:00
6g: new interface rules (code got simpler!)
R=ken OCL=28374 CL=28378
This commit is contained in:
parent
d76f095750
commit
a6ba5ec535
@ -129,7 +129,6 @@ updatetype(Type *n, Type *t)
|
|||||||
n->sym = s;
|
n->sym = s;
|
||||||
n->local = local;
|
n->local = local;
|
||||||
n->siggen = 0;
|
n->siggen = 0;
|
||||||
n->methptr = 0;
|
|
||||||
n->printed = 0;
|
n->printed = 0;
|
||||||
n->method = nil;
|
n->method = nil;
|
||||||
n->vargen = 0;
|
n->vargen = 0;
|
||||||
@ -293,7 +292,7 @@ addmethod(Node *n, Type *t, int local)
|
|||||||
if(pa == T)
|
if(pa == T)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
f = dclmethod(pa);
|
f = methtype(pa);
|
||||||
if(f == T)
|
if(f == T)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
|
@ -137,7 +137,6 @@ struct Type
|
|||||||
uchar chan;
|
uchar chan;
|
||||||
uchar recur; // to detect loops
|
uchar recur; // to detect loops
|
||||||
uchar trecur; // to detect loops
|
uchar trecur; // to detect loops
|
||||||
uchar methptr; // 1=direct 2=pointer
|
|
||||||
uchar printed;
|
uchar printed;
|
||||||
uchar embedded; // TFIELD embedded type
|
uchar embedded; // TFIELD embedded type
|
||||||
uchar siggen;
|
uchar siggen;
|
||||||
@ -725,9 +724,7 @@ int isinter(Type*);
|
|||||||
int isnilinter(Type*);
|
int isnilinter(Type*);
|
||||||
int isddd(Type*);
|
int isddd(Type*);
|
||||||
Type* maptype(Type*, Type*);
|
Type* maptype(Type*, Type*);
|
||||||
Type* dclmethod(Type*);
|
|
||||||
Type* methtype(Type*);
|
Type* methtype(Type*);
|
||||||
int methconv(Type*);
|
|
||||||
Sym* signame(Type*);
|
Sym* signame(Type*);
|
||||||
int eqtype(Type*, Type*, int);
|
int eqtype(Type*, Type*, int);
|
||||||
int eqtypenoname(Type*, Type*);
|
int eqtypenoname(Type*, Type*);
|
||||||
@ -787,10 +784,8 @@ int lookdot0(Sym*, Type*, Type**);
|
|||||||
Type* lookdot1(Sym*, Type*, Type*);
|
Type* lookdot1(Sym*, Type*, Type*);
|
||||||
int adddot1(Sym*, Type*, int, Type**);
|
int adddot1(Sym*, Type*, int, Type**);
|
||||||
Node* adddot(Node*);
|
Node* adddot(Node*);
|
||||||
void expand0(Type*);
|
|
||||||
void expand1(Type*, int);
|
|
||||||
void expandmeth(Sym*, Type*);
|
void expandmeth(Sym*, Type*);
|
||||||
void genptrtramp(Sym*, Sym*, Type*, Type*, Sym*, Type*);
|
void genwrapper(Type*, Type*, Sym*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dcl.c
|
* dcl.c
|
||||||
|
@ -140,6 +140,12 @@ ieeedtod(uint64 *ieee, double native)
|
|||||||
*ieee = ((uint64)h << 32) | l;
|
*ieee = ((uint64)h << 32) | l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sigcmp(Sig *a, Sig *b)
|
||||||
|
{
|
||||||
|
return strcmp(a->name, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add DATA for signature s.
|
* Add DATA for signature s.
|
||||||
* progt - type in program
|
* progt - type in program
|
||||||
@ -165,13 +171,6 @@ ieeedtod(uint64 *ieee, double native)
|
|||||||
* } meth[1]; // one or more - last name is nil
|
* } meth[1]; // one or more - last name is nil
|
||||||
* };
|
* };
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
|
||||||
sigcmp(Sig *a, Sig *b)
|
|
||||||
{
|
|
||||||
return strcmp(a->name, b->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
|
dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
|
||||||
{
|
{
|
||||||
@ -180,12 +179,16 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
|
|||||||
Sig *a, *b;
|
Sig *a, *b;
|
||||||
char buf[NSYMB];
|
char buf[NSYMB];
|
||||||
Type *this;
|
Type *this;
|
||||||
Iter savet;
|
|
||||||
Prog *oldlist;
|
Prog *oldlist;
|
||||||
Sym *method;
|
Sym *method;
|
||||||
uint32 sighash;
|
uint32 sighash;
|
||||||
int ot;
|
int ot;
|
||||||
|
|
||||||
|
if(debug['r']) {
|
||||||
|
print("dumpsigt progt=%T ifacet=%T rcvrt=%T methodt=%T s=%S\n",
|
||||||
|
progt, ifacet, rcvrt, methodt, s);
|
||||||
|
}
|
||||||
|
|
||||||
a = nil;
|
a = nil;
|
||||||
o = 0;
|
o = 0;
|
||||||
oldlist = nil;
|
oldlist = nil;
|
||||||
@ -201,6 +204,16 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
|
|||||||
if(method == nil)
|
if(method == nil)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// get receiver type for this particular method.
|
||||||
|
this = getthisx(f->type)->type->type;
|
||||||
|
if(f->embedded != 2 && isptr[this->etype] && !isptr[progt->etype]) {
|
||||||
|
// pointer receiver method but value method set.
|
||||||
|
// ignore.
|
||||||
|
if(debug['r'])
|
||||||
|
print("ignore %T for %T\n", f, progt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
b = mal(sizeof(*b));
|
b = mal(sizeof(*b));
|
||||||
b->link = a;
|
b->link = a;
|
||||||
a = b;
|
a = b;
|
||||||
@ -216,31 +229,19 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
|
|||||||
|
|
||||||
if(!a->sym->siggen) {
|
if(!a->sym->siggen) {
|
||||||
a->sym->siggen = 1;
|
a->sym->siggen = 1;
|
||||||
// TODO(rsc): This test is still not quite right.
|
|
||||||
|
|
||||||
this = structfirst(&savet, getthis(f->type))->type;
|
if(!eqtype(this, ifacet, 0)) {
|
||||||
if(isptr[this->etype] != isptr[ifacet->etype]) {
|
|
||||||
if(oldlist == nil)
|
if(oldlist == nil)
|
||||||
oldlist = pc;
|
oldlist = pc;
|
||||||
|
|
||||||
// indirect vs direct mismatch
|
// It would be okay to call genwrapper here always,
|
||||||
Sym *oldname, *newname;
|
// but we can generate more efficient code
|
||||||
Type *oldthis, *newthis;
|
// using genembedtramp if all that is necessary
|
||||||
|
// is a pointer adjustment and a JMP.
|
||||||
newthis = ifacet;
|
if(f->embedded && isptr[ifacet->etype])
|
||||||
if(isptr[newthis->etype])
|
|
||||||
oldthis = ifacet->type;
|
|
||||||
else
|
|
||||||
oldthis = ptrto(ifacet);
|
|
||||||
newname = a->sym;
|
|
||||||
oldname = methodsym(method, oldthis);
|
|
||||||
genptrtramp(method, oldname, oldthis, f->type, newname, newthis);
|
|
||||||
} else
|
|
||||||
if(f->embedded) {
|
|
||||||
// TODO(rsc): only works for pointer receivers
|
|
||||||
if(oldlist == nil)
|
|
||||||
oldlist = pc;
|
|
||||||
genembedtramp(ifacet, a);
|
genembedtramp(ifacet, a);
|
||||||
|
else
|
||||||
|
genwrapper(ifacet, f, a->sym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o++;
|
o++;
|
||||||
@ -449,23 +450,17 @@ dumpsignatures(void)
|
|||||||
rcvrt = t;
|
rcvrt = t;
|
||||||
|
|
||||||
// if there's a pointer, methods are on base.
|
// if there's a pointer, methods are on base.
|
||||||
if(isptr[methodt->etype] && methodt->type->sym != S) {
|
methodt = methtype(progt);
|
||||||
methodt = methodt->type;
|
if(methodt == T) {
|
||||||
|
// if that failed, go back to progt,
|
||||||
|
// assuming we're writing out a signature
|
||||||
|
// for a type with no methods
|
||||||
|
methodt = progt;
|
||||||
|
} else {
|
||||||
expandmeth(methodt->sym, methodt);
|
expandmeth(methodt->sym, methodt);
|
||||||
|
|
||||||
// if methodt had a name, we don't want to see
|
|
||||||
// it in the method names that go into the sigt.
|
|
||||||
// e.g., if
|
|
||||||
// type item *rat
|
|
||||||
// then item needs its own sigt distinct from *rat,
|
|
||||||
// but it needs to have all of *rat's methods, using
|
|
||||||
// the *rat (not item) in the method names.
|
|
||||||
if(rcvrt->sym != S)
|
|
||||||
rcvrt = ptrto(methodt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// and if ifacet is too wide, the methods
|
// if ifacet is too wide, the methods will see a pointer.
|
||||||
// will see a pointer anyway.
|
|
||||||
if(ifacet->width > 8) {
|
if(ifacet->width > 8) {
|
||||||
ifacet = ptrto(progt);
|
ifacet = ptrto(progt);
|
||||||
rcvrt = ptrto(progt);
|
rcvrt = ptrto(progt);
|
||||||
@ -473,7 +468,7 @@ dumpsignatures(void)
|
|||||||
|
|
||||||
// don't emit non-trivial signatures for types defined outside this file.
|
// don't emit non-trivial signatures for types defined outside this file.
|
||||||
// non-trivial signatures might also drag in generated trampolines,
|
// non-trivial signatures might also drag in generated trampolines,
|
||||||
// and ar can't handle duplicates of the trampolines.
|
// and ar can't handle duplicate functions.
|
||||||
// only pay attention to types with symbols, because
|
// only pay attention to types with symbols, because
|
||||||
// the ... structs and maybe other internal structs
|
// the ... structs and maybe other internal structs
|
||||||
// don't get marked as local.
|
// don't get marked as local.
|
||||||
|
@ -1495,7 +1495,7 @@ isddd(Type *t)
|
|||||||
* return type to hang methods off (r).
|
* return type to hang methods off (r).
|
||||||
*/
|
*/
|
||||||
Type*
|
Type*
|
||||||
dclmethod(Type *t)
|
methtype(Type *t)
|
||||||
{
|
{
|
||||||
int ptr;
|
int ptr;
|
||||||
|
|
||||||
@ -1517,15 +1517,6 @@ dclmethod(Type *t)
|
|||||||
if(t->sym == S)
|
if(t->sym == S)
|
||||||
return T;
|
return T;
|
||||||
|
|
||||||
// check that all method receivers are consistent
|
|
||||||
if(t->methptr != 0 && t->methptr != (1<<ptr)) {
|
|
||||||
if(t->methptr != 3) {
|
|
||||||
t->methptr = 3;
|
|
||||||
yyerror("methods on both %T and *%T", t, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t->methptr |= 1<<ptr;
|
|
||||||
|
|
||||||
// check types
|
// check types
|
||||||
if(!issimple[t->etype])
|
if(!issimple[t->etype])
|
||||||
switch(t->etype) {
|
switch(t->etype) {
|
||||||
@ -1543,50 +1534,6 @@ dclmethod(Type *t)
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* this is dclmethod() without side effects.
|
|
||||||
*/
|
|
||||||
Type*
|
|
||||||
methtype(Type *t)
|
|
||||||
{
|
|
||||||
if(t == T)
|
|
||||||
return T;
|
|
||||||
if(isptr[t->etype]) {
|
|
||||||
if(t->sym != S)
|
|
||||||
return T;
|
|
||||||
t = t->type;
|
|
||||||
}
|
|
||||||
if(t == T || t->etype == TINTER || t->sym == S)
|
|
||||||
return T;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* given type t in a method call, returns op
|
|
||||||
* to convert t into appropriate receiver.
|
|
||||||
* returns OADDR if t==x and method takes *x
|
|
||||||
* returns OIND if t==*x and method takes x
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
methconv(Type *t)
|
|
||||||
{
|
|
||||||
Type *m;
|
|
||||||
|
|
||||||
m = methtype(t);
|
|
||||||
if(m == T)
|
|
||||||
return 0;
|
|
||||||
if(m->methptr&2) {
|
|
||||||
// want pointer
|
|
||||||
if(t == m)
|
|
||||||
return OADDR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// want non-pointer
|
|
||||||
if(t != m)
|
|
||||||
return OIND;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
iscomposite(Type *t)
|
iscomposite(Type *t)
|
||||||
{
|
{
|
||||||
@ -2604,19 +2551,22 @@ struct Symlink
|
|||||||
{
|
{
|
||||||
Type* field;
|
Type* field;
|
||||||
uchar good;
|
uchar good;
|
||||||
|
uchar followptr;
|
||||||
Symlink* link;
|
Symlink* link;
|
||||||
};
|
};
|
||||||
static Symlink* slist;
|
static Symlink* slist;
|
||||||
|
|
||||||
void
|
static void
|
||||||
expand0(Type *t)
|
expand0(Type *t, int followptr)
|
||||||
{
|
{
|
||||||
Type *f, *u;
|
Type *f, *u;
|
||||||
Symlink *sl;
|
Symlink *sl;
|
||||||
|
|
||||||
u = t;
|
u = t;
|
||||||
if(isptr[u->etype])
|
if(isptr[u->etype]) {
|
||||||
|
followptr = 1;
|
||||||
u = u->type;
|
u = u->type;
|
||||||
|
}
|
||||||
|
|
||||||
u = methtype(t);
|
u = methtype(t);
|
||||||
if(u != T) {
|
if(u != T) {
|
||||||
@ -2629,13 +2579,14 @@ expand0(Type *t)
|
|||||||
sl = mal(sizeof(*sl));
|
sl = mal(sizeof(*sl));
|
||||||
sl->field = f;
|
sl->field = f;
|
||||||
sl->link = slist;
|
sl->link = slist;
|
||||||
|
sl->followptr = followptr;
|
||||||
slist = sl;
|
slist = sl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
expand1(Type *t, int d)
|
expand1(Type *t, int d, int followptr)
|
||||||
{
|
{
|
||||||
Type *f, *u;
|
Type *f, *u;
|
||||||
|
|
||||||
@ -2646,11 +2597,13 @@ expand1(Type *t, int d)
|
|||||||
t->trecur = 1;
|
t->trecur = 1;
|
||||||
|
|
||||||
if(d != nelem(dotlist)-1)
|
if(d != nelem(dotlist)-1)
|
||||||
expand0(t);
|
expand0(t, followptr);
|
||||||
|
|
||||||
u = t;
|
u = t;
|
||||||
if(isptr[u->etype])
|
if(isptr[u->etype]) {
|
||||||
|
followptr = 1;
|
||||||
u = u->type;
|
u = u->type;
|
||||||
|
}
|
||||||
if(u->etype != TSTRUCT && u->etype != TINTER)
|
if(u->etype != TSTRUCT && u->etype != TINTER)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -2659,7 +2612,7 @@ expand1(Type *t, int d)
|
|||||||
continue;
|
continue;
|
||||||
if(f->sym == S)
|
if(f->sym == S)
|
||||||
continue;
|
continue;
|
||||||
expand1(f->type, d-1);
|
expand1(f->type, d-1, followptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -2682,7 +2635,7 @@ expandmeth(Sym *s, Type *t)
|
|||||||
|
|
||||||
// generate all reachable methods
|
// generate all reachable methods
|
||||||
slist = nil;
|
slist = nil;
|
||||||
expand1(t, nelem(dotlist)-1);
|
expand1(t, nelem(dotlist)-1, 0);
|
||||||
|
|
||||||
// check each method to be uniquely reachable
|
// check each method to be uniquely reachable
|
||||||
for(sl=slist; sl!=nil; sl=sl->link) {
|
for(sl=slist; sl!=nil; sl=sl->link) {
|
||||||
@ -2704,7 +2657,8 @@ expandmeth(Sym *s, Type *t)
|
|||||||
f = typ(TFIELD);
|
f = typ(TFIELD);
|
||||||
*f = *sl->field;
|
*f = *sl->field;
|
||||||
f->embedded = 1; // needs a trampoline
|
f->embedded = 1; // needs a trampoline
|
||||||
|
if(sl->followptr)
|
||||||
|
f->embedded = 2;
|
||||||
f->down = t->method;
|
f->down = t->method;
|
||||||
t->method = f;
|
t->method = f;
|
||||||
|
|
||||||
@ -2742,43 +2696,46 @@ structargs(Type **tl, int mustname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate a trampoline to convert
|
* Generate a wrapper function to convert from
|
||||||
* from an indirect receiver to a direct receiver
|
* a receiver of type T to a receiver of type U.
|
||||||
* or vice versa.
|
* That is,
|
||||||
*
|
*
|
||||||
* method - short name of method (Len)
|
* func (t T) M() {
|
||||||
* oldname - old mangled method name (x·y·Len)
|
* ...
|
||||||
* oldthis - old this type (y)
|
* }
|
||||||
* oldtype - type of method being called;
|
*
|
||||||
* only in and out params are known okay,
|
* already exists; this function generates
|
||||||
* receiver might be != oldthis.
|
*
|
||||||
* newnam [sic] - new mangled method name (x·*y·Len)
|
* func (u U) M() {
|
||||||
* newthis - new this type (*y)
|
* u.M()
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* where the types T and U are such that u.M() is valid
|
||||||
|
* and calls the T.M method.
|
||||||
|
* The resulting function is for use in method tables.
|
||||||
|
*
|
||||||
|
* rcvrtype - U
|
||||||
|
* method - M func (t T)(), a TFIELD type struct
|
||||||
|
* newnam - the eventual mangled name of this function
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
genptrtramp(Sym *method, Sym *oldname, Type *oldthis, Type *oldtype, Sym *newnam, Type *newthis)
|
genwrapper(Type *rcvrtype, Type *method, Sym *newnam)
|
||||||
{
|
{
|
||||||
Node *fn, *args, *l, *in, *call, *out, *this, *rcvr, *meth;
|
Node *this, *in, *out, *fn, *args, *call;
|
||||||
|
Node *l;
|
||||||
Iter savel;
|
Iter savel;
|
||||||
|
|
||||||
if(debug['r']) {
|
if(debug['r']) {
|
||||||
print("\ngenptrtramp method=%S oldname=%S oldthis=%T\n",
|
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
|
||||||
method, oldname, oldthis);
|
rcvrtype, method, newnam);
|
||||||
print("\toldtype=%T newnam=%S newthis=%T\n",
|
|
||||||
oldtype, newnam, newthis);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dclcontext = PEXTERN;
|
dclcontext = PEXTERN;
|
||||||
markdcl();
|
markdcl();
|
||||||
|
|
||||||
this = nametodcl(newname(lookup(".this")), newthis);
|
this = nametodcl(newname(lookup(".this")), rcvrtype);
|
||||||
in = structargs(getinarg(oldtype), 1);
|
in = structargs(getinarg(method->type), 1);
|
||||||
out = structargs(getoutarg(oldtype), 0);
|
out = structargs(getoutarg(method->type), 0);
|
||||||
|
|
||||||
// fix up oldtype
|
|
||||||
markdcl();
|
|
||||||
oldtype = functype(nametodcl(newname(lookup(".this")), oldthis), in, out);
|
|
||||||
popdcl();
|
|
||||||
|
|
||||||
fn = nod(ODCLFUNC, N, N);
|
fn = nod(ODCLFUNC, N, N);
|
||||||
fn->nname = newname(newnam);
|
fn->nname = newname(newnam);
|
||||||
@ -2791,19 +2748,10 @@ genptrtramp(Sym *method, Sym *oldname, Type *oldthis, Type *oldtype, Sym *newnam
|
|||||||
args = list(args, l->left);
|
args = list(args, l->left);
|
||||||
args = rev(args);
|
args = rev(args);
|
||||||
|
|
||||||
// method to call
|
// generate call
|
||||||
if(isptr[oldthis->etype])
|
call = nod(OCALL, adddot(nod(ODOT, this->left, newname(method->sym))), args);
|
||||||
rcvr = nod(OADDR, this->left, N);
|
|
||||||
else
|
|
||||||
rcvr = nod(OIND, this->left, N);
|
|
||||||
gettype(rcvr, N);
|
|
||||||
meth = nod(ODOTMETH, rcvr, newname(oldname));
|
|
||||||
meth->xoffset = BADWIDTH; // TODO(rsc): necessary?
|
|
||||||
meth->type = oldtype;
|
|
||||||
|
|
||||||
call = nod(OCALL, meth, args);
|
|
||||||
fn->nbody = call;
|
fn->nbody = call;
|
||||||
if(oldtype->outtuple > 0)
|
if(method->type->outtuple > 0)
|
||||||
fn->nbody = nod(ORETURN, call, N);
|
fn->nbody = nod(ORETURN, call, N);
|
||||||
|
|
||||||
if(debug['r'])
|
if(debug['r'])
|
||||||
@ -2850,11 +2798,13 @@ ifacecheck(Type *dst, Type *src, int lineno, int explicit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type*
|
Type*
|
||||||
ifacelookdot(Sym *s, Type *t)
|
ifacelookdot(Sym *s, Type *t, int *followptr)
|
||||||
{
|
{
|
||||||
int c, d;
|
int i, c, d;
|
||||||
Type *m;
|
Type *m;
|
||||||
|
|
||||||
|
*followptr = 0;
|
||||||
|
|
||||||
if(t == T)
|
if(t == T)
|
||||||
return T;
|
return T;
|
||||||
|
|
||||||
@ -2864,9 +2814,16 @@ ifacelookdot(Sym *s, Type *t)
|
|||||||
yyerror("%T.%S is ambiguous", t, s);
|
yyerror("%T.%S is ambiguous", t, s);
|
||||||
return T;
|
return T;
|
||||||
}
|
}
|
||||||
if(c == 1)
|
if(c == 1) {
|
||||||
|
for(i=0; i<d; i++) {
|
||||||
|
if(isptr[dotlist[i].field->type->etype]) {
|
||||||
|
*followptr = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return T;
|
return T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2875,23 +2832,11 @@ ifacelookdot(Sym *s, Type *t)
|
|||||||
int
|
int
|
||||||
ifaceokT2I(Type *t0, Type *iface, Type **m)
|
ifaceokT2I(Type *t0, Type *iface, Type **m)
|
||||||
{
|
{
|
||||||
Type *t, *im, *tm;
|
Type *t, *im, *tm, *rcvr;
|
||||||
int imhash;
|
int imhash, followptr;
|
||||||
|
|
||||||
t = methtype(t0);
|
t = methtype(t0);
|
||||||
|
|
||||||
// stopgap: check for
|
|
||||||
// non-pointer type in T2I, methods want pointers.
|
|
||||||
// supposed to do something better eventually
|
|
||||||
// but this will catch errors while we decide the
|
|
||||||
// details of the "better" solution.
|
|
||||||
// only warn if iface is not interface{}.
|
|
||||||
if(t == t0 && t->methptr == 2 && iface->type != T) {
|
|
||||||
yyerror("probably wanted *%T not %T", t, t);
|
|
||||||
*m = iface->type;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this is too slow,
|
// if this is too slow,
|
||||||
// could sort these first
|
// could sort these first
|
||||||
// and then do one loop.
|
// and then do one loop.
|
||||||
@ -2905,11 +2850,20 @@ ifaceokT2I(Type *t0, Type *iface, Type **m)
|
|||||||
|
|
||||||
for(im=iface->type; im; im=im->down) {
|
for(im=iface->type; im; im=im->down) {
|
||||||
imhash = typehash(im, 0, 0);
|
imhash = typehash(im, 0, 0);
|
||||||
tm = ifacelookdot(im->sym, t);
|
tm = ifacelookdot(im->sym, t, &followptr);
|
||||||
if(tm == T || typehash(tm, 0, 0) != imhash) {
|
if(tm == T || typehash(tm, 0, 0) != imhash) {
|
||||||
*m = im;
|
*m = im;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
// 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) {
|
||||||
|
if(debug['r'])
|
||||||
|
yyerror("interface pointer mismatch");
|
||||||
|
*m = im;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1590,8 +1590,7 @@ lookdot1(Sym *s, Type *t, Type *f)
|
|||||||
int
|
int
|
||||||
lookdot(Node *n, Type *t)
|
lookdot(Node *n, Type *t)
|
||||||
{
|
{
|
||||||
Type *f1, *f2, *tt;
|
Type *f1, *f2, *tt, *rcvr;
|
||||||
int op;
|
|
||||||
Sym *s;
|
Sym *s;
|
||||||
|
|
||||||
s = n->right->sym;
|
s = n->right->sym;
|
||||||
@ -1618,18 +1617,19 @@ lookdot(Node *n, Type *t)
|
|||||||
|
|
||||||
if(f2 != T) {
|
if(f2 != T) {
|
||||||
tt = n->left->type;
|
tt = n->left->type;
|
||||||
if((op = methconv(tt)) != 0) {
|
rcvr = getthisx(f2->type)->type->type;
|
||||||
switch(op) {
|
if(!eqtype(rcvr, tt, 0)) {
|
||||||
case OADDR:
|
if(rcvr->etype == tptr && eqtype(rcvr->type, tt, 0)) {
|
||||||
walktype(n->left, Elv);
|
walktype(n->left, Elv);
|
||||||
addrescapes(n->left);
|
addrescapes(n->left);
|
||||||
n->left = nod(OADDR, n->left, N);
|
n->left = nod(OADDR, n->left, N);
|
||||||
n->left->type = ptrto(tt);
|
n->left->type = ptrto(tt);
|
||||||
break;
|
} else if(tt->etype == tptr && eqtype(tt->type, rcvr, 0)) {
|
||||||
case OIND:
|
|
||||||
n->left = nod(OIND, n->left, N);
|
n->left = nod(OIND, n->left, N);
|
||||||
n->left->type = tt->type;
|
n->left->type = tt->type;
|
||||||
break;
|
} else {
|
||||||
|
// method is attached to wrong type?
|
||||||
|
fatal("method mismatch: %T for %T", rcvr, tt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n->right = methodname(n->right, n->left->type);
|
n->right = methodname(n->right, n->left->type);
|
||||||
|
Loading…
Reference in New Issue
Block a user