ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /limbo/decls.c/
#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 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 = "<nil>";
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;
}