shithub: mc

Download patch

ref: cd1d6a74365f76fa168bf642d940a56d5939bf7b
parent: a79ce9169174d4157037d84d85bf630c3094e0f8
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Jan 29 18:23:58 EST 2016

Use a stack of substitution maps.

	It sucks that I need it.

--- a/parse/infer.c
+++ b/parse/infer.c
@@ -344,7 +344,7 @@
 }
 
 /* Freshens the type of a declaration. */
-static Type *tyfreshen(Inferstate *st, Htab *subst, Type *t)
+static Type *tyfreshen(Inferstate *st, Tysubst *subst, Type *t)
 {
 	char *from, *to;
 
@@ -357,9 +357,9 @@
 	from = tystr(t);
 	tybind(st, t);
 	if (!subst) {
-		subst = mkht(tyhash, tyeq);
+		subst = mksubst();
 		t = tyspecialize(t, subst, st->delayed);
-		htfree(subst);
+		substfree(subst);
 	} else {
 		t = tyspecialize(t, subst, st->delayed);
 	}
@@ -467,12 +467,12 @@
 	return t;
 }
 
-static Type *tysubstmap(Inferstate *st, Htab *subst, Type *t, Type *orig)
+static Type *tysubstmap(Inferstate *st, Tysubst *subst, Type *t, Type *orig)
 {
 	size_t i;
 
 	for (i = 0; i < t->ngparam; i++) {
-		htput(subst, t->gparam[i], tf(st, orig->arg[i]));
+		substput(subst, t->gparam[i], tf(st, orig->arg[i]));
 	}
 	t = tyfreshen(st, subst, t);
 	return t;
@@ -480,11 +480,11 @@
 
 static Type *tysubst(Inferstate *st, Type *t, Type *orig)
 {
-	Htab *subst;
+	Tysubst *subst;
 
-	subst = mkht(tyhash, tyeq);
+	subst = mksubst();
 	t = tysubstmap(st, subst, t, orig);
-	htfree(subst);
+	substfree(subst);
 	return t;
 }
 
@@ -1096,7 +1096,7 @@
 static Type *initvar(Inferstate *st, Node *n, Node *s)
 {
 	Type *t, *param;
-	Htab *subst;
+	Tysubst *subst;
 
 	if (s->decl.ishidden)
 		fatal(n, "attempting to refer to hidden decl %s", ctxstr(st, n));
@@ -1103,13 +1103,13 @@
 
 	param = NULL;
 	if (s->decl.isgeneric) {
-		subst = mkht(tyhash, tyeq);
+		subst = mksubst();
 		t = tysubstmap(st, subst, tf(st, s->decl.type), s->decl.type);
 		if (s->decl.trait) {
-			param = htget(subst, s->decl.trait->param);
+			param = substget(subst, s->decl.trait->param);
 			delayedcheck(st, n, curstab());
 		}
-		htfree(subst);
+		substfree(subst);
 	} else {
 		t = s->decl.type;
 	}
@@ -1647,8 +1647,8 @@
 static void specializeimpl(Inferstate *st, Node *n)
 {
 	Node *dcl, *proto, *name, *sym;
+	Tysubst *subst;
 	Type *ty;
-	Htab *ht;
 	Trait *t;
 	size_t i, j;
 
@@ -1693,12 +1693,12 @@
 			fatal(n, "trait specialization requires concrete type, got %s",
 					tystr(n->impl.type));
 		verifytraits(st, n, t->param, n->impl.type);
-		ht = mkht(tyhash, tyeq);
-		htput(ht, t->param, n->impl.type);
+		subst = mksubst();
+		substput(subst, t->param, n->impl.type);
 		for (j = 0; j < t->naux; j++)
-			htput(ht, t->aux[j], n->impl.aux[j]);
-		ty = tyspecialize(type(st, proto), ht, st->delayed);
-		htfree(ht);
+			substput(subst, t->aux[j], n->impl.aux[j]);
+		ty = tyspecialize(type(st, proto), subst, st->delayed);
+		substfree(subst);
 
 		inferdecl(st, dcl);
 		unify(st, n, type(st, dcl), ty);
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -18,6 +18,7 @@
 typedef struct Strbuf Strbuf;
 typedef struct Htab Htab;
 typedef struct Str Str;
+typedef struct Tysubst Tysubst;
 
 typedef struct Tok Tok;
 typedef struct Node Node;
@@ -128,6 +129,11 @@
 	Str strval;
 };
 
+struct Tysubst {
+	Htab **subst;
+	size_t nsubst;
+};
+
 struct Stab {
 	Stab *super;
 	char *name;
@@ -611,8 +617,14 @@
 Op exprop(Node *n);
 
 /* specialize generics */
+Tysubst *mksubst();
+void substfree();
+void substput(Tysubst *subst, Type *from, Type *to);
+Type *substget(Tysubst *subst, Type *from);
+void substpush(Tysubst *subst);
+void substpop(Tysubst *subst);
 Node *specializedcl(Node *n, Type *to, Node **name);
-Type *tyspecialize(Type *t, Htab *tymap, Htab *delayed);
+Type *tyspecialize(Type *t, Tysubst *tymap, Htab *delayed);
 Node *genericname(Node *n, Type *t);
 void geninit(Node *file);
 
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -12,8 +12,58 @@
 
 #include "parse.h"
 
-static Node *specializenode(Node *g, Htab *tsmap);
+static Node *specializenode(Node *g, Tysubst *tsmap);
 
+Tysubst *mksubst()
+{
+	Tysubst *subst;
+
+	subst = zalloc(sizeof(Tysubst));
+	substpush(subst);
+	return subst;
+}
+
+void substfree(Tysubst *subst)
+{
+	size_t i;
+
+	for (i = 0; i < subst->nsubst; i++)
+		htfree(subst->subst[i]);
+	lfree(&subst->subst, &subst->nsubst);
+}
+
+void substpush(Tysubst *subst)
+{
+	lappend(&subst->subst, &subst->nsubst, mkht(tyhash, tyeq));
+}
+
+void substpop(Tysubst *subst)
+{
+	Htab *ht;
+
+	ht = lpop(&subst->subst, &subst->nsubst);
+	htfree(ht);
+}
+
+void substput(Tysubst *subst, Type *from, Type *to)
+{
+	htput(subst->subst[subst->nsubst - 1], from, to);
+}
+
+Type *substget(Tysubst *subst, Type *from)
+{
+	Type *t;
+	size_t i;
+
+	t = NULL;
+	for (i = subst->nsubst; i > 0; i--) {
+		t = htget(subst->subst[i-1], from);
+		if (t)
+			break;
+	}
+	return t;
+}
+
 void addtraits(Type *t, Bitset *traits)
 {
 	size_t b;
@@ -32,14 +82,15 @@
  * parameters (type schemes in most literature)
  * replaced with type variables that we can unify
  * against */
-Type *tyspecialize(Type *orig, Htab *tsmap, Htab *delayed)
+Type *tyspecialize(Type *orig, Tysubst *tsmap, Htab *delayed)
 {
 	Type *t, *ret, *tmp, **arg, *var;
 	size_t i, narg;
 
 	t = tysearch(orig);
-	if (hthas(tsmap, t))
-		return htget(tsmap, t);
+	tmp = substget(tsmap, t);
+	if (tmp)
+		return tmp;
 	arg = NULL;
 	narg = 0;
 	switch (t->type) {
@@ -46,14 +97,21 @@
 	case Typaram:
 		ret = mktyvar(t->loc);
 		addtraits(ret, t->traits);
-		htput(tsmap, t, ret);
+		substput(tsmap, t, ret);
 		break;
 	case Tygeneric:
 		var = mktyvar(t->loc);
-		htput(tsmap, t, var);
+		substput(tsmap, t, var);
+		if (orig->type == Tyunres) {
+			substpush(tsmap);
+			for (i = 0; i < orig->narg; i++)
+				substput(tsmap, t->gparam[i], orig->arg[i]);
+		}
 		for (i = 0; i < t->ngparam; i++)
 			lappend(&arg, &narg, tyspecialize(t->gparam[i], tsmap, delayed));
 		ret = mktyname(t->loc, t->name, tyspecialize(t->sub[0], tsmap, delayed));
+		if (orig->type == Tyunres)
+			substpop(tsmap);
 		ret->issynth = 1;
 		ret->arg = arg;
 		ret->narg = narg;
@@ -63,7 +121,7 @@
 		if (!hasparams(t))
 			return t;
 		var = mktyvar(t->loc);
-		htput(tsmap, t, var);
+		substput(tsmap, t, var);
 		for (i = 0; i < t->narg; i++)
 			lappend(&arg, &narg, tyspecialize(t->arg[i], tsmap, delayed));
 		ret = mktyname(t->loc, t->name, tyspecialize(t->sub[0], tsmap, delayed));
@@ -73,7 +131,7 @@
 		break;
 	case Tystruct:
 		ret = tydup(t);
-		htput(tsmap, t, ret);
+		substput(tsmap, t, ret);
 		pushstab(NULL);
 		for (i = 0; i < t->nmemb; i++)
 			ret->sdecls[i] = specializenode(t->sdecls[i], tsmap);
@@ -81,7 +139,7 @@
 		break;
 	case Tyunion:
 		ret = tydup(t);
-		htput(tsmap, t, ret);
+		substput(tsmap, t, ret);
 		for (i = 0; i < t->nmemb; i++) {
 			tmp = NULL;
 			if (ret->udecls[i]->etype)
@@ -104,7 +162,7 @@
 	default:
 		if (t->nsub > 0) {
 			ret = tydup(t);
-			htput(tsmap, t, ret);
+			substput(tsmap, t, ret);
 			for (i = 0; i < t->nsub; i++)
 				ret->sub[i] = tyspecialize(t->sub[i], tsmap, delayed);
 		} else {
@@ -118,7 +176,7 @@
 /* Checks if the type 't' is generic, and if it is
  * substitutes the types. This is here for efficiency,
  * so we don't gratuitously duplicate types */
-static Type *tysubst(Type *t, Htab *tsmap)
+static Type *tysubst(Type *t, Tysubst *tsmap)
 {
 	if (hasparams(t))
 		return tyspecialize(t, tsmap, NULL);
@@ -130,7 +188,7 @@
  * Fills the substitution map with a mapping from
  * the type parameter 'from' to it's substititon 'to'
  */
-static void fillsubst(Htab *tsmap, Type *to, Type *from)
+static void fillsubst(Tysubst *tsmap, Type *to, Type *from)
 {
 	size_t i;
 
@@ -137,7 +195,7 @@
 	if (from->type == Typaram) {
 		if (debugopt['S'])
 			printf("mapping %s => %s\n", tystr(from), tystr(to));
-		htput(tsmap, from, to);
+		substput(tsmap, from, to);
 		return;
 	}
 	assert(to->nsub == from->nsub);
@@ -249,7 +307,7 @@
  * need to be specialized to make it concrete
  * instead of generic, and returns it.
  */
-static Node *specializenode(Node *n, Htab *tsmap)
+static Node *specializenode(Node *n, Tysubst *tsmap)
 {
 	Node *r;
 	size_t i;
@@ -397,8 +455,8 @@
 Node *specializedcl(Node *g, Type *to, Node **name)
 {
 	extern int stabstkoff;
+	Tysubst *tsmap;
 	Node *d, *n;
-	Htab *tsmap;
 	Stab *st;
 
 	assert(g->type == Ndecl);
@@ -428,7 +486,7 @@
 		pushstab(st);
 
 	/* specialize */
-	tsmap = mkht(tyhash, tyeq);
+	tsmap = mksubst();
 	fillsubst(tsmap, to, g->decl.type);
 
 	d = mkdecl(g->loc, n, tysubst(g->decl.type, tsmap));
@@ -443,6 +501,7 @@
 	lappend(&file->file.stmts, &file->file.nstmts, d);
 	if (d->decl.name->name.ns)
 		popstab();
+	substfree(tsmap);
 	return d;
 }