mirror of
https://github.com/golang/go
synced 2024-11-22 12:14:42 -07:00
cmd/gc: implement method values
R=ken2, ken CC=golang-dev https://golang.org/cl/7546052
This commit is contained in:
parent
6e15683cae
commit
d3c758d7d2
@ -543,6 +543,7 @@ ismem(Node *n)
|
|||||||
case OINDREG:
|
case OINDREG:
|
||||||
case ONAME:
|
case ONAME:
|
||||||
case OPARAM:
|
case OPARAM:
|
||||||
|
case OCLOSUREVAR:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1163,11 +1164,11 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
|
|||||||
// Generate an instruction referencing *n
|
// Generate an instruction referencing *n
|
||||||
// to force segv on nil pointer dereference.
|
// to force segv on nil pointer dereference.
|
||||||
void
|
void
|
||||||
checkref(Node *n)
|
checkref(Node *n, int force)
|
||||||
{
|
{
|
||||||
Node m1, m2;
|
Node m1, m2;
|
||||||
|
|
||||||
if(n->type->type->width < unmappedzero)
|
if(!force && isptr[n->type->etype] && n->type->type->width < unmappedzero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
regalloc(&m1, types[TUINTPTR], n);
|
regalloc(&m1, types[TUINTPTR], n);
|
||||||
@ -1209,8 +1210,6 @@ checkoffset(Addr *a, int canemitcode)
|
|||||||
void
|
void
|
||||||
naddr(Node *n, Addr *a, int canemitcode)
|
naddr(Node *n, Addr *a, int canemitcode)
|
||||||
{
|
{
|
||||||
Prog *p;
|
|
||||||
|
|
||||||
a->type = D_NONE;
|
a->type = D_NONE;
|
||||||
a->name = D_NONE;
|
a->name = D_NONE;
|
||||||
a->reg = NREG;
|
a->reg = NREG;
|
||||||
@ -1283,16 +1282,9 @@ naddr(Node *n, Addr *a, int canemitcode)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OCLOSUREVAR:
|
case OCLOSUREVAR:
|
||||||
if(!canemitcode)
|
a->type = D_OREG;
|
||||||
fatal("naddr OCLOSUREVAR cannot emit code");
|
a->reg = 7;
|
||||||
p = gins(AMOVW, N, N);
|
a->offset = n->xoffset;
|
||||||
p->from.type = D_OREG;
|
|
||||||
p->from.reg = 7;
|
|
||||||
p->from.offset = n->xoffset;
|
|
||||||
p->to.type = D_REG;
|
|
||||||
p->to.reg = 1;
|
|
||||||
a->type = D_REG;
|
|
||||||
a->reg = 1;
|
|
||||||
a->sym = S;
|
a->sym = S;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -555,6 +555,7 @@ ismem(Node *n)
|
|||||||
case OINDREG:
|
case OINDREG:
|
||||||
case ONAME:
|
case ONAME:
|
||||||
case OPARAM:
|
case OPARAM:
|
||||||
|
case OCLOSUREVAR:
|
||||||
return 1;
|
return 1;
|
||||||
case OADDR:
|
case OADDR:
|
||||||
if(flag_largemodel)
|
if(flag_largemodel)
|
||||||
@ -1057,11 +1058,11 @@ gins(int as, Node *f, Node *t)
|
|||||||
// Generate an instruction referencing *n
|
// Generate an instruction referencing *n
|
||||||
// to force segv on nil pointer dereference.
|
// to force segv on nil pointer dereference.
|
||||||
void
|
void
|
||||||
checkref(Node *n)
|
checkref(Node *n, int force)
|
||||||
{
|
{
|
||||||
Node m;
|
Node m;
|
||||||
|
|
||||||
if(n->type->type->width < unmappedzero)
|
if(!force && isptr[n->type->etype] && n->type->type->width < unmappedzero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
regalloc(&m, types[TUINTPTR], n);
|
regalloc(&m, types[TUINTPTR], n);
|
||||||
@ -1098,8 +1099,6 @@ checkoffset(Addr *a, int canemitcode)
|
|||||||
void
|
void
|
||||||
naddr(Node *n, Addr *a, int canemitcode)
|
naddr(Node *n, Addr *a, int canemitcode)
|
||||||
{
|
{
|
||||||
Prog *p;
|
|
||||||
|
|
||||||
a->scale = 0;
|
a->scale = 0;
|
||||||
a->index = D_NONE;
|
a->index = D_NONE;
|
||||||
a->type = D_NONE;
|
a->type = D_NONE;
|
||||||
@ -1163,14 +1162,9 @@ naddr(Node *n, Addr *a, int canemitcode)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OCLOSUREVAR:
|
case OCLOSUREVAR:
|
||||||
if(!canemitcode)
|
a->type = D_DX+D_INDIR;
|
||||||
fatal("naddr OCLOSUREVAR cannot emit code");
|
|
||||||
p = gins(AMOVQ, N, N);
|
|
||||||
p->from.type = D_DX+D_INDIR;
|
|
||||||
p->from.offset = n->xoffset;
|
|
||||||
p->to.type = D_BX;
|
|
||||||
a->type = D_BX;
|
|
||||||
a->sym = S;
|
a->sym = S;
|
||||||
|
a->offset = n->xoffset;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OCFUNC:
|
case OCFUNC:
|
||||||
|
@ -1150,6 +1150,7 @@ ismem(Node *n)
|
|||||||
case OINDREG:
|
case OINDREG:
|
||||||
case ONAME:
|
case ONAME:
|
||||||
case OPARAM:
|
case OPARAM:
|
||||||
|
case OCLOSUREVAR:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -2160,11 +2161,11 @@ gins(int as, Node *f, Node *t)
|
|||||||
// Generate an instruction referencing *n
|
// Generate an instruction referencing *n
|
||||||
// to force segv on nil pointer dereference.
|
// to force segv on nil pointer dereference.
|
||||||
void
|
void
|
||||||
checkref(Node *n)
|
checkref(Node *n, int force)
|
||||||
{
|
{
|
||||||
Node m;
|
Node m;
|
||||||
|
|
||||||
if(n->type->type->width < unmappedzero)
|
if(!force && isptr[n->type->etype] && n->type->type->width < unmappedzero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
regalloc(&m, types[TUINTPTR], n);
|
regalloc(&m, types[TUINTPTR], n);
|
||||||
@ -2201,8 +2202,6 @@ checkoffset(Addr *a, int canemitcode)
|
|||||||
void
|
void
|
||||||
naddr(Node *n, Addr *a, int canemitcode)
|
naddr(Node *n, Addr *a, int canemitcode)
|
||||||
{
|
{
|
||||||
Prog *p;
|
|
||||||
|
|
||||||
a->scale = 0;
|
a->scale = 0;
|
||||||
a->index = D_NONE;
|
a->index = D_NONE;
|
||||||
a->type = D_NONE;
|
a->type = D_NONE;
|
||||||
@ -2239,13 +2238,8 @@ naddr(Node *n, Addr *a, int canemitcode)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OCLOSUREVAR:
|
case OCLOSUREVAR:
|
||||||
if(!canemitcode)
|
a->type = D_DX+D_INDIR;
|
||||||
fatal("naddr OCLOSUREVAR cannot emit code");
|
a->offset = n->xoffset;
|
||||||
p = gins(AMOVL, N, N);
|
|
||||||
p->from.type = D_DX+D_INDIR;
|
|
||||||
p->from.offset = n->xoffset;
|
|
||||||
p->to.type = D_BX;
|
|
||||||
a->type = D_BX;
|
|
||||||
a->sym = S;
|
a->sym = S;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -255,26 +255,166 @@ walkclosure(Node *func, NodeList **init)
|
|||||||
return clos;
|
return clos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case for closures that get called in place.
|
static Node *makepartialcall(Node*, Type*, Node*);
|
||||||
// Optimize runtime.closure(X, __func__xxxx_, .... ) away
|
|
||||||
// to __func__xxxx_(Y ....).
|
|
||||||
// On entry, expect n->op == OCALL, n->left->op == OCLOSURE.
|
|
||||||
void
|
void
|
||||||
walkcallclosure(Node *n, NodeList **init)
|
typecheckpartialcall(Node *fn, Node *sym)
|
||||||
{
|
{
|
||||||
USED(init);
|
switch(fn->op) {
|
||||||
if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
|
case ODOTINTER:
|
||||||
dump("walkcallclosure", n);
|
case ODOTMETH:
|
||||||
fatal("abuse of walkcallclosure");
|
break;
|
||||||
|
default:
|
||||||
|
fatal("invalid typecheckpartialcall");
|
||||||
}
|
}
|
||||||
|
|
||||||
// New arg list for n. First the closure-args
|
// Create top-level function.
|
||||||
// and then the original parameter list.
|
fn->nname = makepartialcall(fn, fn->type, sym);
|
||||||
n->list = concat(n->left->enter, n->list);
|
fn->op = OCALLPART;
|
||||||
n->left = n->left->closure->nname;
|
fn->type = fn->right->type;
|
||||||
dowidth(n->left->type);
|
}
|
||||||
n->type = getoutargx(n->left->type);
|
|
||||||
// for a single valued function, pull the field type out of the struct
|
static Node*
|
||||||
if (n->type && n->type->type && !n->type->type->down)
|
makepartialcall(Node *fn, Type *t0, Node *meth)
|
||||||
n->type = n->type->type->type;
|
{
|
||||||
|
Node *ptr, *n, *call, *xtype, *xfunc, *cv;
|
||||||
|
Type *rcvrtype, *basetype, *t;
|
||||||
|
NodeList *body, *l, *callargs, *retargs;
|
||||||
|
char *p;
|
||||||
|
Sym *sym;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// TODO: names are not right
|
||||||
|
rcvrtype = fn->left->type;
|
||||||
|
if(exportname(meth->sym->name))
|
||||||
|
p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name);
|
||||||
|
else
|
||||||
|
p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym);
|
||||||
|
basetype = rcvrtype;
|
||||||
|
if(isptr[rcvrtype->etype])
|
||||||
|
basetype = basetype->type;
|
||||||
|
if(basetype->sym == S)
|
||||||
|
fatal("missing base type for %T", rcvrtype);
|
||||||
|
|
||||||
|
sym = pkglookup(p, basetype->sym->pkg);
|
||||||
|
free(p);
|
||||||
|
if(sym->flags & SymUniq)
|
||||||
|
return sym->def;
|
||||||
|
sym->flags |= SymUniq;
|
||||||
|
|
||||||
|
xtype = nod(OTFUNC, N, N);
|
||||||
|
i = 0;
|
||||||
|
l = nil;
|
||||||
|
callargs = nil;
|
||||||
|
xfunc = nod(ODCLFUNC, N, N);
|
||||||
|
for(t = getinargx(t0)->type; t; t = t->down) {
|
||||||
|
snprint(namebuf, sizeof namebuf, "a%d", i++);
|
||||||
|
n = newname(lookup(namebuf));
|
||||||
|
n->class = PPARAM;
|
||||||
|
xfunc->dcl = list(xfunc->dcl, n);
|
||||||
|
callargs = list(callargs, n);
|
||||||
|
l = list(l, nod(ODCLFIELD, n, typenod(t->type)));
|
||||||
|
}
|
||||||
|
xtype->list = l;
|
||||||
|
i = 0;
|
||||||
|
l = nil;
|
||||||
|
retargs = nil;
|
||||||
|
for(t = getoutargx(t0)->type; t; t = t->down) {
|
||||||
|
snprint(namebuf, sizeof namebuf, "r%d", i++);
|
||||||
|
n = newname(lookup(namebuf));
|
||||||
|
n->class = PPARAMOUT;
|
||||||
|
xfunc->dcl = list(xfunc->dcl, n);
|
||||||
|
retargs = list(retargs, n);
|
||||||
|
l = list(l, nod(ODCLFIELD, n, typenod(t->type)));
|
||||||
|
}
|
||||||
|
xtype->rlist = l;
|
||||||
|
|
||||||
|
xfunc->dupok = 1;
|
||||||
|
xfunc->nname = newname(sym);
|
||||||
|
xfunc->nname->sym->flags |= SymExported; // disable export
|
||||||
|
xfunc->nname->ntype = xtype;
|
||||||
|
xfunc->nname->defn = xfunc;
|
||||||
|
declare(xfunc->nname, PFUNC);
|
||||||
|
|
||||||
|
// Declare and initialize variable holding receiver.
|
||||||
|
body = nil;
|
||||||
|
cv = nod(OCLOSUREVAR, N, N);
|
||||||
|
cv->xoffset = widthptr;
|
||||||
|
cv->type = rcvrtype;
|
||||||
|
ptr = nod(ONAME, N, N);
|
||||||
|
ptr->sym = lookup("rcvr");
|
||||||
|
ptr->class = PAUTO;
|
||||||
|
ptr->addable = 1;
|
||||||
|
ptr->ullman = 1;
|
||||||
|
ptr->used = 1;
|
||||||
|
ptr->curfn = xfunc;
|
||||||
|
xfunc->dcl = list(xfunc->dcl, ptr);
|
||||||
|
if(isptr[rcvrtype->etype] || isinter(rcvrtype)) {
|
||||||
|
ptr->ntype = typenod(rcvrtype);
|
||||||
|
body = list(body, nod(OAS, ptr, cv));
|
||||||
|
} else {
|
||||||
|
ptr->ntype = typenod(ptrto(rcvrtype));
|
||||||
|
body = list(body, nod(OAS, ptr, nod(OADDR, cv, N)));
|
||||||
|
}
|
||||||
|
|
||||||
|
call = nod(OCALL, nod(OXDOT, ptr, meth), N);
|
||||||
|
call->list = callargs;
|
||||||
|
if(t0->outtuple == 0) {
|
||||||
|
body = list(body, call);
|
||||||
|
} else {
|
||||||
|
n = nod(OAS2, N, N);
|
||||||
|
n->list = retargs;
|
||||||
|
n->rlist = list1(call);
|
||||||
|
body = list(body, n);
|
||||||
|
n = nod(ORETURN, N, N);
|
||||||
|
body = list(body, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfunc->nbody = body;
|
||||||
|
|
||||||
|
typecheck(&xfunc, Etop);
|
||||||
|
sym->def = xfunc;
|
||||||
|
xtop = list(xtop, xfunc);
|
||||||
|
|
||||||
|
return xfunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node*
|
||||||
|
walkpartialcall(Node *n, NodeList **init)
|
||||||
|
{
|
||||||
|
Node *clos, *typ;
|
||||||
|
|
||||||
|
// Create closure in the form of a composite literal.
|
||||||
|
// For x.M with receiver (x) type T, the generated code looks like:
|
||||||
|
//
|
||||||
|
// clos = &struct{F uintptr; R T}{M.T·f, x}
|
||||||
|
//
|
||||||
|
// Like walkclosure above.
|
||||||
|
|
||||||
|
if(isinter(n->left->type)) {
|
||||||
|
n->left = cheapexpr(n->left, init);
|
||||||
|
checknotnil(n->left, init);
|
||||||
|
}
|
||||||
|
|
||||||
|
typ = nod(OTSTRUCT, N, N);
|
||||||
|
typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
|
||||||
|
typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type)));
|
||||||
|
|
||||||
|
clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
|
||||||
|
clos->esc = n->esc;
|
||||||
|
clos->right->implicit = 1;
|
||||||
|
clos->list = list1(nod(OCFUNC, n->nname->nname, N));
|
||||||
|
clos->list = list(clos->list, n->left);
|
||||||
|
|
||||||
|
// Force type conversion from *struct to the func type.
|
||||||
|
clos = nod(OCONVNOP, clos, N);
|
||||||
|
clos->type = n->type;
|
||||||
|
|
||||||
|
typecheck(&clos, Erv);
|
||||||
|
// typecheck will insert a PTRLIT node under CONVNOP,
|
||||||
|
// tag it with escape analysis result.
|
||||||
|
clos->left->esc = n->esc;
|
||||||
|
walkexpr(&clos, init);
|
||||||
|
|
||||||
|
return clos;
|
||||||
}
|
}
|
||||||
|
@ -491,6 +491,9 @@ gen(Node *n)
|
|||||||
case ORETURN:
|
case ORETURN:
|
||||||
cgen_ret(n);
|
cgen_ret(n);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OCHECKNOTNIL:
|
||||||
|
checkref(n->left, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret:
|
ret:
|
||||||
@ -807,7 +810,7 @@ cgen_slice(Node *n, Node *res)
|
|||||||
if(n->op == OSLICEARR) {
|
if(n->op == OSLICEARR) {
|
||||||
if(!isptr[n->left->type->etype])
|
if(!isptr[n->left->type->etype])
|
||||||
fatal("slicearr is supposed to work on pointer: %+N\n", n);
|
fatal("slicearr is supposed to work on pointer: %+N\n", n);
|
||||||
checkref(n->left);
|
checkref(n->left, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isnil(n->left)) {
|
if(isnil(n->left)) {
|
||||||
|
@ -452,6 +452,7 @@ enum
|
|||||||
OCALLFUNC, // f()
|
OCALLFUNC, // f()
|
||||||
OCALLMETH, // t.Method()
|
OCALLMETH, // t.Method()
|
||||||
OCALLINTER, // err.Error()
|
OCALLINTER, // err.Error()
|
||||||
|
OCALLPART, // t.Method (without ())
|
||||||
OCAP, // cap
|
OCAP, // cap
|
||||||
OCLOSE, // close
|
OCLOSE, // close
|
||||||
OCLOSURE, // f = func() { etc }
|
OCLOSURE, // f = func() { etc }
|
||||||
@ -564,6 +565,7 @@ enum
|
|||||||
OITAB, // itable word of an interface value.
|
OITAB, // itable word of an interface value.
|
||||||
OCLOSUREVAR, // variable reference at beginning of closure function
|
OCLOSUREVAR, // variable reference at beginning of closure function
|
||||||
OCFUNC, // reference to c function pointer (not go func value)
|
OCFUNC, // reference to c function pointer (not go func value)
|
||||||
|
OCHECKNOTNIL, // emit code to ensure pointer/interface not nil
|
||||||
|
|
||||||
// arch-specific registers
|
// arch-specific registers
|
||||||
OREGISTER, // a register, such as AX.
|
OREGISTER, // a register, such as AX.
|
||||||
@ -989,7 +991,8 @@ Node* closurebody(NodeList *body);
|
|||||||
void closurehdr(Node *ntype);
|
void closurehdr(Node *ntype);
|
||||||
void typecheckclosure(Node *func, int top);
|
void typecheckclosure(Node *func, int top);
|
||||||
Node* walkclosure(Node *func, NodeList **init);
|
Node* walkclosure(Node *func, NodeList **init);
|
||||||
void walkcallclosure(Node *n, NodeList **init);
|
void typecheckpartialcall(Node*, Node*);
|
||||||
|
Node* walkpartialcall(Node*, NodeList**);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* const.c
|
* const.c
|
||||||
@ -1419,7 +1422,8 @@ EXTERN Node* nodfp;
|
|||||||
int anyregalloc(void);
|
int anyregalloc(void);
|
||||||
void betypeinit(void);
|
void betypeinit(void);
|
||||||
void bgen(Node *n, int true, int likely, Prog *to);
|
void bgen(Node *n, int true, int likely, Prog *to);
|
||||||
void checkref(Node*);
|
void checkref(Node *n, int force);
|
||||||
|
void checknotnil(Node*, NodeList**);
|
||||||
void cgen(Node*, Node*);
|
void cgen(Node*, Node*);
|
||||||
void cgen_asop(Node *n);
|
void cgen_asop(Node *n);
|
||||||
void cgen_call(Node *n, int proc);
|
void cgen_call(Node *n, int proc);
|
||||||
|
@ -357,7 +357,7 @@ inlnode(Node **np)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
// TODO do them here (or earlier) instead of in walkcallclosure,
|
// TODO do them here (or earlier),
|
||||||
// so escape analysis can avoid more heapmoves.
|
// so escape analysis can avoid more heapmoves.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3723,3 +3723,17 @@ isbadimport(Strlit *path)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
checknotnil(Node *x, NodeList **init)
|
||||||
|
{
|
||||||
|
Node *n;
|
||||||
|
|
||||||
|
if(isinter(x->type)) {
|
||||||
|
x = nod(OITAB, x, N);
|
||||||
|
typecheck(&x, Erv);
|
||||||
|
}
|
||||||
|
n = nod(OCHECKNOTNIL, x, N);
|
||||||
|
n->typecheck = 1;
|
||||||
|
*init = list(*init, n);
|
||||||
|
}
|
||||||
|
@ -732,6 +732,7 @@ reswitch:
|
|||||||
yyerror("rhs of . must be a name"); // impossible
|
yyerror("rhs of . must be a name"); // impossible
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
r = n->right;
|
||||||
|
|
||||||
if(n->left->op == OTYPE) {
|
if(n->left->op == OTYPE) {
|
||||||
if(!looktypedot(n, t, 0)) {
|
if(!looktypedot(n, t, 0)) {
|
||||||
@ -775,7 +776,12 @@ reswitch:
|
|||||||
switch(n->op) {
|
switch(n->op) {
|
||||||
case ODOTINTER:
|
case ODOTINTER:
|
||||||
case ODOTMETH:
|
case ODOTMETH:
|
||||||
ok |= Ecall;
|
if(top&Ecall)
|
||||||
|
ok |= Ecall;
|
||||||
|
else {
|
||||||
|
typecheckpartialcall(n, r);
|
||||||
|
ok |= Erv;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ok |= Erv;
|
ok |= Erv;
|
||||||
@ -1694,10 +1700,6 @@ ret:
|
|||||||
yyerror("%N is not a type", n);
|
yyerror("%N is not a type", n);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if((ok & Ecall) && !(top & Ecall)) {
|
|
||||||
yyerror("method %N is not an expression, must be called", n);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
// TODO(rsc): simplify
|
// TODO(rsc): simplify
|
||||||
if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
|
if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
|
||||||
yyerror("%N used as value", n);
|
yyerror("%N used as value", n);
|
||||||
@ -2560,6 +2562,7 @@ islvalue(Node *n)
|
|||||||
// fall through
|
// fall through
|
||||||
case OIND:
|
case OIND:
|
||||||
case ODOTPTR:
|
case ODOTPTR:
|
||||||
|
case OCLOSUREVAR:
|
||||||
return 1;
|
return 1;
|
||||||
case ODOT:
|
case ODOT:
|
||||||
return islvalue(n->left);
|
return islvalue(n->left);
|
||||||
|
@ -184,6 +184,7 @@ walkstmt(Node **np)
|
|||||||
case OLABEL:
|
case OLABEL:
|
||||||
case ODCLCONST:
|
case ODCLCONST:
|
||||||
case ODCLTYPE:
|
case ODCLTYPE:
|
||||||
|
case OCHECKNOTNIL:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBLOCK:
|
case OBLOCK:
|
||||||
@ -396,13 +397,28 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
case OIMAG:
|
case OIMAG:
|
||||||
case ODOTMETH:
|
case ODOTMETH:
|
||||||
case ODOTINTER:
|
case ODOTINTER:
|
||||||
|
walkexpr(&n->left, init);
|
||||||
|
goto ret;
|
||||||
|
|
||||||
case OIND:
|
case OIND:
|
||||||
|
if(n->left->type->type->width == 0) {
|
||||||
|
n->left = cheapexpr(n->left, init);
|
||||||
|
checknotnil(n->left, init);
|
||||||
|
}
|
||||||
walkexpr(&n->left, init);
|
walkexpr(&n->left, init);
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
case ODOT:
|
case ODOT:
|
||||||
|
usefield(n);
|
||||||
|
walkexpr(&n->left, init);
|
||||||
|
goto ret;
|
||||||
|
|
||||||
case ODOTPTR:
|
case ODOTPTR:
|
||||||
usefield(n);
|
usefield(n);
|
||||||
|
if(n->op == ODOTPTR && n->left->type->type->width == 0) {
|
||||||
|
n->left = cheapexpr(n->left, init);
|
||||||
|
checknotnil(n->left, init);
|
||||||
|
}
|
||||||
walkexpr(&n->left, init);
|
walkexpr(&n->left, init);
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
@ -524,13 +540,6 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
if(n->list && n->list->n->op == OAS)
|
if(n->list && n->list->n->op == OAS)
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
/*
|
|
||||||
if(n->left->op == OCLOSURE) {
|
|
||||||
walkcallclosure(n, init);
|
|
||||||
t = n->left->type;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
walkexpr(&n->left, init);
|
walkexpr(&n->left, init);
|
||||||
walkexprlist(n->list, init);
|
walkexprlist(n->list, init);
|
||||||
|
|
||||||
@ -1321,6 +1330,10 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
n = walkclosure(n, init);
|
n = walkclosure(n, init);
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
|
case OCALLPART:
|
||||||
|
n = walkpartialcall(n, init);
|
||||||
|
goto ret;
|
||||||
}
|
}
|
||||||
fatal("missing switch %O", n->op);
|
fatal("missing switch %O", n->op);
|
||||||
|
|
||||||
|
297
test/method5.go
Normal file
297
test/method5.go
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
// run
|
||||||
|
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Concrete types implementing M method.
|
||||||
|
// Smaller than a word, word-sized, larger than a word.
|
||||||
|
// Value and pointer receivers.
|
||||||
|
|
||||||
|
type Tinter interface {
|
||||||
|
M(int, byte) (byte, int)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tsmallv byte
|
||||||
|
|
||||||
|
func (v Tsmallv) M(x int, b byte) (byte, int) { return b, x+int(v) }
|
||||||
|
|
||||||
|
type Tsmallp byte
|
||||||
|
|
||||||
|
func (p *Tsmallp) M(x int, b byte) (byte, int) { return b, x+int(*p) }
|
||||||
|
|
||||||
|
type Twordv uintptr
|
||||||
|
|
||||||
|
func (v Twordv) M(x int, b byte) (byte, int) { return b, x+int(v) }
|
||||||
|
|
||||||
|
type Twordp uintptr
|
||||||
|
|
||||||
|
func (p *Twordp) M(x int, b byte) (byte, int) { return b, x+int(*p) }
|
||||||
|
|
||||||
|
type Tbigv [2]uintptr
|
||||||
|
|
||||||
|
func (v Tbigv) M(x int, b byte) (byte, int) { return b, x+int(v[0])+int(v[1]) }
|
||||||
|
|
||||||
|
type Tbigp [2]uintptr
|
||||||
|
|
||||||
|
func (p *Tbigp) M(x int, b byte) (byte, int) { return b, x+int(p[0])+int(p[1]) }
|
||||||
|
|
||||||
|
// Again, with an unexported method.
|
||||||
|
|
||||||
|
type tsmallv byte
|
||||||
|
|
||||||
|
func (v tsmallv) m(x int, b byte) (byte, int) { return b, x+int(v) }
|
||||||
|
|
||||||
|
type tsmallp byte
|
||||||
|
|
||||||
|
func (p *tsmallp) m(x int, b byte) (byte, int) { return b, x+int(*p) }
|
||||||
|
|
||||||
|
type twordv uintptr
|
||||||
|
|
||||||
|
func (v twordv) m(x int, b byte) (byte, int) { return b, x+int(v) }
|
||||||
|
|
||||||
|
type twordp uintptr
|
||||||
|
|
||||||
|
func (p *twordp) m(x int, b byte) (byte, int) { return b, x+int(*p) }
|
||||||
|
|
||||||
|
type tbigv [2]uintptr
|
||||||
|
|
||||||
|
func (v tbigv) m(x int, b byte) (byte, int) { return b, x+int(v[0])+int(v[1]) }
|
||||||
|
|
||||||
|
type tbigp [2]uintptr
|
||||||
|
|
||||||
|
func (p *tbigp) m(x int, b byte) (byte, int) { return b, x+int(p[0])+int(p[1]) }
|
||||||
|
|
||||||
|
type tinter interface {
|
||||||
|
m(int, byte) (byte, int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Embedding via pointer.
|
||||||
|
|
||||||
|
type T1 struct {
|
||||||
|
T2
|
||||||
|
}
|
||||||
|
|
||||||
|
type T2 struct {
|
||||||
|
*T3
|
||||||
|
}
|
||||||
|
|
||||||
|
type T3 struct {
|
||||||
|
*T4
|
||||||
|
}
|
||||||
|
|
||||||
|
type T4 struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t4 T4) M(x int, b byte) (byte, int) { return b, x+40 }
|
||||||
|
|
||||||
|
var failed = false
|
||||||
|
|
||||||
|
func CheckI(name string, i Tinter, inc int) {
|
||||||
|
b, x := i.M(1000, 99)
|
||||||
|
if b != 99 || x != 1000+inc {
|
||||||
|
failed = true
|
||||||
|
print(name, ".M(1000, 99) = ", b, ", ", x, " want 99, ", 1000+inc, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckF("(i="+name+")", i.M, inc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckF(name string, f func(int, byte) (byte, int), inc int) {
|
||||||
|
b, x := f(1000, 99)
|
||||||
|
if b != 99 || x != 1000+inc {
|
||||||
|
failed = true
|
||||||
|
print(name, "(1000, 99) = ", b, ", ", x, " want 99, ", 1000+inc, "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkI(name string, i tinter, inc int) {
|
||||||
|
b, x := i.m(1000, 99)
|
||||||
|
if b != 99 || x != 1000+inc {
|
||||||
|
failed = true
|
||||||
|
print(name, ".m(1000, 99) = ", b, ", ", x, " want 99, ", 1000+inc, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkF("(i="+name+")", i.m, inc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkF(name string, f func(int, byte) (byte, int), inc int) {
|
||||||
|
b, x := f(1000, 99)
|
||||||
|
if b != 99 || x != 1000+inc {
|
||||||
|
failed = true
|
||||||
|
print(name, "(1000, 99) = ", b, ", ", x, " want 99, ", 1000+inc, "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldPanic(f func()) {
|
||||||
|
defer func() {
|
||||||
|
if recover() == nil {
|
||||||
|
panic("not panicking")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldNotPanic(f func()) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sv := Tsmallv(1)
|
||||||
|
CheckI("sv", sv, 1)
|
||||||
|
CheckF("sv.M", sv.M, 1)
|
||||||
|
CheckF("(&sv).M", (&sv).M, 1)
|
||||||
|
psv := &sv
|
||||||
|
CheckI("psv", psv, 1)
|
||||||
|
CheckF("psv.M", psv.M, 1)
|
||||||
|
CheckF("(*psv).M", (*psv).M, 1)
|
||||||
|
|
||||||
|
sp := Tsmallp(2)
|
||||||
|
CheckI("&sp", &sp, 2)
|
||||||
|
CheckF("sp.M", sp.M, 2)
|
||||||
|
CheckF("(&sp).M", (&sp).M, 2)
|
||||||
|
psp := &sp
|
||||||
|
CheckI("psp", psp, 2)
|
||||||
|
CheckF("psp.M", psp.M, 2)
|
||||||
|
CheckF("(*psp).M", (*psp).M, 2)
|
||||||
|
|
||||||
|
wv := Twordv(3)
|
||||||
|
CheckI("wv", wv, 3)
|
||||||
|
CheckF("wv.M", wv.M, 3)
|
||||||
|
CheckF("(&wv).M", (&wv).M, 3)
|
||||||
|
pwv := &wv
|
||||||
|
CheckI("pwv", pwv, 3)
|
||||||
|
CheckF("pwv.M", pwv.M, 3)
|
||||||
|
CheckF("(*pwv).M", (*pwv).M, 3)
|
||||||
|
|
||||||
|
wp := Twordp(4)
|
||||||
|
CheckI("&wp", &wp, 4)
|
||||||
|
CheckF("wp.M", wp.M, 4)
|
||||||
|
CheckF("(&wp).M", (&wp).M, 4)
|
||||||
|
pwp := &wp
|
||||||
|
CheckI("pwp", pwp, 4)
|
||||||
|
CheckF("pwp.M", pwp.M, 4)
|
||||||
|
CheckF("(*pwp).M", (*pwp).M, 4)
|
||||||
|
|
||||||
|
bv := Tbigv([2]uintptr{5, 6})
|
||||||
|
pbv := &bv
|
||||||
|
CheckI("bv", bv, 11)
|
||||||
|
CheckF("bv.M", bv.M, 11)
|
||||||
|
CheckF("(&bv).M", (&bv).M, 11)
|
||||||
|
CheckI("pbv", pbv, 11)
|
||||||
|
CheckF("pbv.M", pbv.M, 11)
|
||||||
|
CheckF("(*pbv).M", (*pbv).M, 11)
|
||||||
|
|
||||||
|
bp := Tbigp([2]uintptr{7,8})
|
||||||
|
CheckI("&bp", &bp, 15)
|
||||||
|
CheckF("bp.M", bp.M, 15)
|
||||||
|
CheckF("(&bp).M", (&bp).M, 15)
|
||||||
|
pbp := &bp
|
||||||
|
CheckI("pbp", pbp, 15)
|
||||||
|
CheckF("pbp.M", pbp.M, 15)
|
||||||
|
CheckF("(*pbp).M", (*pbp).M, 15)
|
||||||
|
|
||||||
|
_sv := tsmallv(1)
|
||||||
|
checkI("_sv", _sv, 1)
|
||||||
|
checkF("_sv.m", _sv.m, 1)
|
||||||
|
checkF("(&_sv).m", (&_sv).m, 1)
|
||||||
|
_psv := &_sv
|
||||||
|
checkI("_psv", _psv, 1)
|
||||||
|
checkF("_psv.m", _psv.m, 1)
|
||||||
|
checkF("(*_psv).m", (*_psv).m, 1)
|
||||||
|
|
||||||
|
_sp := tsmallp(2)
|
||||||
|
checkI("&_sp", &_sp, 2)
|
||||||
|
checkF("_sp.m", _sp.m, 2)
|
||||||
|
checkF("(&_sp).m", (&_sp).m, 2)
|
||||||
|
_psp := &_sp
|
||||||
|
checkI("_psp", _psp, 2)
|
||||||
|
checkF("_psp.m", _psp.m, 2)
|
||||||
|
checkF("(*_psp).m", (*_psp).m, 2)
|
||||||
|
|
||||||
|
_wv := twordv(3)
|
||||||
|
checkI("_wv", _wv, 3)
|
||||||
|
checkF("_wv.m", _wv.m, 3)
|
||||||
|
checkF("(&_wv).m", (&_wv).m, 3)
|
||||||
|
_pwv := &_wv
|
||||||
|
checkI("_pwv", _pwv, 3)
|
||||||
|
checkF("_pwv.m", _pwv.m, 3)
|
||||||
|
checkF("(*_pwv).m", (*_pwv).m, 3)
|
||||||
|
|
||||||
|
_wp := twordp(4)
|
||||||
|
checkI("&_wp", &_wp, 4)
|
||||||
|
checkF("_wp.m", _wp.m, 4)
|
||||||
|
checkF("(&_wp).m", (&_wp).m, 4)
|
||||||
|
_pwp := &_wp
|
||||||
|
checkI("_pwp", _pwp, 4)
|
||||||
|
checkF("_pwp.m", _pwp.m, 4)
|
||||||
|
checkF("(*_pwp).m", (*_pwp).m, 4)
|
||||||
|
|
||||||
|
_bv := tbigv([2]uintptr{5, 6})
|
||||||
|
_pbv := &_bv
|
||||||
|
checkI("_bv", _bv, 11)
|
||||||
|
checkF("_bv.m", _bv.m, 11)
|
||||||
|
checkF("(&_bv).m", (&_bv).m, 11)
|
||||||
|
checkI("_pbv", _pbv, 11)
|
||||||
|
checkF("_pbv.m", _pbv.m, 11)
|
||||||
|
checkF("(*_pbv).m", (*_pbv).m, 11)
|
||||||
|
|
||||||
|
_bp := tbigp([2]uintptr{7,8})
|
||||||
|
checkI("&_bp", &_bp, 15)
|
||||||
|
checkF("_bp.m", _bp.m, 15)
|
||||||
|
checkF("(&_bp).m", (&_bp).m, 15)
|
||||||
|
_pbp := &_bp
|
||||||
|
checkI("_pbp", _pbp, 15)
|
||||||
|
checkF("_pbp.m", _pbp.m, 15)
|
||||||
|
checkF("(*_pbp).m", (*_pbp).m, 15)
|
||||||
|
|
||||||
|
t4 := T4{}
|
||||||
|
t3 := T3{&t4}
|
||||||
|
t2 := T2{&t3}
|
||||||
|
t1 := T1{t2}
|
||||||
|
CheckI("t4", t4, 40)
|
||||||
|
CheckI("&t4", &t4, 40)
|
||||||
|
CheckI("t3", t3, 40)
|
||||||
|
CheckI("&t3", &t3, 40)
|
||||||
|
CheckI("t2", t2, 40)
|
||||||
|
CheckI("&t2", &t2, 40)
|
||||||
|
CheckI("t1", t1, 40)
|
||||||
|
CheckI("&t1", &t1, 40)
|
||||||
|
|
||||||
|
// x.M panics if x is an interface type and is nil,
|
||||||
|
// or if x.M expands to (*x).M where x is nil,
|
||||||
|
// or if x.M expands to x.y.z.w.M where something
|
||||||
|
// along the evaluation of x.y.z.w is nil.
|
||||||
|
var f func(int, byte) (byte, int)
|
||||||
|
shouldPanic(func() { psv = nil; f = psv.M })
|
||||||
|
shouldPanic(func() { pwv = nil; f = pwv.M })
|
||||||
|
shouldPanic(func() { pbv = nil; f = pbv.M })
|
||||||
|
shouldPanic(func() { var i Tinter; f = i.M })
|
||||||
|
shouldPanic(func() { _psv = nil; f = _psv.m })
|
||||||
|
shouldPanic(func() { _pwv = nil; f = _pwv.m })
|
||||||
|
shouldPanic(func() { _pbv = nil; f = _pbv.m })
|
||||||
|
shouldPanic(func() { var _i tinter; f = _i.m })
|
||||||
|
shouldPanic(func() { var t1 T1; f = t1.M })
|
||||||
|
shouldPanic(func() { var t2 T2; f = t2.M })
|
||||||
|
shouldPanic(func() { var t3 *T3; f = t3.M })
|
||||||
|
shouldPanic(func() { var t3 T3; f = t3.M })
|
||||||
|
|
||||||
|
if f != nil {
|
||||||
|
panic("something set f")
|
||||||
|
}
|
||||||
|
|
||||||
|
// x.M does not panic if x is a nil pointer and
|
||||||
|
// M is a method with a pointer receiver.
|
||||||
|
shouldNotPanic(func() { psp = nil; f = psp.M })
|
||||||
|
shouldNotPanic(func() { pwp = nil; f = pwp.M })
|
||||||
|
shouldNotPanic(func() { pbp = nil; f = pbp.M })
|
||||||
|
shouldNotPanic(func() { _psp = nil; f = _psp.m })
|
||||||
|
shouldNotPanic(func() { _pwp = nil; f = _pwp.m })
|
||||||
|
shouldNotPanic(func() { _pbp = nil; f = _pbp.m })
|
||||||
|
shouldNotPanic(func() { var t4 T4; f = t4.M })
|
||||||
|
if f == nil {
|
||||||
|
panic("nothing set f")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user