summaryrefslogtreecommitdiff
path: root/limbo/decls.c
diff options
context:
space:
mode:
Diffstat (limited to 'limbo/decls.c')
-rw-r--r--limbo/decls.c1367
1 files changed, 1367 insertions, 0 deletions
diff --git a/limbo/decls.c b/limbo/decls.c
new file mode 100644
index 00000000..4edab461
--- /dev/null
+++ b/limbo/decls.c
@@ -0,0 +1,1367 @@
+#include "limbo.h"
+
+char *storename[Dend]=
+{
+ /* Dtype */ "type",
+ /* Dfn */ "function",
+ /* Dglobal */ "global",
+ /* Darg */ "argument",
+ /* Dlocal */ "local",
+ /* Dconst */ "con",
+ /* Dfield */ "field",
+ /* Dtag */ "pick tag",
+ /* Dimport */ "import",
+ /* Dunbound */ "unbound",
+ /* Dundef */ "undefined",
+ /* Dwundef */ "undefined",
+};
+
+char *storeart[Dend] =
+{
+ /* Dtype */ "a ",
+ /* Dfn */ "a ",
+ /* Dglobal */ "a ",
+ /* Darg */ "an ",
+ /* Dlocal */ "a ",
+ /* Dconst */ "a ",
+ /* Dfield */ "a ",
+ /* Dtag */ "a",
+ /* Dimport */ "an ",
+ /* Dunbound */ "",
+ /* Dundef */ "",
+ /* Dwundef */ "",
+};
+
+int storespace[Dend] =
+{
+ /* Dtype */ 0,
+ /* Dfn */ 0,
+ /* Dglobal */ 1,
+ /* Darg */ 1,
+ /* Dlocal */ 1,
+ /* Dconst */ 0,
+ /* Dfield */ 1,
+ /* Dtag */ 0,
+ /* Dimport */ 0,
+ /* Dunbound */ 0,
+ /* Dundef */ 0,
+ /* Dwundef */ 0,
+};
+
+static Decl *scopes[MaxScope];
+static Decl *tails[MaxScope];
+static Node *scopenode[MaxScope];
+static uchar scopekind[MaxScope];
+static Decl zdecl;
+
+static void freeloc(Decl*);
+
+void
+popscopes(void)
+{
+ Decl *d;
+ Dlist *id;
+
+ /*
+ * clear out any decls left in syms
+ */
+ while(scope >= ScopeBuiltin){
+ for(d = scopes[scope--]; d != nil; d = d->next){
+ if(d->sym != nil){
+ d->sym->decl = d->old;
+ d->old = nil;
+ }
+ }
+ }
+
+ for(id = impdecls; id != nil; id = id->next){
+ for(d = id->d->ty->ids; d != nil; d = d->next){
+ d->sym->decl = nil;
+ d->old = nil;
+ }
+ }
+ impdecls = nil;
+
+ scope = ScopeBuiltin;
+ scopes[ScopeBuiltin] = nil;
+ tails[ScopeBuiltin] = nil;
+}
+
+void
+declstart(void)
+{
+ Decl *d;
+
+ iota = mkids(&nosrc, enter("iota", 0), tint, nil);
+ iota->init = mkconst(&nosrc, 0);
+
+ scope = ScopeNils;
+ scopes[ScopeNils] = nil;
+ tails[ScopeNils] = nil;
+
+ nildecl = mkdecl(&nosrc, Dglobal, tany);
+ nildecl->sym = enter("nil", 0);
+ installids(Dglobal, nildecl);
+ d = mkdecl(&nosrc, Dglobal, tstring);
+ d->sym = enter("", 0);
+ installids(Dglobal, d);
+
+ scope = ScopeGlobal;
+ scopes[ScopeGlobal] = nil;
+ tails[ScopeGlobal] = nil;
+}
+
+void
+redecl(Decl *d)
+{
+ Decl *old;
+
+ old = d->sym->decl;
+ if(old->store == Dwundef)
+ return;
+ error(d->src.start, "redeclaration of %K, previously declared as %k on line %L",
+ d, old, old->src.start);
+}
+
+void
+checkrefs(Decl *d)
+{
+ Decl *id, *m;
+ long refs;
+
+ for(; d != nil; d = d->next){
+ if(d->das)
+ d->refs--;
+ switch(d->store){
+ case Dtype:
+ refs = d->refs;
+ if(d->ty->kind == Tadt){
+ for(id = d->ty->ids; id != nil; id = id->next){
+ d->refs += id->refs;
+ if(id->store != Dfn)
+ continue;
+ if(id->init == nil && id->link == nil && d->importid == nil)
+ error(d->src.start, "function %s.%s not defined", d->sym->name, id->sym->name);
+ if(superwarn && !id->refs && d->importid == nil)
+ warn(d->src.start, "function %s.%s not referenced", d->sym->name, id->sym->name);
+ }
+ }
+ if(d->ty->kind == Tmodule){
+ for(id = d->ty->ids; id != nil; id = id->next){
+ refs += id->refs;
+ if(id->iface != nil)
+ id->iface->refs += id->refs;
+ if(id->store == Dtype){
+ for(m = id->ty->ids; m != nil; m = m->next){
+ refs += m->refs;
+ if(m->iface != nil)
+ m->iface->refs += m->refs;
+ }
+ }
+ }
+ d->refs = refs;
+ }
+ if(superwarn && !refs && d->importid == nil)
+ warn(d->src.start, "%K not referenced", d);
+ break;
+ case Dglobal:
+ if(!superwarn)
+ break;
+ case Dlocal:
+ case Darg:
+ if(!d->refs && d->sym != nil
+ && d->sym->name != nil && d->sym->name[0] != '.')
+ warn(d->src.start, "%K not referenced", d);
+ break;
+ case Dconst:
+ if(superwarn && !d->refs && d->sym != nil)
+ warn(d->src.start, "%K not referenced", d);
+ if(d->ty == tstring && d->init != nil)
+ d->init->decl->refs += d->refs;
+ break;
+ case Dfn:
+ if(d->init == nil && d->importid == nil)
+ error(d->src.start, "%K not defined", d);
+ if(superwarn && !d->refs)
+ warn(d->src.start, "%K not referenced", d);
+ break;
+ case Dimport:
+ if(superwarn && !d->refs)
+ warn(d->src.start, "%K not referenced", d);
+ break;
+ }
+ if(d->das)
+ d->refs++;
+ }
+}
+
+Node*
+vardecl(Decl *ids, Type *t)
+{
+ Node *n;
+
+ n = mkn(Ovardecl, mkn(Oseq, nil, nil), nil);
+ n->decl = ids;
+ n->ty = t;
+ return n;
+}
+
+void
+vardecled(Node *n)
+{
+ Decl *ids, *last;
+ Type *t;
+ int store;
+
+ store = Dlocal;
+ if(scope == ScopeGlobal)
+ store = Dglobal;
+ if(n->ty->kind == Texception && n->ty->cons){
+ store = Dconst;
+ fatal("Texception in vardecled");
+ }
+ ids = n->decl;
+ installids(store, ids);
+ t = n->ty;
+ for(last = ids; ids != nil; ids = ids->next){
+ ids->ty = t;
+ last = ids;
+ }
+ n->left->decl = last;
+}
+
+Node*
+condecl(Decl *ids, Node *init)
+{
+ Node *n;
+
+ n = mkn(Ocondecl, mkn(Oseq, nil, nil), init);
+ n->decl = ids;
+ return n;
+}
+
+void
+condecled(Node *n)
+{
+ Decl *ids, *last;
+
+ ids = n->decl;
+ installids(Dconst, ids);
+ for(last = ids; ids != nil; ids = ids->next){
+ ids->ty = tunknown;
+ last = ids;
+ }
+ n->left->decl = last;
+}
+
+Node*
+exdecl(Decl *ids, Decl *tids)
+{
+ Node *n;
+ Type *t;
+
+ t = mktype(&ids->src.start, &ids->src.stop, Texception, nil, tids);
+ t->cons = 1;
+ n = mkn(Oexdecl, mkn(Oseq, nil, nil), nil);
+ n->decl = ids;
+ n->ty = t;
+ return n;
+}
+
+void
+exdecled(Node *n)
+{
+ Decl *ids, *last;
+ Type *t;
+
+ ids = n->decl;
+ installids(Dconst, ids);
+ t = n->ty;
+ for(last = ids; ids != nil; ids = ids->next){
+ ids->ty = t;
+ last = ids;
+ }
+ n->left->decl = last;
+}
+
+Node*
+importdecl(Node *m, Decl *ids)
+{
+ Node *n;
+
+ n = mkn(Oimport, mkn(Oseq, nil, nil), m);
+ n->decl = ids;
+ return n;
+}
+
+void
+importdecled(Node *n)
+{
+ Decl *ids, *last;
+
+ ids = n->decl;
+ installids(Dimport, ids);
+ for(last = ids; ids != nil; ids = ids->next){
+ ids->ty = tunknown;
+ last = ids;
+ }
+ n->left->decl = last;
+}
+
+Node*
+mkscope(Node *body)
+{
+ Node *n;
+
+ n = mkn(Oscope, nil, body);
+ if(body != nil)
+ n->src = body->src;
+ return n;
+}
+
+Node*
+fndecl(Node *n, Type *t, Node *body)
+{
+ n = mkbin(Ofunc, n, body);
+ n->ty = t;
+ return n;
+}
+
+void
+fndecled(Node *n)
+{
+ Decl *d;
+ Node *left;
+
+ left = n->left;
+ if(left->op == Oname){
+ d = left->decl->sym->decl;
+ if(d == nil || d->store == Dimport){
+ d = mkids(&left->src, left->decl->sym, n->ty, nil);
+ installids(Dfn, d);
+ }
+ left->decl = d;
+ d->refs++;
+ }
+ if(left->op == Odot)
+ pushscope(nil, Sother);
+ if(n->ty->polys != nil){
+ pushscope(nil, Sother);
+ installids(Dtype, n->ty->polys);
+ }
+ pushscope(nil, Sother);
+ installids(Darg, n->ty->ids);
+ n->ty->ids = popscope();
+ if(n->ty->val != nil)
+ mergepolydecs(n->ty);
+ if(n->ty->polys != nil)
+ n->ty->polys = popscope();
+ if(left->op == Odot)
+ popscope();
+}
+
+/*
+ * check the function declaration only
+ * the body will be type checked later by fncheck
+ */
+Decl *
+fnchk(Node *n)
+{
+ int bad;
+ Decl *d, *inadt, *adtp;
+ Type *t;
+
+ bad = 0;
+ d = n->left->decl;
+ if(n->left->op == Odot)
+ d = n->left->right->decl;
+ if(d == nil)
+ fatal("decl() fnchk nil");
+ n->left->decl = d;
+ if(d->store == Dglobal || d->store == Dfield)
+ d->store = Dfn;
+ if(d->store != Dfn || d->init != nil){
+ nerror(n, "redeclaration of function %D, previously declared as %k on line %L",
+ d, d, d->src.start);
+ if(d->store == Dfn && d->init != nil)
+ bad = 1;
+ }
+ d->init = n;
+
+ t = n->ty;
+ inadt = d->dot;
+ if(inadt != nil && (inadt->store != Dtype || inadt->ty->kind != Tadt))
+ inadt = nil;
+ if(n->left->op == Odot){
+ pushscope(nil, Sother);
+ adtp = outerpolys(n->left);
+ if(adtp != nil)
+ installids(Dtype, adtp);
+ if(!polyequal(adtp, n->decl))
+ nerror(n, "adt polymorphic type mismatch");
+ n->decl = nil;
+ }
+ t = validtype(t, inadt);
+ if(n->left->op == Odot)
+ popscope();
+ if(debug['d'])
+ print("declare function %D ty %T newty %T\n", d, d->ty, t);
+ t = usetype(t);
+
+ if(!polyequal(d->ty->polys, t->polys))
+ nerror(n, "function polymorphic type mismatch");
+ if(!tcompat(d->ty, t, 0))
+ nerror(n, "type mismatch: %D defined as %T declared as %T on line %L",
+ d, t, d->ty, d->src.start);
+ else if(!raisescompat(d->ty->u.eraises, t->u.eraises))
+ nerror(n, "raises mismatch: %D", d);
+ if(t->varargs != 0)
+ nerror(n, "cannot define functions with a '*' argument, such as %D", d);
+
+ t->u.eraises = d->ty->u.eraises;
+
+ d->ty = t;
+ d->offset = idoffsets(t->ids, MaxTemp, IBY2WD);
+ d->src = n->src;
+
+ d->locals = nil;
+
+ n->ty = t;
+
+ return bad ? nil: d;
+}
+
+Node*
+globalas(Node *dst, Node *v, int valok)
+{
+ Node *tv;
+
+ if(v == nil)
+ return nil;
+ if(v->op == Oas || v->op == Odas){
+ v = globalas(v->left, v->right, valok);
+ if(v == nil)
+ return nil;
+ }else if(valok && !initable(dst, v, 0))
+ return nil;
+ switch(dst->op){
+ case Oname:
+ if(dst->decl->init != nil)
+ nerror(dst, "duplicate assignment to %V, previously assigned on line %L",
+ dst, dst->decl->init->src.start);
+ if(valok)
+ dst->decl->init = v;
+ return v;
+ case Otuple:
+ if(valok && v->op != Otuple)
+ fatal("can't deal with %n in tuple case of globalas", v);
+ tv = v->left;
+ for(dst = dst->left; dst != nil; dst = dst->right){
+ globalas(dst->left, tv->left, valok);
+ if(valok)
+ tv = tv->right;
+ }
+ return v;
+ }
+ fatal("can't deal with %n in globalas", dst);
+ return nil;
+}
+
+int
+needsstore(Decl *d)
+{
+ if(!d->refs)
+ return 0;
+ if(d->importid != nil)
+ return 0;
+ if(storespace[d->store])
+ return 1;
+ return 0;
+}
+
+/*
+ * return the list of all referenced storage variables
+ */
+Decl*
+vars(Decl *d)
+{
+ Decl *v, *n;
+
+ while(d != nil && !needsstore(d))
+ d = d->next;
+ for(v = d; v != nil; v = v->next){
+ while(v->next != nil){
+ n = v->next;
+ if(needsstore(n))
+ break;
+ v->next = n->next;
+ }
+ }
+ return d;
+}
+
+/*
+ * declare variables from the left side of a := statement
+ */
+static int
+recdasdecl(Node *n, int store, int *nid)
+{
+ Decl *d, *old;
+ int ok;
+
+ switch(n->op){
+ case Otuple:
+ ok = 1;
+ for(n = n->left; n != nil; n = n->right)
+ ok &= recdasdecl(n->left, store, nid);
+ return ok;
+ case Oname:
+ if(n->decl == nildecl){
+ *nid = -1;
+ return 1;
+ }
+ d = mkids(&n->src, n->decl->sym, nil, nil);
+ installids(store, d);
+ old = d->old;
+ if(old != nil
+ && old->store != Dfn
+ && old->store != Dwundef
+ && old->store != Dundef)
+ warn(d->src.start, "redeclaration of %K, previously declared as %k on line %L",
+ d, old, old->src.start);
+ n->decl = d;
+ d->refs++;
+ d->das = 1;
+ if(*nid >= 0)
+ (*nid)++;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+recmark(Node *n, int nid)
+{
+ switch(n->op){
+ case Otuple:
+ for(n = n->left; n != nil; n = n->right)
+ nid = recmark(n->left, nid);
+ break;
+ case Oname:
+ n->decl->nid = nid;
+ nid = 0;
+ break;
+ }
+ return nid;
+}
+
+int
+dasdecl(Node *n)
+{
+ int store, ok, nid;
+
+ nid = 0;
+ if(scope == ScopeGlobal)
+ store = Dglobal;
+ else
+ store = Dlocal;
+
+ ok = recdasdecl(n, store, &nid);
+ if(!ok)
+ nerror(n, "illegal declaration expression %V", n);
+ if(ok && store == Dlocal && nid > 1)
+ recmark(n, nid);
+ return ok;
+}
+
+/*
+ * declare global variables in nested := expressions
+ */
+void
+gdasdecl(Node *n)
+{
+ if(n == nil)
+ return;
+
+ if(n->op == Odas){
+ gdasdecl(n->right);
+ dasdecl(n->left);
+ }else{
+ gdasdecl(n->left);
+ gdasdecl(n->right);
+ }
+}
+
+Decl*
+undefed(Src *src, Sym *s)
+{
+ Decl *d;
+
+ d = mkids(src, s, tnone, nil);
+ error(src->start, "%s is not declared", s->name);
+ installids(Dwundef, d);
+ return d;
+}
+
+/*
+int
+inloop()
+{
+ int i;
+
+ for (i = scope; i > 0; i--)
+ if (scopekind[i] == Sloop)
+ return 1;
+ return 0;
+}
+*/
+
+int
+nested()
+{
+ int i;
+
+ for (i = scope; i > 0; i--)
+ if (scopekind[i] == Sscope || scopekind[i] == Sloop)
+ return 1;
+ return 0;
+}
+
+void
+decltozero(Node *n)
+{
+ Node *scp;
+
+ if ((scp = scopenode[scope]) != nil) {
+ /* can happen if we do
+ * x[i] := ......
+ * which is an error
+ */
+ if (n->right != nil && errors == 0)
+ fatal("Ovardecl/Oname/Otuple has right field\n");
+ n->right = scp->left;
+ scp->left = n;
+ }
+}
+
+void
+pushscope(Node *scp, int kind)
+{
+ if(scope >= MaxScope)
+ fatal("scope too deep");
+ scope++;
+ scopes[scope] = nil;
+ tails[scope] = nil;
+ scopenode[scope] = scp;
+ scopekind[scope] = kind;
+}
+
+Decl*
+curscope(void)
+{
+ return scopes[scope];
+}
+
+/*
+ * revert to old declarations for each symbol in the currect scope.
+ * remove the effects of any imported adt types
+ * whenever the adt is imported from a module,
+ * we record in the type's decl the module to use
+ * when calling members. the process is reversed here.
+ */
+Decl*
+popscope(void)
+{
+ Decl *id;
+ Type *t;
+
+if (debug['X'])
+ print("popscope\n");
+ for(id = scopes[scope]; id != nil; id = id->next){
+ if(id->sym != nil){
+if (debug['X'])
+ print("%s : %s %d\n", id->sym->name, kindname[id->ty->kind], id->init != nil ? id->init->op : 0);
+ id->sym->decl = id->old;
+ id->old = nil;
+ }
+ if(id->importid != nil)
+ id->importid->refs += id->refs;
+ t = id->ty;
+ if(id->store == Dtype
+ && t->decl != nil
+ && t->decl->timport == id)
+ t->decl->timport = id->timport;
+ if(id->store == Dlocal)
+ freeloc(id);
+ }
+ return scopes[scope--];
+}
+
+/*
+ * make a new scope,
+ * preinstalled with some previously installed identifiers
+ * don't add the identifiers to the scope chain,
+ * so they remain separate from any newly installed ids
+ *
+ * these routines assume no ids are imports
+ */
+void
+repushids(Decl *ids)
+{
+ Sym *s;
+
+ if(scope >= MaxScope)
+ fatal("scope too deep");
+ scope++;
+ scopes[scope] = nil;
+ tails[scope] = nil;
+ scopenode[scope] = nil;
+ scopekind[scope] = Sother;
+
+ for(; ids != nil; ids = ids->next){
+ if(ids->scope != scope
+ && (ids->dot == nil || !isimpmod(ids->dot->sym)
+ || ids->scope != ScopeGlobal || scope != ScopeGlobal + 1))
+ fatal("repushids scope mismatch");
+ s = ids->sym;
+ if(s != nil && ids->store != Dtag){
+ if(s->decl != nil && s->decl->scope >= scope)
+ ids->old = s->decl->old;
+ else
+ ids->old = s->decl;
+ s->decl = ids;
+ }
+ }
+}
+
+/*
+ * pop a scope which was started with repushids
+ * return any newly installed ids
+ */
+Decl*
+popids(Decl *ids)
+{
+ for(; ids != nil; ids = ids->next){
+ if(ids->sym != nil && ids->store != Dtag){
+ ids->sym->decl = ids->old;
+ ids->old = nil;
+ }
+ }
+ return popscope();
+}
+
+void
+installids(int store, Decl *ids)
+{
+ Decl *d, *last;
+ Sym *s;
+
+ last = nil;
+ for(d = ids; d != nil; d = d->next){
+ d->scope = scope;
+ if(d->store == Dundef)
+ d->store = store;
+ s = d->sym;
+ if(s != nil){
+ if(s->decl != nil && s->decl->scope >= scope){
+ redecl(d);
+ d->old = s->decl->old;
+ }else
+ d->old = s->decl;
+ s->decl = d;
+ }
+ last = d;
+ }
+ if(ids != nil){
+ d = tails[scope];
+ if(d == nil)
+ scopes[scope] = ids;
+ else
+ d->next = ids;
+ tails[scope] = last;
+ }
+}
+
+Decl*
+lookup(Sym *sym)
+{
+ int s;
+ Decl *d;
+
+ for(s = scope; s >= ScopeBuiltin; s--){
+ for(d = scopes[s]; d != nil; d = d->next){
+ if(d->sym == sym)
+ return d;
+ }
+ }
+ return nil;
+}
+
+Decl*
+mkids(Src *src, Sym *s, Type *t, Decl *next)
+{
+ Decl *d;
+
+ d = mkdecl(src, Dundef, t);
+ d->next = next;
+ d->sym = s;
+ return d;
+}
+
+Decl*
+mkdecl(Src *src, int store, Type *t)
+{
+ Decl *d;
+ static Decl z;
+
+ d = allocmem(sizeof *d);
+ *d = z;
+ d->src = *src;
+ d->store = store;
+ d->ty = t;
+ d->nid = 1;
+ return d;
+}
+
+Decl*
+dupdecl(Decl *old)
+{
+ Decl *d;
+
+ d = allocmem(sizeof *d);
+ *d = *old;
+ d->next = nil;
+ return d;
+}
+
+Decl*
+dupdecls(Decl *old)
+{
+ Decl *d, *nd, *first, *last;
+
+ first = last = nil;
+ for(d = old; d != nil; d = d->next){
+ nd = dupdecl(d);
+ if(first == nil)
+ first = nd;
+ else
+ last->next = nd;
+ last = nd;
+ }
+ return first;
+}
+
+Decl*
+appdecls(Decl *d, Decl *dd)
+{
+ Decl *t;
+
+ if(d == nil)
+ return dd;
+ for(t = d; t->next != nil; t = t->next)
+ ;
+ t->next = dd;
+ return d;
+}
+
+Decl*
+revids(Decl *id)
+{
+ Decl *d, *next;
+
+ d = nil;
+ for(; id != nil; id = next){
+ next = id->next;
+ id->next = d;
+ d = id;
+ }
+ return d;
+}
+
+long
+idoffsets(Decl *id, long offset, int al)
+{
+ int a, algn;
+ Decl *d;
+
+ algn = 1;
+ for(; id != nil; id = id->next){
+ if(storespace[id->store]){
+usedty(id->ty);
+ if(id->store == Dlocal && id->link != nil){
+ /* id->nid always 1 */
+ id->offset = id->link->offset;
+ continue;
+ }
+ a = id->ty->align;
+ if(id->nid > 1){
+ for(d = id->next; d != nil && d->nid == 0; d = d->next)
+ if(d->ty->align > a)
+ a = d->ty->align;
+ algn = a;
+ }
+ offset = align(offset, a);
+ id->offset = offset;
+ offset += id->ty->size;
+ if(id->nid == 0 && (id->next == nil || id->next->nid != 0))
+ offset = align(offset, algn);
+ }
+ }
+ return align(offset, al);
+}
+
+long
+idindices(Decl *id)
+{
+ int i;
+
+ i = 0;
+ for(; id != nil; id = id->next){
+ if(storespace[id->store]){
+ usedty(id->ty);
+ id->offset = i++;
+ }
+ }
+ return i;
+}
+
+int
+declconv(Fmt *f)
+{
+ Decl *d;
+ char buf[4096], *s;
+
+ d = va_arg(f->args, Decl*);
+ if(d->sym == nil)
+ s = "<???>";
+ else
+ s = d->sym->name;
+ seprint(buf, buf+sizeof(buf), "%s %s", storename[d->store], s);
+ return fmtstrcpy(f, buf);
+}
+
+int
+storeconv(Fmt *f)
+{
+ Decl *d;
+ char buf[4096];
+
+ d = va_arg(f->args, Decl*);
+ seprint(buf, buf+sizeof(buf), "%s%s", storeart[d->store], storename[d->store]);
+ return fmtstrcpy(f, buf);
+}
+
+int
+dotconv(Fmt *f)
+{
+ Decl *d;
+ char buf[4096], *p, *s;
+
+ d = va_arg(f->args, Decl*);
+ buf[0] = 0;
+ p = buf;
+ if(d->dot != nil && !isimpmod(d->dot->sym)){
+ s = ".";
+ if(d->dot->ty != nil && d->dot->ty->kind == Tmodule)
+ s = "->";
+ p = seprint(buf, buf+sizeof(buf), "%D%s", d->dot, s);
+ }
+ seprint(p, buf+sizeof(buf), "%s", d->sym->name);
+ return fmtstrcpy(f, buf);
+}
+
+/*
+ * merge together two sorted lists, yielding a sorted list
+ */
+static Decl*
+namemerge(Decl *e, Decl *f)
+{
+ Decl rock, *d;
+
+ d = &rock;
+ while(e != nil && f != nil){
+ if(strcmp(e->sym->name, f->sym->name) <= 0){
+ d->next = e;
+ e = e->next;
+ }else{
+ d->next = f;
+ f = f->next;
+ }
+ d = d->next;
+ }
+ if(e != nil)
+ d->next = e;
+ else
+ d->next = f;
+ return rock.next;
+}
+
+/*
+ * recursively split lists and remerge them after they are sorted
+ */
+static Decl*
+recnamesort(Decl *d, int n)
+{
+ Decl *r, *dd;
+ int i, m;
+
+ if(n <= 1)
+ return d;
+ m = n / 2 - 1;
+ dd = d;
+ for(i = 0; i < m; i++)
+ dd = dd->next;
+ r = dd->next;
+ dd->next = nil;
+ return namemerge(recnamesort(d, n / 2),
+ recnamesort(r, (n + 1) / 2));
+}
+
+/*
+ * sort the ids by name
+ */
+Decl*
+namesort(Decl *d)
+{
+ Decl *dd;
+ int n;
+
+ n = 0;
+ for(dd = d; dd != nil; dd = dd->next)
+ n++;
+ return recnamesort(d, n);
+}
+
+void
+printdecls(Decl *d)
+{
+ for(; d != nil; d = d->next)
+ print("%ld: %K %T ref %d\n", d->offset, d, d->ty, d->refs);
+}
+
+void
+mergepolydecs(Type *t)
+{
+ Node *n, *nn;
+ Decl *id, *ids, *ids1;
+
+ for(n = t->val; n != nil; n = n->right){
+ nn = n->left;
+ for(ids = nn->decl; ids != nil; ids = ids->next){
+ id = ids->sym->decl;
+ if(id == nil){
+ undefed(&ids->src, ids->sym);
+ break;
+ }
+ if(id->store != Dtype){
+ error(ids->src.start, "%K is not a type", id);
+ break;
+ }
+ if(id->ty->kind != Tpoly){
+ error(ids->src.start, "%K is not a polymorphic type", id);
+ break;
+ }
+ if(id->ty->ids != nil)
+ error(ids->src.start, "%K redefined", id);
+ pushscope(nil, Sother);
+ fielddecled(nn->left);
+ id->ty->ids = popscope();
+ for(ids1 = id->ty->ids; ids1 != nil; ids1 = ids1->next){
+ ids1->dot = id;
+ bindtypes(ids1->ty);
+ if(ids1->ty->kind != Tfn){
+ error(ids1->src.start, "only function types expected");
+ id->ty->ids = nil;
+ }
+ }
+ }
+ }
+ t->val = nil;
+}
+
+static void
+adjfnptrs(Decl *d, Decl *polys1, Decl *polys2)
+{
+ int n;
+ Decl *id, *idt, *idf, *arg;
+
+ if(debug['U'])
+ print("adjnptrs %s\n", d->sym->name);
+ n = 0;
+ for(id = d->ty->ids; id != nil; id = id->next)
+ n++;
+ for(idt = polys1; idt != nil; idt = idt->next)
+ for(idf = idt->ty->ids; idf != nil; idf = idf->next)
+ n -= 2;
+ for(idt = polys2; idt != nil; idt = idt->next)
+ for(idf = idt->ty->ids; idf != nil; idf = idf->next)
+ n -= 2;
+ for(arg = d->ty->ids; --n >= 0; arg = arg->next)
+ ;
+ for(idt = polys1; idt != nil; idt = idt->next){
+ for(idf = idt->ty->ids; idf != nil; idf = idf->next){
+ idf->link = arg;
+ arg = arg->next->next;
+ }
+ }
+ for(idt = polys2; idt != nil; idt = idt->next){
+ for(idf = idt->ty->ids; idf != nil; idf = idf->next){
+ idf->link = arg;
+ arg = arg->next->next;
+ }
+ }
+}
+
+static void
+addptrs(Decl *polys, Decl** fps, Decl **last, int link, Src *src)
+{
+ Decl *idt, *idf, *fp;
+
+ if(debug['U'])
+ print("addptrs\n");
+ for(idt = polys; idt != nil; idt = idt->next){
+ for(idf = idt->ty->ids; idf != nil; idf = idf->next){
+ fp = mkdecl(src, Darg, tany);
+ fp->sym = idf->sym;
+ if(link)
+ idf->link = fp;
+ if(*fps == nil)
+ *fps = fp;
+ else
+ (*last)->next = fp;
+ *last = fp;
+ fp = mkdecl(src, Darg, tint);
+ fp->sym = idf->sym;
+ (*last)->next = fp;
+ *last = fp;
+ }
+ }
+}
+
+void
+addfnptrs(Decl *d, int link)
+{
+ Decl *fps, *last, *polys;
+
+ if(debug['U'])
+ print("addfnptrs %s %d\n", d->sym->name, link);
+ polys = encpolys(d);
+ if(d->ty->flags&FULLARGS){
+ if(link)
+ adjfnptrs(d, d->ty->polys, polys);
+ if(0 && debug['U']){
+ for(d = d->ty->ids; d != nil; d = d->next)
+ print("%s=%ld(%d) ", d->sym->name, d->offset, tattr[d->ty->kind].isptr);
+ print("\n");
+ }
+ return;
+ }
+ d->ty->flags |= FULLARGS;
+ fps = last = nil;
+ addptrs(d->ty->polys, &fps, &last, link, &d->src);
+ addptrs(polys, &fps, &last, link, &d->src);
+ for(last = d->ty->ids; last != nil && last->next != nil; last = last->next)
+ ;
+ if(last != nil)
+ last->next = fps;
+ else
+ d->ty->ids = fps;
+ d->offset = idoffsets(d->ty->ids, MaxTemp, IBY2WD);
+ if(0 && debug['U']){
+ for(d = d->ty->ids; d != nil; d = d->next)
+ print("%s=%ld(%d) ", d->sym->name, d->offset, tattr[d->ty->kind].isptr);
+ print("\n");
+ }
+}
+
+void
+rmfnptrs(Decl *d)
+{
+ int n;
+ Decl *id, *idt, *idf;
+
+ if(debug['U'])
+ print("rmfnptrs %s\n", d->sym->name);
+ if(!(d->ty->flags&FULLARGS))
+ return;
+ d->ty->flags &= ~FULLARGS;
+ n = 0;
+ for(id = d->ty->ids; id != nil; id = id->next)
+ n++;
+ for(idt = d->ty->polys; idt != nil; idt = idt->next)
+ for(idf = idt->ty->ids; idf != nil; idf = idf->next)
+ n -= 2;
+ for(idt = encpolys(d); idt != nil; idt = idt->next)
+ for(idf = idt->ty->ids; idf != nil; idf = idf->next)
+ n -= 2;
+ if(n == 0){
+ d->ty->ids = nil;
+ return;
+ }
+ for(id = d->ty->ids; --n > 0; id = id->next)
+ ;
+ id->next = nil;
+ d->offset = idoffsets(d->ty->ids, MaxTemp, IBY2WD);
+}
+
+int
+local(Decl *d)
+{
+ for(d = d->dot; d != nil; d = d->dot)
+ if(d->store == Dtype && d->ty->kind == Tmodule)
+ return 0;
+ return 1;
+}
+
+Decl*
+module(Decl *d)
+{
+ for(d = d->dot; d != nil; d = d->dot)
+ if(d->store == Dtype && d->ty->kind == Tmodule)
+ return d;
+ return nil;
+}
+
+Decl*
+outerpolys(Node *n)
+{
+ Decl *d;
+
+ if(n->op == Odot){
+ d = n->right->decl;
+ if(d == nil)
+ fatal("decl() outeradt nil");
+ d = d->dot;
+ if(d != nil && d->store == Dtype && d->ty->kind == Tadt)
+ return d->ty->polys;
+ }
+ return nil;
+}
+
+Decl*
+encpolys(Decl *d)
+{
+ if((d = d->dot) == nil)
+ return nil;
+ return d->ty->polys;
+}
+
+Decl*
+fnlookup(Sym *s, Type *t, Node **m)
+{
+ Decl *id;
+ Node *mod;
+
+ id = nil;
+ mod = nil;
+ if(t->kind == Tpoly || t->kind == Tmodule)
+ id = namedot(t->ids, s);
+ else if(t->kind == Tref){
+ t = t->tof;
+ if(t->kind == Tadt){
+ id = namedot(t->ids, s);
+ if(t->decl != nil && t->decl->timport != nil)
+ mod = t->decl->timport->eimport;
+ }
+ else if(t->kind == Tadtpick){
+ id = namedot(t->ids, s);
+ if(t->decl != nil && t->decl->timport != nil)
+ mod = t->decl->timport->eimport;
+ t = t->decl->dot->ty;
+ if(id == nil)
+ id = namedot(t->ids, s);
+ if(t->decl != nil && t->decl->timport != nil)
+ mod = t->decl->timport->eimport;
+ }
+ }
+ if(id == nil){
+ id = lookup(s);
+ if(id != nil)
+ mod = id->eimport;
+ }
+ if(m != nil)
+ *m = mod;
+ return id;
+}
+
+int
+isimpmod(Sym *s)
+{
+ Decl *d;
+
+ for(d = impmods; d != nil; d = d->next)
+ if(d->sym == s)
+ return 1;
+ return 0;
+}
+
+int
+dequal(Decl *d1, Decl *d2, int full)
+{
+ return d1->sym == d2->sym &&
+ d1->store == d2->store &&
+ d1->implicit == d2->implicit &&
+ d1->cyc == d2->cyc &&
+ (!full || tequal(d1->ty, d2->ty)) &&
+ (!full || d1->store == Dfn || sametree(d1->init, d2->init));
+}
+
+static int
+tzero(Type *t)
+{
+ return t->kind == Texception || tmustzero(t);
+}
+
+static int
+isptr(Type *t)
+{
+ return t->kind == Texception || tattr[t->kind].isptr;
+}
+
+/* can d share the same stack location as another local ? */
+void
+shareloc(Decl *d)
+{
+ int z;
+ Type *t, *tt;
+ Decl *dd, *res;
+
+ if(d->store != Dlocal || d->nid != 1)
+ return;
+ t = d->ty;
+ res = nil;
+ for(dd = fndecls; dd != nil; dd = dd->next){
+ if(d == dd)
+ fatal("d==dd in shareloc");
+ if(dd->store != Dlocal || dd->nid != 1 || dd->link != nil || dd->tref != 0)
+ continue;
+ tt = dd->ty;
+ if(t->size != tt->size || t->align != tt->align)
+ continue;
+ z = tzero(t)+tzero(tt);
+ if(z > 0)
+ continue; /* for now */
+ if(t == tt || tequal(t, tt))
+ res = dd;
+ else{
+ if(z == 1)
+ continue;
+ if(z == 0 || isptr(t) || isptr(tt) || mktdesc(t) == mktdesc(tt))
+ res = dd;
+ }
+ if(res != nil){
+ /* print("%L %K share %L %K\n", d->src.start, d, res->src.start, res); */
+ d->link = res;
+ res->tref = 1;
+ return;
+ }
+ }
+ return;
+}
+
+static void
+freeloc(Decl *d)
+{
+ if(d->link != nil)
+ d->link->tref = 0;
+}