root/src/cmd/gc/dcl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dflag
  2. dcopy
  3. push
  4. pushdcl
  5. popdcl
  6. poptodcl
  7. markdcl
  8. dumpdcl
  9. testdclstack
  10. redeclare
  11. declare
  12. addvar
  13. variter
  14. constiter
  15. newname
  16. dclname
  17. typenod
  18. oldname
  19. colasname
  20. colasdefn
  21. colas
  22. ifacedcl
  23. funchdr
  24. funcargs
  25. funcargs2
  26. funcbody
  27. typedcl0
  28. typedcl1
  29. checkembeddedtype
  30. structfield
  31. checkdupfields
  32. tostruct
  33. tofunargs
  34. interfacefield
  35. tointerface
  36. embedded
  37. findtype
  38. checkarglist
  39. fakethis
  40. isifacemethod
  41. functype
  42. methodsym
  43. methodname
  44. methodname1
  45. addmethod
  46. funccompile
  47. funcsym

// 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        <u.h>
#include        <libc.h>
#include        "go.h"
#include        "y.tab.h"

static  void    funcargs(Node*);
static  void    funcargs2(Type*);

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;

        USED(st);

        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(" %S\n", s);
        }
}

void
testdclstack(void)
{
        Sym *d;

        for(d=dclstack; d!=S; d=d->link) {
                if(d->name == nil) {
                        if(nerrors != 0)
                                errorexit();
                        yyerror("mark left on the stack");
                        continue;
                }
        }
}

void
redeclare(Sym *s, char *where)
{
        Strlit *pkgstr;
        int line1, line2;

        if(s->lastlineno == 0) {
                pkgstr = s->origpkg ? s->origpkg->path : s->pkg->path;
                yyerror("%S redeclared %s\n"
                        "\tprevious declaration during import \"%Z\"",
                        s, where, pkgstr);
        } else {
                line1 = parserline();
                line2 = s->lastlineno;
                
                // When an import and a declaration collide in separate files,
                // present the import as the "redeclared", because the declaration
                // is visible where the import is, but not vice versa.
                // See issue 4510.
                if(s->def == N) {
                        line2 = line1;
                        line1 = s->lastlineno;
                }

                yyerrorl(line1, "%S redeclared %s\n"
                        "\tprevious declaration at %L",
                        s, where, line2);
        }
}

static int vargen;

/*
 * declare individual names - var, typ, const
 */
void
declare(Node *n, int ctxt)
{
        Sym *s;
        int gen;
        static int typegen;
        
        if(ctxt == PDISCARD)
                return;

        if(isblank(n))
                return;

        n->lineno = parserline();
        s = n->sym;

        // kludgy: typecheckok means we're past parsing.  Eg genwrapper may declare out of package names later.
        if(importpkg == nil && !typecheckok && s->pkg != localpkg)
                yyerror("cannot declare name %S", s);

        if(ctxt == PEXTERN && strcmp(s->name, "init") == 0)
                yyerror("cannot declare init - must be func", s);

        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 && ctxt == PAUTO && strstr(s->name, "·") == nil)
                        gen = ++vargen;
                pushdcl(s);
                n->curfn = curfn;
        }
        if(ctxt == PAUTO)
                n->xoffset = 0;

        if(s->block == block) {
                // functype will print errors about duplicate function arguments.
                // Don't repeat the error here.
                if(ctxt != PPARAM && ctxt != PPARAMOUT)
                        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 expression in var declaration");
                                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 expression in var declaration");
        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("const declaration cannot have type without expression");
                cl = lastconst;
                t = lasttype;
        } else {
                lastconst = cl;
                lasttype = t;
        }
        cl = listtreecopy(cl);

        for(; vl; vl=vl->next) {
                if(cl == nil) {
                        yyerror("missing value in const declaration");
                        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 expression in const declaration");
        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;
                        n->addrtaken = 1;
                        c->closure = n;
                        c->xoffset = 0;
                        curfn->cvars = list(curfn->cvars, c);
                }
                // return ref to closure var, not original
                return n->closure;
        }
        return n;
}

/*
 * := 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)) {
                        yyerrorl(defn->lineno, "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)
                yyerrorl(defn->lineno, "no new variables on left side of :=");
}

Node*
colas(NodeList *left, NodeList *right, int32 lno)
{
        Node *as;

        as = nod(OAS2, N, N);
        as->list = left;
        as->rlist = right;
        as->colas = 1;
        as->lineno = lno;
        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 = PPARAM;
        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.
        dclcontext = PAUTO;
        funcbody(n);
}

/*
 * declare the function proper
 * and declare the arguments.
 * called in extern-declaration context
 * returns in auto-declaration context.
 */
void
funchdr(Node *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 if (n->ntype)
                funcargs(n->ntype);
        else
                funcargs2(n->type);
}

static void
funcargs(Node *nt)
{
        Node *n, *nn;
        NodeList *l;
        int gen;

        if(nt->op != OTFUNC)
                fatal("funcargs %O", nt->op);

        // re-start the variable generation number
        // we want to use small numbers for the return variables,
        // so let them have the chunk starting at 1.
        vargen = count(nt->rlist);

        // declare the receiver and in arguments.
        // no n->defn because type checking of func header
        // will not fill in the types until later
        if(nt->left != N) {
                n = nt->left;
                if(n->op != ODCLFIELD)
                        fatal("funcargs receiver %O", n->op);
                if(n->left != N) {
                        n->left->op = ONAME;
                        n->left->ntype = n->right;
                        declare(n->left, PPARAM);
                        if(dclcontext == PAUTO)
                                n->left->vargen = ++vargen;
                }
        }
        for(l=nt->list; l; l=l->next) {
                n = l->n;
                if(n->op != ODCLFIELD)
                        fatal("funcargs in %O", n->op);
                if(n->left != N) {
                        n->left->op = ONAME;
                        n->left->ntype = n->right;
                        declare(n->left, PPARAM);
                        if(dclcontext == PAUTO)
                                n->left->vargen = ++vargen;
                }
        }

        // declare the out arguments.
        gen = count(nt->list);
        int i = 0;
        for(l=nt->rlist; l; l=l->next) {
                n = l->n;

                if(n->op != ODCLFIELD)
                        fatal("funcargs out %O", n->op);

                if(n->left == N) {
                        // Name so that escape analysis can track it. ~r stands for 'result'.
                        snprint(namebuf, sizeof(namebuf), "~r%d", gen++);
                        n->left = newname(lookup(namebuf));
                        // TODO: n->left->missing = 1;
                } 

                n->left->op = ONAME;

                if(isblank(n->left)) {
                        // Give it a name so we can assign to it during return. ~b stands for 'blank'.
                        // The name must be different from ~r above because if you have
                        //      func f() (_ int)
                        //      func g() int
                        // f is allowed to use a plain 'return' with no arguments, while g is not.
                        // So the two cases must be distinguished.
                        // We do not record a pointer to the original node (n->orig).
                        // Having multiple names causes too much confusion in later passes.
                        nn = nod(OXXX, N, N);
                        *nn = *n->left;
                        nn->orig = nn;
                        snprint(namebuf, sizeof(namebuf), "~b%d", gen++);
                        nn->sym = lookup(namebuf);
                        n->left = nn;
                }

                n->left->ntype = n->right;
                declare(n->left, PPARAMOUT);
                if(dclcontext == PAUTO)
                        n->left->vargen = ++i;
        }
}

/*
 * Same as funcargs, except run over an already constructed TFUNC.
 * This happens during import, where the hidden_fndcl rule has
 * used functype directly to parse the function's type.
 */
static void
funcargs2(Type *t)
{
        Type *ft;
        Node *n;

        if(t->etype != TFUNC)
                fatal("funcargs2 %T", t);
        
        if(t->thistuple)
                for(ft=getthisx(t)->type; ft; ft=ft->down) {
                        if(!ft->nname || !ft->nname->sym)
                                continue;
                        n = ft->nname;  // no need for newname(ft->nname->sym)
                        n->type = ft->type;
                        declare(n, PPARAM);
                }

        if(t->intuple)
                for(ft=getinargx(t)->type; ft; ft=ft->down) {
                        if(!ft->nname || !ft->nname->sym)
                                continue;
                        n = ft->nname;
                        n->type = ft->type;
                        declare(n, PPARAM);
                }

        if(t->outtuple)
                for(ft=getoutargx(t)->type; ft; ft=ft->down) {
                        if(!ft->nname || !ft->nname->sym)
                                continue;
                        n = ft->nname;
                        n->type = ft->type;
                        declare(n, 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 = newname(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);
}

/*
 * structs, functions, and methods.
 * they don't belong here, but where do they belong?
 */

static void
checkembeddedtype(Type *t)
{
        if (t == T)
                return;

        if(t->sym == S && isptr[t->etype]) {
                t = t->type;
                if(t->etype == TINTER)
                        yyerror("embedded type cannot be a pointer to interface");
        }
        if(isptr[t->etype])
                yyerror("embedded type cannot be a pointer");
        else if(t->etype == TFORW && t->embedlineno == 0)
                t->embedlineno = lineno;
}

static Type*
structfield(Node *n)
{
        Type *f;
        int lno;

        lno = lineno;
        lineno = n->lineno;

        if(n->op != ODCLFIELD)
                fatal("structfield: oops %N\n", n);

        f = typ(TFIELD);
        f->isddd = n->isddd;

        if(n->right != N) {
                typecheck(&n->right, Etype);
                n->type = n->right->type;
                if(n->left != N)
                        n->left->type = n->type;
                if(n->embedded)
                        checkembeddedtype(n->type);
        }
        n->right = N;
                
        f->type = n->type;
        if(f->type == T)
                f->broke = 1;

        switch(n->val.ctype) {
        case CTSTR:
                f->note = n->val.u.sval;
                break;
        default:
                yyerror("field annotation must be string");
                // fallthrough
        case CTxxx:
                f->note = nil;
                break;
        }

        if(n->left && n->left->op == ONAME) {
                f->nname = n->left;
                f->embedded = n->embedded;
                f->sym = f->nname->sym;
        }

        lineno = lno;
        return f;
}

static uint32 uniqgen;

static void
checkdupfields(Type *t, char* what)
{
        int lno;

        lno = lineno;

        for( ; t; t=t->down) {
                if(t->sym && t->nname && !isblank(t->nname)) {
                        if(t->sym->uniqgen == uniqgen) {
                                lineno = t->nname->lineno;
                                yyerror("duplicate %s %s", what, t->sym->name);
                        } else
                                t->sym->uniqgen = uniqgen;
                }
        }

        lineno = lno;
}

/*
 * convert a parsed id/type list into
 * a type for struct/interface/arglist
 */
Type*
tostruct(NodeList *l)
{
        Type *t, *f, **tp;
        t = typ(TSTRUCT);

        for(tp = &t->type; l; l=l->next) {
                f = structfield(l->n);

                *tp = f;
                tp = &f->down;
        }

        for(f=t->type; f && !t->broke; f=f->down)
                if(f->broke)
                        t->broke = 1;

        uniqgen++;
        checkdupfields(t->type, "field");

        if (!t->broke)
                checkwidth(t);

        return t;
}

static Type*
tofunargs(NodeList *l)
{
        Type *t, *f, **tp;

        t = typ(TSTRUCT);
        t->funarg = 1;

        for(tp = &t->type; l; l=l->next) {
                f = structfield(l->n);
                f->funarg = 1;

                // esc.c needs to find f given a PPARAM to add the tag.
                if(l->n->left && l->n->left->class == PPARAM)
                        l->n->left->paramfld = f;

                *tp = f;
                tp = &f->down;
        }

        for(f=t->type; f && !t->broke; f=f->down)
                if(f->broke)
                        t->broke = 1;

        return t;
}

static Type*
interfacefield(Node *n)
{
        Type *f;
        int lno;

        lno = lineno;
        lineno = n->lineno;

        if(n->op != ODCLFIELD)
                fatal("interfacefield: oops %N\n", n);

        if (n->val.ctype != CTxxx)
                yyerror("interface method cannot have annotation");

        f = typ(TFIELD);
        f->isddd = n->isddd;
        
        if(n->right != N) {
                if(n->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->left->type = n->type;
                        queuemethod(n);

                        if(n->left->op == ONAME) {
                                f->nname = n->left;
                                f->embedded = n->embedded;
                                f->sym = f->nname->sym;
                        }

                } else {

                        typecheck(&n->right, Etype);
                        n->type = n->right->type;

                        if(n->embedded)
                                checkembeddedtype(n->type);

                        if(n->type)
                                switch(n->type->etype) {
                                case TINTER:
                                        break;
                                case TFORW:
                                        yyerror("interface type loop involving %T", n->type);
                                        f->broke = 1;
                                        break;
                                default:
                                        yyerror("interface contains embedded non-interface %T", n->type);
                                        f->broke = 1;
                                        break;
                                }
                }
        }

        n->right = N;
        
        f->type = n->type;
        if(f->type == T)
                f->broke = 1;
        
        lineno = lno;
        return f;
}

Type*
tointerface(NodeList *l)
{
        Type *t, *f, **tp, *t1;

        t = typ(TINTER);

        tp = &t->type;
        for(; l; l=l->next) {
                f = interfacefield(l->n);

                if (l->n->left == N && f->type->etype == TINTER) {
                        // embedded interface, inline methods
                        for(t1=f->type->type; t1; t1=t1->down) {
                                f = typ(TFIELD);
                                f->type = t1->type;
                                f->broke = t1->broke;
                                f->sym = t1->sym;
                                if(f->sym)
                                        f->nname = newname(f->sym);
                                *tp = f;
                                tp = &f->down;
                        }
                } else {
                        *tp = f;
                        tp = &f->down;
                }
        }

        for(f=t->type; f && !t->broke; f=f->down)
                if(f->broke)
                        t->broke = 1;

        uniqgen++;
        checkdupfields(t->type, "method");
        t = sortinter(t);
        checkwidth(t);

        return t;
}

Node*
embedded(Sym *s, Pkg *pkg)
{
        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;
        }

        if(exportname(name))
                n = newname(lookup(name));
        else if(s->pkg == builtinpkg)
                // The name of embedded builtins belongs to pkg.
                n = newname(pkglookup(name, pkg));
        else
                n = newname(pkglookup(name, s->pkg));
        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;
                }

                // during import l->n->op is OKEY, but l->n->left->sym == S
                // means it was a '?', not that it was
                // a lone type This doesn't matter for the exported
                // declarations, which are parsed by rules that don't
                // use checkargs, but can happen for func literals in
                // the inline bodies.
                // TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
                if(importpkg && n->sym == S)
                        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;
        Sym *s;

        t = typ(TFUNC);

        rcvr = nil;
        if(this)
                rcvr = list1(this);
        t->type = tofunargs(rcvr);
        t->type->down = tofunargs(out);
        t->type->down->down = tofunargs(in);

        uniqgen++;
        checkdupfields(t->type->type, "argument");
        checkdupfields(t->type->down->type, "argument");
        checkdupfields(t->type->down->down->type, "argument");

        if (t->type->broke || t->type->down->broke || t->type->down->down->broke)
                t->broke = 1;

        if(this)
                t->thistuple = 1;
        t->outtuple = count(out);
        t->intuple = count(in);
        t->outnamed = 0;
        if(t->outtuple > 0 && out->n->left != N && out->n->left->orig != N) {
                s = out->n->left->orig->sym;
                if(s != S && (s->name[0] != '~' || s->name[1] != 'r')) // ~r%d is the name invented for an unnamed result
                        t->outnamed = 1;
        }

        return t;
}

Sym*
methodsym(Sym *nsym, Type *t0, int iface)
{
        Sym *s;
        char *p;
        Type *t;
        char *suffix;
        Pkg *spkg;
        static Pkg *toppkg;

        t = t0;
        if(t == T)
                goto bad;
        s = t->sym;
        if(s == S && isptr[t->etype]) {
                t = t->type;
                if(t == T)
                        goto bad;
                s = t->sym;
        }
        spkg = nil;
        if(s != S)
                spkg = s->pkg;

        // 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((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) {
                if(t0->sym == S && isptr[t0->etype])
                        p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
                else
                        p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
        } else {
                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);
        }
        if(spkg == nil) {
                if(toppkg == nil)
                        toppkg = mkpkg(strlit("go"));
                spkg = toppkg;
        }
        s = pkglookup(p, spkg);
        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);

        if(exportname(t->sym->name))
                n = newname(lookup(p));
        else
                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, int nointerface)
{
        Type *f, *d, *pa;
        Node *n;

        // 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, 1);
        if(f == T) {
                t = pa;
                if(t == T) // rely on typecheck having complained before
                        return;
                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->broke) // rely on typecheck having complained before
                                return;
                        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 (%lT / %lT)", pa, pa, t);
                return;
        }

        pa = f;
        if(pa->etype == TSTRUCT) {
                for(f=pa->type; f; f=f->down) {
                        if(f->sym == sf) {
                                yyerror("type %T has both field and method named %S", pa, sf);
                                return;
                        }
                }
        }

        if(local && !pa->local) {
                // defining method on non-local type.
                yyerror("cannot define new methods on non-local type %T", pa);
                return;
        }

        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;
        }

        f = structfield(n);
        f->nointerface = nointerface;

        // during import unexported method names should be in the type's package
        if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)
                fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name);

        if(d == T)
                pa->method = f;
        else
                d->down = f;
        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.
        // TODO(rsc): this is the old jit closure handling code.
        // with the new closures, isclosure is always 0; delete this block.
        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;
}

Sym*
funcsym(Sym *s)
{
        char *p;
        Sym *s1;
        
        p = smprint("%s·f", s->name);
        s1 = pkglookup(p, s->pkg);
        free(p);
        if(s1->def == N) {
                s1->def = newname(s1);
                s1->def->shortname = newname(s);
                funcsyms = list(funcsyms, s1->def);
        }
        return s1;
}

/* [<][>][^][v][top][bottom][index][help] */