shithub: mc

Download patch

ref: 49d3b0cf04719267479faebe9e2ffe0089a2f9ac
parent: c0705c9a9457e5a13e20bb71d8b14e4399ffc02f
author: Ori Bernstein <[email protected]>
date: Mon Oct 8 10:42:57 EDT 2012

Bind types when resolving them.

--- a/parse/infer.c
+++ b/parse/infer.c
@@ -41,6 +41,10 @@
 static void infernode(Inferstate *st, Node *n, Type *ret, int *sawret);
 static void inferexpr(Inferstate *st, Node *n, Type *ret, int *sawret);
 static void typesub(Inferstate *st, Node *n);
+static void tybind(Inferstate *st, Type *t);
+static void bind(Inferstate *st, Node *n);
+static void tyunbind(Inferstate *st, Type *t);
+static void unbind(Inferstate *st, Node *n);
 static Type *unify(Inferstate *st, Node *ctx, Type *a, Type *b);
 static Type *tf(Inferstate *st, Type *t);
 
@@ -227,6 +231,7 @@
     if (t->resolved)
         return;
     t->resolved = 1;
+    tybind(st, t);
     /* if this is a generic type, bind the params. */
     /* Walk through aggregate type members */
     if (t->type == Tystruct) {
@@ -256,6 +261,7 @@
         t->cstrs = bsdup(base->cstrs);
     if (tyinfinite(st, t, NULL))
         fatal(t->line, "Type %s includes itself", tystr(t));
+    tyunbind(st, t);
 }
 
 /* fixd the most accurate type mapping we have (ie,
@@ -355,7 +361,7 @@
 
 /* Binds the type parameters present in the
  * current type into the type environment */
-static void tybind(Inferstate *st, Htab *bt, Type *t)
+static void putbindings(Inferstate *st, Htab *bt, Type *t)
 {
     size_t i;
 
@@ -371,11 +377,23 @@
 
     htput(bt, t->pname, t);
     for (i = 0; i < t->nparam; i++)
-        tybind(st, bt, t->param[i]);
+        putbindings(st, bt, t->param[i]);
     for (i = 0; i < t->nsub; i++)
-        tybind(st, bt, t->sub[i]);
+        putbindings(st, bt, t->sub[i]);
 }
 
+static void tybind(Inferstate *st, Type *t)
+{
+    Htab *bt;
+
+    if (t->type != Tygeneric)
+        return;
+    st->ingeneric++;
+    bt = mkht(strhash, streq);
+    lappend(&st->tybindings, &st->ntybindings, bt);
+    putbindings(st, bt, t);
+}
+
 /* Binds the type parameters in the
  * declaration into the type environment */
 static void bind(Inferstate *st, Node *n)
@@ -388,11 +406,12 @@
     if (!n->decl.init)
         fatal(n->line, "generic %s has no initializer", n->decl);
 
+    st->ingeneric++;
     bt = mkht(strhash, streq);
     lappend(&st->tybindings, &st->ntybindings, bt);
 
-    tybind(st, bt, n->decl.type);
-    tybind(st, bt, n->decl.init->expr.type);
+    putbindings(st, bt, n->decl.type);
+    putbindings(st, bt, n->decl.init->expr.type);
 }
 
 /* Rolls back the binding of type parameters in
@@ -403,8 +422,18 @@
         return;
     htfree(st->tybindings[st->ntybindings - 1]);
     lpop(&st->tybindings, &st->ntybindings);
+    st->ingeneric--;
 }
 
+static void tyunbind(Inferstate *st, Type *t)
+{
+    if (t->type != Tygeneric)
+        return;
+    htfree(st->tybindings[st->ntybindings - 1]);
+    lpop(&st->tybindings, &st->ntybindings);
+    st->ingeneric--;
+}
+
 static void checkcast(Inferstate *st, Node *n)
 {
     /* FIXME: actually verify the casts. Right now, it's ok to leave this
@@ -1044,15 +1073,11 @@
             popstab();
             break;
         case Ndecl:
-            if (n->decl.isgeneric)
-                st->ingeneric++;
             bind(st, n);
             inferdecl(st, n);
             unbind(st, n);
             if (type(st, n)->type == Typaram && !st->ingeneric)
                 fatal(n->line, "Generic type %s in non-generic near %s\n", tystr(type(st, n)), ctxstr(st, n));
-            if (n->decl.isgeneric)
-                st->ingeneric--;
             break;
         case Nblock:
             setsuper(n->block.scope, curstab());
@@ -1098,7 +1123,7 @@
             setsuper(n->func.scope, curstab());
             if (st->ntybindings > 0)
                 for (i = 0; i < n->func.nargs; i++)
-                    tybind(st, st->tybindings[st->ntybindings - 1], n->func.args[i]->decl.type);
+                    putbindings(st, st->tybindings[st->ntybindings - 1], n->func.args[i]->decl.type);
             pushstab(n->func.scope);
             inferstab(st, n->block.scope);
             inferfunc(st, n);