diff options
Diffstat (limited to 'src/cmd/gc/dcl.c')
-rw-r--r-- | src/cmd/gc/dcl.c | 1254 |
1 files changed, 1254 insertions, 0 deletions
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c new file mode 100644 index 000000000..5bfeeb97a --- /dev/null +++ b/src/cmd/gc/dcl.c @@ -0,0 +1,1254 @@ +// Copyright 2009 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. + +#include "go.h" +#include "y.tab.h" + +static void funcargs(Node*); + +static int +dflag(void) +{ + if(!debug['d']) + return 0; + if(debug['y']) + return 1; + if(incannedimport) + return 0; + return 1; +} + +/* + * declaration stack & operations + */ + +static void +dcopy(Sym *a, Sym *b) +{ + a->pkg = b->pkg; + a->name = b->name; + a->def = b->def; + a->block = b->block; + a->lastlineno = b->lastlineno; +} + +static Sym* +push(void) +{ + Sym *d; + + d = mal(sizeof(*d)); + d->lastlineno = lineno; + d->link = dclstack; + dclstack = d; + return d; +} + +static Sym* +pushdcl(Sym *s) +{ + Sym *d; + + d = push(); + dcopy(d, s); + if(dflag()) + print("\t%L push %S %p\n", lineno, s, s->def); + return d; +} + +void +popdcl(void) +{ + Sym *d, *s; + int lno; + +// if(dflag()) +// print("revert\n"); + + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) + break; + s = pkglookup(d->name, d->pkg); + lno = s->lastlineno; + dcopy(s, d); + d->lastlineno = lno; + if(dflag()) + print("\t%L pop %S %p\n", lineno, s, s->def); + } + if(d == S) + fatal("popdcl: no mark"); + dclstack = d->link; + block = d->block; +} + +void +poptodcl(void) +{ + // pop the old marker and push a new one + // (cannot reuse the existing one) + // because we use the markers to identify blocks + // for the goto restriction checks. + popdcl(); + markdcl(); +} + +void +markdcl(void) +{ + Sym *d; + + d = push(); + d->name = nil; // used as a mark in fifo + d->block = block; + + blockgen++; + block = blockgen; + +// if(dflag()) +// print("markdcl\n"); +} + +void +dumpdcl(char *st) +{ + Sym *s, *d; + int i; + + i = 0; + for(d=dclstack; d!=S; d=d->link) { + i++; + print(" %.2d %p", i, d); + if(d->name == nil) { + print("\n"); + continue; + } + print(" '%s'", d->name); + s = pkglookup(d->name, d->pkg); + print(" %lS\n", s); + } +} + +void +testdclstack(void) +{ + Sym *d; + + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) { + yyerror("mark left on the stack"); + continue; + } + } +} + +void +redeclare(Sym *s, char *where) +{ + if(s->lastlineno == 0) + yyerror("%S redeclared %s\n" + "\tprevious declaration during import", + s, where); + else + yyerror("%S redeclared %s\n" + "\tprevious declaration at %L", + s, where, s->lastlineno); +} + +/* + * declare individual names - var, typ, const + */ +void +declare(Node *n, int ctxt) +{ + Sym *s; + int gen; + static int typegen, vargen; + + if(isblank(n)) + return; + + n->lineno = parserline(); + s = n->sym; + gen = 0; + if(ctxt == PEXTERN) { + externdcl = list(externdcl, n); + if(dflag()) + print("\t%L global decl %S %p\n", lineno, s, n); + } else { + if(curfn == nil && ctxt == PAUTO) + fatal("automatic outside function"); + if(curfn != nil) + curfn->dcl = list(curfn->dcl, n); + if(n->op == OTYPE) + gen = ++typegen; + else if(n->op == ONAME) + gen = ++vargen; + pushdcl(s); + n->curfn = curfn; + } + if(ctxt == PAUTO) + n->xoffset = BADWIDTH; + + if(s->block == block) + redeclare(s, "in this block"); + + s->block = block; + s->lastlineno = parserline(); + s->def = n; + n->vargen = gen; + n->funcdepth = funcdepth; + n->class = ctxt; + + autoexport(n, ctxt); +} + +void +addvar(Node *n, Type *t, int ctxt) +{ + if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T) + fatal("addvar: n=%N t=%T nil", n, t); + + n->op = ONAME; + declare(n, ctxt); + n->type = t; +} + +/* + * declare variables from grammar + * new_name_list (type | [type] = expr_list) + */ +NodeList* +variter(NodeList *vl, Node *t, NodeList *el) +{ + int doexpr; + Node *v, *e, *as2; + NodeList *init; + + init = nil; + doexpr = el != nil; + + if(count(el) == 1 && count(vl) > 1) { + e = el->n; + as2 = nod(OAS2, N, N); + as2->list = vl; + as2->rlist = list1(e); + for(; vl; vl=vl->next) { + v = vl->n; + v->op = ONAME; + declare(v, dclcontext); + v->ntype = t; + v->defn = as2; + if(funcdepth > 0) + init = list(init, nod(ODCL, v, N)); + } + return list(init, as2); + } + + for(; vl; vl=vl->next) { + if(doexpr) { + if(el == nil) { + yyerror("missing expr in var dcl"); + break; + } + e = el->n; + el = el->next; + } else + e = N; + + v = vl->n; + v->op = ONAME; + declare(v, dclcontext); + v->ntype = t; + + if(e != N || funcdepth > 0 || isblank(v)) { + if(funcdepth > 0) + init = list(init, nod(ODCL, v, N)); + e = nod(OAS, v, e); + init = list(init, e); + if(e->right != N) + v->defn = e; + } + } + if(el != nil) + yyerror("extra expr in var dcl"); + return init; +} + +/* + * declare constants from grammar + * new_name_list [[type] = expr_list] + */ +NodeList* +constiter(NodeList *vl, Node *t, NodeList *cl) +{ + Node *v, *c; + NodeList *vv; + + vv = nil; + if(cl == nil) { + if(t != N) + yyerror("constdcl cannot have type without expr"); + cl = lastconst; + t = lasttype; + } else { + lastconst = cl; + lasttype = t; + } + cl = listtreecopy(cl); + + for(; vl; vl=vl->next) { + if(cl == nil) { + yyerror("missing expr in const dcl"); + break; + } + c = cl->n; + cl = cl->next; + + v = vl->n; + v->op = OLITERAL; + declare(v, dclcontext); + + v->ntype = t; + v->defn = c; + + vv = list(vv, nod(ODCLCONST, v, N)); + } + if(cl != nil) + yyerror("extra expr in const dcl"); + iota += 1; + return vv; +} + +/* + * this generates a new name node, + * typically for labels or other one-off names. + */ +Node* +newname(Sym *s) +{ + Node *n; + + if(s == S) + fatal("newname nil"); + + n = nod(ONAME, N, N); + n->sym = s; + n->type = T; + n->addable = 1; + n->ullman = 1; + n->xoffset = 0; + return n; +} + +/* + * this generates a new name node for a name + * being declared. + */ +Node* +dclname(Sym *s) +{ + Node *n; + + n = newname(s); + n->op = ONONAME; // caller will correct it + return n; +} + +Node* +typenod(Type *t) +{ + // if we copied another type with *t = *u + // then t->nod might be out of date, so + // check t->nod->type too + if(t->nod == N || t->nod->type != t) { + t->nod = nod(OTYPE, N, N); + t->nod->type = t; + t->nod->sym = t->sym; + } + return t->nod; +} + + +/* + * this will return an old name + * that has already been pushed on the + * declaration list. a diagnostic is + * generated if no name has been defined. + */ +Node* +oldname(Sym *s) +{ + Node *n; + Node *c; + + n = s->def; + if(n == N) { + // maybe a top-level name will come along + // to give this a definition later. + // walkdef will check s->def again once + // all the input source has been processed. + n = newname(s); + n->op = ONONAME; + n->iota = iota; // save current iota value in const declarations + } + if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) { + // inner func is referring to var in outer func. + // + // TODO(rsc): If there is an outer variable x and we + // are parsing x := 5 inside the closure, until we get to + // the := it looks like a reference to the outer x so we'll + // make x a closure variable unnecessarily. + if(n->closure == N || n->closure->funcdepth != funcdepth) { + // create new closure var. + c = nod(ONAME, N, N); + c->sym = s; + c->class = PPARAMREF; + c->isddd = n->isddd; + c->defn = n; + c->addable = 0; + c->ullman = 2; + c->funcdepth = funcdepth; + c->outer = n->closure; + n->closure = c; + c->closure = n; + c->xoffset = 0; + curfn->cvars = list(curfn->cvars, c); + } + // return ref to closure var, not original + return n->closure; + } + return n; +} + +/* + * same for types + */ +Type* +newtype(Sym *s) +{ + Type *t; + + t = typ(TFORW); + t->sym = s; + t->type = T; + return t; +} + + +/* + * := declarations + */ + +static int +colasname(Node *n) +{ + switch(n->op) { + case ONAME: + case ONONAME: + case OPACK: + case OTYPE: + case OLITERAL: + return n->sym != S; + } + return 0; +} + +void +colasdefn(NodeList *left, Node *defn) +{ + int nnew, nerr; + NodeList *l; + Node *n; + + nnew = 0; + nerr = 0; + for(l=left; l; l=l->next) { + n = l->n; + if(isblank(n)) + continue; + if(!colasname(n)) { + yyerror("non-name %#N on left side of :=", n); + nerr++; + continue; + } + if(n->sym->block == block) + continue; + + nnew++; + n = newname(n->sym); + declare(n, dclcontext); + n->defn = defn; + defn->ninit = list(defn->ninit, nod(ODCL, n, N)); + l->n = n; + } + if(nnew == 0 && nerr == 0) + yyerror("no new variables on left side of :="); +} + +Node* +colas(NodeList *left, NodeList *right) +{ + Node *as; + + as = nod(OAS2, N, N); + as->list = left; + as->rlist = right; + as->colas = 1; + colasdefn(left, as); + + // make the tree prettier; not necessary + if(count(left) == 1 && count(right) == 1) { + as->left = as->list->n; + as->right = as->rlist->n; + as->list = nil; + as->rlist = nil; + as->op = OAS; + } + + return as; +} + +/* + * declare the arguments in an + * interface field declaration. + */ +void +ifacedcl(Node *n) +{ + if(n->op != ODCLFIELD || n->right == N) + fatal("ifacedcl"); + + dclcontext = PAUTO; + markdcl(); + funcdepth++; + n->outer = curfn; + curfn = n; + funcargs(n->right); + + // funcbody is normally called after the parser has + // seen the body of a function but since an interface + // field declaration does not have a body, we must + // call it now to pop the current declaration context. + funcbody(n); +} + +/* + * declare the function proper + * and declare the arguments. + * called in extern-declaration context + * returns in auto-declaration context. + */ +void +funchdr(Node *n) +{ + + if(n->nname != N) { + n->nname->op = ONAME; + declare(n->nname, PFUNC); + n->nname->defn = n; + } + + // change the declaration context from extern to auto + if(funcdepth == 0 && dclcontext != PEXTERN) + fatal("funchdr: dclcontext"); + + dclcontext = PAUTO; + markdcl(); + funcdepth++; + + n->outer = curfn; + curfn = n; + if(n->nname) + funcargs(n->nname->ntype); + else + funcargs(n->ntype); +} + +static void +funcargs(Node *nt) +{ + Node *n; + NodeList *l; + int gen; + + if(nt->op != OTFUNC) + fatal("funcargs %O", nt->op); + + // declare the receiver and in arguments. + // no n->defn because type checking of func header + // will fill in the types before we can demand them. + if(nt->left != N) { + n = nt->left; + if(n->op != ODCLFIELD) + fatal("funcargs1 %O", n->op); + if(n->left != N) { + n->left->op = ONAME; + n->left->ntype = n->right; + declare(n->left, PPARAM); + } + } + for(l=nt->list; l; l=l->next) { + n = l->n; + if(n->op != ODCLFIELD) + fatal("funcargs2 %O", n->op); + if(n->left != N) { + n->left->op = ONAME; + n->left->ntype = n->right; + declare(n->left, PPARAM); + } + } + + // declare the out arguments. + gen = 0; + for(l=nt->rlist; l; l=l->next) { + n = l->n; + if(n->op != ODCLFIELD) + fatal("funcargs3 %O", n->op); + if(n->left != N) { + n->left->op = ONAME; + n->left->ntype = n->right; + if(isblank(n->left)) { + // Give it a name so we can assign to it during return. + snprint(namebuf, sizeof(namebuf), ".anon%d", gen++); + n->left->sym = lookup(namebuf); + } + declare(n->left, PPARAMOUT); + } + } +} + +/* + * finish the body. + * called in auto-declaration context. + * returns in extern-declaration context. + */ +void +funcbody(Node *n) +{ + // change the declaration context from auto to extern + if(dclcontext != PAUTO) + fatal("funcbody: dclcontext"); + popdcl(); + funcdepth--; + curfn = n->outer; + n->outer = N; + if(funcdepth == 0) + dclcontext = PEXTERN; +} + +/* + * new type being defined with name s. + */ +Node* +typedcl0(Sym *s) +{ + Node *n; + + n = dclname(s); + n->op = OTYPE; + declare(n, dclcontext); + return n; +} + +/* + * node n, which was returned by typedcl0 + * is being declared to have uncompiled type t. + * return the ODCLTYPE node to use. + */ +Node* +typedcl1(Node *n, Node *t, int local) +{ + n->ntype = t; + n->local = local; + return nod(ODCLTYPE, n, N); +} + +/* + * typedcl1 but during imports + */ +void +typedcl2(Type *pt, Type *t) +{ + Node *n; + + // override declaration in unsafe.go for Pointer. + // there is no way in Go code to define unsafe.Pointer + // so we have to supply it. + if(incannedimport && + strcmp(importpkg->name, "unsafe") == 0 && + strcmp(pt->nod->sym->name, "Pointer") == 0) { + t = types[TUNSAFEPTR]; + } + + if(pt->etype == TFORW) + goto ok; + if(!eqtype(pt->orig, t)) + yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t); + return; + +ok: + n = pt->nod; + copytype(pt->nod, t); + // unzero nod + pt->nod = n; + + pt->sym->lastlineno = parserline(); + declare(n, PEXTERN); + + checkwidth(pt); +} + +/* + * structs, functions, and methods. + * they don't belong here, but where do they belong? + */ + + +/* + * turn a parsed struct into a type + */ +static Type** +stotype(NodeList *l, int et, Type **t, int funarg) +{ + Type *f, *t1, *t2, **t0; + Strlit *note; + int lno; + Node *n, *left; + char *what; + + t0 = t; + lno = lineno; + what = "field"; + if(et == TINTER) + what = "method"; + + for(; l; l=l->next) { + n = l->n; + lineno = n->lineno; + note = nil; + + if(n->op != ODCLFIELD) + fatal("stotype: oops %N\n", n); + left = n->left; + if(funarg && isblank(left)) + left = N; + if(n->right != N) { + if(et == TINTER && left != N) { + // queue resolution of method type for later. + // right now all we need is the name list. + // avoids cycles for recursive interface types. + n->type = typ(TINTERMETH); + n->type->nname = n->right; + n->right = N; + left->type = n->type; + queuemethod(n); + } else { + typecheck(&n->right, Etype); + n->type = n->right->type; + if(n->type == T) + continue; + if(left != N) + left->type = n->type; + n->right = N; + if(n->embedded && n->type != T) { + t1 = n->type; + if(t1->sym == S && isptr[t1->etype]) { + t1 = t1->type; + if(t1->etype == TINTER) + yyerror("embedded type cannot be a pointer to interface"); + } + if(isptr[t1->etype]) + yyerror("embedded type cannot be a pointer"); + else if(t1->etype == TFORW && t1->embedlineno == 0) + t1->embedlineno = lineno; + } + } + } + + if(n->type == T) { + // assume error already printed + continue; + } + + switch(n->val.ctype) { + case CTSTR: + if(et != TSTRUCT) + yyerror("interface method cannot have annotation"); + note = n->val.u.sval; + break; + default: + if(et != TSTRUCT) + yyerror("interface method cannot have annotation"); + else + yyerror("field annotation must be string"); + case CTxxx: + note = nil; + break; + } + + if(et == TINTER && left == N) { + // embedded interface - inline the methods + if(n->type->etype != TINTER) { + if(n->type->etype == TFORW) + yyerror("interface type loop involving %T", n->type); + else + yyerror("interface contains embedded non-interface %T", n->type); + continue; + } + for(t1=n->type->type; t1!=T; t1=t1->down) { + f = typ(TFIELD); + f->type = t1->type; + f->width = BADWIDTH; + f->nname = newname(t1->sym); + f->sym = t1->sym; + for(t2=*t0; t2!=T; t2=t2->down) { + if(t2->sym == f->sym) { + yyerror("duplicate method %s", t2->sym->name); + break; + } + } + *t = f; + t = &f->down; + } + continue; + } + + f = typ(TFIELD); + f->type = n->type; + f->note = note; + f->width = BADWIDTH; + f->isddd = n->isddd; + + if(left != N && left->op == ONAME) { + f->nname = left; + f->embedded = n->embedded; + f->sym = f->nname->sym; + if(importpkg && !exportname(f->sym->name)) + f->sym = pkglookup(f->sym->name, structpkg); + if(f->sym && !isblank(f->nname)) { + for(t1=*t0; t1!=T; t1=t1->down) { + if(t1->sym == f->sym) { + yyerror("duplicate %s %s", what, t1->sym->name); + break; + } + } + } + } + + *t = f; + t = &f->down; + } + + *t = T; + lineno = lno; + return t; +} + +Type* +dostruct(NodeList *l, int et) +{ + Type *t; + int funarg; + + /* + * convert a parsed id/type list into + * a type for struct/interface/arglist + */ + + funarg = 0; + if(et == TFUNC) { + funarg = 1; + et = TSTRUCT; + } + t = typ(et); + t->funarg = funarg; + stotype(l, et, &t->type, funarg); + if(t->type == T && l != nil) { + t->broke = 1; + return t; + } + if(et == TINTER) + t = sortinter(t); + if(!funarg) + checkwidth(t); + return t; +} + + +Node* +embedded(Sym *s) +{ + Node *n; + char *name; + + // Names sometimes have disambiguation junk + // appended after a center dot. Discard it when + // making the name for the embedded struct field. + enum { CenterDot = 0xB7 }; + name = s->name; + if(utfrune(s->name, CenterDot)) { + name = strdup(s->name); + *utfrune(name, CenterDot) = 0; + } + + n = newname(lookup(name)); + n = nod(ODCLFIELD, n, oldname(s)); + n->embedded = 1; + return n; +} + +/* + * check that the list of declarations is either all anonymous or all named + */ + +static Node* +findtype(NodeList *l) +{ + for(; l; l=l->next) + if(l->n->op == OKEY) + return l->n->right; + return N; +} + +NodeList* +checkarglist(NodeList *all, int input) +{ + int named; + Node *n, *t, *nextt; + NodeList *l; + + named = 0; + for(l=all; l; l=l->next) { + if(l->n->op == OKEY) { + named = 1; + break; + } + } + if(named) { + n = N; + for(l=all; l; l=l->next) { + n = l->n; + if(n->op != OKEY && n->sym == S) { + yyerror("mixed named and unnamed function parameters"); + break; + } + } + if(l == nil && n != N && n->op != OKEY) + yyerror("final function parameter must have type"); + } + + nextt = nil; + for(l=all; l; l=l->next) { + // can cache result from findtype to avoid + // quadratic behavior here, but unlikely to matter. + n = l->n; + if(named) { + if(n->op == OKEY) { + t = n->right; + n = n->left; + nextt = nil; + } else { + if(nextt == nil) + nextt = findtype(l); + t = nextt; + } + } else { + t = n; + n = N; + } + if(n != N && n->sym == S) { + t = n; + n = N; + } + if(n != N) + n = newname(n->sym); + n = nod(ODCLFIELD, n, t); + if(n->right != N && n->right->op == ODDD) { + if(!input) + yyerror("cannot use ... in output argument list"); + else if(l->next != nil) + yyerror("can only use ... as final argument in list"); + n->right->op = OTARRAY; + n->right->right = n->right->left; + n->right->left = N; + n->isddd = 1; + if(n->left != N) + n->left->isddd = 1; + } + l->n = n; + } + return all; +} + + +Node* +fakethis(void) +{ + Node *n; + + n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT)))); + return n; +} + +/* + * Is this field a method on an interface? + * Those methods have an anonymous + * *struct{} as the receiver. + * (See fakethis above.) + */ +int +isifacemethod(Type *f) +{ + Type *rcvr; + Type *t; + + rcvr = getthisx(f)->type; + if(rcvr->sym != S) + return 0; + t = rcvr->type; + if(!isptr[t->etype]) + return 0; + t = t->type; + if(t->sym != S || t->etype != TSTRUCT || t->type != T) + return 0; + return 1; +} + +/* + * turn a parsed function declaration + * into a type + */ +Type* +functype(Node *this, NodeList *in, NodeList *out) +{ + Type *t; + NodeList *rcvr; + + t = typ(TFUNC); + + rcvr = nil; + if(this) + rcvr = list1(this); + t->type = dostruct(rcvr, TFUNC); + t->type->down = dostruct(out, TFUNC); + t->type->down->down = dostruct(in, TFUNC); + + if(this) + t->thistuple = 1; + t->outtuple = count(out); + t->intuple = count(in); + t->outnamed = t->outtuple > 0 && out->n->left != N; + + return t; +} + +Sym* +methodsym(Sym *nsym, Type *t0, int iface) +{ + Sym *s; + char *p; + Type *t; + char *suffix; + + t = t0; + if(t == T) + goto bad; + s = t->sym; + if(s == S) { + if(!isptr[t->etype]) + goto bad; + t = t->type; + if(t == T) + goto bad; + s = t->sym; + if(s == S) + goto bad; + } + + // if t0 == *t and t0 has a sym, + // we want to see *t, not t0, in the method name. + if(t != t0 && t0->sym) + t0 = ptrto(t); + + suffix = ""; + if(iface) { + dowidth(t0); + if(t0->width < types[tptr]->width) + suffix = "·i"; + } + if(t0->sym == S && isptr[t0->etype]) + p = smprint("(%#hT).%s%s", t0, nsym->name, suffix); + else + p = smprint("%#hT.%s%s", t0, nsym->name, suffix); + s = pkglookup(p, s->pkg); + free(p); + return s; + +bad: + yyerror("illegal receiver type: %T", t0); + return S; +} + +Node* +methodname(Node *n, Type *t) +{ + Sym *s; + + s = methodsym(n->sym, t, 0); + if(s == S) + return n; + return newname(s); +} + +Node* +methodname1(Node *n, Node *t) +{ + char *star; + char *p; + + star = nil; + if(t->op == OIND) { + star = "*"; + t = t->left; + } + if(t->sym == S || isblank(n)) + return newname(n->sym); + if(star) + p = smprint("(%s%S).%S", star, t->sym, n->sym); + else + p = smprint("%S.%S", t->sym, n->sym); + n = newname(pkglookup(p, t->sym->pkg)); + free(p); + return n; +} + +/* + * add a method, declared as a function, + * n is fieldname, pa is base type, t is function type + */ +void +addmethod(Sym *sf, Type *t, int local) +{ + Type *f, *d, *pa; + Node *n; + + pa = nil; + + // get field sym + if(sf == S) + fatal("no method symbol"); + + // get parent type sym + pa = getthisx(t)->type; // ptr to this structure + if(pa == T) { + yyerror("missing receiver"); + return; + } + + pa = pa->type; + f = methtype(pa); + if(f == T) { + t = pa; + if(t != T) { + if(isptr[t->etype]) { + if(t->sym != S) { + yyerror("invalid receiver type %T (%T is a pointer type)", pa, t); + return; + } + t = t->type; + } + } + if(t != T) { + if(t->sym == S) { + yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t); + return; + } + if(isptr[t->etype]) { + yyerror("invalid receiver type %T (%T is a pointer type)", pa, t); + return; + } + if(t->etype == TINTER) { + yyerror("invalid receiver type %T (%T is an interface type)", pa, t); + return; + } + } + // Should have picked off all the reasons above, + // but just in case, fall back to generic error. + yyerror("invalid receiver type %T", pa); + return; + } + + pa = f; + if(importpkg && !exportname(sf->name)) + sf = pkglookup(sf->name, importpkg); + + n = nod(ODCLFIELD, newname(sf), N); + n->type = t; + + d = T; // last found + for(f=pa->method; f!=T; f=f->down) { + d = f; + if(f->etype != TFIELD) + fatal("addmethod: not TFIELD: %N", f); + if(strcmp(sf->name, f->sym->name) != 0) + continue; + if(!eqtype(t, f->type)) + yyerror("method redeclared: %T.%S\n\t%T\n\t%T", pa, sf, f->type, t); + return; + } + + if(local && !pa->local) { + // defining method on non-local type. + yyerror("cannot define new methods on non-local type %T", pa); + return; + } + + if(d == T) + stotype(list1(n), 0, &pa->method, 0); + else + stotype(list1(n), 0, &d->down, 0); + return; +} + +void +funccompile(Node *n, int isclosure) +{ + stksize = BADWIDTH; + maxarg = 0; + + if(n->type == T) { + if(nerrors == 0) + fatal("funccompile missing type"); + return; + } + + // assign parameter offsets + checkwidth(n->type); + + // record offset to actual frame pointer. + // for closure, have to skip over leading pointers and PC slot. + nodfp->xoffset = 0; + if(isclosure) { + NodeList *l; + for(l=n->nname->ntype->list; l; l=l->next) { + nodfp->xoffset += widthptr; + if(l->n->left == N) // found slot for PC + break; + } + } + + if(curfn) + fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym); + + stksize = 0; + dclcontext = PAUTO; + funcdepth = n->funcdepth + 1; + compile(n); + curfn = nil; + funcdepth = 0; + dclcontext = PEXTERN; +} + + + |