shithub: mc

Download patch

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;