summaryrefslogtreecommitdiff
path: root/limbo/types.c
diff options
context:
space:
mode:
Diffstat (limited to 'limbo/types.c')
-rw-r--r--limbo/types.c4745
1 files changed, 4745 insertions, 0 deletions
diff --git a/limbo/types.c b/limbo/types.c
new file mode 100644
index 00000000..449b53d7
--- /dev/null
+++ b/limbo/types.c
@@ -0,0 +1,4745 @@
+#include "limbo.h"
+#include "mp.h"
+#include "libsec.h"
+
+char *kindname[Tend] =
+{
+ /* Tnone */ "no type",
+ /* Tadt */ "adt",
+ /* Tadtpick */ "adt",
+ /* Tarray */ "array",
+ /* Tbig */ "big",
+ /* Tbyte */ "byte",
+ /* Tchan */ "chan",
+ /* Treal */ "real",
+ /* Tfn */ "fn",
+ /* Tint */ "int",
+ /* Tlist */ "list",
+ /* Tmodule */ "module",
+ /* Tref */ "ref",
+ /* Tstring */ "string",
+ /* Ttuple */ "tuple",
+ /* Texception */ "exception",
+ /* Tfix */ "fixed point",
+ /* Tpoly */ "polymorphic",
+
+ /* Tainit */ "array initializers",
+ /* Talt */ "alt channels",
+ /* Tany */ "polymorphic type",
+ /* Tarrow */ "->",
+ /* Tcase */ "case int labels",
+ /* Tcasel */ "case big labels",
+ /* Tcasec */ "case string labels",
+ /* Tdot */ ".",
+ /* Terror */ "type error",
+ /* Tgoto */ "goto labels",
+ /* Tid */ "id",
+ /* Tiface */ "module interface",
+ /* Texcept */ "exception handler table",
+ /* Tinst */ "instantiated type",
+};
+
+Tattr tattr[Tend] =
+{
+ /* isptr refable conable big vis */
+ /* Tnone */ { 0, 0, 0, 0, 0, },
+ /* Tadt */ { 0, 1, 1, 1, 1, },
+ /* Tadtpick */ { 0, 1, 0, 1, 1, },
+ /* Tarray */ { 1, 0, 0, 0, 1, },
+ /* Tbig */ { 0, 0, 1, 1, 1, },
+ /* Tbyte */ { 0, 0, 1, 0, 1, },
+ /* Tchan */ { 1, 0, 0, 0, 1, },
+ /* Treal */ { 0, 0, 1, 1, 1, },
+ /* Tfn */ { 0, 1, 0, 0, 1, },
+ /* Tint */ { 0, 0, 1, 0, 1, },
+ /* Tlist */ { 1, 0, 0, 0, 1, },
+ /* Tmodule */ { 1, 0, 0, 0, 1, },
+ /* Tref */ { 1, 0, 0, 0, 1, },
+ /* Tstring */ { 1, 0, 1, 0, 1, },
+ /* Ttuple */ { 0, 1, 1, 1, 1, },
+ /* Texception */ { 0, 0, 0, 1, 1, },
+ /* Tfix */ { 0, 0, 1, 0, 1, },
+ /* Tpoly */ { 1, 0, 0, 0, 1, },
+
+ /* Tainit */ { 0, 0, 0, 1, 0, },
+ /* Talt */ { 0, 0, 0, 1, 0, },
+ /* Tany */ { 1, 0, 0, 0, 0, },
+ /* Tarrow */ { 0, 0, 0, 0, 1, },
+ /* Tcase */ { 0, 0, 0, 1, 0, },
+ /* Tcasel */ { 0, 0, 0, 1, 0, },
+ /* Tcasec */ { 0, 0, 0, 1, 0, },
+ /* Tdot */ { 0, 0, 0, 0, 1, },
+ /* Terror */ { 0, 1, 1, 0, 0, },
+ /* Tgoto */ { 0, 0, 0, 1, 0, },
+ /* Tid */ { 0, 0, 0, 0, 1, },
+ /* Tiface */ { 0, 0, 0, 1, 0, },
+ /* Texcept */ { 0, 0, 0, 1, 0, },
+ /* Tinst */ { 0, 1, 1, 1, 1, },
+};
+
+static Teq *eqclass[Tend];
+
+static Type ztype;
+static int eqrec;
+static int eqset;
+static int tcomset;
+
+static int idcompat(Decl*, Decl*, int, int);
+static int rtcompat(Type *t1, Type *t2, int any, int);
+static int assumeteq(Type *t1, Type *t2);
+static int assumetcom(Type *t1, Type *t2);
+static int cleartcomrec(Type *t);
+static int rtequal(Type*, Type*);
+static int cleareqrec(Type*);
+static int idequal(Decl*, Decl*, int, int*);
+static int pyequal(Type*, Type*);
+static int rtsign(Type*, uchar*, int, int);
+static int clearrec(Type*);
+static int idsign(Decl*, int, uchar*, int, int);
+static int idsign1(Decl*, int, uchar*, int, int);
+static int raisessign(Node *n, uchar *sig, int lensig, int spos);
+static void ckfix(Type*, double);
+static int fnunify(Type*, Type*, Tpair**, int);
+static int rtunify(Type*, Type*, Tpair**, int);
+static int idunify(Decl*, Decl*, Tpair**, int);
+static int toccurs(Type*, Tpair**);
+static int fncleareqrec(Type*, Type*);
+static Type* comtype(Src*, Type*, Decl*);
+static Type* duptype(Type*);
+static int tpolys(Type*);
+
+static void
+addtmap(Type *t1, Type *t2, Tpair **tpp)
+{
+ Tpair *tp;
+
+ tp = allocmem(sizeof *tp);
+ tp->t1 = t1;
+ tp->t2 = t2;
+ tp->nxt = *tpp;
+ *tpp = tp;
+}
+
+Type*
+valtmap(Type *t, Tpair *tp)
+{
+ for( ; tp != nil; tp = tp->nxt)
+ if(tp->t1 == t)
+ return tp->t2;
+ return t;
+}
+
+Typelist*
+addtype(Type *t, Typelist *hd)
+{
+ Typelist *tl, *p;
+
+ tl = allocmem(sizeof(*tl));
+ tl->t = t;
+ tl->nxt = nil;
+ if(hd == nil)
+ return tl;
+ for(p = hd; p->nxt != nil; p = p->nxt)
+ ;
+ p->nxt = tl;
+ return hd;
+}
+
+void
+typeinit(void)
+{
+ Decl *id;
+
+ anontupsym = enter(".tuple", 0);
+
+ ztype.sbl = -1;
+ ztype.ok = 0;
+ ztype.rec = 0;
+
+ tbig = mktype(&noline, &noline, Tbig, nil, nil);
+ tbig->size = IBY2LG;
+ tbig->align = IBY2LG;
+ tbig->ok = OKmask;
+
+ tbyte = mktype(&noline, &noline, Tbyte, nil, nil);
+ tbyte->size = 1;
+ tbyte->align = 1;
+ tbyte->ok = OKmask;
+
+ tint = mktype(&noline, &noline, Tint, nil, nil);
+ tint->size = IBY2WD;
+ tint->align = IBY2WD;
+ tint->ok = OKmask;
+
+ treal = mktype(&noline, &noline, Treal, nil, nil);
+ treal->size = IBY2FT;
+ treal->align = IBY2FT;
+ treal->ok = OKmask;
+
+ tstring = mktype(&noline, &noline, Tstring, nil, nil);
+ tstring->size = IBY2WD;
+ tstring->align = IBY2WD;
+ tstring->ok = OKmask;
+
+ texception = mktype(&noline, &noline, Texception, nil, nil);
+ texception->size = IBY2WD;
+ texception->align = IBY2WD;
+ texception->ok = OKmask;
+
+ tany = mktype(&noline, &noline, Tany, nil, nil);
+ tany->size = IBY2WD;
+ tany->align = IBY2WD;
+ tany->ok = OKmask;
+
+ tnone = mktype(&noline, &noline, Tnone, nil, nil);
+ tnone->size = 0;
+ tnone->align = 1;
+ tnone->ok = OKmask;
+
+ terror = mktype(&noline, &noline, Terror, nil, nil);
+ terror->size = 0;
+ terror->align = 1;
+ terror->ok = OKmask;
+
+ tunknown = mktype(&noline, &noline, Terror, nil, nil);
+ tunknown->size = 0;
+ tunknown->align = 1;
+ tunknown->ok = OKmask;
+
+ tfnptr = mktype(&noline, &noline, Ttuple, nil, nil);
+ id = tfnptr->ids = mkids(&nosrc, nil, tany, nil);
+ id->store = Dfield;
+ id->offset = 0;
+ id->sym = enter("t0", 0);
+ id->src = nosrc;
+ id = tfnptr->ids->next = mkids(&nosrc, nil, tint, nil);
+ id->store = Dfield;
+ id->offset = IBY2WD;
+ id->sym = enter("t1", 0);
+ id->src = nosrc;
+
+ rtexception = mktype(&noline, &noline, Tref, texception, nil);
+ rtexception->size = IBY2WD;
+ rtexception->align = IBY2WD;
+ rtexception->ok = OKmask;
+}
+
+void
+typestart(void)
+{
+ descriptors = nil;
+ nfns = 0;
+ nadts = 0;
+ selfdecl = nil;
+ if(tfnptr->decl != nil)
+ tfnptr->decl->desc = nil;
+
+ memset(eqclass, 0, sizeof eqclass);
+
+ typebuiltin(mkids(&nosrc, enter("int", 0), nil, nil), tint);
+ typebuiltin(mkids(&nosrc, enter("big", 0), nil, nil), tbig);
+ typebuiltin(mkids(&nosrc, enter("byte", 0), nil, nil), tbyte);
+ typebuiltin(mkids(&nosrc, enter("string", 0), nil, nil), tstring);
+ typebuiltin(mkids(&nosrc, enter("real", 0), nil, nil), treal);
+}
+
+Teq*
+modclass(void)
+{
+ return eqclass[Tmodule];
+}
+
+Type*
+mktype(Line *start, Line *stop, int kind, Type *tof, Decl *args)
+{
+ Type *t;
+
+ t = allocmem(sizeof *t);
+ *t = ztype;
+ t->src.start = *start;
+ t->src.stop = *stop;
+ t->kind = kind;
+ t->tof = tof;
+ t->ids = args;
+ return t;
+}
+
+Type*
+mktalt(Case *c)
+{
+ Type *t;
+ char buf[32];
+ static int nalt;
+
+ t = mktype(&noline, &noline, Talt, nil, nil);
+ t->decl = mkdecl(&nosrc, Dtype, t);
+ seprint(buf, buf+sizeof(buf), ".a%d", nalt++);
+ t->decl->sym = enter(buf, 0);
+ t->cse = c;
+ return usetype(t);
+}
+
+/*
+ * copy t and the top level of ids
+ */
+Type*
+copytypeids(Type *t)
+{
+ Type *nt;
+ Decl *id, *new, *last;
+
+ nt = allocmem(sizeof *nt);
+ *nt = *t;
+ last = nil;
+ for(id = t->ids; id != nil; id = id->next){
+ new = allocmem(sizeof *id);
+ *new = *id;
+ if(last == nil)
+ nt->ids = new;
+ else
+ last->next = new;
+ last = new;
+ }
+ return nt;
+}
+
+/*
+ * make each of the ids have type t
+ */
+Decl*
+typeids(Decl *ids, Type *t)
+{
+ Decl *id;
+
+ if(ids == nil)
+ return nil;
+
+ ids->ty = t;
+ for(id = ids->next; id != nil; id = id->next){
+ id->ty = t;
+ }
+ return ids;
+}
+
+void
+typebuiltin(Decl *d, Type *t)
+{
+ d->ty = t;
+ t->decl = d;
+ installids(Dtype, d);
+}
+
+Node *
+fielddecl(int store, Decl *ids)
+{
+ Node *n;
+
+ n = mkn(Ofielddecl, nil, nil);
+ n->decl = ids;
+ for(; ids != nil; ids = ids->next)
+ ids->store = store;
+ return n;
+}
+
+Node *
+typedecl(Decl *ids, Type *t)
+{
+ Node *n;
+
+ if(t->decl == nil)
+ t->decl = ids;
+ n = mkn(Otypedecl, nil, nil);
+ n->decl = ids;
+ n->ty = t;
+ for(; ids != nil; ids = ids->next)
+ ids->ty = t;
+ return n;
+}
+
+void
+typedecled(Node *n)
+{
+ installids(Dtype, n->decl);
+}
+
+Node *
+adtdecl(Decl *ids, Node *fields)
+{
+ Node *n;
+ Type *t;
+
+ n = mkn(Oadtdecl, nil, nil);
+ t = mktype(&ids->src.start, &ids->src.stop, Tadt, nil, nil);
+ n->decl = ids;
+ n->left = fields;
+ n->ty = t;
+ t->decl = ids;
+ for(; ids != nil; ids = ids->next)
+ ids->ty = t;
+ return n;
+}
+
+void
+adtdecled(Node *n)
+{
+ Decl *d, *ids;
+
+ d = n->ty->decl;
+ installids(Dtype, d);
+ if(n->ty->polys != nil){
+ pushscope(nil, Sother);
+ installids(Dtype, n->ty->polys);
+ }
+ pushscope(nil, Sother);
+ fielddecled(n->left);
+ n->ty->ids = popscope();
+ if(n->ty->polys != nil)
+ n->ty->polys = popscope();
+ for(ids = n->ty->ids; ids != nil; ids = ids->next)
+ ids->dot = d;
+}
+
+void
+fielddecled(Node *n)
+{
+ for(; n != nil; n = n->right){
+ switch(n->op){
+ case Oseq:
+ fielddecled(n->left);
+ break;
+ case Oadtdecl:
+ adtdecled(n);
+ return;
+ case Otypedecl:
+ typedecled(n);
+ return;
+ case Ofielddecl:
+ installids(Dfield, n->decl);
+ return;
+ case Ocondecl:
+ condecled(n);
+ gdasdecl(n->right);
+ return;
+ case Oexdecl:
+ exdecled(n);
+ return;
+ case Opickdecl:
+ pickdecled(n);
+ return;
+ default:
+ fatal("can't deal with %O in fielddecled", n->op);
+ }
+ }
+}
+
+int
+pickdecled(Node *n)
+{
+ Decl *d;
+ int tag;
+
+ if(n == nil)
+ return 0;
+ tag = pickdecled(n->left);
+ pushscope(nil, Sother);
+ fielddecled(n->right->right);
+ d = n->right->left->decl;
+ d->ty->ids = popscope();
+ installids(Dtag, d);
+ for(; d != nil; d = d->next)
+ d->tag = tag++;
+ return tag;
+}
+
+/*
+ * make the tuple type used to initialize adt t
+ */
+Type*
+mkadtcon(Type *t)
+{
+ Decl *id, *new, *last;
+ Type *nt;
+
+ nt = allocmem(sizeof *nt);
+ *nt = *t;
+ last = nil;
+ nt->ids = nil;
+ nt->kind = Ttuple;
+ for(id = t->ids; id != nil; id = id->next){
+ if(id->store != Dfield)
+ continue;
+ new = allocmem(sizeof *id);
+ *new = *id;
+ new->cyc = 0;
+ if(last == nil)
+ nt->ids = new;
+ else
+ last->next = new;
+ last = new;
+ }
+ last->next = nil;
+ return nt;
+}
+
+/*
+ * make the tuple type used to initialize t,
+ * an adt with pick fields tagged by tg
+ */
+Type*
+mkadtpickcon(Type *t, Type *tgt)
+{
+ Decl *id, *new, *last;
+ Type *nt;
+
+ last = mkids(&tgt->decl->src, nil, tint, nil);
+ last->store = Dfield;
+ nt = mktype(&t->src.start, &t->src.stop, Ttuple, nil, last);
+ for(id = t->ids; id != nil; id = id->next){
+ if(id->store != Dfield)
+ continue;
+ new = allocmem(sizeof *id);
+ *new = *id;
+ new->cyc = 0;
+ last->next = new;
+ last = new;
+ }
+ for(id = tgt->ids; id != nil; id = id->next){
+ if(id->store != Dfield)
+ continue;
+ new = allocmem(sizeof *id);
+ *new = *id;
+ new->cyc = 0;
+ last->next = new;
+ last = new;
+ }
+ last->next = nil;
+ return nt;
+}
+
+/*
+ * make an identifier type
+ */
+Type*
+mkidtype(Src *src, Sym *s)
+{
+ Type *t;
+
+ t = mktype(&src->start, &src->stop, Tid, nil, nil);
+ if(s->unbound == nil){
+ s->unbound = mkdecl(src, Dunbound, nil);
+ s->unbound->sym = s;
+ }
+ t->decl = s->unbound;
+ return t;
+}
+
+/*
+ * make a qualified type for t->s
+ */
+Type*
+mkarrowtype(Line *start, Line *stop, Type *t, Sym *s)
+{
+ Src src;
+
+ src.start = *start;
+ src.stop = *stop;
+ t = mktype(start, stop, Tarrow, t, nil);
+ if(s->unbound == nil){
+ s->unbound = mkdecl(&src, Dunbound, nil);
+ s->unbound->sym = s;
+ }
+ t->decl = s->unbound;
+ return t;
+}
+
+/*
+ * make a qualified type for t.s
+ */
+Type*
+mkdottype(Line *start, Line *stop, Type *t, Sym *s)
+{
+ Src src;
+
+ src.start = *start;
+ src.stop = *stop;
+ t = mktype(start, stop, Tdot, t, nil);
+ if(s->unbound == nil){
+ s->unbound = mkdecl(&src, Dunbound, nil);
+ s->unbound->sym = s;
+ }
+ t->decl = s->unbound;
+ return t;
+}
+
+Type*
+mkinsttype(Src* src, Type *tt, Typelist *tl)
+{
+ Type *t;
+
+ t = mktype(&src->start, &src->stop, Tinst, tt, nil);
+ t->u.tlist = tl;
+ return t;
+}
+
+/*
+ * look up the name f in the fields of a module, adt, or tuple
+ */
+Decl*
+namedot(Decl *ids, Sym *s)
+{
+ for(; ids != nil; ids = ids->next)
+ if(ids->sym == s)
+ return ids;
+ return nil;
+}
+
+/*
+ * complete the declaration of an adt
+ * methods frames get sized in module definition or during function definition
+ * place the methods at the end of the field list
+ */
+void
+adtdefd(Type *t)
+{
+ Decl *d, *id, *next, *aux, *store, *auxhd, *tagnext;
+ int seentags;
+
+ if(debug['x'])
+ print("adt %T defd\n", t);
+ d = t->decl;
+ tagnext = nil;
+ store = nil;
+ for(id = t->polys; id != nil; id = id->next){
+ id->store = Dtype;
+ id->ty = verifytypes(id->ty, d, nil);
+ }
+ for(id = t->ids; id != nil; id = next){
+ if(id->store == Dtag){
+ if(t->tags != nil)
+ error(id->src.start, "only one set of pick fields allowed");
+ tagnext = pickdefd(t, id);
+ next = tagnext;
+ if(store != nil)
+ store->next = next;
+ else
+ t->ids = next;
+ continue;
+ }else{
+ id->dot = d;
+ next = id->next;
+ store = id;
+ }
+ }
+ aux = nil;
+ store = nil;
+ auxhd = nil;
+ seentags = 0;
+ for(id = t->ids; id != nil; id = next){
+ if(id == tagnext)
+ seentags = 1;
+
+ next = id->next;
+ id->dot = d;
+ id->ty = topvartype(verifytypes(id->ty, d, nil), id, 1, 1);
+ if(id->store == Dfield && id->ty->kind == Tfn)
+ id->store = Dfn;
+ if(id->store == Dfn || id->store == Dconst){
+ if(store != nil)
+ store->next = next;
+ else
+ t->ids = next;
+ if(aux != nil)
+ aux->next = id;
+ else
+ auxhd = id;
+ aux = id;
+ }else{
+ if(seentags)
+ error(id->src.start, "pick fields must be the last data fields in an adt");
+ store = id;
+ }
+ }
+ if(aux != nil)
+ aux->next = nil;
+ if(store != nil)
+ store->next = auxhd;
+ else
+ t->ids = auxhd;
+
+ for(id = t->tags; id != nil; id = id->next){
+ id->ty = verifytypes(id->ty, d, nil);
+ if(id->ty->tof == nil)
+ id->ty->tof = mkadtpickcon(t, id->ty);
+ }
+}
+
+/*
+ * assemble the data structure for an adt with a pick clause.
+ * since the scoping rules for adt pick fields are strange,
+ * we have a cutomized check for overlapping defitions.
+ */
+Decl*
+pickdefd(Type *t, Decl *tg)
+{
+ Decl *id, *xid, *lasttg, *d;
+ Type *tt;
+ int tag;
+
+ lasttg = nil;
+ d = t->decl;
+ t->tags = tg;
+ tag = 0;
+ while(tg != nil){
+ tt = tg->ty;
+ if(tt->kind != Tadtpick || tg->tag != tag)
+ break;
+ tt->decl = tg;
+ lasttg = tg;
+ for(; tg != nil; tg = tg->next){
+ if(tg->ty != tt)
+ break;
+ tag++;
+ lasttg = tg;
+ tg->dot = d;
+ }
+ for(id = tt->ids; id != nil; id = id->next){
+ xid = namedot(t->ids, id->sym);
+ if(xid != nil)
+ error(id->src.start, "redeclaration of %K, previously declared as %k on line %L",
+ id, xid, xid->src.start);
+ id->dot = d;
+ }
+ }
+ if(lasttg == nil){
+ error(t->src.start, "empty pick field declaration in %T", t);
+ t->tags = nil;
+ }else
+ lasttg->next = nil;
+ d->tag = tag;
+ return tg;
+}
+
+Node*
+moddecl(Decl *ids, Node *fields)
+{
+ Node *n;
+ Type *t;
+
+ n = mkn(Omoddecl, mkn(Oseq, nil, nil), nil);
+ t = mktype(&ids->src.start, &ids->src.stop, Tmodule, nil, nil);
+ n->decl = ids;
+ n->left = fields;
+ n->ty = t;
+ return n;
+}
+
+void
+moddecled(Node *n)
+{
+ Decl *d, *ids, *im, *dot;
+ Type *t;
+ Sym *s;
+ char buf[StrSize];
+ int isimp;
+ Dlist *dm, *dl;
+
+ d = n->decl;
+ installids(Dtype, d);
+ isimp = 0;
+ for(ids = d; ids != nil; ids = ids->next){
+ for(im = impmods; im != nil; im = im->next){
+ if(ids->sym == im->sym){
+ isimp = 1;
+ d = ids;
+ dm = malloc(sizeof(Dlist));
+ dm->d = ids;
+ dm->next = nil;
+ if(impdecls == nil)
+ impdecls = dm;
+ else{
+ for(dl = impdecls; dl->next != nil; dl = dl->next)
+ ;
+ dl->next = dm;
+ }
+ }
+ }
+ ids->ty = n->ty;
+ }
+ pushscope(nil, Sother);
+ fielddecled(n->left);
+
+ d->ty->ids = popscope();
+
+ /*
+ * make the current module the -> parent of all contained decls->
+ */
+ for(ids = d->ty->ids; ids != nil; ids = ids->next)
+ ids->dot = d;
+
+ t = d->ty;
+ t->decl = d;
+ if(debug['m'])
+ print("declare module %s\n", d->sym->name);
+
+ /*
+ * add the iface declaration in case it's needed later
+ */
+ seprint(buf, buf+sizeof(buf), ".m.%s", d->sym->name);
+ installids(Dglobal, mkids(&d->src, enter(buf, 0), tnone, nil));
+
+ if(isimp){
+ for(ids = d->ty->ids; ids != nil; ids = ids->next){
+ s = ids->sym;
+ if(s->decl != nil && s->decl->scope >= scope){
+ dot = s->decl->dot;
+ if(s->decl->store != Dwundef && dot != nil && dot != d && isimpmod(dot->sym) && dequal(ids, s->decl, 0))
+ continue;
+ redecl(ids);
+ ids->old = s->decl->old;
+ }else
+ ids->old = s->decl;
+ s->decl = ids;
+ ids->scope = scope;
+ }
+ }
+}
+
+/*
+ * for each module in id,
+ * link by field ext all of the decls for
+ * functions needed in external linkage table
+ * collect globals and make a tuple for all of them
+ */
+Type*
+mkiface(Decl *m)
+{
+ Decl *iface, *last, *globals, *glast, *id, *d;
+ Type *t;
+ char buf[StrSize];
+
+ iface = last = allocmem(sizeof(Decl));
+ globals = glast = mkdecl(&m->src, Dglobal, mktype(&m->src.start, &m->src.stop, Tadt, nil, nil));
+ for(id = m->ty->ids; id != nil; id = id->next){
+ switch(id->store){
+ case Dglobal:
+ glast = glast->next = dupdecl(id);
+ id->iface = globals;
+ glast->iface = id;
+ break;
+ case Dfn:
+ id->iface = last = last->next = dupdecl(id);
+ last->iface = id;
+ break;
+ case Dtype:
+ if(id->ty->kind != Tadt)
+ break;
+ for(d = id->ty->ids; d != nil; d = d->next){
+ if(d->store == Dfn){
+ d->iface = last = last->next = dupdecl(d);
+ last->iface = d;
+ }
+ }
+ break;
+ }
+ }
+ last->next = nil;
+ iface = namesort(iface->next);
+
+ if(globals->next != nil){
+ glast->next = nil;
+ globals->ty->ids = namesort(globals->next);
+ globals->ty->decl = globals;
+ globals->sym = enter(".mp", 0);
+ globals->dot = m;
+ globals->next = iface;
+ iface = globals;
+ }
+
+ /*
+ * make the interface type and install an identifier for it
+ * the iface has a ref count if it is loaded
+ */
+ t = mktype(&m->src.start, &m->src.stop, Tiface, nil, iface);
+ seprint(buf, buf+sizeof(buf), ".m.%s", m->sym->name);
+ id = enter(buf, 0)->decl;
+ t->decl = id;
+ id->ty = t;
+
+ /*
+ * dummy node so the interface is initialized
+ */
+ id->init = mkn(Onothing, nil, nil);
+ id->init->ty = t;
+ id->init->decl = id;
+ return t;
+}
+
+void
+joiniface(Type *mt, Type *t)
+{
+ Decl *id, *d, *iface, *globals;
+
+ iface = t->ids;
+ globals = iface;
+ if(iface != nil && iface->store == Dglobal)
+ iface = iface->next;
+ for(id = mt->tof->ids; id != nil; id = id->next){
+ switch(id->store){
+ case Dglobal:
+ for(d = id->ty->ids; d != nil; d = d->next)
+ d->iface->iface = globals;
+ break;
+ case Dfn:
+ id->iface->iface = iface;
+ iface = iface->next;
+ break;
+ default:
+ fatal("unknown store %k in joiniface", id);
+ break;
+ }
+ }
+ if(iface != nil)
+ fatal("join iface not matched");
+ mt->tof = t;
+}
+
+void
+addiface(Decl *m, Decl *d)
+{
+ Type *t;
+ Decl *id, *last, *dd, *lastorig;
+ Dlist *dl;
+
+ if(d == nil || !local(d))
+ return;
+ modrefable(d->ty);
+ if(m == nil){
+ if(impdecls->next != nil)
+ for(dl = impdecls; dl != nil; dl = dl->next)
+ if(dl->d->ty->tof != impdecl->ty->tof) /* impdecl last */
+ addiface(dl->d, d);
+ addiface(impdecl, d);
+ return;
+ }
+ t = m->ty->tof;
+ last = nil;
+ lastorig = nil;
+ for(id = t->ids; id != nil; id = id->next){
+ if(d == id || d == id->iface)
+ return;
+ last = id;
+ if(id->tag == 0)
+ lastorig = id;
+ }
+ dd = dupdecl(d);
+ if(d->dot == nil)
+ d->dot = dd->dot = m;
+ d->iface = dd;
+ dd->iface = d;
+if(debug['v']) print("addiface %p %p\n", d, dd);
+ if(last == nil)
+ t->ids = dd;
+ else
+ last->next = dd;
+ dd->tag = 1; /* mark so not signed */
+ if(lastorig == nil)
+ t->ids = namesort(t->ids);
+ else
+ lastorig->next = namesort(lastorig->next);
+}
+
+/*
+ * eliminate unused declarations from interfaces
+ * label offset within interface
+ */
+void
+narrowmods(void)
+{
+ Teq *eq;
+ Decl *id, *last;
+ Type *t;
+ long offset;
+
+ for(eq = modclass(); eq != nil; eq = eq->eq){
+ t = eq->ty->tof;
+
+ if(t->linkall == 0){
+ last = nil;
+ for(id = t->ids; id != nil; id = id->next){
+ if(id->refs == 0){
+ if(last == nil)
+ t->ids = id->next;
+ else
+ last->next = id->next;
+ }else
+ last = id;
+ }
+
+ /*
+ * need to resize smaller interfaces
+ */
+ resizetype(t);
+ }
+
+ offset = 0;
+ for(id = t->ids; id != nil; id = id->next)
+ id->offset = offset++;
+
+ /*
+ * rathole to stuff number of entries in interface
+ */
+ t->decl->init->val = offset;
+ }
+}
+
+/*
+ * check to see if any data field of module m if referenced.
+ * if so, mark all data in m
+ */
+void
+moddataref(void)
+{
+ Teq *eq;
+ Decl *id;
+
+ for(eq = modclass(); eq != nil; eq = eq->eq){
+ id = eq->ty->tof->ids;
+ if(id != nil && id->store == Dglobal && id->refs)
+ for(id = eq->ty->ids; id != nil; id = id->next)
+ if(id->store == Dglobal)
+ modrefable(id->ty);
+ }
+}
+
+/*
+ * move the global declarations in interface to the front
+ */
+Decl*
+modglobals(Decl *mod, Decl *globals)
+{
+ Decl *id, *head, *last;
+
+ /*
+ * make a copy of all the global declarations
+ * used for making a type descriptor for globals ONLY
+ * note we now have two declarations for the same variables,
+ * which is apt to cause problems if code changes
+ *
+ * here we fix up the offsets for the real declarations
+ */
+ idoffsets(mod->ty->ids, 0, 1);
+
+ last = head = allocmem(sizeof(Decl));
+ for(id = mod->ty->ids; id != nil; id = id->next)
+ if(id->store == Dglobal)
+ last = last->next = dupdecl(id);
+
+ last->next = globals;
+ return head->next;
+}
+
+/*
+ * snap all id type names to the actual type
+ * check that all types are completely defined
+ * verify that the types look ok
+ */
+Type*
+validtype(Type *t, Decl *inadt)
+{
+ if(t == nil)
+ return t;
+ bindtypes(t);
+ t = verifytypes(t, inadt, nil);
+ cycsizetype(t);
+ teqclass(t);
+ return t;
+}
+
+Type*
+usetype(Type *t)
+{
+ if(t == nil)
+ return t;
+ t = validtype(t, nil);
+ reftype(t);
+ return t;
+}
+
+Type*
+internaltype(Type *t)
+{
+ bindtypes(t);
+ t->ok = OKverify;
+ sizetype(t);
+ t->ok = OKmask;
+ return t;
+}
+
+/*
+ * checks that t is a valid top-level type
+ */
+Type*
+topvartype(Type *t, Decl *id, int tyok, int polyok)
+{
+ if(t->kind == Tadt && t->tags != nil || t->kind == Tadtpick)
+ error(id->src.start, "cannot declare %s with type %T", id->sym->name, t);
+ if(!tyok && t->kind == Tfn)
+ error(id->src.start, "cannot declare %s to be a function", id->sym->name);
+ if(!polyok && (t->kind == Tadt || t->kind == Tadtpick) && ispolyadt(t))
+ error(id->src.start, "cannot declare %s of a polymorphic type", id->sym->name);
+ return t;
+}
+
+Type*
+toptype(Src *src, Type *t)
+{
+ if(t->kind == Tadt && t->tags != nil || t->kind == Tadtpick)
+ error(src->start, "%T, an adt with pick fields, must be used with ref", t);
+ if(t->kind == Tfn)
+ error(src->start, "data cannot have a fn type like %T", t);
+ return t;
+}
+
+static Type*
+comtype(Src *src, Type *t, Decl* adtd)
+{
+ if(adtd == nil && (t->kind == Tadt || t->kind == Tadtpick) && ispolyadt(t))
+ error(src->start, "polymorphic type %T illegal here", t);
+ return t;
+}
+
+void
+usedty(Type *t)
+{
+ if(t != nil && (t->ok | OKmodref) != OKmask)
+ fatal("used ty %t %2.2ux", t, t->ok);
+}
+
+void
+bindtypes(Type *t)
+{
+ Decl *id;
+ Typelist *tl;
+
+ if(t == nil)
+ return;
+ if((t->ok & OKbind) == OKbind)
+ return;
+ t->ok |= OKbind;
+ switch(t->kind){
+ case Tadt:
+ if(t->polys != nil){
+ pushscope(nil, Sother);
+ installids(Dtype, t->polys);
+ }
+ if(t->val != nil)
+ mergepolydecs(t);
+ if(t->polys != nil){
+ popscope();
+ for(id = t->polys; id != nil; id = id->next)
+ bindtypes(id->ty);
+ }
+ break;
+ case Tadtpick:
+ case Tmodule:
+ case Terror:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tnone:
+ case Tany:
+ case Tiface:
+ case Tainit:
+ case Talt:
+ case Tcase:
+ case Tcasel:
+ case Tcasec:
+ case Tgoto:
+ case Texcept:
+ case Tfix:
+ case Tpoly:
+ break;
+ case Tarray:
+ case Tarrow:
+ case Tchan:
+ case Tdot:
+ case Tlist:
+ case Tref:
+ bindtypes(t->tof);
+ break;
+ case Tid:
+ id = t->decl->sym->decl;
+ if(id == nil)
+ id = undefed(&t->src, t->decl->sym);
+ /* save a little space */
+ id->sym->unbound = nil;
+ t->decl = id;
+ break;
+ case Ttuple:
+ case Texception:
+ for(id = t->ids; id != nil; id = id->next)
+ bindtypes(id->ty);
+ break;
+ case Tfn:
+ if(t->polys != nil){
+ pushscope(nil, Sother);
+ installids(Dtype, t->polys);
+ }
+ for(id = t->ids; id != nil; id = id->next)
+ bindtypes(id->ty);
+ bindtypes(t->tof);
+ if(t->val != nil)
+ mergepolydecs(t);
+ if(t->polys != nil){
+ popscope();
+ for(id = t->polys; id != nil; id = id->next)
+ bindtypes(id->ty);
+ }
+ break;
+ case Tinst:
+ bindtypes(t->tof);
+ for(tl = t->u.tlist; tl != nil; tl = tl->nxt)
+ bindtypes(tl->t);
+ break;
+ default:
+ fatal("bindtypes: unknown type kind %d", t->kind);
+ }
+}
+
+/*
+ * walk the type checking for validity
+ */
+Type*
+verifytypes(Type *t, Decl *adtt, Decl *poly)
+{
+ Node *n;
+ Decl *id, *id1, *last;
+ char buf[32];
+ int i, cyc;
+ Ok ok, ok1;
+ double max;
+ Typelist *tl;
+
+ if(t == nil)
+ return nil;
+ if((t->ok & OKverify) == OKverify)
+ return t;
+ t->ok |= OKverify;
+if((t->ok & (OKverify|OKbind)) != (OKverify|OKbind))
+fatal("verifytypes bogus ok for %t", t);
+ cyc = t->flags&CYCLIC;
+ switch(t->kind){
+ case Terror:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tnone:
+ case Tany:
+ case Tiface:
+ case Tainit:
+ case Talt:
+ case Tcase:
+ case Tcasel:
+ case Tcasec:
+ case Tgoto:
+ case Texcept:
+ break;
+ case Tfix:
+ n = t->val;
+ max = 0.0;
+ if(n->op == Oseq){
+ ok = echeck(n->left, 0, 0, n);
+ ok1 = echeck(n->right, 0, 0, n);
+ if(!ok.ok || !ok1.ok)
+ return terror;
+ if(n->left->ty != treal || n->right->ty != treal){
+ error(t->src.start, "fixed point scale/maximum not real");
+ return terror;
+ }
+ n->right = fold(n->right);
+ if(n->right->op != Oconst){
+ error(t->src.start, "fixed point maximum not constant");
+ return terror;
+ }
+ if((max = n->right->rval) <= 0){
+ error(t->src.start, "non-positive fixed point maximum");
+ return terror;
+ }
+ n = n->left;
+ }
+ else{
+ ok = echeck(n, 0, 0, nil);
+ if(!ok.ok)
+ return terror;
+ if(n->ty != treal){
+ error(t->src.start, "fixed point scale not real");
+ return terror;
+ }
+ }
+ n = t->val = fold(n);
+ if(n->op != Oconst){
+ error(t->src.start, "fixed point scale not constant");
+ return terror;
+ }
+ if(n->rval <= 0){
+ error(t->src.start, "non-positive fixed point scale");
+ return terror;
+ }
+ ckfix(t, max);
+ break;
+ case Tref:
+ t->tof = comtype(&t->src, verifytypes(t->tof, adtt, nil), adtt);
+ if(t->tof != nil && !tattr[t->tof->kind].refable){
+ error(t->src.start, "cannot have a ref %T", t->tof);
+ return terror;
+ }
+ if(0 && t->tof->kind == Tfn && t->tof->ids != nil && t->tof->ids->implicit)
+ error(t->src.start, "function references cannot have a self argument");
+ if(0 && t->tof->kind == Tfn && t->polys != nil)
+ error(t->src.start, "function references cannot be polymorphic");
+ break;
+ case Tchan:
+ case Tarray:
+ case Tlist:
+ t->tof = comtype(&t->src, toptype(&t->src, verifytypes(t->tof, adtt, nil)), adtt);
+ break;
+ case Tid:
+ t->ok &= ~OKverify;
+ t = verifytypes(idtype(t), adtt, nil);
+ break;
+ case Tarrow:
+ t->ok &= ~OKverify;
+ t = verifytypes(arrowtype(t, adtt), adtt, nil);
+ break;
+ case Tdot:
+ /*
+ * verify the parent adt & lookup the tag fields
+ */
+ t->ok &= ~OKverify;
+ t = verifytypes(dottype(t, adtt), adtt, nil);
+ break;
+ case Tadt:
+ /*
+ * this is where Tadt may get tag fields added
+ */
+ adtdefd(t);
+ break;
+ case Tadtpick:
+ for(id = t->ids; id != nil; id = id->next){
+ id->ty = topvartype(verifytypes(id->ty, id->dot, nil), id, 0, 1);
+ if(id->store == Dconst)
+ error(t->src.start, "pick fields cannot be a con like %s", id->sym->name);
+ }
+ verifytypes(t->decl->dot->ty, nil, nil);
+ break;
+ case Tmodule:
+ for(id = t->ids; id != nil; id = id->next){
+ id->ty = verifytypes(id->ty, nil, nil);
+ if(id->store == Dglobal && id->ty->kind == Tfn)
+ id->store = Dfn;
+ if(id->store != Dtype && id->store != Dfn)
+ topvartype(id->ty, id, 0, 0);
+ }
+ break;
+ case Ttuple:
+ case Texception:
+ if(t->decl == nil){
+ t->decl = mkdecl(&t->src, Dtype, t);
+ t->decl->sym = enter(".tuple", 0);
+ }
+ i = 0;
+ for(id = t->ids; id != nil; id = id->next){
+ id->store = Dfield;
+ if(id->sym == nil){
+ seprint(buf, buf+sizeof(buf), "t%d", i);
+ id->sym = enter(buf, 0);
+ }
+ i++;
+ id->ty = toptype(&id->src, verifytypes(id->ty, adtt, nil));
+ /* id->ty = comtype(&id->src, toptype(&id->src, verifytypes(id->ty, adtt, nil)), adtt); */
+ }
+ break;
+ case Tfn:
+ last = nil;
+ for(id = t->ids; id != nil; id = id->next){
+ id->store = Darg;
+ id->ty = topvartype(verifytypes(id->ty, adtt, nil), id, 0, 1);
+ if(id->implicit){
+ Decl *selfd;
+
+ selfd = poly ? poly : adtt;
+ if(selfd == nil)
+ error(t->src.start, "function is not a member of an adt, so can't use self");
+ else if(id != t->ids)
+ error(id->src.start, "only the first argument can use self");
+ else if(id->ty != selfd->ty && (id->ty->kind != Tref || id->ty->tof != selfd->ty))
+ error(id->src.start, "self argument's type must be %s or ref %s",
+ selfd->sym->name, selfd->sym->name);
+ }
+ last = id;
+ }
+ for(id = t->polys; id != nil; id = id->next){
+ if(adtt != nil){
+ for(id1 = adtt->ty->polys; id1 != nil; id1 = id1->next){
+ if(id1->sym == id->sym)
+ id->ty = id1->ty;
+ }
+ }
+ id->store = Dtype;
+ id->ty = verifytypes(id->ty, adtt, nil);
+ }
+ t->tof = comtype(&t->src, toptype(&t->src, verifytypes(t->tof, adtt, nil)), adtt);
+ if(t->varargs && (last == nil || last->ty != tstring))
+ error(t->src.start, "variable arguments must be preceded by a string");
+ if(t->varargs && t->polys != nil)
+ error(t->src.start, "polymorphic functions must not have variable arguments");
+ break;
+ case Tpoly:
+ for(id = t->ids; id != nil; id = id->next){
+ id->store = Dfn;
+ id->ty = verifytypes(id->ty, adtt, t->decl);
+ }
+ break;
+ case Tinst:
+ t->ok &= ~OKverify;
+ t->tof = verifytypes(t->tof, adtt, nil);
+ for(tl = t->u.tlist; tl != nil; tl = tl->nxt)
+ tl->t = verifytypes(tl->t, adtt, nil);
+ t = verifytypes(insttype(t, adtt, nil), adtt, nil);
+ break;
+ default:
+ fatal("verifytypes: unknown type kind %d", t->kind);
+ }
+ if(cyc)
+ t->flags |= CYCLIC;
+ return t;
+}
+
+/*
+ * resolve an id type
+ */
+Type*
+idtype(Type *t)
+{
+ Decl *id;
+ Type *tt;
+
+ id = t->decl;
+ if(id->store == Dunbound)
+ fatal("idtype: unbound decl");
+ tt = id->ty;
+ if(id->store != Dtype && id->store != Dtag){
+ if(id->store == Dundef){
+ id->store = Dwundef;
+ error(t->src.start, "%s is not declared", id->sym->name);
+ }else if(id->store == Dimport){
+ id->store = Dwundef;
+ error(t->src.start, "%s's type cannot be determined", id->sym->name);
+ }else if(id->store != Dwundef)
+ error(t->src.start, "%s is not a type", id->sym->name);
+ return terror;
+ }
+ if(tt == nil){
+ error(t->src.start, "%t not fully defined", t);
+ return terror;
+ }
+ return tt;
+}
+
+/*
+ * resolve a -> qualified type
+ */
+Type*
+arrowtype(Type *t, Decl *adtt)
+{
+ Type *tt;
+ Decl *id;
+
+ id = t->decl;
+ if(id->ty != nil){
+ if(id->store == Dunbound)
+ fatal("arrowtype: unbound decl has a type");
+ return id->ty;
+ }
+
+ /*
+ * special hack to allow module variables to derive other types
+ */
+ tt = t->tof;
+ if(tt->kind == Tid){
+ id = tt->decl;
+ if(id->store == Dunbound)
+ fatal("arrowtype: Tid's decl unbound");
+ if(id->store == Dimport){
+ id->store = Dwundef;
+ error(t->src.start, "%s's type cannot be determined", id->sym->name);
+ return terror;
+ }
+
+ /*
+ * forward references to module variables can't be resolved
+ */
+ if(id->store != Dtype && !(id->ty->ok & OKbind)){
+ error(t->src.start, "%s's type cannot be determined", id->sym->name);
+ return terror;
+ }
+
+ if(id->store == Dwundef)
+ return terror;
+ tt = id->ty = verifytypes(id->ty, adtt, nil);
+ if(tt == nil){
+ error(t->tof->src.start, "%T is not a module", t->tof);
+ return terror;
+ }
+ }else
+ tt = verifytypes(t->tof, adtt, nil);
+ t->tof = tt;
+ if(tt == terror)
+ return terror;
+ if(tt->kind != Tmodule){
+ error(t->src.start, "%T is not a module", tt);
+ return terror;
+ }
+ id = namedot(tt->ids, t->decl->sym);
+ if(id == nil){
+ error(t->src.start, "%s is not a member of %T", t->decl->sym->name, tt);
+ return terror;
+ }
+ if(id->store == Dtype && id->ty != nil){
+ t->decl = id;
+ return id->ty;
+ }
+ error(t->src.start, "%T is not a type", t);
+ return terror;
+}
+
+/*
+ * resolve a . qualified type
+ */
+Type*
+dottype(Type *t, Decl *adtt)
+{
+ Type *tt;
+ Decl *id;
+
+ if(t->decl->ty != nil){
+ if(t->decl->store == Dunbound)
+ fatal("dottype: unbound decl has a type");
+ return t->decl->ty;
+ }
+ t->tof = tt = verifytypes(t->tof, adtt, nil);
+ if(tt == terror)
+ return terror;
+ if(tt->kind != Tadt){
+ error(t->src.start, "%T is not an adt", tt);
+ return terror;
+ }
+ id = namedot(tt->tags, t->decl->sym);
+ if(id != nil && id->ty != nil){
+ t->decl = id;
+ return id->ty;
+ }
+ error(t->src.start, "%s is not a pick tag of %T", t->decl->sym->name, tt);
+ return terror;
+}
+
+Type*
+insttype(Type *t, Decl *adtt, Tpair **tp)
+{
+ Type *tt;
+ Typelist *tl;
+ Decl *ids;
+ Tpair *tp1, *tp2;
+ Src src;
+
+ src = t->src;
+ if(tp == nil){
+ tp2 = nil;
+ tp = &tp2;
+ }
+ if(t->tof->kind != Tadt && t->tof->kind != Tadtpick){
+ error(src.start, "%T is not an adt", t->tof);
+ return terror;
+ }
+ if(t->tof->kind == Tadt)
+ ids = t->tof->polys;
+ else
+ ids = t->tof->decl->dot->ty->polys;
+ if(ids == nil){
+ error(src.start, "%T is not a polymorphic adt", t->tof);
+ return terror;
+ }
+ for(tl = t->u.tlist; tl != nil && ids != nil; tl = tl->nxt, ids = ids->next){
+ tt = tl->t;
+ if(!tattr[tt->kind].isptr){
+ error(src.start, "%T is not a pointer type", tt);
+ return terror;
+ }
+ unifysrc = src;
+ if(!tunify(ids->ty, tt, &tp1)){
+ error(src.start, "type %T does not match %T", tt, ids->ty);
+ return terror;
+ }
+ /* usetype(tt); */
+ tt = verifytypes(tt, adtt, nil);
+ addtmap(ids->ty, tt, tp);
+ }
+ if(tl != nil){
+ error(src.start, "too many actual types in instantiation");
+ return terror;
+ }
+ if(ids != nil){
+ error(src.start, "too few actual types in instantiation");
+ return terror;
+ }
+ tp1 = *tp;
+ tt = t->tof;
+ t = expandtype(tt, t, adtt, tp);
+ if(t == tt && adtt == nil)
+ t = duptype(t);
+ if(t != tt){
+ t->u.tmap = tp1;
+ if(debug['w']){
+ print("tmap for %T: ", t);
+ for( ; tp1!=nil; tp1=tp1->nxt)
+ print("%T -> %T ", tp1->t1, tp1->t2);
+ print("\n");
+ }
+ }
+ t->src = src;
+ return t;
+}
+
+/*
+ * walk a type, putting all adts, modules, and tuples into equivalence classes
+ */
+void
+teqclass(Type *t)
+{
+ Decl *id, *tg;
+ Teq *teq;
+
+ if(t == nil || (t->ok & OKclass) == OKclass)
+ return;
+ t->ok |= OKclass;
+ switch(t->kind){
+ case Terror:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tnone:
+ case Tany:
+ case Tiface:
+ case Tainit:
+ case Talt:
+ case Tcase:
+ case Tcasel:
+ case Tcasec:
+ case Tgoto:
+ case Texcept:
+ case Tfix:
+ case Tpoly:
+ return;
+ case Tref:
+ teqclass(t->tof);
+ return;
+ case Tchan:
+ case Tarray:
+ case Tlist:
+ teqclass(t->tof);
+ if(!debug['Z'])
+ return;
+ break;
+ case Tadt:
+ case Tadtpick:
+ case Ttuple:
+ case Texception:
+ for(id = t->ids; id != nil; id = id->next)
+ teqclass(id->ty);
+ for(tg = t->tags; tg != nil; tg = tg->next)
+ teqclass(tg->ty);
+ for(id = t->polys; id != nil; id = id->next)
+ teqclass(id->ty);
+ break;
+ case Tmodule:
+ t->tof = mkiface(t->decl);
+ for(id = t->ids; id != nil; id = id->next)
+ teqclass(id->ty);
+ break;
+ case Tfn:
+ for(id = t->ids; id != nil; id = id->next)
+ teqclass(id->ty);
+ for(id = t->polys; id != nil; id = id->next)
+ teqclass(id->ty);
+ teqclass(t->tof);
+ return;
+ default:
+ fatal("teqclass: unknown type kind %d", t->kind);
+ return;
+ }
+
+ /*
+ * find an equivalent type
+ * stupid linear lookup could be made faster
+ */
+ if((t->ok & OKsized) != OKsized)
+ fatal("eqclass type not sized: %t", t);
+
+ for(teq = eqclass[t->kind]; teq != nil; teq = teq->eq){
+ if(t->size == teq->ty->size && tequal(t, teq->ty)){
+ t->eq = teq;
+ if(t->kind == Tmodule)
+ joiniface(t, t->eq->ty->tof);
+ return;
+ }
+ }
+
+ /*
+ * if no equiv type, make one
+ */
+ t->eq = allocmem(sizeof(Teq));
+ t->eq->id = 0;
+ t->eq->ty = t;
+ t->eq->eq = eqclass[t->kind];
+ eqclass[t->kind] = t->eq;
+}
+
+/*
+ * record that we've used the type
+ * using a type uses all types reachable from that type
+ */
+void
+reftype(Type *t)
+{
+ Decl *id, *tg;
+
+ if(t == nil || (t->ok & OKref) == OKref)
+ return;
+ t->ok |= OKref;
+ if(t->decl != nil && t->decl->refs == 0)
+ t->decl->refs++;
+ switch(t->kind){
+ case Terror:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tnone:
+ case Tany:
+ case Tiface:
+ case Tainit:
+ case Talt:
+ case Tcase:
+ case Tcasel:
+ case Tcasec:
+ case Tgoto:
+ case Texcept:
+ case Tfix:
+ case Tpoly:
+ break;
+ case Tref:
+ case Tchan:
+ case Tarray:
+ case Tlist:
+ if(t->decl != nil){
+ if(nadts >= lenadts){
+ lenadts = nadts + 32;
+ adts = reallocmem(adts, lenadts * sizeof *adts);
+ }
+ adts[nadts++] = t->decl;
+ }
+ reftype(t->tof);
+ break;
+ case Tadt:
+ case Tadtpick:
+ case Ttuple:
+ case Texception:
+ if(t->kind == Tadt || t->kind == Ttuple && t->decl->sym != anontupsym){
+ if(nadts >= lenadts){
+ lenadts = nadts + 32;
+ adts = reallocmem(adts, lenadts * sizeof *adts);
+ }
+ adts[nadts++] = t->decl;
+ }
+ for(id = t->ids; id != nil; id = id->next)
+ if(id->store != Dfn)
+ reftype(id->ty);
+ for(tg = t->tags; tg != nil; tg = tg->next)
+ reftype(tg->ty);
+ for(id = t->polys; id != nil; id = id->next)
+ reftype(id->ty);
+ if(t->kind == Tadtpick)
+ reftype(t->decl->dot->ty);
+ break;
+ case Tmodule:
+ /*
+ * a module's elements should get used individually
+ * but do the globals for any sbl file
+ */
+ if(bsym != nil)
+ for(id = t->ids; id != nil; id = id->next)
+ if(id->store == Dglobal)
+ reftype(id->ty);
+ break;
+ case Tfn:
+ for(id = t->ids; id != nil; id = id->next)
+ reftype(id->ty);
+ for(id = t->polys; id != nil; id = id->next)
+ reftype(id->ty);
+ reftype(t->tof);
+ break;
+ default:
+ fatal("reftype: unknown type kind %d", t->kind);
+ break;
+ }
+}
+
+/*
+ * check all reachable types for cycles and illegal forward references
+ * find the size of all the types
+ */
+void
+cycsizetype(Type *t)
+{
+ Decl *id, *tg;
+
+ if(t == nil || (t->ok & (OKcycsize|OKcyc|OKsized)) == (OKcycsize|OKcyc|OKsized))
+ return;
+ t->ok |= OKcycsize;
+ switch(t->kind){
+ case Terror:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tnone:
+ case Tany:
+ case Tiface:
+ case Tainit:
+ case Talt:
+ case Tcase:
+ case Tcasel:
+ case Tcasec:
+ case Tgoto:
+ case Texcept:
+ case Tfix:
+ case Tpoly:
+ t->ok |= OKcyc;
+ sizetype(t);
+ break;
+ case Tref:
+ case Tchan:
+ case Tarray:
+ case Tlist:
+ cyctype(t);
+ sizetype(t);
+ cycsizetype(t->tof);
+ break;
+ case Tadt:
+ case Ttuple:
+ case Texception:
+ cyctype(t);
+ sizetype(t);
+ for(id = t->ids; id != nil; id = id->next)
+ cycsizetype(id->ty);
+ for(tg = t->tags; tg != nil; tg = tg->next){
+ if((tg->ty->ok & (OKcycsize|OKcyc|OKsized)) == (OKcycsize|OKcyc|OKsized))
+ continue;
+ tg->ty->ok |= (OKcycsize|OKcyc|OKsized);
+ for(id = tg->ty->ids; id != nil; id = id->next)
+ cycsizetype(id->ty);
+ }
+ for(id = t->polys; id != nil; id = id->next)
+ cycsizetype(id->ty);
+ break;
+ case Tadtpick:
+ t->ok &= ~OKcycsize;
+ cycsizetype(t->decl->dot->ty);
+ break;
+ case Tmodule:
+ cyctype(t);
+ sizetype(t);
+ for(id = t->ids; id != nil; id = id->next)
+ cycsizetype(id->ty);
+ sizeids(t->ids, 0);
+ break;
+ case Tfn:
+ cyctype(t);
+ sizetype(t);
+ for(id = t->ids; id != nil; id = id->next)
+ cycsizetype(id->ty);
+ for(id = t->polys; id != nil; id = id->next)
+ cycsizetype(id->ty);
+ cycsizetype(t->tof);
+ sizeids(t->ids, MaxTemp);
+ break;
+ default:
+ fatal("cycsizetype: unknown type kind %d", t->kind);
+ break;
+ }
+}
+
+/* check for circularity in type declarations
+ * - has to be called before verifytypes
+ */
+void
+tcycle(Type *t)
+{
+ Decl *id;
+ Type *tt;
+ Typelist *tl;
+
+ if(t == nil)
+ return;
+ switch(t->kind){
+ default:
+ break;
+ case Tchan:
+ case Tarray:
+ case Tref:
+ case Tlist:
+ case Tdot:
+ tcycle(t->tof);
+ break;
+ case Tfn:
+ case Ttuple:
+ tcycle(t->tof);
+ for(id = t->ids; id != nil; id = id->next)
+ tcycle(id->ty);
+ break;
+ case Tarrow:
+ if(t->rec&TRvis){
+ error(t->src.start, "circularity in definition of %T", t);
+ *t = *terror; /* break the cycle */
+ return;
+ }
+ tt = t->tof;
+ t->rec |= TRvis;
+ tcycle(tt);
+ if(tt->kind == Tid)
+ tt = tt->decl->ty;
+ id = namedot(tt->ids, t->decl->sym);
+ if(id != nil)
+ tcycle(id->ty);
+ t->rec &= ~TRvis;
+ break;
+ case Tid:
+ if(t->rec&TRvis){
+ error(t->src.start, "circularity in definition of %T", t);
+ *t = *terror; /* break the cycle */
+ return;
+ }
+ t->rec |= TRvis;
+ tcycle(t->decl->ty);
+ t->rec &= ~TRvis;
+ break;
+ case Tinst:
+ tcycle(t->tof);
+ for(tl = t->u.tlist; tl != nil; tl = tl->nxt)
+ tcycle(tl->t);
+ break;
+ }
+}
+
+/*
+ * marks for checking for arcs
+ */
+enum
+{
+ ArcValue = 1 << 0,
+ ArcList = 1 << 1,
+ ArcArray = 1 << 2,
+ ArcRef = 1 << 3,
+ ArcCyc = 1 << 4, /* cycle found */
+ ArcPolycyc = 1 << 5,
+};
+
+void
+cyctype(Type *t)
+{
+ Decl *id, *tg;
+
+ if((t->ok & OKcyc) == OKcyc)
+ return;
+ t->ok |= OKcyc;
+ t->rec |= TRcyc;
+ switch(t->kind){
+ case Terror:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tnone:
+ case Tany:
+ case Tfn:
+ case Tchan:
+ case Tarray:
+ case Tref:
+ case Tlist:
+ case Tfix:
+ case Tpoly:
+ break;
+ case Tadt:
+ case Tmodule:
+ case Ttuple:
+ case Texception:
+ for(id = t->ids; id != nil; id = id->next)
+ cycfield(t, id);
+ for(tg = t->tags; tg != nil; tg = tg->next){
+ if((tg->ty->ok & OKcyc) == OKcyc)
+ continue;
+ tg->ty->ok |= OKcyc;
+ for(id = tg->ty->ids; id != nil; id = id->next)
+ cycfield(t, id);
+ }
+ break;
+ default:
+ fatal("checktype: unknown type kind %d", t->kind);
+ break;
+ }
+ t->rec &= ~TRcyc;
+}
+
+void
+cycfield(Type *base, Decl *id)
+{
+ int arc;
+
+ if(!storespace[id->store])
+ return;
+ arc = cycarc(base, id->ty);
+
+ if((arc & (ArcCyc|ArcValue)) == (ArcCyc|ArcValue)){
+ if(id->cycerr == 0)
+ error(base->src.start, "illegal type cycle without a reference in field %s of %t",
+ id->sym->name, base);
+ id->cycerr = 1;
+ }else if(arc & ArcCyc){
+ if((arc & ArcArray) && id->cyc == 0 && !(arc & ArcPolycyc)){
+ if(id->cycerr == 0)
+ error(base->src.start, "illegal circular reference to type %T in field %s of %t",
+ id->ty, id->sym->name, base);
+ id->cycerr = 1;
+ }
+ id->cycle = 1;
+ }else if(id->cyc != 0){
+ if(id->cycerr == 0)
+ error(id->src.start, "spurious cyclic qualifier for field %s of %t", id->sym->name, base);
+ id->cycerr = 1;
+ }
+}
+
+int
+cycarc(Type *base, Type *t)
+{
+ Decl *id, *tg;
+ int me, arc;
+
+ if(t == nil)
+ return 0;
+ if(t->rec & TRcyc){
+ if(tequal(t, base)){
+ if(t->kind == Tmodule)
+ return ArcCyc | ArcRef;
+ else
+ return ArcCyc | ArcValue;
+ }
+ return 0;
+ }
+ t->rec |= TRcyc;
+ me = 0;
+ switch(t->kind){
+ case Terror:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tnone:
+ case Tany:
+ case Tchan:
+ case Tfn:
+ case Tfix:
+ case Tpoly:
+ break;
+ case Tarray:
+ me = cycarc(base, t->tof) & ~ArcValue | ArcArray;
+ break;
+ case Tref:
+ me = cycarc(base, t->tof) & ~ArcValue | ArcRef;
+ break;
+ case Tlist:
+ me = cycarc(base, t->tof) & ~ArcValue | ArcList;
+ break;
+ case Tadt:
+ case Tadtpick:
+ case Tmodule:
+ case Ttuple:
+ case Texception:
+ me = 0;
+ for(id = t->ids; id != nil; id = id->next){
+ if(!storespace[id->store])
+ continue;
+ arc = cycarc(base, id->ty);
+ if((arc & ArcCyc) && id->cycerr == 0)
+ me |= arc;
+ }
+ for(tg = t->tags; tg != nil; tg = tg->next){
+ arc = cycarc(base, tg->ty);
+ if((arc & ArcCyc) && tg->cycerr == 0)
+ me |= arc;
+ }
+
+ if(t->kind == Tmodule)
+ me = me & ArcCyc | ArcRef | ArcPolycyc;
+ else
+ me &= ArcCyc | ArcValue | ArcPolycyc;
+ break;
+ default:
+ fatal("cycarc: unknown type kind %d", t->kind);
+ break;
+ }
+ t->rec &= ~TRcyc;
+ if(t->flags&CYCLIC)
+ me |= ArcPolycyc;
+ return me;
+}
+
+/*
+ * set the sizes and field offsets for t
+ * look only as deeply as needed to size this type.
+ * cycsize type will clean up the rest.
+ */
+void
+sizetype(Type *t)
+{
+ Decl *id, *tg;
+ Szal szal;
+ long sz, al, a;
+
+ if(t == nil)
+ return;
+ if((t->ok & OKsized) == OKsized)
+ return;
+ t->ok |= OKsized;
+if((t->ok & (OKverify|OKsized)) != (OKverify|OKsized))
+fatal("sizetype bogus ok for %t", t);
+ switch(t->kind){
+ default:
+ fatal("sizetype: unknown type kind %d", t->kind);
+ break;
+ case Terror:
+ case Tnone:
+ case Tbyte:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Tany:
+ case Treal:
+ fatal("%T should have a size", t);
+ break;
+ case Tref:
+ case Tchan:
+ case Tarray:
+ case Tlist:
+ case Tmodule:
+ case Tfix:
+ case Tpoly:
+ t->size = t->align = IBY2WD;
+ break;
+ case Ttuple:
+ case Tadt:
+ case Texception:
+ if(t->tags == nil){
+ if(!debug['z']){
+ szal = sizeids(t->ids, 0);
+ t->size = align(szal.size, szal.align);
+ t->align = szal.align;
+ }else{
+ szal = sizeids(t->ids, 0);
+ t->align = IBY2LG;
+ t->size = align(szal.size, IBY2LG);
+ }
+ return;
+ }
+ if(!debug['z']){
+ szal = sizeids(t->ids, IBY2WD);
+ sz = szal.size;
+ al = szal.align;
+ if(al < IBY2WD)
+ al = IBY2WD;
+ }else{
+ szal = sizeids(t->ids, IBY2WD);
+ sz = szal.size;
+ al = IBY2LG;
+ }
+ for(tg = t->tags; tg != nil; tg = tg->next){
+ if((tg->ty->ok & OKsized) == OKsized)
+ continue;
+ tg->ty->ok |= OKsized;
+ if(!debug['z']){
+ szal = sizeids(tg->ty->ids, sz);
+ a = szal.align;
+ if(a < al)
+ a = al;
+ tg->ty->size = align(szal.size, a);
+ tg->ty->align = a;
+ }else{
+ szal = sizeids(tg->ty->ids, sz);
+ tg->ty->size = align(szal.size, IBY2LG);
+ tg->ty->align = IBY2LG;
+ }
+ }
+ break;
+ case Tfn:
+ t->size = 0;
+ t->align = 1;
+ break;
+ case Tainit:
+ t->size = 0;
+ t->align = 1;
+ break;
+ case Talt:
+ t->size = t->cse->nlab * 2*IBY2WD + 2*IBY2WD;
+ t->align = IBY2WD;
+ break;
+ case Tcase:
+ case Tcasec:
+ t->size = t->cse->nlab * 3*IBY2WD + 2*IBY2WD;
+ t->align = IBY2WD;
+ break;
+ case Tcasel:
+ t->size = t->cse->nlab * 6*IBY2WD + 3*IBY2WD;
+ t->align = IBY2LG;
+ break;
+ case Tgoto:
+ t->size = t->cse->nlab * IBY2WD + IBY2WD;
+ if(t->cse->iwild != nil)
+ t->size += IBY2WD;
+ t->align = IBY2WD;
+ break;
+ case Tiface:
+ sz = IBY2WD;
+ for(id = t->ids; id != nil; id = id->next){
+ sz = align(sz, IBY2WD) + IBY2WD;
+ sz += id->sym->len + 1;
+ if(id->dot->ty->kind == Tadt)
+ sz += id->dot->sym->len + 1;
+ }
+ t->size = sz;
+ t->align = IBY2WD;
+ break;
+ case Texcept:
+ t->size = 0;
+ t->align = IBY2WD;
+ break;
+ }
+}
+
+Szal
+sizeids(Decl *id, long off)
+{
+ Szal szal;
+ int a, al;
+
+ al = 1;
+ for(; id != nil; id = id->next){
+ if(storespace[id->store]){
+ sizetype(id->ty);
+ /*
+ * alignment can be 0 if we have
+ * illegal forward declarations.
+ * just patch a; other code will flag an error
+ */
+ a = id->ty->align;
+ if(a == 0)
+ a = 1;
+
+ if(a > al)
+ al = a;
+
+ off = align(off, a);
+ id->offset = off;
+ off += id->ty->size;
+ }
+ }
+ szal.size = off;
+ szal.align = al;
+ return szal;
+}
+
+long
+align(long off, int align)
+{
+ if(align == 0)
+ fatal("align 0");
+ while(off % align)
+ off++;
+ return off;
+}
+
+/*
+ * recalculate a type's size
+ */
+void
+resizetype(Type *t)
+{
+ if((t->ok & OKsized) == OKsized){
+ t->ok &= ~OKsized;
+ cycsizetype(t);
+ }
+}
+
+/*
+ * check if a module is accessable from t
+ * if so, mark that module interface
+ */
+void
+modrefable(Type *t)
+{
+ Decl *id, *m, *tg;
+
+ if(t == nil || (t->ok & OKmodref) == OKmodref)
+ return;
+ if((t->ok & OKverify) != OKverify)
+ fatal("modrefable unused type %t", t);
+ t->ok |= OKmodref;
+ switch(t->kind){
+ case Terror:
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tnone:
+ case Tany:
+ case Tfix:
+ case Tpoly:
+ break;
+ case Tchan:
+ case Tref:
+ case Tarray:
+ case Tlist:
+ modrefable(t->tof);
+ break;
+ case Tmodule:
+ t->tof->linkall = 1;
+ t->decl->refs++;
+ for(id = t->ids; id != nil; id = id->next){
+ switch(id->store){
+ case Dglobal:
+ case Dfn:
+ modrefable(id->ty);
+ break;
+ case Dtype:
+ if(id->ty->kind != Tadt)
+ break;
+ for(m = id->ty->ids; m != nil; m = m->next)
+ if(m->store == Dfn)
+ modrefable(m->ty);
+ break;
+ }
+ }
+ break;
+ case Tfn:
+ case Tadt:
+ case Ttuple:
+ case Texception:
+ for(id = t->ids; id != nil; id = id->next)
+ if(id->store != Dfn)
+ modrefable(id->ty);
+ for(tg = t->tags; tg != nil; tg = tg->next){
+/*
+ if((tg->ty->ok & OKmodref) == OKmodref)
+ continue;
+*/
+ tg->ty->ok |= OKmodref;
+ for(id = tg->ty->ids; id != nil; id = id->next)
+ modrefable(id->ty);
+ }
+ for(id = t->polys; id != nil; id = id->next)
+ modrefable(id->ty);
+ modrefable(t->tof);
+ break;
+ case Tadtpick:
+ modrefable(t->decl->dot->ty);
+ break;
+ default:
+ fatal("unknown type kind %d", t->kind);
+ break;
+ }
+}
+
+Desc*
+gendesc(Decl *d, long size, Decl *decls)
+{
+ Desc *desc;
+
+ if(debug['D'])
+ print("generate desc for %D\n", d);
+ if(ispoly(d))
+ addfnptrs(d, 0);
+ desc = usedesc(mkdesc(size, decls));
+ return desc;
+}
+
+Desc*
+mkdesc(long size, Decl *d)
+{
+ uchar *pmap;
+ long len, n;
+
+ len = (size+8*IBY2WD-1) / (8*IBY2WD);
+ pmap = allocmem(len);
+ memset(pmap, 0, len);
+ n = descmap(d, pmap, 0);
+ if(n >= 0)
+ n = n / (8*IBY2WD) + 1;
+ else
+ n = 0;
+ if(n > len)
+ fatal("wrote off end of decl map: %ld %ld", n, len);
+ return enterdesc(pmap, size, n);
+}
+
+Desc*
+mktdesc(Type *t)
+{
+ Desc *d;
+ uchar *pmap;
+ long len, n;
+
+usedty(t);
+ if(debug['D'])
+ print("generate desc for %T\n", t);
+ if(t->decl == nil){
+ t->decl = mkdecl(&t->src, Dtype, t);
+ t->decl->sym = enter("_mktdesc_", 0);
+ }
+ if(t->decl->desc != nil)
+ return t->decl->desc;
+ len = (t->size+8*IBY2WD-1) / (8*IBY2WD);
+ pmap = allocmem(len);
+ memset(pmap, 0, len);
+ n = tdescmap(t, pmap, 0);
+ if(n >= 0)
+ n = n / (8*IBY2WD) + 1;
+ else
+ n = 0;
+ if(n > len)
+ fatal("wrote off end of type map for %T: %ld %ld 0x%2.2ux", t, n, len, t->ok);
+ d = enterdesc(pmap, t->size, n);
+ t->decl->desc = d;
+ if(debug['j']){
+ uchar *m, *e;
+
+ print("generate desc for %T\n", t);
+ print("\tdesc\t$%d,%lud,\"", d->id, d->size);
+ e = d->map + d->nmap;
+ for(m = d->map; m < e; m++)
+ print("%.2x", *m);
+ print("\"\n");
+ }
+ return d;
+}
+
+Desc*
+enterdesc(uchar *map, long size, long nmap)
+{
+ Desc *d, *last;
+ int c;
+
+ last = nil;
+ for(d = descriptors; d != nil; d = d->next){
+ if(d->size > size || d->size == size && d->nmap > nmap)
+ break;
+ if(d->size == size && d->nmap == nmap){
+ c = memcmp(d->map, map, nmap);
+ if(c == 0){
+ free(map);
+ return d;
+ }
+ if(c > 0)
+ break;
+ }
+ last = d;
+ }
+ d = allocmem(sizeof *d);
+ d->id = -1;
+ d->used = 0;
+ d->map = map;
+ d->size = size;
+ d->nmap = nmap;
+ if(last == nil){
+ d->next = descriptors;
+ descriptors = d;
+ }else{
+ d->next = last->next;
+ last->next = d;
+ }
+ return d;
+}
+
+Desc*
+usedesc(Desc *d)
+{
+ d->used = 1;
+ return d;
+}
+
+/*
+ * create the pointer description byte map for every type in decls
+ * each bit corresponds to a word, and is 1 if occupied by a pointer
+ * the high bit in the byte maps the first word
+ */
+long
+descmap(Decl *decls, uchar *map, long start)
+{
+ Decl *d;
+ long last, m;
+
+ if(debug['D'])
+ print("descmap offset %ld\n", start);
+ last = -1;
+ for(d = decls; d != nil; d = d->next){
+ if(d->store == Dtype && d->ty->kind == Tmodule
+ || d->store == Dfn
+ || d->store == Dconst)
+ continue;
+ if(d->store == Dlocal && d->link != nil)
+ continue;
+ m = tdescmap(d->ty, map, d->offset + start);
+ if(debug['D']){
+ if(d->sym != nil)
+ print("descmap %s type %T offset %ld returns %ld\n",
+ d->sym->name, d->ty, d->offset+start, m);
+ else
+ print("descmap type %T offset %ld returns %ld\n", d->ty, d->offset+start, m);
+ }
+ if(m >= 0)
+ last = m;
+ }
+ return last;
+}
+
+long
+tdescmap(Type *t, uchar *map, long offset)
+{
+ Label *lab;
+ long i, e, m;
+ int bit;
+
+ if(t == nil)
+ return -1;
+
+ m = -1;
+ if(t->kind == Talt){
+ lab = t->cse->labs;
+ e = t->cse->nlab;
+ offset += IBY2WD * 2;
+ for(i = 0; i < e; i++){
+ if(lab[i].isptr){
+ bit = offset / IBY2WD % 8;
+ map[offset / (8*IBY2WD)] |= 1 << (7 - bit);
+ m = offset;
+ }
+ offset += 2*IBY2WD;
+ }
+ return m;
+ }
+ if(t->kind == Tcasec){
+ e = t->cse->nlab;
+ offset += IBY2WD;
+ for(i = 0; i < e; i++){
+ bit = offset / IBY2WD % 8;
+ map[offset / (8*IBY2WD)] |= 1 << (7 - bit);
+ offset += IBY2WD;
+ bit = offset / IBY2WD % 8;
+ map[offset / (8*IBY2WD)] |= 1 << (7 - bit);
+ m = offset;
+ offset += 2*IBY2WD;
+ }
+ return m;
+ }
+
+ if(tattr[t->kind].isptr){
+ bit = offset / IBY2WD % 8;
+ map[offset / (8*IBY2WD)] |= 1 << (7 - bit);
+ return offset;
+ }
+ if(t->kind == Tadtpick)
+ t = t->tof;
+ if(t->kind == Ttuple || t->kind == Tadt || t->kind == Texception){
+ if(debug['D'])
+ print("descmap adt offset %ld\n", offset);
+ if(t->rec != 0)
+ fatal("illegal cyclic type %t in tdescmap", t);
+ t->rec = 1;
+ offset = descmap(t->ids, map, offset);
+ t->rec = 0;
+ return offset;
+ }
+
+ return -1;
+}
+
+/*
+ * can a t2 be assigned to a t1?
+ * any means Tany matches all types,
+ * not just references
+ */
+int
+tcompat(Type *t1, Type *t2, int any)
+{
+ int ok, v;
+
+ if(t1 == t2)
+ return 1;
+ if(t1 == nil || t2 == nil)
+ return 0;
+ if(t2->kind == Texception && t1->kind != Texception)
+ t2 = mkextuptype(t2);
+ tcomset = 0;
+ ok = rtcompat(t1, t2, any, 0);
+ v = cleartcomrec(t1) + cleartcomrec(t2);
+ if(v != tcomset)
+ fatal("recid t1 %t and t2 %t not balanced in tcompat: %d v %d", t1, t2, v, tcomset);
+ return ok;
+}
+
+static int
+rtcompat(Type *t1, Type *t2, int any, int inaorc)
+{
+ if(t1 == t2)
+ return 1;
+ if(t1 == nil || t2 == nil)
+ return 0;
+ if(t1->kind == Terror || t2->kind == Terror)
+ return 1;
+ if(t2->kind == Texception && t1->kind != Texception)
+ t2 = mkextuptype(t2);
+
+ if(debug['x'])
+ print("rtcompat: %t and %t\n", t1, t2);
+
+ t1->rec |= TRcom;
+ t2->rec |= TRcom;
+ switch(t1->kind){
+ default:
+ fatal("unknown type %t v %t in rtcompat", t1, t2);
+ case Tstring:
+ return t2->kind == Tstring || t2->kind == Tany;
+ case Texception:
+ if(t2->kind == Texception && t1->cons == t2->cons){
+ if(assumetcom(t1, t2))
+ return 1;
+ return idcompat(t1->ids, t2->ids, 0, inaorc);
+ }
+ return 0;
+ case Tnone:
+ case Tint:
+ case Tbig:
+ case Tbyte:
+ case Treal:
+ return t1->kind == t2->kind;
+ case Tfix:
+ return t1->kind == t2->kind && sametree(t1->val, t2->val);
+ case Tany:
+ if(tattr[t2->kind].isptr)
+ return 1;
+ return any;
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ if(t1->kind != t2->kind){
+ if(t2->kind == Tany)
+ return 1;
+ return 0;
+ }
+ if(t1->kind != Tref && assumetcom(t1, t2))
+ return 1;
+ return rtcompat(t1->tof, t2->tof, 0, t1->kind == Tarray || t1->kind == Tchan || inaorc);
+ case Tfn:
+ break;
+ case Ttuple:
+ if(t2->kind == Tadt && t2->tags == nil
+ || t2->kind == Ttuple){
+ if(assumetcom(t1, t2))
+ return 1;
+ return idcompat(t1->ids, t2->ids, any, inaorc);
+ }
+ if(t2->kind == Tadtpick){
+ t2->tof->rec |= TRcom;
+ if(assumetcom(t1, t2->tof))
+ return 1;
+ return idcompat(t1->ids, t2->tof->ids->next, any, inaorc);
+ }
+ return 0;
+ case Tadt:
+ if(t2->kind == Ttuple && t1->tags == nil){
+ if(assumetcom(t1, t2))
+ return 1;
+ return idcompat(t1->ids, t2->ids, any, inaorc);
+ }
+ if(t1->tags != nil && t2->kind == Tadtpick && !inaorc)
+ t2 = t2->decl->dot->ty;
+ break;
+ case Tadtpick:
+/*
+ if(t2->kind == Ttuple)
+ return idcompat(t1->tof->ids->next, t2->ids, any, inaorc);
+*/
+ break;
+ case Tmodule:
+ if(t2->kind == Tany)
+ return 1;
+ break;
+ case Tpoly:
+ if(t2->kind == Tany)
+ return 1;
+ break;
+ }
+ return tequal(t1, t2);
+}
+
+/*
+ * add the assumption that t1 and t2 are compatable
+ */
+static int
+assumetcom(Type *t1, Type *t2)
+{
+ Type *r1, *r2;
+
+ if(t1->tcom == nil && t2->tcom == nil){
+ tcomset += 2;
+ t1->tcom = t2->tcom = t1;
+ }else{
+ if(t1->tcom == nil){
+ r1 = t1;
+ t1 = t2;
+ t2 = r1;
+ }
+ for(r1 = t1->tcom; r1 != r1->tcom; r1 = r1->tcom)
+ ;
+ for(r2 = t2->tcom; r2 != nil && r2 != r2->tcom; r2 = r2->tcom)
+ ;
+ if(r1 == r2)
+ return 1;
+ if(r2 == nil)
+ tcomset++;
+ t2->tcom = t1;
+ for(; t2 != r1; t2 = r2){
+ r2 = t2->tcom;
+ t2->tcom = r1;
+ }
+ }
+ return 0;
+}
+
+static int
+cleartcomrec(Type *t)
+{
+ Decl *id;
+ int n;
+
+ n = 0;
+ for(; t != nil && (t->rec & TRcom) == TRcom; t = t->tof){
+ t->rec &= ~TRcom;
+ if(t->tcom != nil){
+ t->tcom = nil;
+ n++;
+ }
+ if(t->kind == Tadtpick)
+ n += cleartcomrec(t->tof);
+ if(t->kind == Tmodule)
+ t = t->tof;
+ for(id = t->ids; id != nil; id = id->next)
+ n += cleartcomrec(id->ty);
+ for(id = t->tags; id != nil; id = id->next)
+ n += cleartcomrec(id->ty);
+ for(id = t->polys; id != nil; id = id->next)
+ n += cleartcomrec(id->ty);
+ }
+ return n;
+}
+
+/*
+ * id1 and id2 are the fields in an adt or tuple
+ * simple structural check; ignore names
+ */
+static int
+idcompat(Decl *id1, Decl *id2, int any, int inaorc)
+{
+ for(; id1 != nil; id1 = id1->next){
+ if(id1->store != Dfield)
+ continue;
+ while(id2 != nil && id2->store != Dfield)
+ id2 = id2->next;
+ if(id2 == nil
+ || id1->store != id2->store
+ || !rtcompat(id1->ty, id2->ty, any, inaorc))
+ return 0;
+ id2 = id2->next;
+ }
+ while(id2 != nil && id2->store != Dfield)
+ id2 = id2->next;
+ return id2 == nil;
+}
+
+int
+tequal(Type *t1, Type *t2)
+{
+ int ok, v;
+
+ eqrec = 0;
+ eqset = 0;
+ ok = rtequal(t1, t2);
+ v = cleareqrec(t1) + cleareqrec(t2);
+ if(0 && v != eqset)
+ fatal("recid t1 %t and t2 %t not balanced in tequal: %d %d", t1, t2, v, eqset);
+ eqset = 0;
+ return ok;
+}
+
+/*
+ * structural equality on types
+ */
+static int
+rtequal(Type *t1, Type *t2)
+{
+ /*
+ * this is just a shortcut
+ */
+ if(t1 == t2)
+ return 1;
+
+ if(t1 == nil || t2 == nil)
+ return 0;
+ if(t1->kind == Terror || t2->kind == Terror)
+ return 1;
+
+ if(t1->kind != t2->kind)
+ return 0;
+
+ if(t1->eq != nil && t2->eq != nil)
+ return t1->eq == t2->eq;
+
+ if(debug['x'])
+ print("rtequal: %t and %t\n", t1, t2);
+
+ t1->rec |= TReq;
+ t2->rec |= TReq;
+ switch(t1->kind){
+ default:
+ fatal("unknown type %t v %t in rtequal", t1, t2);
+ case Tnone:
+ case Tbig:
+ case Tbyte:
+ case Treal:
+ case Tint:
+ case Tstring:
+ /*
+ * this should always be caught by t1 == t2 check
+ */
+ fatal("bogus value type %t vs %t in rtequal", t1, t2);
+ return 1;
+ case Tfix:
+ return sametree(t1->val, t2->val);
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ if(t1->kind != Tref && assumeteq(t1, t2))
+ return 1;
+ return rtequal(t1->tof, t2->tof);
+ case Tfn:
+ if(t1->varargs != t2->varargs)
+ return 0;
+ if(!idequal(t1->ids, t2->ids, 0, storespace))
+ return 0;
+ /* if(!idequal(t1->polys, t2->polys, 1, nil)) */
+ if(!pyequal(t1, t2))
+ return 0;
+ return rtequal(t1->tof, t2->tof);
+ case Ttuple:
+ case Texception:
+ if(t1->kind != t2->kind || t1->cons != t2->cons)
+ return 0;
+ if(assumeteq(t1, t2))
+ return 1;
+ return idequal(t1->ids, t2->ids, 0, storespace);
+ case Tadt:
+ case Tadtpick:
+ case Tmodule:
+ if(assumeteq(t1, t2))
+ return 1;
+ /*
+ * compare interfaces when comparing modules
+ */
+ if(t1->kind == Tmodule)
+ return idequal(t1->tof->ids, t2->tof->ids, 1, nil);
+
+ /*
+ * picked adts; check parent,
+ * assuming equiv picked fields,
+ * then check picked fields are equiv
+ */
+ if(t1->kind == Tadtpick && !rtequal(t1->decl->dot->ty, t2->decl->dot->ty))
+ return 0;
+
+ /*
+ * adts with pick tags: check picked fields for equality
+ */
+ if(!idequal(t1->tags, t2->tags, 1, nil))
+ return 0;
+
+ /* if(!idequal(t1->polys, t2->polys, 1, nil)) */
+ if(!pyequal(t1, t2))
+ return 0;
+ return idequal(t1->ids, t2->ids, 1, storespace);
+ case Tpoly:
+ if(assumeteq(t1, t2))
+ return 1;
+ if(t1->decl->sym != t2->decl->sym)
+ return 0;
+ return idequal(t1->ids, t2->ids, 1, nil);
+ }
+}
+
+static int
+assumeteq(Type *t1, Type *t2)
+{
+ Type *r1, *r2;
+
+ if(t1->teq == nil && t2->teq == nil){
+ eqrec++;
+ eqset += 2;
+ t1->teq = t2->teq = t1;
+ }else{
+ if(t1->teq == nil){
+ r1 = t1;
+ t1 = t2;
+ t2 = r1;
+ }
+ for(r1 = t1->teq; r1 != r1->teq; r1 = r1->teq)
+ ;
+ for(r2 = t2->teq; r2 != nil && r2 != r2->teq; r2 = r2->teq)
+ ;
+ if(r1 == r2)
+ return 1;
+ if(r2 == nil)
+ eqset++;
+ t2->teq = t1;
+ for(; t2 != r1; t2 = r2){
+ r2 = t2->teq;
+ t2->teq = r1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * checking structural equality for adts, tuples, and fns
+ */
+static int
+idequal(Decl *id1, Decl *id2, int usenames, int *storeok)
+{
+ /*
+ * this is just a shortcut
+ */
+ if(id1 == id2)
+ return 1;
+
+ for(; id1 != nil; id1 = id1->next){
+ if(storeok != nil && !storeok[id1->store])
+ continue;
+ while(id2 != nil && storeok != nil && !storeok[id2->store])
+ id2 = id2->next;
+ if(id2 == nil
+ || usenames && id1->sym != id2->sym
+ || id1->store != id2->store
+ || id1->implicit != id2->implicit
+ || id1->cyc != id2->cyc
+ || (id1->dot == nil) != (id2->dot == nil)
+ || id1->dot != nil && id2->dot != nil && id1->dot->ty->kind != id2->dot->ty->kind
+ || !rtequal(id1->ty, id2->ty))
+ return 0;
+ id2 = id2->next;
+ }
+ while(id2 != nil && storeok != nil && !storeok[id2->store])
+ id2 = id2->next;
+ return id1 == nil && id2 == nil;
+}
+
+static int
+pyequal(Type *t1, Type *t2)
+{
+ Type *pt1, *pt2;
+ Decl *id1, *id2;
+
+ if(t1 == t2)
+ return 1;
+ id1 = t1->polys;
+ id2 = t2->polys;
+ for(; id1 != nil; id1 = id1->next){
+ if(id2 == nil)
+ return 0;
+ pt1 = id1->ty;
+ pt2 = id2->ty;
+ if(!rtequal(pt1, pt2)){
+ if(t1->u.tmap != nil)
+ pt1 = valtmap(pt1, t1->u.tmap);
+ if(t2->u.tmap != nil)
+ pt2 = valtmap(pt2, t2->u.tmap);
+ if(!rtequal(pt1, pt2))
+ return 0;
+ }
+ id2 = id2->next;
+ }
+ return id1 == nil && id2 == nil;
+}
+
+static int
+cleareqrec(Type *t)
+{
+ Decl *id;
+ int n;
+
+ n = 0;
+ for(; t != nil && (t->rec & TReq) == TReq; t = t->tof){
+ t->rec &= ~TReq;
+ if(t->teq != nil){
+ t->teq = nil;
+ n++;
+ }
+ if(t->kind == Tadtpick)
+ n += cleareqrec(t->decl->dot->ty);
+ if(t->kind == Tmodule)
+ t = t->tof;
+ for(id = t->ids; id != nil; id = id->next)
+ n += cleareqrec(id->ty);
+ for(id = t->tags; id != nil; id = id->next)
+ n += cleareqrec(id->ty);
+ for(id = t->polys; id != nil; id = id->next)
+ n += cleareqrec(id->ty);
+ }
+ return n;
+}
+
+int
+raisescompat(Node *n1, Node *n2)
+{
+ if(n1 == n2)
+ return 1;
+ if(n2 == nil)
+ return 1; /* no need to repeat in definition if given in declaration */
+ if(n1 == nil)
+ return 0;
+ for(n1 = n1->left, n2 = n2->left; n1 != nil && n2 != nil; n1 = n1->right, n2 = n2->right){
+ if(n1->left->decl != n2->left->decl)
+ return 0;
+ }
+ return n1 == n2;
+}
+
+/* t1 a polymorphic type */
+static int
+fnunify(Type *t1, Type *t2, Tpair **tp, int swapped)
+{
+ Decl *id, *ids;
+ Sym *sym;
+
+ for(ids = t1->ids; ids != nil; ids = ids->next){
+ sym = ids->sym;
+ id = fnlookup(sym, t2, nil);
+ if(id != nil)
+ usetype(id->ty);
+ if(id == nil){
+ if(dowarn)
+ error(unifysrc.start, "type %T does not have a '%s' function", t2, sym->name);
+ return 0;
+ }
+ else if(id->ty->kind != Tfn){
+ if(dowarn)
+ error(unifysrc.start, "%T is not a function", id->ty);
+ return 0;
+ }
+ else if(!rtunify(ids->ty, id->ty, tp, !swapped)){
+ if(dowarn)
+ error(unifysrc.start, "%T and %T are not compatible wrt %s", ids->ty, id->ty, sym->name);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+fncleareqrec(Type *t1, Type *t2)
+{
+ Decl *id, *ids;
+ int n;
+
+ n = 0;
+ n += cleareqrec(t1);
+ n += cleareqrec(t2);
+ for(ids = t1->ids; ids != nil; ids = ids->next){
+ id = fnlookup(ids->sym, t2, nil);
+ if(id == nil)
+ continue;
+ else{
+ n += cleareqrec(ids->ty);
+ n += cleareqrec(id->ty);
+ }
+ }
+ return n;
+}
+int
+tunify(Type *t1, Type *t2, Tpair **tp)
+{
+ int ok, v;
+ Tpair *p;
+
+ *tp = nil;
+ eqrec = 0;
+ eqset = 0;
+ ok = rtunify(t1, t2, tp, 0);
+ v = cleareqrec(t1) + cleareqrec(t2);
+ for(p = *tp; p != nil; p = p->nxt)
+ v += fncleareqrec(p->t1, p->t2);
+ if(0 && v != eqset)
+ fatal("recid t1 %t and t2 %t not balanced in tunify: %d %d", t1, t2, v, eqset);
+ return ok;
+}
+
+static int
+rtunify(Type *t1, Type *t2, Tpair **tp, int swapped)
+{
+ Type *tmp;
+
+if(debug['w']) print("rtunifya - %T %T\n", t1, t2);
+ t1 = valtmap(t1, *tp);
+ t2 = valtmap(t2, *tp);
+if(debug['w']) print("rtunifyb - %T %T\n", t1, t2);
+ if(t1 == t2)
+ return 1;
+ if(t1 == nil || t2 == nil)
+ return 0;
+ if(t1->kind == Terror || t2->kind == Terror)
+ return 1;
+ if(t1->kind != Tpoly && t2->kind == Tpoly){
+ tmp = t1;
+ t1 = t2;
+ t2 = tmp;
+ swapped = !swapped;
+ }
+ if(t1->kind == Tpoly){
+/*
+ if(typein(t1, t2))
+ return 0;
+*/
+ if(!tattr[t2->kind].isptr)
+ return 0;
+ if(t2->kind != Tany)
+ addtmap(t1, t2, tp);
+ return fnunify(t1, t2, tp, swapped);
+ }
+ if(t1->kind != Tany && t2->kind == Tany){
+ tmp = t1;
+ t1 = t2;
+ t2 = tmp;
+ swapped = !swapped;
+ }
+ if(t1->kind == Tadt && t1->tags != nil && t2->kind == Tadtpick && !swapped)
+ t2 = t2->decl->dot->ty;
+ if(t2->kind == Tadt && t2->tags != nil && t1->kind == Tadtpick && swapped)
+ t1 = t1->decl->dot->ty;
+ if(t1->kind != Tany && t1->kind != t2->kind)
+ return 0;
+ t1->rec |= TReq;
+ t2->rec |= TReq;
+ switch(t1->kind){
+ default:
+ return tequal(t1, t2);
+ case Tany:
+ return tattr[t2->kind].isptr;
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ if(t1->kind != Tref && assumeteq(t1, t2))
+ return 1;
+ return rtunify(t1->tof, t2->tof, tp, swapped);
+ case Tfn:
+ if(!idunify(t1->ids, t2->ids, tp, swapped))
+ return 0;
+ if(!idunify(t1->polys, t2->polys, tp, swapped))
+ return 0;
+ return rtunify(t1->tof, t2->tof, tp, swapped);
+ case Ttuple:
+ if(assumeteq(t1, t2))
+ return 1;
+ return idunify(t1->ids, t2->ids, tp, swapped);
+ case Tadt:
+ case Tadtpick:
+ if(assumeteq(t1, t2))
+ return 1;
+ if(!idunify(t1->polys, t2->polys, tp, swapped))
+ return 0;
+ if(!idunify(t1->tags, t2->tags, tp, swapped))
+ return 0;
+ return idunify(t1->ids, t2->ids, tp, swapped);
+ case Tmodule:
+ if(assumeteq(t1, t2))
+ return 1;
+ return idunify(t1->tof->ids, t2->tof->ids, tp, swapped);
+ case Tpoly:
+ return t1 == t2;
+ }
+ return 1;
+}
+
+static int
+idunify(Decl *id1, Decl *id2, Tpair **tp, int swapped)
+{
+ if(id1 == id2)
+ return 1;
+ for(; id1 != nil; id1 = id1->next){
+ if(id2 == nil || !rtunify(id1->ty, id2->ty, tp, swapped))
+ return 0;
+ id2 = id2->next;
+ }
+ return id1 == nil && id2 == nil;
+}
+
+int
+polyequal(Decl *id1, Decl *id2)
+{
+ int ck2;
+ Decl *d;
+
+ /* allow id2 list to have an optional for clause */
+ ck2 = 0;
+ for(d = id2; d != nil; d = d->next)
+ if(d->ty->ids != nil)
+ ck2 = 1;
+ for( ; id1 != nil; id1 = id1->next){
+ if(id2 == nil
+ || id1->sym != id2->sym
+ || id1->ty->decl != nil && id2->ty->decl != nil && id1->ty->decl->sym != id2->ty->decl->sym)
+ return 0;
+ if(ck2 && !idequal(id1->ty->ids, id2->ty->ids, 1, nil))
+ return 0;
+ id2 = id2->next;
+ }
+ return id1 == nil && id2 == nil;
+}
+
+Type*
+calltype(Type *f, Node *a, Type *rt)
+{
+ Type *t;
+ Decl *id, *first, *last;
+
+ first = last = nil;
+ t = mktype(&f->src.start, &f->src.stop, Tfn, rt, nil);
+ t->polys = f->kind == Tref ? f->tof->polys : f->polys;
+ for( ; a != nil; a = a->right){
+ id = mkdecl(&f->src, Darg, a->left->ty);
+ if(last == nil)
+ first = id;
+ else
+ last->next = id;
+ last = id;
+ }
+ t->ids = first;
+ if(f->kind == Tref)
+ t = mktype(&f->src.start, &f->src.stop, Tref, t, nil);
+ return t;
+}
+
+static Type*
+duptype(Type *t)
+{
+ Type *nt;
+
+ nt = allocmem(sizeof(*nt));
+ *nt = *t;
+ nt->ok &= ~(OKverify|OKref|OKclass|OKsized|OKcycsize|OKcyc);
+ nt->flags |= INST;
+ nt->eq = nil;
+ nt->sbl = -1;
+ if(t->decl != nil && (nt->kind == Tadt || nt->kind == Tadtpick || nt->kind == Ttuple)){
+ nt->decl = dupdecl(t->decl);
+ nt->decl->ty = nt;
+ nt->decl->link = t->decl;
+ if(t->decl->dot != nil){
+ nt->decl->dot = dupdecl(t->decl->dot);
+ nt->decl->dot->link = t->decl->dot;
+ }
+ }
+ else
+ nt->decl = nil;
+ return nt;
+}
+
+static int
+dpolys(Decl *ids)
+{
+ Decl *p;
+
+ for(p = ids; p != nil; p = p->next)
+ if(tpolys(p->ty))
+ return 1;
+ return 0;
+}
+
+static int
+tpolys(Type *t)
+{
+ int v;
+ Typelist *tl;
+
+ if(t == nil)
+ return 0;
+ if(t->flags&(POLY|NOPOLY))
+ return t->flags&POLY;
+ switch(t->kind){
+ default:
+ v = 0;
+ break;
+ case Tarrow:
+ case Tdot:
+ case Tpoly:
+ v = 1;
+ break;
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ v = tpolys(t->tof);
+ break;
+ case Tid:
+ v = tpolys(t->decl->ty);
+ break;
+ case Tinst:
+ for(tl = t->u.tlist; tl != nil; tl = tl->nxt)
+ if(tpolys(tl->t)){
+ v = 1;
+ break;
+ }
+ v = tpolys(t->tof);
+ break;
+ case Tfn:
+ case Tadt:
+ case Tadtpick:
+ case Ttuple:
+ case Texception:
+ if(t->polys != nil){
+ v = 1;
+ break;
+ }
+ if(t->rec&TRvis)
+ return 0;
+ t->rec |= TRvis;
+ v = tpolys(t->tof) || dpolys(t->polys) || dpolys(t->ids) || dpolys(t->tags);
+ t->rec &= ~TRvis;
+ if(t->kind == Tadtpick && v == 0)
+ v = tpolys(t->decl->dot->ty);
+ break;
+ }
+ if(v)
+ t->flags |= POLY;
+ else
+ t->flags |= NOPOLY;
+ return v;
+}
+
+static int
+doccurs(Decl *ids, Tpair **tp)
+{
+ Decl *p;
+
+ for(p = ids; p != nil; p = p->next)
+ if(toccurs(p->ty, tp))
+ return 1;
+ return 0;
+}
+
+static int
+toccurs(Type *t, Tpair **tp)
+{
+ int o;
+ Typelist *tl;
+
+ if(t == nil)
+ return 0;
+ if(!(t->flags&(POLY|NOPOLY)))
+ tpolys(t);
+ if(t->flags&NOPOLY)
+ return 0;
+ switch(t->kind){
+ default:
+ fatal("unknown type %t in toccurs", t);
+ case Tnone:
+ case Tbig:
+ case Tbyte:
+ case Treal:
+ case Tint:
+ case Tstring:
+ case Tfix:
+ case Tmodule:
+ case Terror:
+ return 0;
+ case Tarrow:
+ case Tdot:
+ return 1;
+ case Tpoly:
+ return valtmap(t, *tp) != t;
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ return toccurs(t->tof, tp);
+ case Tid:
+ return toccurs(t->decl->ty, tp);
+ case Tinst:
+ for(tl = t->u.tlist; tl != nil; tl = tl->nxt)
+ if(toccurs(tl->t, tp))
+ return 1;
+ return toccurs(t->tof, tp);
+ case Tfn:
+ case Tadt:
+ case Tadtpick:
+ case Ttuple:
+ case Texception:
+ if(t->rec&TRvis)
+ return 0;
+ t->rec |= TRvis;
+ o = toccurs(t->tof, tp) || doccurs(t->polys, tp) || doccurs(t->ids, tp) || doccurs(t->tags, tp);
+ t->rec &= ~TRvis;
+ if(t->kind == Tadtpick && o == 0)
+ o = toccurs(t->decl->dot->ty, tp);
+ return o;
+ }
+}
+
+static Decl*
+expandids(Decl *ids, Decl *adtt, Tpair **tp, int sym)
+{
+ Decl *p, *q, *nids, *last;
+
+ nids = last = nil;
+ for(p = ids; p != nil; p = p->next){
+ q = dupdecl(p);
+ q->ty = expandtype(p->ty, nil, adtt, tp);
+ if(sym && q->ty->decl != nil)
+ q->sym = q->ty->decl->sym;
+ if(q->store == Dfn){
+if(debug['v']) print("%p->link = %p\n", q, p);
+ q->link = p;
+ }
+ if(nids == nil)
+ nids = q;
+ else
+ last->next = q;
+ last = q;
+ }
+ return nids;
+}
+
+Type*
+expandtype(Type *t, Type *instt, Decl *adtt, Tpair **tp)
+{
+ Type *nt;
+ Decl *ids;
+
+ if(t == nil)
+ return nil;
+if(debug['w']) print("expandtype %d %lux %T\n", t->kind, (ulong)t, t);
+ if(!toccurs(t, tp))
+ return t;
+if(debug['w']) print("\texpanding\n");
+ switch(t->kind){
+ default:
+ fatal("unknown type %t in expandtype", t);
+ case Tpoly:
+ return valtmap(t, *tp);
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ nt = duptype(t);
+ nt->tof = expandtype(t->tof, nil, adtt, tp);
+ return nt;
+ case Tid:
+ return expandtype(idtype(t), nil, adtt, tp);
+ case Tdot:
+ return expandtype(dottype(t, adtt), nil, adtt, tp);
+ case Tarrow:
+ return expandtype(arrowtype(t, adtt), nil, adtt, tp);
+ case Tinst:
+ if((nt = valtmap(t, *tp)) != t)
+ return nt;
+ return expandtype(insttype(t, adtt, tp), nil, adtt, tp);
+ case Tfn:
+ case Tadt:
+ case Tadtpick:
+ case Ttuple:
+ case Texception:
+ if((nt = valtmap(t, *tp)) != t)
+ return nt;
+ if(t->kind == Tadt)
+ adtt = t->decl;
+ nt = duptype(t);
+ addtmap(t, nt, tp);
+ if(instt != nil)
+ addtmap(instt, nt, tp);
+ nt->tof = expandtype(t->tof, nil, adtt, tp);
+ nt->polys = expandids(t->polys, adtt, tp, 1);
+ nt->ids = expandids(t->ids, adtt, tp, 0);
+ nt->tags = expandids(t->tags, adtt, tp, 0);
+ if(t->kind == Tadt){
+ for(ids = nt->tags; ids != nil; ids = ids->next)
+ ids->ty->decl->dot = nt->decl;
+ }
+ if(t->kind == Tadtpick){
+ nt->decl->dot->ty = expandtype(t->decl->dot->ty, nil, adtt, tp);
+ }
+ if((t->kind == Tadt || t->kind == Tadtpick) && t->u.tmap != nil){
+ Tpair *p;
+
+ nt->u.tmap = nil;
+ for(p = t->u.tmap; p != nil; p = p->nxt)
+ addtmap(valtmap(p->t1, *tp), valtmap(p->t2, *tp), &nt->u.tmap);
+ if(debug['w']){
+ print("new tmap for %T->%T: ", t, nt);
+ for(p=nt->u.tmap;p!=nil;p=p->nxt)print("%T -> %T ", p->t1, p->t2);
+ print("\n");
+ }
+ }
+ return nt;
+ }
+}
+
+/*
+ * create type signatures
+ * sign the same information used
+ * for testing type equality
+ */
+ulong
+sign(Decl *d)
+{
+ Type *t;
+ uchar *sig, md5sig[MD5dlen];
+ char buf[StrSize];
+ int i, sigend, sigalloc, v;
+
+ t = d->ty;
+ if(t->sig != 0)
+ return t->sig;
+
+ if(ispoly(d))
+ rmfnptrs(d);
+
+ sig = 0;
+ sigend = -1;
+ sigalloc = 1024;
+ while(sigend < 0 || sigend >= sigalloc){
+ sigalloc *= 2;
+ sig = reallocmem(sig, sigalloc);
+ eqrec = 0;
+ sigend = rtsign(t, sig, sigalloc, 0);
+ v = clearrec(t);
+ if(v != eqrec)
+ fatal("recid not balanced in sign: %d %d", v, eqrec);
+ eqrec = 0;
+ }
+ sig[sigend] = '\0';
+
+ if(signdump != nil){
+ seprint(buf, buf+sizeof(buf), "%D", d);
+ if(strcmp(buf, signdump) == 0){
+ print("sign %D len %d\n", d, sigend);
+ print("%s\n", (char*)sig);
+ }
+ }
+
+ md5(sig, sigend, md5sig, nil);
+ for(i = 0; i < MD5dlen; i += 4)
+ t->sig ^= md5sig[i+0] | (md5sig[i+1]<<8) | (md5sig[i+2]<<16) | (md5sig[i+3]<<24);
+ if(debug['S'])
+ print("signed %D type %T len %d sig %#lux\n", d, t, sigend, t->sig);
+ free(sig);
+ return t->sig;
+}
+
+enum
+{
+ SIGSELF = 'S',
+ SIGVARARGS = '*',
+ SIGCYC = 'y',
+ SIGREC = '@'
+};
+
+static int sigkind[Tend] =
+{
+ /* Tnone */ 'n',
+ /* Tadt */ 'a',
+ /* Tadtpick */ 'p',
+ /* Tarray */ 'A',
+ /* Tbig */ 'B',
+ /* Tbyte */ 'b',
+ /* Tchan */ 'C',
+ /* Treal */ 'r',
+ /* Tfn */ 'f',
+ /* Tint */ 'i',
+ /* Tlist */ 'L',
+ /* Tmodule */ 'm',
+ /* Tref */ 'R',
+ /* Tstring */ 's',
+ /* Ttuple */ 't',
+ /* Texception */ 'e',
+ /* Tfix */ 'x',
+ /* Tpoly */ 'P',
+};
+
+static int
+rtsign(Type *t, uchar *sig, int lensig, int spos)
+{
+ Decl *id, *tg;
+ char name[32];
+ int kind, lenname;
+
+ if(t == nil)
+ return spos;
+
+ if(spos < 0 || spos + 8 >= lensig)
+ return -1;
+
+ if(t->eq != nil && t->eq->id){
+ if(t->eq->id < 0 || t->eq->id > eqrec)
+ fatal("sign rec %T %d %d", t, t->eq->id, eqrec);
+
+ sig[spos++] = SIGREC;
+ seprint(name, name+sizeof(name), "%d", t->eq->id);
+ lenname = strlen(name);
+ if(spos + lenname > lensig)
+ return -1;
+ strcpy((char*)&sig[spos], name);
+ spos += lenname;
+ return spos;
+ }
+ if(t->eq != nil){
+ eqrec++;
+ t->eq->id = eqrec;
+ }
+
+ kind = sigkind[t->kind];
+ sig[spos++] = kind;
+ if(kind == 0)
+ fatal("no sigkind for %t", t);
+
+ t->rec = 1;
+ switch(t->kind){
+ default:
+ fatal("bogus type %t in rtsign", t);
+ return -1;
+ case Tnone:
+ case Tbig:
+ case Tbyte:
+ case Treal:
+ case Tint:
+ case Tstring:
+ case Tpoly:
+ return spos;
+ case Tfix:
+ seprint(name, name+sizeof(name), "%g", t->val->rval);
+ lenname = strlen(name);
+ if(spos+lenname-1 >= lensig)
+ return -1;
+ strcpy((char*)&sig[spos], name);
+ spos += lenname;
+ return spos;
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ return rtsign(t->tof, sig, lensig, spos);
+ case Tfn:
+ if(t->varargs != 0)
+ sig[spos++] = SIGVARARGS;
+ if(t->polys != nil)
+ spos = idsign(t->polys, 0, sig, lensig, spos);
+ spos = idsign(t->ids, 0, sig, lensig, spos);
+ if(t->u.eraises)
+ spos = raisessign(t->u.eraises, sig, lensig, spos);
+ return rtsign(t->tof, sig, lensig, spos);
+ case Ttuple:
+ return idsign(t->ids, 0, sig, lensig, spos);
+ case Tadt:
+ /*
+ * this is a little different than in rtequal,
+ * since we flatten the adt we used to represent the globals
+ */
+ if(t->eq == nil){
+ if(strcmp(t->decl->sym->name, ".mp") != 0)
+ fatal("no t->eq field for %t", t);
+ spos--;
+ for(id = t->ids; id != nil; id = id->next){
+ spos = idsign1(id, 1, sig, lensig, spos);
+ if(spos < 0 || spos >= lensig)
+ return -1;
+ sig[spos++] = ';';
+ }
+ return spos;
+ }
+ if(t->polys != nil)
+ spos = idsign(t->polys, 0, sig, lensig, spos);
+ spos = idsign(t->ids, 1, sig, lensig, spos);
+ if(spos < 0 || t->tags == nil)
+ return spos;
+
+ /*
+ * convert closing ')' to a ',', then sign any tags
+ */
+ sig[spos-1] = ',';
+ for(tg = t->tags; tg != nil; tg = tg->next){
+ lenname = tg->sym->len;
+ if(spos + lenname + 2 >= lensig)
+ return -1;
+ strcpy((char*)&sig[spos], tg->sym->name);
+ spos += lenname;
+ sig[spos++] = '=';
+ sig[spos++] = '>';
+
+ spos = rtsign(tg->ty, sig, lensig, spos);
+ if(spos < 0 || spos >= lensig)
+ return -1;
+
+ if(tg->next != nil)
+ sig[spos++] = ',';
+ }
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = ')';
+ return spos;
+ case Tadtpick:
+ spos = idsign(t->ids, 1, sig, lensig, spos);
+ if(spos < 0)
+ return spos;
+ return rtsign(t->decl->dot->ty, sig, lensig, spos);
+ case Tmodule:
+ if(t->tof->linkall == 0)
+ fatal("signing a narrowed module");
+
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = '{';
+ for(id = t->tof->ids; id != nil; id = id->next){
+ if(id->tag)
+ continue;
+ if(strcmp(id->sym->name, ".mp") == 0){
+ spos = rtsign(id->ty, sig, lensig, spos);
+ if(spos < 0)
+ return -1;
+ continue;
+ }
+ spos = idsign1(id, 1, sig, lensig, spos);
+ if(spos < 0 || spos >= lensig)
+ return -1;
+ sig[spos++] = ';';
+ }
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = '}';
+ return spos;
+ }
+}
+
+static int
+idsign(Decl *id, int usenames, uchar *sig, int lensig, int spos)
+{
+ int first;
+
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = '(';
+ first = 1;
+ for(; id != nil; id = id->next){
+ if(id->store == Dlocal)
+ fatal("local %s in idsign", id->sym->name);
+
+ if(!storespace[id->store])
+ continue;
+
+ if(!first){
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = ',';
+ }
+
+ spos = idsign1(id, usenames, sig, lensig, spos);
+ if(spos < 0)
+ return -1;
+ first = 0;
+ }
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = ')';
+ return spos;
+}
+
+static int
+idsign1(Decl *id, int usenames, uchar *sig, int lensig, int spos)
+{
+ char *name;
+ int lenname;
+
+ if(usenames){
+ name = id->sym->name;
+ lenname = id->sym->len;
+ if(spos + lenname + 1 >= lensig)
+ return -1;
+ strcpy((char*)&sig[spos], name);
+ spos += lenname;
+ sig[spos++] = ':';
+ }
+
+ if(spos + 2 >= lensig)
+ return -1;
+
+ if(id->implicit != 0)
+ sig[spos++] = SIGSELF;
+
+ if(id->cyc != 0)
+ sig[spos++] = SIGCYC;
+
+ return rtsign(id->ty, sig, lensig, spos);
+}
+
+static int
+raisessign(Node *n, uchar *sig, int lensig, int spos)
+{
+ int m;
+ char *s;
+ Node *nn;
+
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = '(';
+ for(nn = n->left; nn != nil; nn = nn->right){
+ s = nn->left->decl->sym->name;
+ m = nn->left->decl->sym->len;
+ if(spos+m-1 >= lensig)
+ return -1;
+ strcpy((char*)&sig[spos], s);
+ spos += m;
+ if(nn->right != nil){
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = ',';
+ }
+ }
+ if(spos >= lensig)
+ return -1;
+ sig[spos++] = ')';
+ return spos;
+}
+
+static int
+clearrec(Type *t)
+{
+ Decl *id;
+ int n;
+
+ n = 0;
+ for(; t != nil && t->rec; t = t->tof){
+ t->rec = 0;
+ if(t->eq != nil && t->eq->id != 0){
+ t->eq->id = 0;
+ n++;
+ }
+ if(t->kind == Tmodule){
+ for(id = t->tof->ids; id != nil; id = id->next)
+ n += clearrec(id->ty);
+ return n;
+ }
+ if(t->kind == Tadtpick)
+ n += clearrec(t->decl->dot->ty);
+ for(id = t->ids; id != nil; id = id->next)
+ n += clearrec(id->ty);
+ for(id = t->tags; id != nil; id = id->next)
+ n += clearrec(id->ty);
+ for(id = t->polys; id != nil; id = id->next)
+ n += clearrec(id->ty);
+ }
+ return n;
+}
+
+/* must a variable of the given type be zeroed ? (for uninitialized declarations inside loops) */
+int
+tmustzero(Type *t)
+{
+ if(t==nil)
+ return 0;
+ if(tattr[t->kind].isptr)
+ return 1;
+ if(t->kind == Tadtpick)
+ t = t->tof;
+ if(t->kind == Ttuple || t->kind == Tadt)
+ return mustzero(t->ids);
+ return 0;
+}
+
+int
+mustzero(Decl *decls)
+{
+ Decl *d;
+
+ for (d = decls; d != nil; d = d->next)
+ if (tmustzero(d->ty))
+ return 1;
+ return 0;
+}
+
+int
+typeconv(Fmt *f)
+{
+ Type *t;
+ char *p, buf[1024];
+
+ t = va_arg(f->args, Type*);
+ if(t == nil){
+ p = "nothing";
+ }else{
+ p = buf;
+ buf[0] = 0;
+ tprint(buf, buf+sizeof(buf), t);
+ }
+ return fmtstrcpy(f, p);
+}
+
+int
+stypeconv(Fmt *f)
+{
+ Type *t;
+ char *p, buf[1024];
+
+ t = va_arg(f->args, Type*);
+ if(t == nil){
+ p = "nothing";
+ }else{
+ p = buf;
+ buf[0] = 0;
+ stprint(buf, buf+sizeof(buf), t);
+ }
+ return fmtstrcpy(f, p);
+}
+
+int
+ctypeconv(Fmt *f)
+{
+ Type *t;
+ char buf[1024];
+
+ t = va_arg(f->args, Type*);
+ buf[0] = 0;
+ ctprint(buf, buf+sizeof(buf), t);
+ return fmtstrcpy(f, buf);
+}
+
+char*
+tprint(char *buf, char *end, Type *t)
+{
+ Decl *id;
+ Typelist *tl;
+
+ if(t == nil)
+ return buf;
+ if(t->kind >= Tend)
+ return seprint(buf, end, "kind %d", t->kind);
+ switch(t->kind){
+ case Tarrow:
+ buf = seprint(buf, end, "%T->%s", t->tof, t->decl->sym->name);
+ break;
+ case Tdot:
+ buf = seprint(buf, end, "%T.%s", t->tof, t->decl->sym->name);
+ break;
+ case Tid:
+ case Tpoly:
+ buf = seprint(buf, end, "%s", t->decl->sym->name);
+ break;
+ case Tinst:
+ buf = tprint(buf, end, t->tof);
+ buf = secpy(buf ,end, "[");
+ for(tl = t->u.tlist; tl != nil; tl = tl->nxt){
+ buf = tprint(buf, end, tl->t);
+ if(tl->nxt != nil)
+ buf = secpy(buf, end, ", ");
+ }
+ buf = secpy(buf, end, "]");
+ break;
+ case Tint:
+ case Tbig:
+ case Tstring:
+ case Treal:
+ case Tbyte:
+ case Tany:
+ case Tnone:
+ case Terror:
+ case Tainit:
+ case Talt:
+ case Tcase:
+ case Tcasel:
+ case Tcasec:
+ case Tgoto:
+ case Tiface:
+ case Texception:
+ case Texcept:
+ buf = secpy(buf, end, kindname[t->kind]);
+ break;
+ case Tfix:
+ buf = seprint(buf, end, "%s(%v)", kindname[t->kind], t->val);
+ break;
+ case Tref:
+ buf = secpy(buf, end, "ref ");
+ buf = tprint(buf, end, t->tof);
+ break;
+ case Tchan:
+ case Tarray:
+ case Tlist:
+ buf = seprint(buf, end, "%s of ", kindname[t->kind]);
+ buf = tprint(buf, end, t->tof);
+ break;
+ case Tadtpick:
+ buf = seprint(buf, end, "%s.%s", t->decl->dot->sym->name, t->decl->sym->name);
+ break;
+ case Tadt:
+ if(t->decl->dot != nil && !isimpmod(t->decl->dot->sym))
+ buf = seprint(buf, end, "%s->%s", t->decl->dot->sym->name, t->decl->sym->name);
+ else
+ buf = seprint(buf, end, "%s", t->decl->sym->name);
+ if(t->polys != nil){
+ buf = secpy(buf ,end, "[");
+ for(id = t->polys; id != nil; id = id->next){
+ if(t->u.tmap != nil)
+ buf = tprint(buf, end, valtmap(id->ty, t->u.tmap));
+ else
+ buf = seprint(buf, end, "%s", id->sym->name);
+ if(id->next != nil)
+ buf = secpy(buf, end, ", ");
+ }
+ buf = secpy(buf, end, "]");
+ }
+ break;
+ case Tmodule:
+ buf = seprint(buf, end, "%s", t->decl->sym->name);
+ break;
+ case Ttuple:
+ buf = secpy(buf, end, "(");
+ for(id = t->ids; id != nil; id = id->next){
+ buf = tprint(buf, end, id->ty);
+ if(id->next != nil)
+ buf = secpy(buf, end, ", ");
+ }
+ buf = secpy(buf, end, ")");
+ break;
+ case Tfn:
+ buf = secpy(buf, end, "fn");
+ if(t->polys != nil){
+ buf = secpy(buf, end, "[");
+ for(id = t->polys; id != nil; id = id->next){
+ buf = seprint(buf, end, "%s", id->sym->name);
+ if(id->next != nil)
+ buf = secpy(buf, end, ", ");
+ }
+ buf = secpy(buf, end, "]");
+ }
+ buf = secpy(buf, end, "(");
+ for(id = t->ids; id != nil; id = id->next){
+ if(id->sym == nil)
+ buf = secpy(buf, end, "nil: ");
+ else
+ buf = seprint(buf, end, "%s: ", id->sym->name);
+ if(id->implicit)
+ buf = secpy(buf, end, "self ");
+ buf = tprint(buf, end, id->ty);
+ if(id->next != nil)
+ buf = secpy(buf, end, ", ");
+ }
+ if(t->varargs && t->ids != nil)
+ buf = secpy(buf, end, ", *");
+ else if(t->varargs)
+ buf = secpy(buf, end, "*");
+ if(t->tof != nil && t->tof->kind != Tnone){
+ buf = secpy(buf, end, "): ");
+ buf = tprint(buf, end, t->tof);
+ break;
+ }
+ buf = secpy(buf, end, ")");
+ break;
+ default:
+ yyerror("tprint: unknown type kind %d", t->kind);
+ break;
+ }
+ return buf;
+}
+
+char*
+stprint(char *buf, char *end, Type *t)
+{
+ if(t == nil)
+ return buf;
+ switch(t->kind){
+ case Tid:
+ return seprint(buf, end, "id %s", t->decl->sym->name);
+ case Tadt:
+ case Tadtpick:
+ case Tmodule:
+ buf = secpy(buf, end, kindname[t->kind]);
+ buf = secpy(buf, end, " ");
+ return tprint(buf, end, t);
+ }
+ return tprint(buf, end, t);
+}
+
+/* generalize ref P.A, ref P.B to ref P */
+
+/*
+Type*
+tparentx(Type *t1, Type* t2)
+{
+ if(t1 == nil || t2 == nil || t1->kind != Tref || t2->kind != Tref)
+ return t1;
+ t1 = t1->tof;
+ t2 = t2->tof;
+ if(t1 == nil || t2 == nil || t1->kind != Tadtpick || t2->kind != Tadtpick)
+ return t1;
+ t1 = t1->decl->dot->ty;
+ t2 = t2->decl->dot->ty;
+ if(tequal(t1, t2))
+ return mktype(&t1->src.start, &t1->src.stop, Tref, t1, nil);
+ return t1;
+}
+*/
+
+static int
+tparent0(Type *t1, Type *t2)
+{
+ Decl *id1, *id2;
+
+ if(t1 == t2)
+ return 1;
+ if(t1 == nil || t2 == nil)
+ return 0;
+ if(t1->kind == Tadt && t2->kind == Tadtpick)
+ t2 = t2->decl->dot->ty;
+ if(t1->kind == Tadtpick && t2->kind == Tadt)
+ t1 = t1->decl->dot->ty;
+ if(t1->kind != t2->kind)
+ return 0;
+ switch(t1->kind){
+ default:
+ fatal("unknown type %t v %t in tparent", t1, t2);
+ break;
+ case Terror:
+ case Tstring:
+ case Tnone:
+ case Tint:
+ case Tbig:
+ case Tbyte:
+ case Treal:
+ case Tany:
+ return 1;
+ case Texception:
+ case Tfix:
+ case Tfn:
+ case Tadt:
+ case Tmodule:
+ case Tpoly:
+ return tcompat(t1, t2, 0);
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ return tparent0(t1->tof, t2->tof);
+ case Ttuple:
+ for(id1 = t1->ids, id2 = t2->ids; id1 != nil && id2 != nil; id1 = id1->next, id2 = id2->next)
+ if(!tparent0(id1->ty, id2->ty))
+ return 0;
+ return id1 == nil && id2 == nil;
+ case Tadtpick:
+ return tequal(t1->decl->dot->ty, t2->decl->dot->ty);
+ }
+ return 0;
+}
+
+static Type*
+tparent1(Type *t1, Type *t2)
+{
+ Type *t, *nt;
+ Decl *id, *id1, *id2, *idt;
+
+ if(t1->kind == Tadt && t2->kind == Tadtpick)
+ t2 = t2->decl->dot->ty;
+ if(t1->kind == Tadtpick && t2->kind == Tadt)
+ t1 = t1->decl->dot->ty;
+ switch(t1->kind){
+ default:
+ return t1;
+ case Tref:
+ case Tlist:
+ case Tarray:
+ case Tchan:
+ t = tparent1(t1->tof, t2->tof);
+ if(t == t1->tof)
+ return t1;
+ return mktype(&t1->src.start, &t1->src.stop, t1->kind, t, nil);
+ case Ttuple:
+ nt = nil;
+ id = nil;
+ for(id1 = t1->ids, id2 = t2->ids; id1 != nil && id2 != nil; id1 = id1->next, id2 = id2->next){
+ t = tparent1(id1->ty, id2->ty);
+ if(t != id1->ty){
+ if(nt == nil){
+ nt = mktype(&t1->src.start, &t1->src.stop, Ttuple, nil, dupdecls(t1->ids));
+ for(id = nt->ids, idt = t1->ids; idt != id1; id = id->next, idt = idt->next)
+ ;
+ }
+ id->ty = t;
+ }
+ if(id != nil)
+ id = id->next;
+ }
+ if(nt == nil)
+ return t1;
+ return nt;
+ case Tadtpick:
+ if(tequal(t1, t2))
+ return t1;
+ return t1->decl->dot->ty;
+ }
+ return t1;
+}
+
+Type*
+tparent(Type *t1, Type *t2)
+{
+ if(tparent0(t1, t2))
+ return tparent1(t1, t2);
+ return t1;
+}
+
+/*
+ * make the tuple type used to initialize an exception type
+ */
+Type*
+mkexbasetype(Type *t)
+{
+ Decl *id, *new, *last;
+ Type *nt;
+
+ if(!t->cons)
+ fatal("mkexbasetype on non-constant");
+ last = mkids(&t->decl->src, nil, tstring, nil);
+ last->store = Dfield;
+ nt = mktype(&t->src.start, &t->src.stop, Texception, nil, last);
+ nt->cons = 0;
+ new = mkids(&t->decl->src, nil, tint, nil);
+ new->store = Dfield;
+ last->next = new;
+ last = new;
+ for(id = t->ids; id != nil; id = id->next){
+ new = allocmem(sizeof *id);
+ *new = *id;
+ new->cyc = 0;
+ last->next = new;
+ last = new;
+ }
+ last->next = nil;
+ return usetype(nt);
+}
+
+/*
+ * make an instantiated exception type
+ */
+Type*
+mkextype(Type *t)
+{
+ Type *nt;
+
+ if(!t->cons)
+ fatal("mkextype on non-constant");
+ if(t->tof != nil)
+ return t->tof;
+ nt = copytypeids(t);
+ nt->cons = 0;
+ t->tof = usetype(nt);
+ return t->tof;
+}
+
+/*
+ * convert an instantiated exception type to it's underlying type
+ */
+Type*
+mkextuptype(Type *t)
+{
+ Decl *id;
+ Type *nt;
+
+ if(t->cons)
+ return t;
+ if(t->tof != nil)
+ return t->tof;
+ id = t->ids;
+ if(id == nil)
+ nt = t;
+ else if(id->next == nil)
+ nt = id->ty;
+ else{
+ nt = copytypeids(t);
+ nt->cons = 0;
+ nt->kind = Ttuple;
+ }
+ t->tof = usetype(nt);
+ return t->tof;
+}
+
+static void
+ckfix(Type *t, double max)
+{
+ int p;
+ vlong k, x;
+ double s;
+
+ s = t->val->rval;
+ if(max == 0.0)
+ k = ((vlong)1<<32)-1;
+ else
+ k = 2*(vlong)(max/s+0.5)+1;
+ x = 1;
+ for(p = 0; k > x; p++)
+ x *= 2;
+ if(p == 0 || p > 32){
+ error(t->src.start, "cannot fit fixed type into an int");
+ return;
+ }
+ if(p < 32)
+ t->val->rval /= (double)(1<<(32-p));
+}
+
+double
+scale(Type *t)
+{
+ Node *n;
+
+ if(t->kind == Tint || t->kind == Treal)
+ return 1.0;
+ if(t->kind != Tfix)
+ fatal("scale() on non fixed point type");
+ n = t->val;
+ if(n->op != Oconst)
+ fatal("non constant scale");
+ if(n->ty != treal)
+ fatal("non real scale");
+ return n->rval;
+}
+
+double
+scale2(Type *f, Type *t)
+{
+ return scale(f)/scale(t);
+}
+
+#define I(x) ((int)(x))
+#define V(x) ((Long)(x))
+#define D(x) ((double)(x))
+
+/* put x in normal form */
+static int
+nf(double x, int *mant)
+{
+ int p;
+ double m;
+
+ p = 0;
+ m = x;
+ while(m >= 1){
+ p++;
+ m /= 2;
+ }
+ while(m < 0.5){
+ p--;
+ m *= 2;
+ }
+ m *= D(1<<16)*D(1<<15);
+ if(m >= D(0x7fffffff) - 0.5){
+ *mant = 0x7fffffff;
+ return p;
+ }
+ *mant = I(m+0.5);
+ return p;
+}
+
+static int
+ispow2(double x)
+{
+ int m;
+
+ nf(x, &m);
+ if(m != 1<<30)
+ return 0;
+ return 1;
+}
+
+static int
+round(double x, int n, int *m)
+{
+ if(n != 31)
+ fatal("not 31 in round");
+ return nf(x, m);
+}
+
+static int
+fixmul2(double sx, double sy, double sr, int *rp, int *ra)
+{
+ int k, n, a;
+ double alpha;
+
+ alpha = (sx*sy)/sr;
+ n = 31;
+ k = round(1/alpha, n, &a);
+ *rp = 1-k;
+ *ra = 0;
+ return IMULX;
+}
+
+static int
+fixdiv2(double sx, double sy, double sr, int *rp, int *ra)
+{
+ int k, n, b;
+ double beta;
+
+ beta = sx/(sy*sr);
+ n = 31;
+ k = round(beta, n, &b);
+ *rp = k-1;
+ *ra = 0;
+ return IDIVX;
+}
+
+static int
+fixmul(double sx, double sy, double sr, int *rp, int *ra)
+{
+ int k, m, n, a, v;
+ vlong W;
+ double alpha, eps;
+
+ alpha = (sx*sy)/sr;
+ if(ispow2(alpha))
+ return fixmul2(sx, sy, sr, rp, ra);
+ n = 31;
+ k = round(1/alpha, n, &a);
+ m = n-k;
+ if(m < -n-1)
+ return IMOVW; /* result is zero whatever the values */
+ v = 0;
+ W = 0;
+ eps = D(1<<m)/(alpha*D(a)) - 1;
+ if(eps < 0){
+ v = a-1;
+ eps = -eps;
+ }
+ if(m < 0 && D(1<<n)*eps*D(a) >= D(a)-1+D(1<<m))
+ W = (V(1)<<(-m)) - 1;
+ if(v != 0 || W != 0)
+ m = m<<2|(v != 0)<<1|(W != 0);
+ *rp = m;
+ *ra = a;
+ return v == 0 && W == 0 ? IMULX0: IMULX1;
+}
+
+static int
+fixdiv(double sx, double sy, double sr, int *rp, int *ra)
+{
+ int k, m, n, b, v;
+ vlong W;
+ double beta, eps;
+
+ beta = sx/(sy*sr);
+ if(ispow2(beta))
+ return fixdiv2(sx, sy, sr, rp, ra);
+ n = 31;
+ k = round(beta, n, &b);
+ m = k-n;
+ if(m <= -2*n)
+ return IMOVW; /* result is zero whatever the values */
+ v = 0;
+ W = 0;
+ eps = (D(1<<m)*D(b))/beta - 1;
+ if(eps < 0)
+ v = 1;
+ if(m < 0)
+ W = (V(1)<<(-m)) - 1;
+ if(v != 0 || W != 0)
+ m = m<<2|(v != 0)<<1|(W != 0);
+ *rp = m;
+ *ra = b;
+ return v == 0 && W == 0 ? IDIVX0: IDIVX1;
+}
+
+static int
+fixcast(double sx, double sr, int *rp, int *ra)
+{
+ int op;
+
+ op = fixmul(sx, 1.0, sr, rp, ra);
+ return op-IMULX+ICVTXX;
+}
+
+int
+fixop(int op, Type *tx, Type *ty, Type *tr, int *rp, int *ra)
+{
+ double sx, sy, sr;
+
+ sx = scale(tx);
+ sy = scale(ty);
+ sr = scale(tr);
+ if(op == IMULX)
+ op = fixmul(sx, sy, sr, rp, ra);
+ else if(op == IDIVX)
+ op = fixdiv(sx, sy, sr, rp, ra);
+ else
+ op = fixcast(sx, sr, rp, ra);
+ return op;
+}
+
+int
+ispoly(Decl *d)
+{
+ Type *t;
+
+ if(d == nil)
+ return 0;
+ t = d->ty;
+ if(t->kind == Tfn){
+ if(t->polys != nil)
+ return 1;
+ if((d = d->dot) == nil)
+ return 0;
+ t = d->ty;
+ return t->kind == Tadt && t->polys != nil;
+ }
+ return 0;
+}
+
+int
+ispolyadt(Type *t)
+{
+ return (t->kind == Tadt || t->kind == Tadtpick) && t->polys != nil && !(t->flags & INST);
+}
+
+Decl*
+polydecl(Decl *ids)
+{
+ Decl *id;
+ Type *t;
+
+ for(id = ids; id != nil; id = id->next){
+ t = mktype(&id->src.start, &id->src.stop, Tpoly, nil, nil);
+ id->ty = t;
+ t->decl = id;
+ }
+ return ids;
+}
+
+/* try to convert an expression tree to a type */
+Type*
+exptotype(Node *n)
+{
+ Type *t, *tt;
+ Decl *d;
+ Typelist *tl;
+ Src *src;
+
+ if(n == nil)
+ return nil;
+ t = nil;
+ switch(n->op){
+ case Oname:
+ if((d = n->decl) != nil && d->store == Dtype)
+ t = d->ty;
+ break;
+ case Otype:
+ case Ochan:
+ t = n->ty;
+ break;
+ case Oref:
+ t = exptotype(n->left);
+ if(t != nil)
+ t = mktype(&n->src.start, &n->src.stop, Tref, t, nil);
+ break;
+ case Odot:
+ t = exptotype(n->left);
+ if(t != nil){
+ d = namedot(t->tags, n->right->decl->sym);
+ if(d == nil)
+ t = nil;
+ else
+ t = d->ty;
+ }
+ if(t == nil)
+ t = exptotype(n->right);
+ break;
+ case Omdot:
+ t = exptotype(n->right);
+ break;
+ case Oindex:
+ t = exptotype(n->left);
+ if(t != nil){
+ src = &n->src;
+ tl = nil;
+ for(n = n->right; n != nil; n = n->right){
+ if(n->op == Oseq)
+ tt = exptotype(n->left);
+ else
+ tt = exptotype(n);
+ if(tt == nil)
+ return nil;
+ tl = addtype(tt, tl);
+ if(n->op != Oseq)
+ break;
+ }
+ t = mkinsttype(src, t, tl);
+ }
+ break;
+ }
+ return t;
+}
+
+static char*
+uname(Decl *im)
+{
+ Decl *p;
+ int n;
+ char *s;
+
+ n = 0;
+ for(p = im; p != nil; p = p->next)
+ n += strlen(p->sym->name)+1;
+ s = allocmem(n);
+ strcpy(s, "");
+ for(p = im; p != nil; p = p->next){
+ strcat(s, p->sym->name);
+ if(p->next != nil)
+ strcat(s, "+");
+ }
+ return s;
+}
+
+/* check all implementation modules have consistent declarations
+ * and create their union if needed
+ */
+Decl*
+modimp(Dlist *dl, Decl *im)
+{
+ Decl *u, *d, *dd, *ids, *dot, *last;
+ Sym *s;
+ Dlist *dl0;
+ long sg, sg0;
+ char buf[StrSize], *un;
+
+ if(dl->next == nil)
+ return dl->d;
+ dl0 = dl;
+ sg0 = 0;
+ un = uname(im);
+ seprint(buf, buf+sizeof(buf), ".m.%s", un);
+ installids(Dglobal, mkids(&dl->d->src, enter(buf, 0), tnone, nil));
+ u = dupdecl(dl->d);
+ u->sym = enter(un, 0);
+ u->sym->decl = u;
+ u->ty = mktype(&u->src.start, &u->src.stop, Tmodule, nil, nil);
+ u->ty->decl = u;
+ last = nil;
+ for( ; dl != nil; dl = dl->next){
+ d = dl->d;
+ ids = d->ty->tof->ids; /* iface */
+ if(ids != nil && ids->store == Dglobal) /* .mp */
+ sg = sign(ids);
+ else
+ sg = 0;
+ if(dl == dl0)
+ sg0 = sg;
+ else if(sg != sg0)
+ error(d->src.start, "%s's module data not consistent with that of %s\n", d->sym->name, dl0->d->sym->name);
+ for(ids = d->ty->ids; ids != nil; ids = ids->next){
+ s = ids->sym;
+ if(s->decl != nil && s->decl->scope >= scope){
+ if(ids == s->decl){
+ dd = dupdecl(ids);
+ if(u->ty->ids == nil)
+ u->ty->ids = dd;
+ else
+ last->next = dd;
+ last = dd;
+ continue;
+ }
+ dot = s->decl->dot;
+ if(s->decl->store != Dwundef && dot != nil && dot != d && isimpmod(dot->sym) && dequal(ids, s->decl, 1))
+ ids->refs = s->decl->refs;
+ else
+ redecl(ids);
+ ids->init = s->decl->init;
+ }
+ }
+ }
+ u->ty = usetype(u->ty);
+ return u;
+}
+
+static void
+modres(Decl *d)
+{
+ Decl *ids, *id, *n, *i;
+ Type *t;
+
+ for(ids = d->ty->ids; ids != nil; ids = ids->next){
+ id = ids->sym->decl;
+ if(ids != id){
+ n = ids->next;
+ i = ids->iface;
+ t = ids->ty;
+ *ids = *id;
+ ids->next = n;
+ ids->iface = i;
+ ids->ty = t;
+ }
+ }
+}
+
+/* update the fields of duplicate declarations in other implementation modules
+ * and their union
+ */
+void
+modresolve(void)
+{
+ Dlist *dl;
+
+ dl = impdecls;
+ if(dl->next == nil)
+ return;
+ for( ; dl != nil; dl = dl->next)
+ modres(dl->d);
+ modres(impdecl);
+}