shithub: mc

Download patch

ref: 8dbfb1c654f6589369c518b400368e725e69f808
parent: f76858ddb7d53feb5b52f5828fdd0eaec4a968f4
author: Ori Bernstein <[email protected]>
date: Thu Jun 21 16:24:09 EDT 2012

Generics now bind variables.

    Correctness is not certain.

--- a/parse/gram.y
+++ b/parse/gram.y
@@ -178,6 +178,7 @@
              $$ = $2;}
         | Tgeneric declbody Tendln
             {$2->decl.isconst = 1;
+             $2->decl.isgeneric = 1;
              $$ = $2;}
         | Textern Tvar declbody Tendln
             {$3->decl.isextern = 1;
--- a/parse/htab.c
+++ b/parse/htab.c
@@ -25,6 +25,14 @@
     return ht;
 }
 
+void htfree(Htab *ht)
+{
+    free(ht->keys);
+    free(ht->vals);
+    free(ht->hashes);
+    free(ht);
+}
+
 static ulong hash(Htab *ht, void *k)
 {
     ulong h;
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -14,6 +14,8 @@
 
 static Node **postcheck;
 static size_t npostcheck;
+static Htab **tybindings;
+static size_t ntybindings;
 
 static void infernode(Node *n, Type *ret, int *sawret);
 static void inferexpr(Node *n, Type *ret, int *sawret);
@@ -30,6 +32,19 @@
     st->super = super;
 }
 
+static int bound(Type *t)
+{
+    ssize_t i;
+    Type *p;
+
+    for (i = ntybindings - 1; i >= 0; i--) {
+        p = htget(tybindings[i], t->pname);
+        if (p == t)
+            return 1;
+    }
+    return 0;
+}
+
 static void tyresolve(Type *t)
 {
     size_t i, nn;
@@ -280,6 +295,13 @@
     *ret = var;
 }
 
+static Type *freshen(Type *t)
+{
+    if (t->type != Typaram || bound(t))
+        return t;
+    return mktyvar(t->line);
+}
+
 static void inferexpr(Node *n, Type *ret, int *sawret)
 {
     Node **args;
@@ -410,7 +432,7 @@
             if (!s)
                 fatal(n->line, "Undeclared var %s", ctxstr(args[0]));
             else
-                settype(n, s->decl.type);
+                settype(n, freshen(s->decl.type));
             n->expr.did = s->decl.did;
             break;
         case Olit:      /* <lit>:@a::tyclass -> @a */
@@ -475,6 +497,50 @@
     free(k);
 }
 
+static void tybind(Htab *bt, Type *t)
+{
+    size_t i;
+
+    if (!t)
+        return;
+    if (t->type != Typaram)
+        return;
+
+    if (hthas(bt, t->pname))
+        unify(NULL, htget(bt, t->pname), t);
+    else if (bound(t))
+        return;
+
+    htput(bt, t->pname, t);
+    for (i = 0; i < t->nsub; i++)
+        tybind(bt, t->sub[i]);
+    printf("Bound @%s\n", t->pname);
+}
+
+static void bind(Node *n)
+{
+    Htab *bt;
+
+    if (!n->decl.isgeneric)
+        return;
+    if (!n->decl.init)
+        fatal(n->line, "generic %s has no initializer", n->decl);
+
+    bt = mkht(strhash, streq);
+    lappend(&tybindings, &ntybindings, bt);
+
+    tybind(bt, n->decl.type);
+    tybind(bt, n->decl.init->expr.type);
+}
+
+static void unbind(Node *n)
+{
+    if (!n->decl.isgeneric)
+        return;
+    htfree(tybindings[ntybindings - 1]);
+    lpop(&tybindings, &ntybindings);
+}
+
 static void infernode(Node *n, Type *ret, int *sawret)
 {
     size_t i;
@@ -502,7 +568,9 @@
             popstab();
             break;
         case Ndecl:
+            bind(n);
             inferdecl(n);
+            unbind(n);
             break;
         case Nblock:
             setsuper(n->block.scope, curstab());
@@ -532,6 +600,8 @@
             break;
         case Nfunc:
             setsuper(n->func.scope, curstab());
+            for (i = 0; i < n->func.nargs; i++)
+                tybind(tybindings[ntybindings - 1], n->func.args[i]->decl.type);
             pushstab(n->func.scope);
             inferstab(n->block.scope);
             inferfunc(n);
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -239,6 +239,7 @@
 size_t bscount(Bitset *bs);
 
 Htab *mkht(ulong (*hash)(void *key), int (*cmp)(void *k1, void *k2));
+void htfree(Htab *ht);
 int htput(Htab *ht, void *k, void *v);
 void *htget(Htab *ht, void *k);
 int hthas(Htab *ht, void *k);