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);