root/src/cmd/gc/subr.c

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

DEFINITIONS

This source file includes following definitions.
  1. errorexit
  2. parserline
  3. adderr
  4. errcmp
  5. flusherrors
  6. hcrash
  7. yyerrorl
  8. yyerror
  9. warn
  10. warnl
  11. fatal
  12. linehist
  13. setlineno
  14. stringhash
  15. lookup
  16. pkglookup
  17. restrictlookup
  18. importdot
  19. gethunk
  20. mal
  21. remal
  22. nod
  23. saveorignode
  24. ispaddedfield
  25. algtype1
  26. algtype
  27. maptype
  28. typ
  29. methcmp
  30. sortinter
  31. nodintconst
  32. nodfltconst
  33. nodconst
  34. nodnil
  35. nodbool
  36. aindex
  37. treecopy
  38. isnil
  39. isptrto
  40. istype
  41. isfixedarray
  42. isslice
  43. isblank
  44. isblanksym
  45. isinter
  46. isnilinter
  47. isideal
  48. methtype
  49. cplxsubtype
  50. eqnote
  51. onlist
  52. eqtype
  53. eqtype1
  54. eqtypenoname
  55. assignop
  56. convertop
  57. assignconv
  58. subtype
  59. is64
  60. noconv
  61. argtype
  62. shallow
  63. deep
  64. syslook
  65. typehash
  66. ptrto
  67. frame
  68. ullmancalc
  69. badtype
  70. structfirst
  71. structnext
  72. funcfirst
  73. funcnext
  74. getthis
  75. getoutarg
  76. getinarg
  77. getthisx
  78. getoutargx
  79. getinargx
  80. brcom
  81. brrev
  82. safeexpr
  83. copyexpr
  84. cheapexpr
  85. localexpr
  86. setmaxarg
  87. ucistrcmp
  88. lookdot0
  89. adddot1
  90. adddot
  91. expand0
  92. expand1
  93. expandmeth
  94. structargs
  95. genwrapper
  96. hashmem
  97. hashfor
  98. genhash
  99. eqfield
  100. eqmemfunc
  101. eqmem
  102. geneq
  103. ifacelookdot
  104. implements
  105. simsimtype
  106. concat
  107. list1
  108. list
  109. listsort
  110. listtreecopy
  111. liststmt
  112. count
  113. structcount
  114. powtwo
  115. tounsigned
  116. smagic
  117. umagic
  118. ngotype
  119. pathtoprefix
  120. mkpkg
  121. strlit
  122. addinit
  123. isbadimport
  124. checknil

// 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        "md5.h"
#include        "y.tab.h"
#include        "yerr.h"

typedef struct Error Error;
struct Error
{
        int lineno;
        int seq;
        char *msg;
};
static Error *err;
static int nerr;
static int merr;

void
errorexit(void)
{
        flusherrors();
        if(outfile)
                remove(outfile);
        exits("error");
}

extern int yychar;
int
parserline(void)
{
        if(yychar != 0 && yychar != -2) // parser has one symbol lookahead
                return prevlineno;
        return lineno;
}

static void
adderr(int line, char *fmt, va_list arg)
{
        Fmt f;
        Error *p;

        fmtstrinit(&f);
        fmtprint(&f, "%L: ", line);
        fmtvprint(&f, fmt, arg);
        fmtprint(&f, "\n");

        if(nerr >= merr) {
                if(merr == 0)
                        merr = 16;
                else
                        merr *= 2;
                p = realloc(err, merr*sizeof err[0]);
                if(p == nil) {
                        merr = nerr;
                        flusherrors();
                        print("out of memory\n");
                        errorexit();
                }
                err = p;
        }
        err[nerr].seq = nerr;
        err[nerr].lineno = line;
        err[nerr].msg = fmtstrflush(&f);
        nerr++;
}

static int
errcmp(const void *va, const void *vb)
{
        Error *a, *b;

        a = (Error*)va;
        b = (Error*)vb;
        if(a->lineno != b->lineno)
                return a->lineno - b->lineno;
        if(a->seq != b->seq)
                return a->seq - b->seq;
        return strcmp(a->msg, b->msg);
}

void
flusherrors(void)
{
        int i;

        Bflush(&bstdout);
        if(nerr == 0)
                return;
        qsort(err, nerr, sizeof err[0], errcmp);
        for(i=0; i<nerr; i++)
                if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0)
                        print("%s", err[i].msg);
        nerr = 0;
}

static void
hcrash(void)
{
        if(debug['h']) {
                flusherrors();
                if(outfile)
                        remove(outfile);
                *(volatile int*)0 = 0;
        }
}

void
yyerrorl(int line, char *fmt, ...)
{
        va_list arg;

        va_start(arg, fmt);
        adderr(line, fmt, arg);
        va_end(arg);

        hcrash();
        nerrors++;
        if(nsavederrors+nerrors >= 10 && !debug['e']) {
                flusherrors();
                print("%L: too many errors\n", line);
                errorexit();
        }
}

extern int yystate, yychar;

void
yyerror(char *fmt, ...)
{
        int i;
        static int lastsyntax;
        va_list arg;
        char buf[512], *p;

        if(strncmp(fmt, "syntax error", 12) == 0) {
                nsyntaxerrors++;
                
                if(debug['x'])  
                        print("yyerror: yystate=%d yychar=%d\n", yystate, yychar);

                // An unexpected EOF caused a syntax error. Use the previous
                // line number since getc generated a fake newline character.
                if(curio.eofnl)
                        lexlineno = prevlineno;

                // only one syntax error per line
                if(lastsyntax == lexlineno)
                        return;
                lastsyntax = lexlineno;
                        
                if(strstr(fmt, "{ or {") || strstr(fmt, " or ?") || strstr(fmt, " or @")) {
                        // The grammar has { and LBRACE but both show up as {.
                        // Rewrite syntax error referring to "{ or {" to say just "{".
                        strecpy(buf, buf+sizeof buf, fmt);
                        p = strstr(buf, "{ or {");
                        if(p)
                                memmove(p+1, p+6, strlen(p+6)+1);
                        
                        // The grammar has ? and @ but only for reading imports.
                        // Silence them in ordinary errors.
                        p = strstr(buf, " or ?");
                        if(p)
                                memmove(p, p+5, strlen(p+5)+1);
                        p = strstr(buf, " or @");
                        if(p)
                                memmove(p, p+5, strlen(p+5)+1);
                        fmt = buf;
                }
                
                // look for parse state-specific errors in list (see go.errors).
                for(i=0; i<nelem(yymsg); i++) {
                        if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) {
                                yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg);
                                return;
                        }
                }
                
                // plain "syntax error" gets "near foo" added
                if(strcmp(fmt, "syntax error") == 0) {
                        yyerrorl(lexlineno, "syntax error near %s", lexbuf);
                        return;
                }
                
                // if bison says "syntax error, more info"; print "syntax error: more info".
                if(fmt[12] == ',') {
                        yyerrorl(lexlineno, "syntax error:%s", fmt+13);
                        return;
                }

                yyerrorl(lexlineno, "%s", fmt);
                return;
        }

        va_start(arg, fmt);
        adderr(parserline(), fmt, arg);
        va_end(arg);

        hcrash();
        nerrors++;
        if(nsavederrors+nerrors >= 10 && !debug['e']) {
                flusherrors();
                print("%L: too many errors\n", parserline());
                errorexit();
        }
}

void
warn(char *fmt, ...)
{
        va_list arg;

        va_start(arg, fmt);
        adderr(parserline(), fmt, arg);
        va_end(arg);

        hcrash();
}

void
warnl(int line, char *fmt, ...)
{
        va_list arg;

        va_start(arg, fmt);
        adderr(line, fmt, arg);
        va_end(arg);
        if(debug['m'])
                flusherrors();
}

void
fatal(char *fmt, ...)
{
        va_list arg;

        flusherrors();

        print("%L: internal compiler error: ", lineno);
        va_start(arg, fmt);
        vfprint(1, fmt, arg);
        va_end(arg);
        print("\n");
        
        // If this is a released compiler version, ask for a bug report.
        if(strncmp(getgoversion(), "release", 7) == 0) {
                print("\n");
                print("Please file a bug report including a short program that triggers the error.\n");
                print("http://code.google.com/p/go/issues/entry?template=compilerbug\n");
        }
        hcrash();
        errorexit();
}

void
linehist(char *file, int32 off, int relative)
{
        if(debug['i']) {
                if(file != nil) {
                        if(off < 0)
                                print("pragma %s", file);
                        else
                        if(off > 0)
                                print("line %s", file);
                        else
                                print("import %s", file);
                } else
                        print("end of import");
                print(" at line %L\n", lexlineno);
        }
        
        if(off < 0 && file[0] != '/' && !relative)
                file = smprint("%s/%s", ctxt->pathname, file);
        linklinehist(ctxt, lexlineno, file, off);
}

int32
setlineno(Node *n)
{
        int32 lno;

        lno = lineno;
        if(n != N)
        switch(n->op) {
        case ONAME:
        case OTYPE:
        case OPACK:
        case OLITERAL:
                break;
        default:
                lineno = n->lineno;
                if(lineno == 0) {
                        if(debug['K'])
                                warn("setlineno: line 0");
                        lineno = lno;
                }
        }
        return lno;
}

uint32
stringhash(char *p)
{
        uint32 h;
        int c;

        h = 0;
        for(;;) {
                c = *p++;
                if(c == 0)
                        break;
                h = h*PRIME1 + c;
        }

        if((int32)h < 0) {
                h = -h;
                if((int32)h < 0)
                        h = 0;
        }
        return h;
}

Sym*
lookup(char *name)
{
        return pkglookup(name, localpkg);
}

Sym*
pkglookup(char *name, Pkg *pkg)
{
        Sym *s;
        uint32 h;
        int c;

        h = stringhash(name) % NHASH;
        c = name[0];
        for(s = hash[h]; s != S; s = s->link) {
                if(s->name[0] != c || s->pkg != pkg)
                        continue;
                if(strcmp(s->name, name) == 0)
                        return s;
        }

        s = mal(sizeof(*s));
        s->name = mal(strlen(name)+1);
        strcpy(s->name, name);

        s->pkg = pkg;

        s->link = hash[h];
        hash[h] = s;
        s->lexical = LNAME;

        return s;
}

Sym*
restrictlookup(char *name, Pkg *pkg)
{
        if(!exportname(name) && pkg != localpkg)
                yyerror("cannot refer to unexported name %s.%s", pkg->name, name);
        return pkglookup(name, pkg);
}


// find all the exported symbols in package opkg
// and make them available in the current package
void
importdot(Pkg *opkg, Node *pack)
{
        Sym *s, *s1;
        uint32 h;
        int n;
        char *pkgerror;

        n = 0;
        for(h=0; h<NHASH; h++) {
                for(s = hash[h]; s != S; s = s->link) {
                        if(s->pkg != opkg)
                                continue;
                        if(s->def == N)
                                continue;
                        if(!exportname(s->name) || utfrune(s->name, 0xb7))      // 0xb7 = center dot
                                continue;
                        s1 = lookup(s->name);
                        if(s1->def != N) {
                                pkgerror = smprint("during import \"%Z\"", opkg->path);
                                redeclare(s1, pkgerror);
                                continue;
                        }
                        s1->def = s->def;
                        s1->block = s->block;
                        s1->def->pack = pack;
                        s1->origpkg = opkg;
                        n++;
                }
        }
        if(n == 0) {
                // can't possibly be used - there were no symbols
                yyerrorl(pack->lineno, "imported and not used: \"%Z\"", opkg->path);
        }
}

static void
gethunk(void)
{
        char *h;
        int32 nh;

        nh = NHUNK;
        if(thunk >= 10L*NHUNK)
                nh = 10L*NHUNK;
        h = (char*)malloc(nh);
        if(h == nil) {
                flusherrors();
                yyerror("out of memory");
                errorexit();
        }
        hunk = h;
        nhunk = nh;
        thunk += nh;
}

void*
mal(int32 n)
{
        void *p;

        if(n >= NHUNK) {
                p = malloc(n);
                if(p == nil) {
                        flusherrors();
                        yyerror("out of memory");
                        errorexit();
                }
                memset(p, 0, n);
                return p;
        }

        while((uintptr)hunk & MAXALIGN) {
                hunk++;
                nhunk--;
        }
        if(nhunk < n)
                gethunk();

        p = hunk;
        nhunk -= n;
        hunk += n;
        memset(p, 0, n);
        return p;
}

void*
remal(void *p, int32 on, int32 n)
{
        void *q;

        q = (uchar*)p + on;
        if(q != hunk || nhunk < n) {
                if(on+n >= NHUNK) {
                        q = mal(on+n);
                        memmove(q, p, on);
                        return q;
                }
                if(nhunk < on+n)
                        gethunk();
                memmove(hunk, p, on);
                p = hunk;
                hunk += on;
                nhunk -= on;
        }
        hunk += n;
        nhunk -= n;
        return p;
}

Node*
nod(int op, Node *nleft, Node *nright)
{
        Node *n;

        n = mal(sizeof(*n));
        n->op = op;
        n->left = nleft;
        n->right = nright;
        n->lineno = parserline();
        n->xoffset = BADWIDTH;
        n->orig = n;
        n->curfn = curfn;
        return n;
}

void
saveorignode(Node *n)
{
        Node *norig;

        if(n->orig != N)
                return;
        norig = nod(n->op, N, N);
        *norig = *n;
        n->orig = norig;
}

// ispaddedfield reports whether the given field
// is followed by padding. For the case where t is
// the last field, total gives the size of the enclosing struct.
static int
ispaddedfield(Type *t, vlong total)
{
        if(t->etype != TFIELD)
                fatal("ispaddedfield called non-field %T", t);
        if(t->down == T)
                return t->width + t->type->width != total;
        return t->width + t->type->width != t->down->width;
}

int
algtype1(Type *t, Type **bad)
{
        int a, ret;
        Type *t1;
        
        if(bad)
                *bad = T;

        if(t->noalg)
                return ANOEQ;

        switch(t->etype) {
        case TANY:
        case TFORW:
                // will be defined later.
                *bad = t;
                return -1;

        case TINT8:
        case TUINT8:
        case TINT16:
        case TUINT16:
        case TINT32:
        case TUINT32:
        case TINT64:
        case TUINT64:
        case TINT:
        case TUINT:
        case TUINTPTR:
        case TBOOL:
        case TPTR32:
        case TPTR64:
        case TCHAN:
        case TUNSAFEPTR:
                return AMEM;

        case TFUNC:
        case TMAP:
                if(bad)
                        *bad = t;
                return ANOEQ;

        case TFLOAT32:
                return AFLOAT32;

        case TFLOAT64:
                return AFLOAT64;

        case TCOMPLEX64:
                return ACPLX64;

        case TCOMPLEX128:
                return ACPLX128;

        case TSTRING:
                return ASTRING;
        
        case TINTER:
                if(isnilinter(t))
                        return ANILINTER;
                return AINTER;
        
        case TARRAY:
                if(isslice(t)) {
                        if(bad)
                                *bad = t;
                        return ANOEQ;
                }
                a = algtype1(t->type, bad);
                if(a == ANOEQ || a == AMEM) {
                        if(a == ANOEQ && bad)
                                *bad = t;
                        return a;
                }
                return -1;  // needs special compare

        case TSTRUCT:
                if(t->type != T && t->type->down == T && !isblanksym(t->type->sym)) {
                        // One-field struct is same as that one field alone.
                        return algtype1(t->type->type, bad);
                }
                ret = AMEM;
                for(t1=t->type; t1!=T; t1=t1->down) {
                        // All fields must be comparable.
                        a = algtype1(t1->type, bad);
                        if(a == ANOEQ)
                                return ANOEQ;

                        // Blank fields, padded fields, fields with non-memory
                        // equality need special compare.
                        if(a != AMEM || isblanksym(t1->sym) || ispaddedfield(t1, t->width)) {
                                ret = -1;
                                continue;
                        }
                }
                return ret;
        }

        fatal("algtype1: unexpected type %T", t);
        return 0;
}

int
algtype(Type *t)
{
        int a;
        
        a = algtype1(t, nil);
        if(a == AMEM || a == ANOEQ) {
                if(isslice(t))
                        return ASLICE;
                switch(t->width) {
                case 0:
                        return a + AMEM0 - AMEM;
                case 1:
                        return a + AMEM8 - AMEM;
                case 2:
                        return a + AMEM16 - AMEM;
                case 4:
                        return a + AMEM32 - AMEM;
                case 8:
                        return a + AMEM64 - AMEM;
                case 16:
                        return a + AMEM128 - AMEM;
                }
        }
        return a;
}

Type*
maptype(Type *key, Type *val)
{
        Type *t;
        Type *bad;
        int atype;

        if(key != nil) {
                atype = algtype1(key, &bad);
                switch(bad == T ? key->etype : bad->etype) {
                default:
                        if(atype == ANOEQ)
                                yyerror("invalid map key type %T", key);
                        break;
                case TANY:
                        // will be resolved later.
                        break;
                case TFORW:
                        // map[key] used during definition of key.
                        // postpone check until key is fully defined.
                        // if there are multiple uses of map[key]
                        // before key is fully defined, the error
                        // will only be printed for the first one.
                        // good enough.
                        if(key->maplineno == 0)
                                key->maplineno = lineno;
                        break;
                }
        }
        t = typ(TMAP);
        t->down = key;
        t->type = val;
        return t;
}

Type*
typ(int et)
{
        Type *t;

        t = mal(sizeof(*t));
        t->etype = et;
        t->width = BADWIDTH;
        t->lineno = lineno;
        t->orig = t;
        return t;
}

static int
methcmp(const void *va, const void *vb)
{
        Type *a, *b;
        int i;
        
        a = *(Type**)va;
        b = *(Type**)vb;
        if(a->sym == S && b->sym == S)
                return 0;
        if(a->sym == S)
                return -1;
        if(b->sym == S)
                return 1;
        i = strcmp(a->sym->name, b->sym->name);
        if(i != 0)
                return i;
        if(!exportname(a->sym->name)) {
                i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
                if(i != 0)
                        return i;
        }
        return 0;
}

Type*
sortinter(Type *t)
{
        Type *f;
        int i;
        Type **a;
        
        if(t->type == nil || t->type->down == nil)
                return t;

        i=0;
        for(f=t->type; f; f=f->down)
                i++;
        a = mal(i*sizeof f);
        i = 0;
        for(f=t->type; f; f=f->down)
                a[i++] = f;
        qsort(a, i, sizeof a[0], methcmp);
        while(i-- > 0) {
                a[i]->down = f;
                f = a[i];
        }
        t->type = f;
        return t;
}

Node*
nodintconst(int64 v)
{
        Node *c;

        c = nod(OLITERAL, N, N);
        c->addable = 1;
        c->val.u.xval = mal(sizeof(*c->val.u.xval));
        mpmovecfix(c->val.u.xval, v);
        c->val.ctype = CTINT;
        c->type = types[TIDEAL];
        ullmancalc(c);
        return c;
}

Node*
nodfltconst(Mpflt* v)
{
        Node *c;

        c = nod(OLITERAL, N, N);
        c->addable = 1;
        c->val.u.fval = mal(sizeof(*c->val.u.fval));
        mpmovefltflt(c->val.u.fval, v);
        c->val.ctype = CTFLT;
        c->type = types[TIDEAL];
        ullmancalc(c);
        return c;
}

void
nodconst(Node *n, Type *t, int64 v)
{
        memset(n, 0, sizeof(*n));
        n->op = OLITERAL;
        n->addable = 1;
        ullmancalc(n);
        n->val.u.xval = mal(sizeof(*n->val.u.xval));
        mpmovecfix(n->val.u.xval, v);
        n->val.ctype = CTINT;
        n->type = t;

        if(isfloat[t->etype])
                fatal("nodconst: bad type %T", t);
}

Node*
nodnil(void)
{
        Node *c;

        c = nodintconst(0);
        c->val.ctype = CTNIL;
        c->type = types[TNIL];
        return c;
}

Node*
nodbool(int b)
{
        Node *c;

        c = nodintconst(0);
        c->val.ctype = CTBOOL;
        c->val.u.bval = b;
        c->type = idealbool;
        return c;
}

Type*
aindex(Node *b, Type *t)
{
        Type *r;
        int64 bound;

        bound = -1;     // open bound
        typecheck(&b, Erv);
        if(b != nil) {
                switch(consttype(b)) {
                default:
                        yyerror("array bound must be an integer expression");
                        break;
                case CTINT:
                case CTRUNE:
                        bound = mpgetfix(b->val.u.xval);
                        if(bound < 0)
                                yyerror("array bound must be non negative");
                        break;
                }
        }

        // fixed array
        r = typ(TARRAY);
        r->type = t;
        r->bound = bound;
        return r;
}

Node*
treecopy(Node *n)
{
        Node *m;

        if(n == N)
                return N;

        switch(n->op) {
        default:
                m = nod(OXXX, N, N);
                *m = *n;
                m->orig = m;
                m->left = treecopy(n->left);
                m->right = treecopy(n->right);
                m->list = listtreecopy(n->list);
                if(m->defn)
                        abort();
                break;

        case ONONAME:
                if(n->sym == lookup("iota")) {
                        // Not sure yet whether this is the real iota,
                        // but make a copy of the Node* just in case,
                        // so that all the copies of this const definition
                        // don't have the same iota value.
                        m = nod(OXXX, N, N);
                        *m = *n;
                        m->iota = iota;
                        break;
                }
                // fall through
        case ONAME:
        case OLITERAL:
        case OTYPE:
                m = n;
                break;
        }
        return m;
}


int
isnil(Node *n)
{
        if(n == N)
                return 0;
        if(n->op != OLITERAL)
                return 0;
        if(n->val.ctype != CTNIL)
                return 0;
        return 1;
}

int
isptrto(Type *t, int et)
{
        if(t == T)
                return 0;
        if(!isptr[t->etype])
                return 0;
        t = t->type;
        if(t == T)
                return 0;
        if(t->etype != et)
                return 0;
        return 1;
}

int
istype(Type *t, int et)
{
        return t != T && t->etype == et;
}

int
isfixedarray(Type *t)
{
        return t != T && t->etype == TARRAY && t->bound >= 0;
}

int
isslice(Type *t)
{
        return t != T && t->etype == TARRAY && t->bound < 0;
}

int
isblank(Node *n)
{
        if(n == N)
                return 0;
        return isblanksym(n->sym);
}

int
isblanksym(Sym *s)
{
        char *p;

        if(s == S)
                return 0;
        p = s->name;
        if(p == nil)
                return 0;
        return p[0] == '_' && p[1] == '\0';
}

int
isinter(Type *t)
{
        return t != T && t->etype == TINTER;
}

int
isnilinter(Type *t)
{
        if(!isinter(t))
                return 0;
        if(t->type != T)
                return 0;
        return 1;
}

int
isideal(Type *t)
{
        if(t == T)
                return 0;
        if(t == idealstring || t == idealbool)
                return 1;
        switch(t->etype) {
        case TNIL:
        case TIDEAL:
                return 1;
        }
        return 0;
}

/*
 * given receiver of type t (t == r or t == *r)
 * return type to hang methods off (r).
 */
Type*
methtype(Type *t, int mustname)
{
        if(t == T)
                return T;

        // strip away pointer if it's there
        if(isptr[t->etype]) {
                if(t->sym != S)
                        return T;
                t = t->type;
                if(t == T)
                        return T;
        }

        // need a type name
        if(t->sym == S && (mustname || t->etype != TSTRUCT))
                return T;

        // check types
        if(!issimple[t->etype])
        switch(t->etype) {
        default:
                return T;
        case TSTRUCT:
        case TARRAY:
        case TMAP:
        case TCHAN:
        case TSTRING:
        case TFUNC:
                break;
        }

        return t;
}

int
cplxsubtype(int et)
{
        switch(et) {
        case TCOMPLEX64:
                return TFLOAT32;
        case TCOMPLEX128:
                return TFLOAT64;
        }
        fatal("cplxsubtype: %E\n", et);
        return 0;
}

static int
eqnote(Strlit *a, Strlit *b)
{
        if(a == b)
                return 1;
        if(a == nil || b == nil)
                return 0;
        if(a->len != b->len)
                return 0;
        return memcmp(a->s, b->s, a->len) == 0;
}

typedef struct TypePairList TypePairList;
struct TypePairList
{
        Type *t1;
        Type *t2;
        TypePairList *next;
};

static int
onlist(TypePairList *l, Type *t1, Type *t2) 
{
        for(; l; l=l->next)
                if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1))
                        return 1;
        return 0;
}

static int eqtype1(Type*, Type*, TypePairList*);

// Return 1 if t1 and t2 are identical, following the spec rules.
//
// Any cyclic type must go through a named type, and if one is
// named, it is only identical to the other if they are the same
// pointer (t1 == t2), so there's no chance of chasing cycles
// ad infinitum, so no need for a depth counter.
int
eqtype(Type *t1, Type *t2)
{
        return eqtype1(t1, t2, nil);
}

static int
eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal)
{
        TypePairList l;

        if(t1 == t2)
                return 1;
        if(t1 == T || t2 == T || t1->etype != t2->etype)
                return 0;
        if(t1->sym || t2->sym) {
                // Special case: we keep byte and uint8 separate
                // for error messages.  Treat them as equal.
                switch(t1->etype) {
                case TUINT8:
                        if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype))
                                return 1;
                        break;
                case TINT:
                case TINT32:
                        if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype))
                                return 1;
                        break;
                }
                return 0;
        }

        if(onlist(assumed_equal, t1, t2))
                return 1;
        l.next = assumed_equal;
        l.t1 = t1;
        l.t2 = t2;

        switch(t1->etype) {
        case TINTER:
        case TSTRUCT:
                for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
                        if(t1->etype != TFIELD || t2->etype != TFIELD)
                                fatal("struct/interface missing field: %T %T", t1, t2);
                        if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note))
                                goto no;
                }
                if(t1 == T && t2 == T)
                        goto yes;
                goto no;

        case TFUNC:
                // Loop over structs: receiver, in, out.
                for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
                        Type *ta, *tb;

                        if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
                                fatal("func missing struct: %T %T", t1, t2);

                        // Loop over fields in structs, ignoring argument names.
                        for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
                                if(ta->etype != TFIELD || tb->etype != TFIELD)
                                        fatal("func struct missing field: %T %T", ta, tb);
                                if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l))
                                        goto no;
                        }
                        if(ta != T || tb != T)
                                goto no;
                }
                if(t1 == T && t2 == T)
                        goto yes;
                goto no;
        
        case TARRAY:
                if(t1->bound != t2->bound)
                        goto no;
                break;
        
        case TCHAN:
                if(t1->chan != t2->chan)
                        goto no;
                break;
        }

        if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l))
                goto yes;
        goto no;

yes:
        return 1;

no:
        return 0;
}

// Are t1 and t2 equal struct types when field names are ignored?
// For deciding whether the result struct from g can be copied
// directly when compiling f(g()).
int
eqtypenoname(Type *t1, Type *t2)
{
        if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
                return 0;

        t1 = t1->type;
        t2 = t2->type;
        for(;;) {
                if(!eqtype(t1, t2))
                        return 0;
                if(t1 == T)
                        return 1;
                t1 = t1->down;
                t2 = t2->down;
        }
}

// Is type src assignment compatible to type dst?
// If so, return op code to use in conversion.
// If not, return 0.
int
assignop(Type *src, Type *dst, char **why)
{
        Type *missing, *have;
        int ptr;

        if(why != nil)
                *why = "";

        // TODO(rsc,lvd): This behaves poorly in the presence of inlining.
        // https://code.google.com/p/go/issues/detail?id=2795
        if(safemode && importpkg == nil && src != T && src->etype == TUNSAFEPTR) {
                yyerror("cannot use unsafe.Pointer");
                errorexit();
        }

        if(src == dst)
                return OCONVNOP;
        if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
                return 0;

        // 1. src type is identical to dst.
        if(eqtype(src, dst))
                return OCONVNOP;
        
        // 2. src and dst have identical underlying types
        // and either src or dst is not a named type or
        // both are empty interface types.
        // For assignable but different non-empty interface types,
        // we want to recompute the itab.
        if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || isnilinter(src)))
                return OCONVNOP;

        // 3. dst is an interface type and src implements dst.
        if(dst->etype == TINTER && src->etype != TNIL) {
                if(implements(src, dst, &missing, &have, &ptr))
                        return OCONVIFACE;

                // we'll have complained about this method anyway, suppress spurious messages.
                if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke))
                        return OCONVIFACE;

                if(why != nil) {
                        if(isptrto(src, TINTER))
                                *why = smprint(":\n\t%T is pointer to interface, not interface", src);
                        else if(have && have->sym == missing->sym && have->nointerface)
                                *why = smprint(":\n\t%T does not implement %T (%S method is marked 'nointerface')",
                                        src, dst, missing->sym);
                        else if(have && have->sym == missing->sym)
                                *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
                                        "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
                                        have->sym, have->type, missing->sym, missing->type);
                        else if(ptr)
                                *why = smprint(":\n\t%T does not implement %T (%S method has pointer receiver)",
                                        src, dst, missing->sym);
                        else if(have)
                                *why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
                                        "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
                                        have->sym, have->type, missing->sym, missing->type);
                        else
                                *why = smprint(":\n\t%T does not implement %T (missing %S method)",
                                        src, dst, missing->sym);
                }
                return 0;
        }
        if(isptrto(dst, TINTER)) {
                if(why != nil)
                        *why = smprint(":\n\t%T is pointer to interface, not interface", dst);
                return 0;
        }
        if(src->etype == TINTER && dst->etype != TBLANK) {
                if(why != nil && implements(dst, src, &missing, &have, &ptr))
                        *why = ": need type assertion";
                return 0;
        }

        // 4. src is a bidirectional channel value, dst is a channel type,
        // src and dst have identical element types, and
        // either src or dst is not a named type.
        if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
        if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
                return OCONVNOP;

        // 5. src is the predeclared identifier nil and dst is a nillable type.
        if(src->etype == TNIL) {
                switch(dst->etype) {
                case TARRAY:
                        if(dst->bound != -100)  // not slice
                                break;
                case TPTR32:
                case TPTR64:
                case TFUNC:
                case TMAP:
                case TCHAN:
                case TINTER:
                        return OCONVNOP;
                }
        }

        // 6. rule about untyped constants - already converted by defaultlit.
        
        // 7. Any typed value can be assigned to the blank identifier.
        if(dst->etype == TBLANK)
                return OCONVNOP;

        return 0;
}

// Can we convert a value of type src to a value of type dst?
// If so, return op code to use in conversion (maybe OCONVNOP).
// If not, return 0.
int
convertop(Type *src, Type *dst, char **why)
{
        int op;
        
        if(why != nil)
                *why = "";

        if(src == dst)
                return OCONVNOP;
        if(src == T || dst == T)
                return 0;
        
        // 1. src can be assigned to dst.
        if((op = assignop(src, dst, why)) != 0)
                return op;

        // The rules for interfaces are no different in conversions
        // than assignments.  If interfaces are involved, stop now
        // with the good message from assignop.
        // Otherwise clear the error.
        if(src->etype == TINTER || dst->etype == TINTER)
                return 0;
        if(why != nil)
                *why = "";

        // 2. src and dst have identical underlying types.
        if(eqtype(src->orig, dst->orig))
                return OCONVNOP;
        
        // 3. src and dst are unnamed pointer types 
        // and their base types have identical underlying types.
        if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
        if(eqtype(src->type->orig, dst->type->orig))
                return OCONVNOP;

        // 4. src and dst are both integer or floating point types.
        if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
                if(simtype[src->etype] == simtype[dst->etype])
                        return OCONVNOP;
                return OCONV;
        }

        // 5. src and dst are both complex types.
        if(iscomplex[src->etype] && iscomplex[dst->etype]) {
                if(simtype[src->etype] == simtype[dst->etype])
                        return OCONVNOP;
                return OCONV;
        }

        // 6. src is an integer or has type []byte or []rune
        // and dst is a string type.
        if(isint[src->etype] && dst->etype == TSTRING)
                return ORUNESTR;

        if(isslice(src) && dst->etype == TSTRING) {
                if(src->type->etype == bytetype->etype)
                        return OARRAYBYTESTR;
                if(src->type->etype == runetype->etype)
                        return OARRAYRUNESTR;
        }
        
        // 7. src is a string and dst is []byte or []rune.
        // String to slice.
        if(src->etype == TSTRING && isslice(dst)) {
                if(dst->type->etype == bytetype->etype)
                        return OSTRARRAYBYTE;
                if(dst->type->etype == runetype->etype)
                        return OSTRARRAYRUNE;
        }
        
        // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
        if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR)
                return OCONVNOP;

        // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
        if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR))
                return OCONVNOP;

        return 0;
}

// Convert node n for assignment to type t.
Node*
assignconv(Node *n, Type *t, char *context)
{
        int op;
        Node *r, *old;
        char *why;
        
        if(n == N || n->type == T || n->type->broke)
                return n;

        if(t->etype == TBLANK && n->type->etype == TNIL)
                yyerror("use of untyped nil");

        old = n;
        old->diag++;  // silence errors about n; we'll issue one below
        defaultlit(&n, t);
        old->diag--;
        if(t->etype == TBLANK)
                return n;

        // Convert ideal bool from comparison to plain bool
        // if the next step is non-bool (like interface{}).
        if(n->type == idealbool && t->etype != TBOOL) {
                if(n->op == ONAME || n->op == OLITERAL) {
                        r = nod(OCONVNOP, n, N);
                        r->type = types[TBOOL];
                        r->typecheck = 1;
                        r->implicit = 1;
                        n = r;
                }
        }

        if(eqtype(n->type, t))
                return n;

        op = assignop(n->type, t, &why);
        if(op == 0) {
                yyerror("cannot use %lN as type %T in %s%s", n, t, context, why);
                op = OCONV;
        }

        r = nod(op, n, N);
        r->type = t;
        r->typecheck = 1;
        r->implicit = 1;
        r->orig = n->orig;
        return r;
}

static int
subtype(Type **stp, Type *t, int d)
{
        Type *st;

loop:
        st = *stp;
        if(st == T)
                return 0;

        d++;
        if(d >= 10)
                return 0;

        switch(st->etype) {
        default:
                return 0;

        case TPTR32:
        case TPTR64:
        case TCHAN:
        case TARRAY:
                stp = &st->type;
                goto loop;

        case TANY:
                if(!st->copyany)
                        return 0;
                *stp = t;
                break;

        case TMAP:
                if(subtype(&st->down, t, d))
                        break;
                stp = &st->type;
                goto loop;

        case TFUNC:
                for(;;) {
                        if(subtype(&st->type, t, d))
                                break;
                        if(subtype(&st->type->down->down, t, d))
                                break;
                        if(subtype(&st->type->down, t, d))
                                break;
                        return 0;
                }
                break;

        case TSTRUCT:
                for(st=st->type; st!=T; st=st->down)
                        if(subtype(&st->type, t, d))
                                return 1;
                return 0;
        }
        return 1;
}

/*
 * Is this a 64-bit type?
 */
int
is64(Type *t)
{
        if(t == T)
                return 0;
        switch(simtype[t->etype]) {
        case TINT64:
        case TUINT64:
        case TPTR64:
                return 1;
        }
        return 0;
}

/*
 * Is a conversion between t1 and t2 a no-op?
 */
int
noconv(Type *t1, Type *t2)
{
        int e1, e2;

        e1 = simtype[t1->etype];
        e2 = simtype[t2->etype];

        switch(e1) {
        case TINT8:
        case TUINT8:
                return e2 == TINT8 || e2 == TUINT8;

        case TINT16:
        case TUINT16:
                return e2 == TINT16 || e2 == TUINT16;

        case TINT32:
        case TUINT32:
        case TPTR32:
                return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32;

        case TINT64:
        case TUINT64:
        case TPTR64:
                return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64;

        case TFLOAT32:
                return e2 == TFLOAT32;

        case TFLOAT64:
                return e2 == TFLOAT64;
        }
        return 0;
}

void
argtype(Node *on, Type *t)
{
        dowidth(t);
        if(!subtype(&on->type, t, 0))
                fatal("argtype: failed %N %T\n", on, t);
}

Type*
shallow(Type *t)
{
        Type *nt;

        if(t == T)
                return T;
        nt = typ(0);
        *nt = *t;
        if(t->orig == t)
                nt->orig = nt;
        return nt;
}

static Type*
deep(Type *t)
{
        Type *nt, *xt;

        if(t == T)
                return T;

        switch(t->etype) {
        default:
                nt = t; // share from here down
                break;

        case TANY:
                nt = shallow(t);
                nt->copyany = 1;
                break;

        case TPTR32:
        case TPTR64:
        case TCHAN:
        case TARRAY:
                nt = shallow(t);
                nt->type = deep(t->type);
                break;

        case TMAP:
                nt = shallow(t);
                nt->down = deep(t->down);
                nt->type = deep(t->type);
                break;

        case TFUNC:
                nt = shallow(t);
                nt->type = deep(t->type);
                nt->type->down = deep(t->type->down);
                nt->type->down->down = deep(t->type->down->down);
                break;

        case TSTRUCT:
                nt = shallow(t);
                nt->type = shallow(t->type);
                xt = nt->type;

                for(t=t->type; t!=T; t=t->down) {
                        xt->type = deep(t->type);
                        xt->down = shallow(t->down);
                        xt = xt->down;
                }
                break;
        }
        return nt;
}

Node*
syslook(char *name, int copy)
{
        Sym *s;
        Node *n;

        s = pkglookup(name, runtimepkg);
        if(s == S || s->def == N)
                fatal("syslook: can't find runtime.%s", name);

        if(!copy)
                return s->def;

        n = nod(0, N, N);
        *n = *s->def;
        n->type = deep(s->def->type);

        return n;
}

/*
 * compute a hash value for type t.
 * if t is a method type, ignore the receiver
 * so that the hash can be used in interface checks.
 * %T already contains
 * all the necessary logic to generate a representation
 * of the type that completely describes it.
 * using smprint here avoids duplicating that code.
 * using md5 here is overkill, but i got tired of
 * accidental collisions making the runtime think
 * two types are equal when they really aren't.
 */
uint32
typehash(Type *t)
{
        char *p;
        MD5 d;

        if(t->thistuple) {
                // hide method receiver from Tpretty
                t->thistuple = 0;
                p = smprint("%-uT", t);
                t->thistuple = 1;
        } else
                p = smprint("%-uT", t);
        //print("typehash: %s\n", p);
        md5reset(&d);
        md5write(&d, (uchar*)p, strlen(p));
        free(p);
        return md5sum(&d, nil);
}

Type*
ptrto(Type *t)
{
        Type *t1;

        if(tptr == 0)
                fatal("ptrto: no tptr");
        t1 = typ(tptr);
        t1->type = t;
        t1->width = widthptr;
        t1->align = widthptr;
        return t1;
}

void
frame(int context)
{
        char *p;
        NodeList *l;
        Node *n;
        int flag;

        p = "stack";
        l = nil;
        if(curfn)
                l = curfn->dcl;
        if(context) {
                p = "external";
                l = externdcl;
        }

        flag = 1;
        for(; l; l=l->next) {
                n = l->n;
                switch(n->op) {
                case ONAME:
                        if(flag)
                                print("--- %s frame ---\n", p);
                        print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
                        flag = 0;
                        break;

                case OTYPE:
                        if(flag)
                                print("--- %s frame ---\n", p);
                        print("%O %T\n", n->op, n->type);
                        flag = 0;
                        break;
                }
        }
}

/*
 * calculate sethi/ullman number
 * roughly how many registers needed to
 * compile a node. used to compile the
 * hardest side first to minimize registers.
 */
void
ullmancalc(Node *n)
{
        int ul, ur;

        if(n == N)
                return;

        if(n->ninit != nil) {
                ul = UINF;
                goto out;
        }

        switch(n->op) {
        case OREGISTER:
        case OLITERAL:
        case ONAME:
                ul = 1;
                if(n->class == PPARAMREF || (n->class & PHEAP))
                        ul++;
                goto out;
        case OCALL:
        case OCALLFUNC:
        case OCALLMETH:
        case OCALLINTER:
                ul = UINF;
                goto out;
        case OANDAND:
        case OOROR:
                // hard with race detector
                if(flag_race) {
                        ul = UINF;
                        goto out;
                }
        }
        ul = 1;
        if(n->left != N)
                ul = n->left->ullman;
        ur = 1;
        if(n->right != N)
                ur = n->right->ullman;
        if(ul == ur)
                ul += 1;
        if(ur > ul)
                ul = ur;

out:
        if(ul > 200)
                ul = 200; // clamp to uchar with room to grow
        n->ullman = ul;
}

void
badtype(int o, Type *tl, Type *tr)
{
        Fmt fmt;
        char *s;
        
        fmtstrinit(&fmt);
        if(tl != T)
                fmtprint(&fmt, "\n      %T", tl);
        if(tr != T)
                fmtprint(&fmt, "\n      %T", tr);

        // common mistake: *struct and *interface.
        if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
                if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER)
                        fmtprint(&fmt, "\n      (*struct vs *interface)");
                else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT)
                        fmtprint(&fmt, "\n      (*interface vs *struct)");
        }
        s = fmtstrflush(&fmt);
        yyerror("illegal types for operand: %O%s", o, s);
}

/*
 * iterator to walk a structure declaration
 */
Type*
structfirst(Iter *s, Type **nn)
{
        Type *n, *t;

        n = *nn;
        if(n == T)
                goto bad;

        switch(n->etype) {
        default:
                goto bad;

        case TSTRUCT:
        case TINTER:
        case TFUNC:
                break;
        }

        t = n->type;
        if(t == T)
                goto rnil;

        if(t->etype != TFIELD)
                fatal("structfirst: not field %T", t);

        s->t = t;
        return t;

bad:
        fatal("structfirst: not struct %T", n);

rnil:
        return T;
}

Type*
structnext(Iter *s)
{
        Type *n, *t;

        n = s->t;
        t = n->down;
        if(t == T)
                goto rnil;

        if(t->etype != TFIELD)
                goto bad;

        s->t = t;
        return t;

bad:
        fatal("structnext: not struct %T", n);

rnil:
        return T;
}

/*
 * iterator to this and inargs in a function
 */
Type*
funcfirst(Iter *s, Type *t)
{
        Type *fp;

        if(t == T)
                goto bad;

        if(t->etype != TFUNC)
                goto bad;

        s->tfunc = t;
        s->done = 0;
        fp = structfirst(s, getthis(t));
        if(fp == T) {
                s->done = 1;
                fp = structfirst(s, getinarg(t));
        }
        return fp;

bad:
        fatal("funcfirst: not func %T", t);
        return T;
}

Type*
funcnext(Iter *s)
{
        Type *fp;

        fp = structnext(s);
        if(fp == T && !s->done) {
                s->done = 1;
                fp = structfirst(s, getinarg(s->tfunc));
        }
        return fp;
}

Type**
getthis(Type *t)
{
        if(t->etype != TFUNC)
                fatal("getthis: not a func %T", t);
        return &t->type;
}

Type**
getoutarg(Type *t)
{
        if(t->etype != TFUNC)
                fatal("getoutarg: not a func %T", t);
        return &t->type->down;
}

Type**
getinarg(Type *t)
{
        if(t->etype != TFUNC)
                fatal("getinarg: not a func %T", t);
        return &t->type->down->down;
}

Type*
getthisx(Type *t)
{
        return *getthis(t);
}

Type*
getoutargx(Type *t)
{
        return *getoutarg(t);
}

Type*
getinargx(Type *t)
{
        return *getinarg(t);
}

/*
 * return !(op)
 * eg == <=> !=
 */
int
brcom(int a)
{
        switch(a) {
        case OEQ:       return ONE;
        case ONE:       return OEQ;
        case OLT:       return OGE;
        case OGT:       return OLE;
        case OLE:       return OGT;
        case OGE:       return OLT;
        }
        fatal("brcom: no com for %A\n", a);
        return a;
}

/*
 * return reverse(op)
 * eg a op b <=> b r(op) a
 */
int
brrev(int a)
{
        switch(a) {
        case OEQ:       return OEQ;
        case ONE:       return ONE;
        case OLT:       return OGT;
        case OGT:       return OLT;
        case OLE:       return OGE;
        case OGE:       return OLE;
        }
        fatal("brcom: no rev for %A\n", a);
        return a;
}

/*
 * return side effect-free n, appending side effects to init.
 * result is assignable if n is.
 */
Node*
safeexpr(Node *n, NodeList **init)
{
        Node *l;
        Node *r;
        Node *a;

        if(n == N)
                return N;

        if(n->ninit) {
                walkstmtlist(n->ninit);
                *init = concat(*init, n->ninit);
                n->ninit = nil;
        }

        switch(n->op) {
        case ONAME:
        case OLITERAL:
                return n;

        case ODOT:
                l = safeexpr(n->left, init);
                if(l == n->left)
                        return n;
                r = nod(OXXX, N, N);
                *r = *n;
                r->left = l;
                typecheck(&r, Erv);
                walkexpr(&r, init);
                return r;

        case ODOTPTR:
        case OIND:
                l = safeexpr(n->left, init);
                if(l == n->left)
                        return n;
                a = nod(OXXX, N, N);
                *a = *n;
                a->left = l;
                walkexpr(&a, init);
                return a;

        case OINDEX:
        case OINDEXMAP:
                l = safeexpr(n->left, init);
                r = safeexpr(n->right, init);
                if(l == n->left && r == n->right)
                        return n;
                a = nod(OXXX, N, N);
                *a = *n;
                a->left = l;
                a->right = r;
                walkexpr(&a, init);
                return a;
        }

        // make a copy; must not be used as an lvalue
        if(islvalue(n))
                fatal("missing lvalue case in safeexpr: %N", n);
        return cheapexpr(n, init);
}

Node*
copyexpr(Node *n, Type *t, NodeList **init)
{
        Node *a, *l;
        
        l = temp(t);
        a = nod(OAS, l, n);
        typecheck(&a, Etop);
        walkexpr(&a, init);
        *init = list(*init, a);
        return l;
}

/*
 * return side-effect free and cheap n, appending side effects to init.
 * result may not be assignable.
 */
Node*
cheapexpr(Node *n, NodeList **init)
{
        switch(n->op) {
        case ONAME:
        case OLITERAL:
                return n;
        }

        return copyexpr(n, n->type, init);
}

/*
 * return n in a local variable of type t if it is not already.
 * the value is guaranteed not to change except by direct
 * assignment to it.
 */
Node*
localexpr(Node *n, Type *t, NodeList **init)
{
        if(n->op == ONAME && (!n->addrtaken || strncmp(n->sym->name, "autotmp_", 8) == 0) &&
                (n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
                convertop(n->type, t, nil) == OCONVNOP)
                return n;
        
        return copyexpr(n, t, init);
}

void
setmaxarg(Type *t)
{
        int64 w;

        dowidth(t);
        w = t->argwid;
        if(t->argwid >= MAXWIDTH)
                fatal("bad argwid %T", t);
        if(w > maxarg)
                maxarg = w;
}

/*
 * unicode-aware case-insensitive strcmp
 */

static int
ucistrcmp(char *p, char *q)
{
        Rune rp, rq;

        while(*p || *q) {
                if(*p == 0)
                        return +1;
                if(*q == 0)
                        return -1;
                p += chartorune(&rp, p);
                q += chartorune(&rq, q);
                rp = tolowerrune(rp);
                rq = tolowerrune(rq);
                if(rp < rq)
                        return -1;
                if(rp > rq)
                        return +1;
        }
        return 0;
}

/*
 * code to resolve elided DOTs
 * in embedded types
 */

// search depth 0 --
// return count of fields+methods
// found with a given name
static int
lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
{
        Type *f, *u;
        int c;

        u = t;
        if(isptr[u->etype])
                u = u->type;

        c = 0;
        if(u->etype == TSTRUCT || u->etype == TINTER) {
                for(f=u->type; f!=T; f=f->down)
                        if(f->sym == s || (ignorecase && f->type->etype == TFUNC && f->type->thistuple > 0 && ucistrcmp(f->sym->name, s->name) == 0)) {
                                if(save)
                                        *save = f;
                                c++;
                        }
        }
        u = methtype(t, 0);
        if(u != T) {
                for(f=u->method; f!=T; f=f->down)
                        if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) {
                                if(save)
                                        *save = f;
                                c++;
                        }
        }
        return c;
}

// search depth d for field/method s --
// return count of fields+methods
// found at search depth.
// answer is in dotlist array and
// count of number of ways is returned.
int
adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
{
        Type *f, *u;
        int c, a;

        if(t->trecur)
                return 0;
        t->trecur = 1;

        if(d == 0) {
                c = lookdot0(s, t, save, ignorecase);
                goto out;
        }

        c = 0;
        u = t;
        if(isptr[u->etype])
                u = u->type;
        if(u->etype != TSTRUCT && u->etype != TINTER)
                goto out;

        d--;
        for(f=u->type; f!=T; f=f->down) {
                if(!f->embedded)
                        continue;
                if(f->sym == S)
                        continue;
                a = adddot1(s, f->type, d, save, ignorecase);
                if(a != 0 && c == 0)
                        dotlist[d].field = f;
                c += a;
        }

out:
        t->trecur = 0;
        return c;
}

// in T.field
// find missing fields that
// will give shortest unique addressing.
// modify the tree with missing type names.
Node*
adddot(Node *n)
{
        Type *t;
        Sym *s;
        int c, d;

        typecheck(&n->left, Etype|Erv);
        n->diag |= n->left->diag;
        t = n->left->type;
        if(t == T)
                goto ret;
        
        if(n->left->op == OTYPE)
                goto ret;

        if(n->right->op != ONAME)
                goto ret;
        s = n->right->sym;
        if(s == S)
                goto ret;

        for(d=0; d<nelem(dotlist); d++) {
                c = adddot1(s, t, d, nil, 0);
                if(c > 0)
                        goto out;
        }
        goto ret;

out:
        if(c > 1) {
                yyerror("ambiguous selector %N", n);
                n->left = N;
                return n;
        }

        // rebuild elided dots
        for(c=d-1; c>=0; c--)
                n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym));
ret:
        return n;
}


/*
 * code to help generate trampoline
 * functions for methods on embedded
 * subtypes.
 * these are approx the same as
 * the corresponding adddot routines
 * except that they expect to be called
 * with unique tasks and they return
 * the actual methods.
 */

typedef struct  Symlink Symlink;
struct  Symlink
{
        Type*           field;
        uchar           good;
        uchar           followptr;
        Symlink*        link;
};
static  Symlink*        slist;

static void
expand0(Type *t, int followptr)
{
        Type *f, *u;
        Symlink *sl;

        u = t;
        if(isptr[u->etype]) {
                followptr = 1;
                u = u->type;
        }

        if(u->etype == TINTER) {
                for(f=u->type; f!=T; f=f->down) {
                        if(f->sym->flags & SymUniq)
                                continue;
                        f->sym->flags |= SymUniq;
                        sl = mal(sizeof(*sl));
                        sl->field = f;
                        sl->link = slist;
                        sl->followptr = followptr;
                        slist = sl;
                }
                return;
        }

        u = methtype(t, 0);
        if(u != T) {
                for(f=u->method; f!=T; f=f->down) {
                        if(f->sym->flags & SymUniq)
                                continue;
                        f->sym->flags |= SymUniq;
                        sl = mal(sizeof(*sl));
                        sl->field = f;
                        sl->link = slist;
                        sl->followptr = followptr;
                        slist = sl;
                }
        }
}

static void
expand1(Type *t, int d, int followptr)
{
        Type *f, *u;

        if(t->trecur)
                return;
        if(d == 0)
                return;
        t->trecur = 1;

        if(d != nelem(dotlist)-1)
                expand0(t, followptr);

        u = t;
        if(isptr[u->etype]) {
                followptr = 1;
                u = u->type;
        }
        if(u->etype != TSTRUCT && u->etype != TINTER)
                goto out;

        for(f=u->type; f!=T; f=f->down) {
                if(!f->embedded)
                        continue;
                if(f->sym == S)
                        continue;
                expand1(f->type, d-1, followptr);
        }

out:
        t->trecur = 0;
}

void
expandmeth(Type *t)
{
        Symlink *sl;
        Type *f;
        int c, d;

        if(t == T || t->xmethod != nil)
                return;

        // mark top-level method symbols
        // so that expand1 doesn't consider them.
        for(f=t->method; f != nil; f=f->down)
                f->sym->flags |= SymUniq;

        // generate all reachable methods
        slist = nil;
        expand1(t, nelem(dotlist)-1, 0);

        // check each method to be uniquely reachable
        for(sl=slist; sl!=nil; sl=sl->link) {
                sl->field->sym->flags &= ~SymUniq;
                for(d=0; d<nelem(dotlist); d++) {
                        c = adddot1(sl->field->sym, t, d, &f, 0);
                        if(c == 0)
                                continue;
                        if(c == 1) {
                                // addot1 may have dug out arbitrary fields, we only want methods.
                                if(f->type->etype == TFUNC && f->type->thistuple > 0) {
                                        sl->good = 1;
                                        sl->field = f;
                                }
                        }
                        break;
                }
        }

        for(f=t->method; f != nil; f=f->down)
                f->sym->flags &= ~SymUniq;

        t->xmethod = t->method;
        for(sl=slist; sl!=nil; sl=sl->link) {
                if(sl->good) {
                        // add it to the base type method list
                        f = typ(TFIELD);
                        *f = *sl->field;
                        f->embedded = 1;        // needs a trampoline
                        if(sl->followptr)
                                f->embedded = 2;
                        f->down = t->xmethod;
                        t->xmethod = f;
                }
        }
}

/*
 * Given funarg struct list, return list of ODCLFIELD Node fn args.
 */
static NodeList*
structargs(Type **tl, int mustname)
{
        Iter savet;
        Node *a, *n;
        NodeList *args;
        Type *t;
        char buf[100];
        int gen;

        args = nil;
        gen = 0;
        for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
                n = N;
                if(mustname && (t->sym == nil || strcmp(t->sym->name, "_") == 0)) {
                        // invent a name so that we can refer to it in the trampoline
                        snprint(buf, sizeof buf, ".anon%d", gen++);
                        n = newname(lookup(buf));
                } else if(t->sym)
                        n = newname(t->sym);
                a = nod(ODCLFIELD, n, typenod(t->type));
                a->isddd = t->isddd;
                if(n != N)
                        n->isddd = t->isddd;
                args = list(args, a);
        }
        return args;
}

/*
 * Generate a wrapper function to convert from
 * a receiver of type T to a receiver of type U.
 * That is,
 *
 *      func (t T) M() {
 *              ...
 *      }
 *
 * already exists; this function generates
 *
 *      func (u U) M() {
 *              u.M()
 *      }
 *
 * where the types T and U are such that u.M() is valid
 * and calls the T.M method.
 * The resulting function is for use in method tables.
 *
 *      rcvr - U
 *      method - M func (t T)(), a TFIELD type struct
 *      newnam - the eventual mangled name of this function
 */
void
genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
{
        Node *this, *fn, *call, *n, *t, *pad, *dot, *as;
        NodeList *l, *args, *in, *out;
        Type *tpad, *methodrcvr;
        int isddd;
        Val v;
        static int linehistdone = 0;

        if(0 && debug['r'])
                print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
                        rcvr, method, newnam);

        lexlineno++;
        lineno = lexlineno;
        if (linehistdone == 0) {
                // All the wrappers can share the same linehist entry.
                linehist("<autogenerated>", 0, 0);
                linehistdone = 1;
        }

        dclcontext = PEXTERN;
        markdcl();

        this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
        this->left->ntype = this->right;
        in = structargs(getinarg(method->type), 1);
        out = structargs(getoutarg(method->type), 0);

        t = nod(OTFUNC, N, N);
        l = list1(this);
        if(iface && rcvr->width < types[tptr]->width) {
                // Building method for interface table and receiver
                // is smaller than the single pointer-sized word
                // that the interface call will pass in.
                // Add a dummy padding argument after the
                // receiver to make up the difference.
                tpad = typ(TARRAY);
                tpad->type = types[TUINT8];
                tpad->bound = types[tptr]->width - rcvr->width;
                pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
                l = list(l, pad);
        }
        t->list = concat(l, in);
        t->rlist = out;

        fn = nod(ODCLFUNC, N, N);
        fn->nname = newname(newnam);
        fn->nname->defn = fn;
        fn->nname->ntype = t;
        declare(fn->nname, PFUNC);
        funchdr(fn);

        // arg list
        args = nil;
        isddd = 0;
        for(l=in; l; l=l->next) {
                args = list(args, l->n->left);
                isddd = l->n->left->isddd;
        }
        
        methodrcvr = getthisx(method->type)->type->type;

        // generate nil pointer check for better error
        if(isptr[rcvr->etype] && rcvr->type == methodrcvr) {
                // generating wrapper from *T to T.
                n = nod(OIF, N, N);
                n->ntest = nod(OEQ, this->left, nodnil());
                // these strings are already in the reflect tables,
                // so no space cost to use them here.
                l = nil;
                v.ctype = CTSTR;
                v.u.sval = strlit(rcvr->type->sym->pkg->name);  // package name
                l = list(l, nodlit(v));
                v.u.sval = strlit(rcvr->type->sym->name);  // type name
                l = list(l, nodlit(v));
                v.u.sval = strlit(method->sym->name);
                l = list(l, nodlit(v));  // method name
                call = nod(OCALL, syslook("panicwrap", 0), N);
                call->list = l;
                n->nbody = list1(call);
                fn->nbody = list(fn->nbody, n);
        }
        
        dot = adddot(nod(OXDOT, this->left, newname(method->sym)));
        
        // generate call
        if(!flag_race && isptr[rcvr->etype] && isptr[methodrcvr->etype] && method->embedded && !isifacemethod(method->type)) {
                // generate tail call: adjust pointer receiver and jump to embedded method.
                dot = dot->left;        // skip final .M
                if(!isptr[dotlist[0].field->type->etype])
                        dot = nod(OADDR, dot, N);
                as = nod(OAS, this->left, nod(OCONVNOP, dot, N));
                as->right->type = rcvr;
                fn->nbody = list(fn->nbody, as);
                n = nod(ORETJMP, N, N);
                n->left = newname(methodsym(method->sym, methodrcvr, 0));
                fn->nbody = list(fn->nbody, n);
        } else {
                fn->wrapper = 1; // ignore frame for panic+recover matching
                call = nod(OCALL, dot, N);
                call->list = args;
                call->isddd = isddd;
                if(method->type->outtuple > 0) {
                        n = nod(ORETURN, N, N);
                        n->list = list1(call);
                        call = n;
                }
                fn->nbody = list(fn->nbody, call);
        }

        if(0 && debug['r'])
                dumplist("genwrapper body", fn->nbody);

        funcbody(fn);
        curfn = fn;
        // wrappers where T is anonymous (struct or interface) can be duplicated.
        if(rcvr->etype == TSTRUCT ||
                rcvr->etype == TINTER ||
                isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT)
                fn->dupok = 1;
        typecheck(&fn, Etop);
        typechecklist(fn->nbody, Etop);
        inlcalls(fn);
        curfn = nil;
        funccompile(fn, 0);
}

static Node*
hashmem(Type *t)
{
        Node *tfn, *n;
        Sym *sym;
        
        sym = pkglookup("memhash", runtimepkg);

        n = newname(sym);
        n->class = PFUNC;
        tfn = nod(OTFUNC, N, N);
        tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR]))));
        tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
        tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
        typecheck(&tfn, Etype);
        n->type = tfn->type;
        return n;
}

static Node*
hashfor(Type *t)
{
        int a;
        Sym *sym;
        Node *tfn, *n;

        a = algtype1(t, nil);
        switch(a) {
        case AMEM:
                return hashmem(t);
        case AINTER:
                sym = pkglookup("interhash", runtimepkg);
                break;
        case ANILINTER:
                sym = pkglookup("nilinterhash", runtimepkg);
                break;
        case ASTRING:
                sym = pkglookup("strhash", runtimepkg);
                break;
        case AFLOAT32:
                sym = pkglookup("f32hash", runtimepkg);
                break;
        case AFLOAT64:
                sym = pkglookup("f64hash", runtimepkg);
                break;
        case ACPLX64:
                sym = pkglookup("c64hash", runtimepkg);
                break;
        case ACPLX128:
                sym = pkglookup("c128hash", runtimepkg);
                break;
        default:
                sym = typesymprefix(".hash", t);
                break;
        }

        n = newname(sym);
        n->class = PFUNC;
        tfn = nod(OTFUNC, N, N);
        tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR]))));
        tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
        tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
        typecheck(&tfn, Etype);
        n->type = tfn->type;
        return n;
}

/*
 * Generate a helper function to compute the hash of a value of type t.
 */
void
genhash(Sym *sym, Type *t)
{
        Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn;
        Node *hashel;
        Type *first, *t1;
        int old_safemode;
        int64 size, mul, offend;

        if(debug['r'])
                print("genhash %S %T\n", sym, t);

        lineno = 1;  // less confusing than end of input
        dclcontext = PEXTERN;
        markdcl();

        // func sym(h *uintptr, s uintptr, p *T)
        fn = nod(ODCLFUNC, N, N);
        fn->nname = newname(sym);
        fn->nname->class = PFUNC;
        tfn = nod(OTFUNC, N, N);
        fn->nname->ntype = tfn;

        n = nod(ODCLFIELD, newname(lookup("h")), typenod(ptrto(types[TUINTPTR])));
        tfn->list = list(tfn->list, n);
        nh = n->left;
        n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
        tfn->list = list(tfn->list, n);
        n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
        tfn->list = list(tfn->list, n);
        np = n->left;

        funchdr(fn);
        typecheck(&fn->nname->ntype, Etype);

        // genhash is only called for types that have equality but
        // cannot be handled by the standard algorithms,
        // so t must be either an array or a struct.
        switch(t->etype) {
        default:
                fatal("genhash %T", t);
        case TARRAY:
                if(isslice(t))
                        fatal("genhash %T", t);
                // An array of pure memory would be handled by the
                // standard algorithm, so the element type must not be
                // pure memory.
                hashel = hashfor(t->type);
                n = nod(ORANGE, N, nod(OIND, np, N));
                ni = newname(lookup("i"));
                ni->type = types[TINT];
                n->list = list1(ni);
                n->colas = 1;
                colasdefn(n->list, n);
                ni = n->list->n;

                // *h = *h<<3 | *h>>61
                n->nbody = list(n->nbody,
                        nod(OAS,
                                nod(OIND, nh, N),
                                nod(OOR,
                                        nod(OLSH, nod(OIND, nh, N), nodintconst(3)),
                                        nod(ORSH, nod(OIND, nh, N), nodintconst(widthptr*8-3)))));

                // *h *= mul
                // Same multipliers as in runtime.memhash.
                if(widthptr == 4)
                        mul = 3267000013LL;
                else
                        mul = 23344194077549503LL;
                n->nbody = list(n->nbody,
                        nod(OAS,
                                nod(OIND, nh, N),
                                nod(OMUL, nod(OIND, nh, N), nodintconst(mul))));

                // hashel(h, sizeof(p[i]), &p[i])
                call = nod(OCALL, hashel, N);
                call->list = list(call->list, nh);
                call->list = list(call->list, nodintconst(t->type->width));
                nx = nod(OINDEX, np, ni);
                nx->bounded = 1;
                na = nod(OADDR, nx, N);
                na->etype = 1;  // no escape to heap
                call->list = list(call->list, na);
                n->nbody = list(n->nbody, call);

                fn->nbody = list(fn->nbody, n);
                break;

        case TSTRUCT:
                // Walk the struct using memhash for runs of AMEM
                // and calling specific hash functions for the others.
                first = T;
                offend = 0;
                for(t1=t->type;; t1=t1->down) {
                        if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
                                offend = t1->width + t1->type->width;
                                if(first == T)
                                        first = t1;
                                // If it's a memory field but it's padded, stop here.
                                if(ispaddedfield(t1, t->width))
                                        t1 = t1->down;
                                else
                                        continue;
                        }
                        // Run memhash for fields up to this one.
                        if(first != T) {
                                size = offend - first->width; // first->width is offset
                                hashel = hashmem(first->type);
                                // hashel(h, size, &p.first)
                                call = nod(OCALL, hashel, N);
                                call->list = list(call->list, nh);
                                call->list = list(call->list, nodintconst(size));
                                nx = nod(OXDOT, np, newname(first->sym));  // TODO: fields from other packages?
                                na = nod(OADDR, nx, N);
                                na->etype = 1;  // no escape to heap
                                call->list = list(call->list, na);
                                fn->nbody = list(fn->nbody, call);

                                first = T;
                        }
                        if(t1 == T)
                                break;
                        if(isblanksym(t1->sym))
                                continue;

                        // Run hash for this field.
                        hashel = hashfor(t1->type);
                        // hashel(h, size, &p.t1)
                        call = nod(OCALL, hashel, N);
                        call->list = list(call->list, nh);
                        call->list = list(call->list, nodintconst(t1->type->width));
                        nx = nod(OXDOT, np, newname(t1->sym));  // TODO: fields from other packages?
                        na = nod(OADDR, nx, N);
                        na->etype = 1;  // no escape to heap
                        call->list = list(call->list, na);
                        fn->nbody = list(fn->nbody, call);
                }
                // make sure body is not empty.
                fn->nbody = list(fn->nbody, nod(ORETURN, N, N));
                break;
        }

        if(debug['r'])
                dumplist("genhash body", fn->nbody);

        funcbody(fn);
        curfn = fn;
        fn->dupok = 1;
        typecheck(&fn, Etop);
        typechecklist(fn->nbody, Etop);
        curfn = nil;

        // Disable safemode while compiling this code: the code we
        // generate internally can refer to unsafe.Pointer.
        // In this case it can happen if we need to generate an ==
        // for a struct containing a reflect.Value, which itself has
        // an unexported field of type unsafe.Pointer.
        old_safemode = safemode;
        safemode = 0;
        funccompile(fn, 0);
        safemode = old_safemode;
}

// Return node for
//      if p.field != q.field { *eq = false; return }
static Node*
eqfield(Node *p, Node *q, Node *field, Node *eq)
{
        Node *nif, *nx, *ny;

        nx = nod(OXDOT, p, field);
        ny = nod(OXDOT, q, field);
        nif = nod(OIF, N, N);
        nif->ntest = nod(ONE, nx, ny);
        nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, eq, N), nodbool(0)));
        nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
        return nif;
}

static Node*
eqmemfunc(vlong size, Type *type)
{
        char buf[30];
        Node *fn;

        switch(size) {
        default:
                fn = syslook("memequal", 1);
                break;
        case 1:
        case 2:
        case 4:
        case 8:
        case 16:
                snprint(buf, sizeof buf, "memequal%d", (int)size*8);
                fn = syslook(buf, 1);
                break;
        }
        argtype(fn, type);
        argtype(fn, type);
        return fn;
}

// Return node for
//      if memequal(size, &p.field, &q.field, eq); !*eq { return }
static Node*
eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq)
{
        Node *nif, *nx, *ny, *call;

        nx = nod(OADDR, nod(OXDOT, p, field), N);
        nx->etype = 1;  // does not escape
        ny = nod(OADDR, nod(OXDOT, q, field), N);
        ny->etype = 1;  // does not escape
        typecheck(&nx, Erv);
        typecheck(&ny, Erv);

        call = nod(OCALL, eqmemfunc(size, nx->type->type), N);
        call->list = list(call->list, eq);
        call->list = list(call->list, nodintconst(size));
        call->list = list(call->list, nx);
        call->list = list(call->list, ny);

        nif = nod(OIF, N, N);
        nif->ninit = list(nif->ninit, call);
        nif->ntest = nod(ONOT, nod(OIND, eq, N), N);
        nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
        return nif;
}

/*
 * Generate a helper function to check equality of two values of type t.
 */
void
geneq(Sym *sym, Type *t)
{
        Node *n, *fn, *np, *neq, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange;
        Type *t1, *first;
        int old_safemode;
        int64 size;
        int64 offend;

        if(debug['r'])
                print("geneq %S %T\n", sym, t);

        lineno = 1;  // less confusing than end of input
        dclcontext = PEXTERN;
        markdcl();

        // func sym(eq *bool, s uintptr, p, q *T)
        fn = nod(ODCLFUNC, N, N);
        fn->nname = newname(sym);
        fn->nname->class = PFUNC;
        tfn = nod(OTFUNC, N, N);
        fn->nname->ntype = tfn;

        n = nod(ODCLFIELD, newname(lookup("eq")), typenod(ptrto(types[TBOOL])));
        tfn->list = list(tfn->list, n);
        neq = n->left;
        n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
        tfn->list = list(tfn->list, n);
        n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
        tfn->list = list(tfn->list, n);
        np = n->left;
        n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
        tfn->list = list(tfn->list, n);
        nq = n->left;

        funchdr(fn);

        // geneq is only called for types that have equality but
        // cannot be handled by the standard algorithms,
        // so t must be either an array or a struct.
        switch(t->etype) {
        default:
                fatal("geneq %T", t);
        case TARRAY:
                if(isslice(t))
                        fatal("geneq %T", t);
                // An array of pure memory would be handled by the
                // standard memequal, so the element type must not be
                // pure memory.  Even if we unrolled the range loop,
                // each iteration would be a function call, so don't bother
                // unrolling.
                nrange = nod(ORANGE, N, nod(OIND, np, N));
                ni = newname(lookup("i"));
                ni->type = types[TINT];
                nrange->list = list1(ni);
                nrange->colas = 1;
                colasdefn(nrange->list, nrange);
                ni = nrange->list->n;
                
                // if p[i] != q[i] { *eq = false; return }
                nx = nod(OINDEX, np, ni);
                nx->bounded = 1;
                ny = nod(OINDEX, nq, ni);
                ny->bounded = 1;

                nif = nod(OIF, N, N);
                nif->ntest = nod(ONE, nx, ny);
                nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, neq, N), nodbool(0)));
                nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
                nrange->nbody = list(nrange->nbody, nif);
                fn->nbody = list(fn->nbody, nrange);

                // *eq = true;
                fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1)));
                break;

        case TSTRUCT:
                // Walk the struct using memequal for runs of AMEM
                // and calling specific equality tests for the others.
                // Skip blank-named fields.
                first = T;
                offend = 0;
                for(t1=t->type;; t1=t1->down) {
                        if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
                                offend = t1->width + t1->type->width;
                                if(first == T)
                                        first = t1;
                                // If it's a memory field but it's padded, stop here.
                                if(ispaddedfield(t1, t->width))
                                        t1 = t1->down;
                                else
                                        continue;
                        }
                        // Run memequal for fields up to this one.
                        // TODO(rsc): All the calls to newname are wrong for
                        // cross-package unexported fields.
                        if(first != T) {
                                if(first->down == t1) {
                                        fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
                                } else if(first->down->down == t1) {
                                        fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
                                        first = first->down;
                                        if(!isblanksym(first->sym))
                                                fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
                                } else {
                                        // More than two fields: use memequal.
                                        size = offend - first->width; // first->width is offset
                                        fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size, neq));
                                }
                                first = T;
                        }
                        if(t1 == T)
                                break;
                        if(isblanksym(t1->sym))
                                continue;

                        // Check this field, which is not just memory.
                        fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym), neq));
                }

                // *eq = true;
                fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1)));
                break;
        }

        if(debug['r'])
                dumplist("geneq body", fn->nbody);

        funcbody(fn);
        curfn = fn;
        fn->dupok = 1;
        typecheck(&fn, Etop);
        typechecklist(fn->nbody, Etop);
        curfn = nil;
        
        // Disable safemode while compiling this code: the code we
        // generate internally can refer to unsafe.Pointer.
        // In this case it can happen if we need to generate an ==
        // for a struct containing a reflect.Value, which itself has
        // an unexported field of type unsafe.Pointer.
        old_safemode = safemode;
        safemode = 0;
        funccompile(fn, 0);
        safemode = old_safemode;
}

static Type*
ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
{
        int i, c, d;
        Type *m;

        *followptr = 0;

        if(t == T)
                return T;

        for(d=0; d<nelem(dotlist); d++) {
                c = adddot1(s, t, d, &m, ignorecase);
                if(c > 1) {
                        yyerror("%T.%S is ambiguous", t, s);
                        return T;
                }
                if(c == 1) {
                        for(i=0; i<d; i++) {
                                if(isptr[dotlist[i].field->type->etype]) {
                                        *followptr = 1;
                                        break;
                                }
                        }
                        if(m->type->etype != TFUNC || m->type->thistuple == 0) {
                                yyerror("%T.%S is a field, not a method", t, s);
                                return T;
                        }
                        return m;
                }
        }
        return T;
}

int
implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
{
        Type *t0, *im, *tm, *rcvr, *imtype;
        int followptr;

        t0 = t;
        if(t == T)
                return 0;

        // if this is too slow,
        // could sort these first
        // and then do one loop.

        if(t->etype == TINTER) {
                for(im=iface->type; im; im=im->down) {
                        for(tm=t->type; tm; tm=tm->down) {
                                if(tm->sym == im->sym) {
                                        if(eqtype(tm->type, im->type))
                                                goto found;
                                        *m = im;
                                        *samename = tm;
                                        *ptr = 0;
                                        return 0;
                                }
                        }
                        *m = im;
                        *samename = nil;
                        *ptr = 0;
                        return 0;
                found:;
                }
                return 1;
        }

        t = methtype(t, 0);
        if(t != T)
                expandmeth(t);
        for(im=iface->type; im; im=im->down) {
                imtype = methodfunc(im->type, 0);
                tm = ifacelookdot(im->sym, t, &followptr, 0);
                if(tm == T || tm->nointerface || !eqtype(methodfunc(tm->type, 0), imtype)) {
                        if(tm == T)
                                tm = ifacelookdot(im->sym, t, &followptr, 1);
                        *m = im;
                        *samename = tm;
                        *ptr = 0;
                        return 0;
                }
                // if pointer receiver in method,
                // the method does not exist for value types.
                rcvr = getthisx(tm->type)->type->type;
                if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
                        if(0 && debug['r'])
                                yyerror("interface pointer mismatch");

                        *m = im;
                        *samename = nil;
                        *ptr = 1;
                        return 0;
                }
        }
        return 1;
}

/*
 * even simpler simtype; get rid of ptr, bool.
 * assuming that the front end has rejected
 * all the invalid conversions (like ptr -> bool)
 */
int
simsimtype(Type *t)
{
        int et;

        if(t == 0)
                return 0;

        et = simtype[t->etype];
        switch(et) {
        case TPTR32:
                et = TUINT32;
                break;
        case TPTR64:
                et = TUINT64;
                break;
        case TBOOL:
                et = TUINT8;
                break;
        }
        return et;
}

NodeList*
concat(NodeList *a, NodeList *b)
{
        if(a == nil)
                return b;
        if(b == nil)
                return a;

        a->end->next = b;
        a->end = b->end;
        b->end = nil;
        return a;
}

NodeList*
list1(Node *n)
{
        NodeList *l;

        if(n == nil)
                return nil;
        if(n->op == OBLOCK && n->ninit == nil) {
                // Flatten list and steal storage.
                // Poison pointer to catch errant uses.
                l = n->list;
                n->list = (NodeList*)1;
                return l;
        }
        l = mal(sizeof *l);
        l->n = n;
        l->end = l;
        return l;
}

NodeList*
list(NodeList *l, Node *n)
{
        return concat(l, list1(n));
}

void
listsort(NodeList** l, int(*f)(Node*, Node*))
{
        NodeList *l1, *l2, *le;

        if(*l == nil || (*l)->next == nil)
                return;

        l1 = *l;
        l2 = *l;
        for(;;) {
                l2 = l2->next;
                if(l2 == nil)
                        break;
                l2 = l2->next;
                if(l2 == nil)
                        break;
                l1 = l1->next;
        }

        l2 = l1->next;
        l1->next = nil;
        l2->end = (*l)->end;
        (*l)->end = l1;

        l1 = *l;
        listsort(&l1, f);
        listsort(&l2, f);

        if((*f)(l1->n, l2->n) < 0) {
                *l = l1;
        } else {
                *l = l2;
                l2 = l1;
                l1 = *l;
        }

        // now l1 == *l; and l1 < l2

        while ((l1 != nil) && (l2 != nil)) {
                while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0)
                        l1 = l1->next;
                
                // l1 is last one from l1 that is < l2
                le = l1->next;          // le is the rest of l1, first one that is >= l2
                if(le != nil)
                        le->end = (*l)->end;

                (*l)->end = l1;         // cut *l at l1
                *l = concat(*l, l2);    // glue l2 to *l's tail

                l1 = l2;                // l1 is the first element of *l that is < the new l2
                l2 = le;                // ... because l2 now is the old tail of l1
        }

        *l = concat(*l, l2);            // any remainder 
}

NodeList*
listtreecopy(NodeList *l)
{
        NodeList *out;

        out = nil;
        for(; l; l=l->next)
                out = list(out, treecopy(l->n));
        return out;
}

Node*
liststmt(NodeList *l)
{
        Node *n;

        n = nod(OBLOCK, N, N);
        n->list = l;
        if(l)
                n->lineno = l->n->lineno;
        return n;
}

/*
 * return nelem of list
 */
int
count(NodeList *l)
{
        vlong n;

        n = 0;
        for(; l; l=l->next)
                n++;
        if((int)n != n) { // Overflow.
                yyerror("too many elements in list");
        }
        return n;
}

/*
 * return nelem of list
 */
int
structcount(Type *t)
{
        int v;
        Iter s;

        v = 0;
        for(t = structfirst(&s, &t); t != T; t = structnext(&s))
                v++;
        return v;
}

/*
 * return power of 2 of the constant
 * operand. -1 if it is not a power of 2.
 * 1000+ if it is a -(power of 2)
 */
int
powtwo(Node *n)
{
        uvlong v, b;
        int i;

        if(n == N || n->op != OLITERAL || n->type == T)
                goto no;
        if(!isint[n->type->etype])
                goto no;

        v = mpgetfix(n->val.u.xval);
        b = 1ULL;
        for(i=0; i<64; i++) {
                if(b == v)
                        return i;
                b = b<<1;
        }

        if(!issigned[n->type->etype])
                goto no;

        v = -v;
        b = 1ULL;
        for(i=0; i<64; i++) {
                if(b == v)
                        return i+1000;
                b = b<<1;
        }

no:
        return -1;
}

/*
 * return the unsigned type for
 * a signed integer type.
 * returns T if input is not a
 * signed integer type.
 */
Type*
tounsigned(Type *t)
{

        // this is types[et+1], but not sure
        // that this relation is immutable
        switch(t->etype) {
        default:
                print("tounsigned: unknown type %T\n", t);
                t = T;
                break;
        case TINT:
                t = types[TUINT];
                break;
        case TINT8:
                t = types[TUINT8];
                break;
        case TINT16:
                t = types[TUINT16];
                break;
        case TINT32:
                t = types[TUINT32];
                break;
        case TINT64:
                t = types[TUINT64];
                break;
        }
        return t;
}

/*
 * magic number for signed division
 * see hacker's delight chapter 10
 */
void
smagic(Magic *m)
{
        int p;
        uint64 ad, anc, delta, q1, r1, q2, r2, t;
        uint64 mask, two31;

        m->bad = 0;
        switch(m->w) {
        default:
                m->bad = 1;
                return;
        case 8:
                mask = 0xffLL;
                break;
        case 16:
                mask = 0xffffLL;
                break;
        case 32:
                mask = 0xffffffffLL;
                break;
        case 64:
                mask = 0xffffffffffffffffLL;
                break;
        }
        two31 = mask ^ (mask>>1);

        p = m->w-1;
        ad = m->sd;
        if(m->sd < 0)
                ad = -m->sd;

        // bad denominators
        if(ad == 0 || ad == 1 || ad == two31) {
                m->bad = 1;
                return;
        }

        t = two31;
        ad &= mask;

        anc = t - 1 - t%ad;
        anc &= mask;

        q1 = two31/anc;
        r1 = two31 - q1*anc;
        q1 &= mask;
        r1 &= mask;

        q2 = two31/ad;
        r2 = two31 - q2*ad;
        q2 &= mask;
        r2 &= mask;

        for(;;) {
                p++;
                q1 <<= 1;
                r1 <<= 1;
                q1 &= mask;
                r1 &= mask;
                if(r1 >= anc) {
                        q1++;
                        r1 -= anc;
                        q1 &= mask;
                        r1 &= mask;
                }

                q2 <<= 1;
                r2 <<= 1;
                q2 &= mask;
                r2 &= mask;
                if(r2 >= ad) {
                        q2++;
                        r2 -= ad;
                        q2 &= mask;
                        r2 &= mask;
                }

                delta = ad - r2;
                delta &= mask;
                if(q1 < delta || (q1 == delta && r1 == 0)) {
                        continue;
                }
                break;
        }

        m->sm = q2+1;
        if(m->sm & two31)
                m->sm |= ~mask;
        m->s = p-m->w;
}

/*
 * magic number for unsigned division
 * see hacker's delight chapter 10
 */
void
umagic(Magic *m)
{
        int p;
        uint64 nc, delta, q1, r1, q2, r2;
        uint64 mask, two31;

        m->bad = 0;
        m->ua = 0;

        switch(m->w) {
        default:
                m->bad = 1;
                return;
        case 8:
                mask = 0xffLL;
                break;
        case 16:
                mask = 0xffffLL;
                break;
        case 32:
                mask = 0xffffffffLL;
                break;
        case 64:
                mask = 0xffffffffffffffffLL;
                break;
        }
        two31 = mask ^ (mask>>1);

        m->ud &= mask;
        if(m->ud == 0 || m->ud == two31) {
                m->bad = 1;
                return;
        }
        nc = mask - (-m->ud&mask)%m->ud;
        p = m->w-1;

        q1 = two31/nc;
        r1 = two31 - q1*nc;
        q1 &= mask;
        r1 &= mask;

        q2 = (two31-1) / m->ud;
        r2 = (two31-1) - q2*m->ud;
        q2 &= mask;
        r2 &= mask;

        for(;;) {
                p++;
                if(r1 >= nc-r1) {
                        q1 <<= 1;
                        q1++;
                        r1 <<= 1;
                        r1 -= nc;
                } else {
                        q1 <<= 1;
                        r1 <<= 1;
                }
                q1 &= mask;
                r1 &= mask;
                if(r2+1 >= m->ud-r2) {
                        if(q2 >= two31-1) {
                                m->ua = 1;
                        }
                        q2 <<= 1;
                        q2++;
                        r2 <<= 1;
                        r2++;
                        r2 -= m->ud;
                } else {
                        if(q2 >= two31) {
                                m->ua = 1;
                        }
                        q2 <<= 1;
                        r2 <<= 1;
                        r2++;
                }
                q2 &= mask;
                r2 &= mask;

                delta = m->ud - 1 - r2;
                delta &= mask;

                if(p < m->w+m->w)
                if(q1 < delta || (q1 == delta && r1 == 0)) {
                        continue;
                }
                break;
        }
        m->um = q2+1;
        m->s = p-m->w;
}

Sym*
ngotype(Node *n)
{
        if(n->type != T)
                return typenamesym(n->type);
        return S;
}

/*
 * Convert raw string to the prefix that will be used in the symbol
 * table.  All control characters, space, '%' and '"', as well as
 * non-7-bit clean bytes turn into %xx.  The period needs escaping
 * only in the last segment of the path, and it makes for happier
 * users if we escape that as little as possible.
 *
 * If you edit this, edit ../ld/lib.c:/^pathtoprefix too.
 * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too.
 */
static char*
pathtoprefix(char *s)
{
        static char hex[] = "0123456789abcdef";
        char *p, *r, *w, *l;
        int n;

        // find first character past the last slash, if any.
        l = s;
        for(r=s; *r; r++)
                if(*r == '/')
                        l = r+1;

        // check for chars that need escaping
        n = 0;
        for(r=s; *r; r++)
                if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
                        n++;

        // quick exit
        if(n == 0)
                return s;

        // escape
        p = mal((r-s)+1+2*n);
        for(r=s, w=p; *r; r++) {
                if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
                        *w++ = '%';
                        *w++ = hex[(*r>>4)&0xF];
                        *w++ = hex[*r&0xF];
                } else
                        *w++ = *r;
        }
        *w = '\0';
        return p;
}

Pkg*
mkpkg(Strlit *path)
{
        Pkg *p;
        int h;

        h = stringhash(path->s) & (nelem(phash)-1);
        for(p=phash[h]; p; p=p->link)
                if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0)
                        return p;

        p = mal(sizeof *p);
        p->path = path;
        p->prefix = pathtoprefix(path->s);
        p->link = phash[h];
        phash[h] = p;
        return p;
}

Strlit*
strlit(char *s)
{
        Strlit *t;
        
        t = mal(sizeof *t + strlen(s));
        strcpy(t->s, s);
        t->len = strlen(s);
        return t;
}

void
addinit(Node **np, NodeList *init)
{
        Node *n;
        
        if(init == nil)
                return;

        n = *np;
        switch(n->op) {
        case ONAME:
        case OLITERAL:
                // There may be multiple refs to this node;
                // introduce OCONVNOP to hold init list.
                n = nod(OCONVNOP, n, N);
                n->type = n->left->type;
                n->typecheck = 1;
                *np = n;
                break;
        }
        n->ninit = concat(init, n->ninit);
        n->ullman = UINF;
}

static char* reservedimports[] = {
        "go",
        "type",
};

int
isbadimport(Strlit *path)
{
        int i;
        char *s;
        Rune r;

        if(strlen(path->s) != path->len) {
                yyerror("import path contains NUL");
                return 1;
        }
        
        for(i=0; i<nelem(reservedimports); i++) {
                if(strcmp(path->s, reservedimports[i]) == 0) {
                        yyerror("import path \"%s\" is reserved and cannot be used", path->s);
                        return 1;
                }
        }

        s = path->s;
        while(*s) {
                s += chartorune(&r, s);
                if(r == Runeerror) {
                        yyerror("import path contains invalid UTF-8 sequence: \"%Z\"", path);
                        return 1;
                }
                if(r < 0x20 || r == 0x7f) {
                        yyerror("import path contains control character: \"%Z\"", path);
                        return 1;
                }
                if(r == '\\') {
                        yyerror("import path contains backslash; use slash: \"%Z\"", path);
                        return 1;
                }
                if(isspacerune(r)) {
                        yyerror("import path contains space character: \"%Z\"", path);
                        return 1;
                }
                if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}", r)) {
                        yyerror("import path contains invalid character '%C': \"%Z\"", r, path);
                        return 1;
                }
        }
        return 0;
}

void
checknil(Node *x, NodeList **init)
{
        Node *n;
        
        if(isinter(x->type)) {
                x = nod(OITAB, x, N);
                typecheck(&x, Erv);
        }
        n = nod(OCHECKNIL, x, N);
        n->typecheck = 1;
        *init = list(*init, n);
}

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