summaryrefslogtreecommitdiff
path: root/src/cmd/gc/dcl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/dcl.c')
-rw-r--r--src/cmd/gc/dcl.c1254
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;
+}
+
+
+