ref: 2956d456959512a3e8b550899465395e033f7929
parent: 419c0d34a9d401d97a740778625936c6c1464d41
author: Ori Bernstein <[email protected]>
date: Sat Dec 20 20:27:55 EST 2014
Make our type ids more stable across files. Some sort of id string based on the actual type, not the hash of the string representation.
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1358,6 +1358,7 @@
if (debugopt['S'])
printf("specializing trait [%d]%s:%s => %s:%s\n",
n->loc.line, namestr(proto->decl.name), tystr(type(st, proto)), namestr(name), tystr(ty));
+ dcl->decl.vis = t->vis;
lappend(&file->file.stmts, &file->file.nstmts, dcl);
}
}
--- a/parse/node.c
+++ b/parse/node.c
@@ -26,6 +26,24 @@
return l.line;
}
+/*
+ * Bah, this is going to need to know how to fold things.
+ * FIXME: teach it.
+ */
+uint64_t arraysz(Node *sz)
+{
+ Node *n;
+
+ n = sz;
+ if (exprop(n) != Olit)
+ fatal(sz, "too many layers of indirection when finding intializer. (initialization loop?)");
+
+ n = n->expr.args[0];
+ if (n->lit.littype != Lint)
+ fatal(sz, "initializer is not an integer");
+ return n->lit.intval;
+}
+
Node *mknode(Srcloc loc, Ntype nt)
{
Node *n;
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -192,14 +192,14 @@
int nid;
union {
struct {
- char **files;
size_t nfiles;
- size_t nuses;
+ char **files;
Node **uses;
- size_t nlibdeps;
+ size_t nuses;
char **libdeps;
- size_t nstmts;
+ size_t nlibdeps;
Node **stmts;
+ size_t nstmts;
Stab *globls;
} file;
@@ -491,6 +491,7 @@
Type *tybase(Type *t);
char *tyfmt(char *buf, size_t len, Type *t);
char *tystr(Type *t);
+size_t tyidfmt(char *buf, size_t len, Type *t);
int hastrait(Type *t, Trait *c);
int settrait(Type *t, Trait *c);
@@ -530,6 +531,7 @@
Ucon *mkucon(Srcloc l, Node *name, Type *ut, Type *uet);
/* node util functions */
+uint64_t arraysz(Node *sz);
char *namestr(Node *name);
char *declname(Node *n);
Type *decltype(Node *n);
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -360,7 +360,7 @@
Node *genericname(Node *n, Type *t)
{
char buf[1024];
- char *p, *s;
+ char *p;
char *end;
Node *name;
@@ -367,11 +367,10 @@
if (!n->decl.isgeneric)
return n->decl.name;
p = buf;
- end = buf + 1024;
- s = tystr(t);
+ end = buf + sizeof buf;
p += snprintf(p, end - p, "%s", n->decl.name->name.name);
- p += snprintf(p, end - p, "$%lu", strhash(s));
- free(s);
+ p += snprintf(p, end - p, "$");
+ p += tyidfmt(p, end - p, t);
name = mkname(n->loc, buf);
if (n->decl.name->name.ns)
setns(name, n->decl.name->name.ns);
--- a/parse/type.c
+++ b/parse/type.c
@@ -116,7 +116,10 @@
Trait *t;
t = zalloc(sizeof(Trait));
+ t->uid = ntraittab++;
t->loc = loc;
+ if (t->uid < Ntraits)
+ t->vis = Visbuiltin;
t->vis = Visintern;
t->name = name;
t->param = param;
@@ -125,7 +128,6 @@
t->funcs = funcs;
t->nfuncs = nfuncs;
t->isproto = isproto;
- t->uid = ntraittab++;
traittab = xrealloc(traittab, ntraittab*sizeof(Trait*));
traittab[t->uid] = t;
@@ -560,7 +562,6 @@
p += snprintf(p, end - p, "@%s", t->pname);
break;
case Tyunres:
- p += snprintf(p, end - p, "?"); /* indicate unresolved name. should not be seen by user. */
p += namefmt(p, end - p, t->name);
if (t->narg) {
p += snprintf(p, end - p, "(");
@@ -635,10 +636,15 @@
t = (Type *)ty;
switch (t->type) {
- case Typaram: hash = strhash(t->pname); break;
+ /* Important: we want tyhash to be consistent cross-file, since it
+ * is used in naming trait impls and such.
+ *
+ * We should find a better name.
+ */
case Tyvar: hash = inthash(t->tid); break;
- case Tyunion: hash = inthash(t->tid); break;
- case Tystruct: hash = inthash(t->tid); break;
+ case Typaram: hash = strhash(t->pname); break;
+ case Tyunion: hash = inthash(t->type); break;
+ case Tystruct: hash = inthash(t->type); break;
case Tyname: hash = namehash(t->name); break;
default: hash = inthash(t->type); break;
}
@@ -648,22 +654,6 @@
return hash;
}
-static int valeq(Node *a, Node *b)
-{
- if (a == b)
- return 1;
-
- /* unwrap to Nlit */
- if (exprop(a) == Olit)
- a = a->expr.args[0];
- if (exprop(b) == Olit)
- b = b->expr.args[0];
-
- if (a->type != Nlit || b->type != Nlit)
- return 0;
- return liteq(a, b);
-}
-
int tyeq(void *t1, void *t2)
{
Type *a, *b;
@@ -723,7 +713,7 @@
return 0;
break;
case Tyarray:
- if (!valeq(a->asize, b->asize))
+ if (arraysz(a->asize) != arraysz(b->asize))
return 0;
break;
default:
@@ -733,6 +723,101 @@
if (!tyeq(a->sub[i], b->sub[i]))
return 0;
return 1;
+}
+
+size_t tyidfmt(char *buf, size_t sz, Type *ty)
+{
+ size_t i;
+ char *p, *end;
+
+ p = buf;
+ end = buf + sz;
+ switch (ty->type) {
+ case Ntypes:
+ case Tybad: die("invalid type"); break;
+ case Tyvar: die("tyvar has no idstr"); break;
+ case Tyvoid: p += snprintf(p, end - p, "v"); break;
+ case Tychar: p += snprintf(p, end - p, "c"); break;
+ case Tybool: p += snprintf(p, end - p, "t"); break;
+ case Tyint8: p += snprintf(p, end - p, "b"); break;
+ case Tyint16: p += snprintf(p, end - p, "s"); break;
+ case Tyint: p += snprintf(p, end - p, "i"); break;
+ case Tyint32: p += snprintf(p, end - p, "w"); break;
+ case Tyint64: p += snprintf(p, end - p, "q"); break;
+ case Tylong: p += snprintf(p, end - p, "l"); break;
+
+ case Tybyte: p += snprintf(p, end - p, "T"); break;
+ case Tyuint8: p += snprintf(p, end - p, "B"); break;
+ case Tyuint16: p += snprintf(p, end - p, "S"); break;
+ case Tyuint: p += snprintf(p, end - p, "I"); break;
+ case Tyuint32: p += snprintf(p, end - p, "W"); break;
+ case Tyuint64: p += snprintf(p, end - p, "Q"); break;
+ case Tyulong: p += snprintf(p, end - p, "L"); break;
+ case Tyflt32: p += snprintf(p, end - p, "f"); break;
+ case Tyflt64: p += snprintf(p, end - p, "d"); break;
+ case Tyvalist: p += snprintf(p, end - p, "V"); break;
+ case Typtr:
+ p += snprintf(p, end - p, ".p");
+ p += tyidfmt(p, end - p, ty->sub[0]);
+ break;
+ case Tyarray:
+ p += snprintf(p, end - p, ".a%lld", (vlong)arraysz(ty->asize));
+ p += tyidfmt(p, end - p, ty->sub[0]);
+ break;
+ case Tyslice:
+ p += snprintf(p, end - p, ".s");
+ p += tyidfmt(p, end - p, ty->sub[0]);
+ break;
+ case Tyfunc:
+ p += snprintf(p, end - p, ".f");
+ for (i = 0; i < ty->nsub; i++) {
+ p += tyidfmt(p, end - p, ty->sub[i]);
+ p += snprintf(p, end - p, "$");
+ }
+ break;
+ case Tytuple:
+ p += snprintf(p, end - p, ".p");
+ for (i = 0; i < ty->nsub; i++) {
+ p += tyidfmt(p, end - p, ty->sub[i]);
+ }
+ p += snprintf(p, end - p, "$");
+ break;
+ case Tystruct:
+ p += snprintf(p, end - p, ".t");
+ for (i = 0; i < ty->nmemb; i++) {
+ p += snprintf(p, end - p, "%s.", declname(ty->sdecls[i]));
+ p += tyidfmt(p, end - p, decltype(ty->sdecls[i]));
+ p += snprintf(p, end - p, "$");
+ }
+ break;
+ case Tyunion:
+ p += snprintf(p, end - p, ".u");
+ for (i = 0; i < ty->nmemb; i++) {
+ p += snprintf(p, end - p, "%s.", namestr(ty->udecls[i]->name));
+ if (ty->udecls[i]->etype)
+ p += tyidfmt(p, end - p, ty->udecls[i]->etype);
+ p += snprintf(p, end - p, "$");
+ }
+ break;
+ case Typaram:
+ p += snprintf(p, end - p, ".p");
+ p += tyidfmt(p, end - p, ty->sub[0]);
+ break;
+ case Tyunres:
+ case Tyname:
+ p += snprintf(p, end - p, ".n");
+ if (ty->name->name.ns)
+ p += snprintf(p, end - p, "%s", ty->name->name.ns);
+ p += snprintf(p, end - p, ".%s", ty->name->name.name);
+ if (ty->arg)
+ for (i = 0; i < ty->narg; i++)
+ p += tyidfmt(p, end - p, ty->arg[i]);
+ else if (ty->param)
+ for (i = 0; i < ty->nparam; i++)
+ p += tyidfmt(p, end - p, ty->param[i]);
+ break;
+ }
+ return p - buf;
}
void tyinit(Stab *st)
--- a/parse/use.c
+++ b/parse/use.c
@@ -24,12 +24,21 @@
static Htab *tydedup; /* map from name -> type, contains all Tynames loaded ever */
static Htab *tidmap; /* map from tid -> type */
static Htab *trmap; /* map from trait id -> trait */
-static Type ***typefixdest; /* list of types we need to replace */
-static size_t ntypefixdest; /* size of replacement list */
-static intptr_t *typefixid; /* list of types we need to replace */
-static size_t ntypefixid; /* size of replacement list */
+
#define Builtinmask (1 << 30)
+static Type ***typefixdest; /* list of types we need to replace */
+static size_t ntypefixdest; /* size of replacement list */
+static intptr_t *typefixid; /* list of types we need to replace */
+static size_t ntypefixid; /* size of replacement list */
+static Trait ***traitfixdest; /* list of traits we need to replace */
+static size_t ntraitfixdest; /* size of replacement list */
+static Type **traitfixtype; /* list of types we need to set the trait on */
+static size_t ntraitfixtype; /* size of replacement list */
+static intptr_t *traitfixid; /* list of traits we need to replace */
+static size_t ntraitfixid; /* size of replacement list */
+
+
/* Outputs a symbol table to file in a way that can be
* read back usefully. Only writes declarations, types
* and sub-namespaces. Captured variables are ommitted. */
@@ -205,8 +214,12 @@
wrint(fd, 0);
} else {
wrint(fd, bscount(ty->traits));
- for (i = 0; bsiter(ty->traits, &i); i++)
- wrint(fd, i);
+ for (i = 0; bsiter(ty->traits, &i); i++) {
+ if (i < Ntraits)
+ wrint(fd, i | Builtinmask);
+ else
+ wrint(fd, i);
+ }
}
wrint(fd, ty->nsub);
switch (ty->type) {
@@ -285,7 +298,7 @@
static void rdtype(FILE *fd, Type **dest)
{
- intptr_t tid;
+ uintptr_t tid;
tid = rdint(fd);
if (tid & Builtinmask) {
@@ -296,6 +309,23 @@
}
}
+static void rdtrait(FILE *fd, Trait **dest, Type *ty)
+{
+ uintptr_t tid;
+
+ tid = rdint(fd);
+ if (tid & Builtinmask) {
+ if (dest)
+ *dest = traittab[tid & ~Builtinmask];
+ if (ty)
+ settrait(ty, traittab[tid & ~Builtinmask]);
+ } else {
+ lappend(&traitfixdest, &ntraitfixdest, dest);
+ lappend(&traitfixtype, &ntraitfixtype, ty);
+ lappend(&traitfixid, &ntraitfixid, itop(tid));
+ }
+}
+
/* Writes types to a file. Errors on
* internal only types like Tyvar that
* will not be meaningful in another file */
@@ -302,9 +332,7 @@
static Type *tyunpickle(FILE *fd)
{
size_t i, n;
- size_t v;
Type *ty;
- Trait *tr;
Ty t;
t = rdbyte(fd);
@@ -313,14 +341,8 @@
ty->ishidden = 1;
/* tid is generated; don't write */
n = rdint(fd);
- if (n > 0) {
- ty->traits = mkbs();
- for (i = 0; i < n; i++) {
- v = rdint(fd);
- tr = htget(trmap, itop(v));
- settrait(ty, tr);
- }
- }
+ for (i = 0; i < n; i++)
+ rdtrait(fd, NULL, ty);
ty->nsub = rdint(fd);
if (ty->nsub > 0)
ty->sub = zalloc(ty->nsub * sizeof(Type*));
@@ -383,6 +405,7 @@
/* create an empty trait */
tr = mktrait(Zloc, NULL, NULL, NULL, 0, NULL, 0, 0);
uid = rdint(fd);
+ printf("loading trait for uid %d\n", (int)uid);
tr->ishidden = rdbool(fd);
tr->name = unpickle(fd);
tr->param = tyunpickle(fd);
@@ -658,7 +681,7 @@
case Nimpl:
n->impl.traitname = unpickle(fd);
i = rdint(fd);
- n->impl.trait = htget(trmap, itop(i));
+ rdtrait(fd, &n->impl.trait, NULL);
rdtype(fd, &n->impl.type);
n->impl.ndecls = rdint(fd);
n->impl.decls = zalloc(sizeof(Node *)*n->impl.ndecls);
@@ -695,7 +718,7 @@
return s;
}
-static void fixmappings(Stab *st)
+static void fixtypemappings(Stab *st)
{
size_t i;
Type *t, *old;
@@ -733,6 +756,31 @@
lfree(&typefixid, &ntypefixid);
}
+static void fixtraitmappings(Stab *st)
+{
+ size_t i;
+ Trait *t;
+
+ /*
+ * merge duplicate definitions.
+ * This allows us to compare named types by id, instead
+ * of doing a deep walk through the type. This ability is
+ * depended on when we do type inference.
+ */
+ for (i = 0; i < ntraitfixdest; i++) {
+ t = htget(trmap, itop(traitfixid[i]));
+ if (!t)
+ die("Unable to find trait for id %zd\n", traitfixid[i]);
+ if (traitfixdest[i])
+ *traitfixdest[i] = t;
+ if (traitfixtype[i])
+ settrait(traitfixtype[i], t);
+ }
+
+ lfree(&traitfixdest, &ntraitfixdest);
+ lfree(&traitfixid, &ntraitfixid);
+}
+
/* Usefile format:
* U<pkgname>
* T<pickled-type>
@@ -838,7 +886,8 @@
break;
}
}
- fixmappings(s);
+ fixtypemappings(s);
+ fixtraitmappings(s);
htfree(tidmap);
popstab();
return 1;