shithub: mc

Download patch

ref: cc5182284db2880dcfc3b0bd61dbc6ed319bacc3
parent: 32abfabfaf95942558a590a307432b499f392ea9
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Feb 10 18:03:36 EST 2019

Pass the type envs through properly in delayed unification.

--- a/parse/infer.c
+++ b/parse/infer.c
@@ -16,7 +16,7 @@
 #include "parse.h"
 
 typedef struct Traitmap Traitmap;
-typedef struct Enttype Enttype;
+typedef struct Postcheck Postcheck;
 
 struct Traitmap {
 	Bitset *traits;
@@ -29,6 +29,13 @@
 	size_t nfiltertr;
 };
 
+struct Postcheck {
+	Node *node;
+	Stab *stab;
+	Tyenv *env;
+};
+
+
 int allowhidden;
 
 static void infernode(Node **np, Type *ret, int *sawret);
@@ -53,10 +60,8 @@
 
 /* post-inference checking/unification */
 static Htab *delayed;
-static Node **postcheck;
+static Postcheck **postcheck;
 static size_t npostcheck;
-static Stab **postcheckscope;
-static size_t npostcheckscope;
 
 /* generic declarations to be specialized */
 static Node **genericdecls;
@@ -298,10 +303,15 @@
 }
 
 static void
-delayedcheck(Node *n, Stab *s)
+delayedcheck(Node *n)
 {
-	lappend(&postcheck, &npostcheck, n);
-	lappend(&postcheckscope, &npostcheckscope, s);
+	Postcheck *pc;
+
+	pc = xalloc(sizeof(Postcheck));
+	pc->node = n;
+	pc->stab = curstab();
+	pc->env = curenv();
+	lappend(&postcheck, &npostcheck, pc);
 }
 
 static void
@@ -1356,7 +1366,7 @@
 	n->expr.isconst = s->decl.isconst;
 	if (param) {
 		n->expr.param = param;
-		delayedcheck(n, curstab());
+		delayedcheck(n);
 	}
 	if (s->decl.isgeneric && !ingeneric) {
 		t = tyfreshen(NULL, t);
@@ -1363,7 +1373,7 @@
 		addspecialization(n, curstab());
 		if (t->type == Tyvar) {
 			settype(n, mktyvar(n->loc));
-			delayedcheck(n, curstab());
+			delayedcheck(n);
 		} else {
 			settype(n, t);
 		}
@@ -1414,7 +1424,7 @@
 
 	*isconst = 1;
 	/* we want to check outer nodes before inner nodes when unifying nested structs */
-	delayedcheck(n, curstab());
+	delayedcheck(n);
 	for (i = 0; i < n->expr.nargs; i++) {
 		infernode(&n->expr.args[i], NULL, NULL);
 		if (!n->expr.args[i]->expr.isconst)
@@ -1778,7 +1788,7 @@
 	case Omemb:	/* @a.Ident -> @b, verify type(@a.Ident)==@b later */
 		infersub(n, ret, sawret, &isconst);
 		settype(n, mktyvar(n->loc));
-		delayedcheck(n, curstab());
+		delayedcheck(n);
 		break;
 	case Osize:	/* sizeof(@a) -> size */
 		infersub(n, ret, sawret, &isconst);
@@ -1790,7 +1800,7 @@
 		break;
 	case Ocast:	/* (@a : @b) -> @b */
 		infersub(n, ret, sawret, &isconst);
-		delayedcheck(n, curstab());
+		delayedcheck(n);
 		break;
 	case Oret:	/* -> @a -> void */
 		infersub(n, ret, sawret, &isconst);
@@ -1827,7 +1837,9 @@
 			fatal(n, "undeclared var %s", ctxstr(args[0]));
 		if (n->expr.param && !s->decl.trait)
 			fatal(n, "var %s must refer to a trait decl", ctxstr(args[0]));
+		pushenv(s->decl.env);
 		initvar(n, s);
+		popenv(s->decl.env);
 		break;
 	case Ogap:	/* _ -> @a */
 		if (n->expr.type)
@@ -2123,7 +2135,7 @@
 			unify(n, e, b);
 		else
 			t->seqaux = e;
-		delayedcheck(n, curstab());
+		delayedcheck(n);
 		break;
 	case Nmatchstmt:
 		infernode(&n->matchstmt.val, NULL, sawret);
@@ -2267,7 +2279,7 @@
 }
 
 static void
-checkcast(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+checkcast(Node *n, Postcheck ***pc, size_t *npc)
 {
 	/* FIXME: actually verify the casts. Right now, it's ok to leave thi
 	 * unimplemented because bad casts get caught by the backend. */
@@ -2274,16 +2286,14 @@
 }
 
 static void
-infercompn(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+infercompn(Node *n, Postcheck ***post, size_t *npost)
 {
-	Node *aggr;
-	Node *memb;
-	Node **nl;
-	Type *t;
-	size_t i;
-	int found;
-	int ismemb;
+	Node *aggr, *memb, **nl;
+	int found, ismemb;
+	Postcheck *pc;
 	uvlong idx;
+	size_t i;
+	Type *t;
 
 	aggr = n->expr.args[0];
 	memb = n->expr.args[1];
@@ -2302,11 +2312,11 @@
 		if (tybase(t)->type == Typtr)
 			t = tybase(tf(t->sub[0]));
 		if (tybase(t)->type == Tyvar) {
-			if (!rem)
-				fatal(n, "underspecified type defined on %s:%d used near %s",
-						fname(t->loc), lnum(t->loc), ctxstr(n));
-			lappend(rem, nrem, n);
-			lappend(remscope, nremscope, curstab());
+			pc = xalloc(sizeof(Postcheck));
+			pc->node = n;
+			pc->stab = curstab();
+			pc->env = curenv();
+			lappend(post, npost, pc);
 			return;
 		}
 		if (ismemb) {
@@ -2349,11 +2359,12 @@
 }
 
 static void
-checkstruct(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+checkstruct(Node *n, Postcheck ***post, size_t *npost)
 {
 	Type *t, *et;
 	Node *val, *name;
 	size_t i, j;
+	Postcheck *pc;
 
 	t = tybase(tf(n->lit.type));
 	/*
@@ -2379,23 +2390,22 @@
 			}
 		}
 
-		if (!et) {
-			if (rem) {
-				lappend(rem, nrem, n);
-				lappend(remscope, nremscope, curstab());
-				return;
-			} else {
-				fatal(n, "could not find member %s in struct %s, near %s",
-						namestr(name), tystr(t), ctxstr(n));
-			}
+		if (et) {
+			unify(val, et, type(val));
+		} else {
+			assert(post != NULL);
+			pc = xalloc(sizeof(Postcheck));
+			pc->node = n;
+			pc->stab = curstab();
+			pc->env = curenv();
+			lappend(post, npost, pc);
+			return;
 		}
-
-		unify(val, et, type(val));
 	}
 }
 
 static void
-checkvar(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+checkvar(Node *n, Postcheck ***post, size_t *npost)
 {
 	Node *proto, *dcl;
 	Type *ty;
@@ -2403,6 +2413,7 @@
 	proto = decls[n->expr.did];
 	ty = NULL;
 	dcl = NULL;
+	pushenv(proto->decl.env);
 	if (n->expr.param)
 		dcl = htget(proto->decl.impls, tf(n->expr.param));
 	if (dcl)
@@ -2410,6 +2421,7 @@
 	if (!ty)
 		ty = tyfreshen(NULL, type(proto));
 	unify(n, type(n), ty);
+	popenv(proto->decl.env);
 }
 
 static void
@@ -2450,26 +2462,30 @@
 }
 
 static void
-postcheckpass(Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+postcheckpass(Postcheck ***post, size_t *npost)
 {
 	size_t i;
 	Node *n;
 
 	for (i = 0; i < npostcheck; i++) {
-		n = postcheck[i];
-		pushstab(postcheckscope[i]);
+		n = postcheck[i]->node;
+		pushstab(postcheck[i]->stab);
+		pushenv(postcheck[i]->env);
 		if (n->type == Nexpr) {
 			switch (exprop(n)) {
 			case Otupmemb:
-			case Omemb:	infercompn(n, rem, nrem, remscope, nremscope);	break;
-			case Ocast:	checkcast(n, rem, nrem, remscope, nremscope);	break;
-			case Ostruct:	checkstruct(n, rem, nrem, remscope, nremscope);	break;
-			case Ovar:	checkvar(n, rem, nrem, remscope, nremscope);	break;
-			default:	die("should not see %s in postcheck\n", opstr[exprop(n)]);
+			case Omemb:	infercompn(n, post, npost);	break;
+			case Ocast:	checkcast(n, post, npost);	break;
+			case Ostruct:	checkstruct(n, post, npost);	break;
+			case Ovar:	checkvar(n, post, npost);	break;
+			default:
+				die("should not see %s in postcheck\n", opstr[exprop(n)]);
+				break;
 			}
 		} else if (n->type == Niterstmt) {
 			fixiter(n, type(n->iterstmt.seq), type(n->iterstmt.elt));
 		}
+		popenv(postcheck[i]->env);
 		popstab();
 	}
 }
@@ -2477,23 +2493,20 @@
 static void
 postinfer(void)
 {
-	size_t nrem, nremscope;
-	Stab **remscope;
-	Node **rem;
+	Postcheck **post, **last;
+	size_t npost, nlast;
 
+	/* Iterate until we reach a fixpoint. */
+	nlast = 0;
 	while (1) {
-		remscope = NULL;
-		nremscope = 0;
-		rem = NULL;
-		nrem = 0;
-		postcheckpass(&rem, &nrem, &remscope, &nremscope);
-		if (nrem == npostcheck) {
+		post = NULL;
+		npost = 0;
+		postcheckpass(&post, &npost);
+		if (npost == nlast) {
 			break;
 		}
-		postcheck = rem;
-		npostcheck = nrem;
-		postcheckscope = remscope;
-		npostcheckscope = nremscope;
+		last = post;
+		nlast = npost;
 	}
 }
 
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -430,6 +430,7 @@
 	case Ndecl:
 		r->decl.did = ndecls;
 		/* sym */
+		r->decl.env = n->decl.env;
 		r->decl.name = specializenode(n->decl.name, tsmap);
 		r->decl.type = tysubst(n->decl.type, tsmap);
 
@@ -442,13 +443,17 @@
 			putdcl(curstab(), r);
 
 		/* init */
+		pushenv(r->decl.env);
 		r->decl.init = specializenode(n->decl.init, tsmap);
+		popenv(r->decl.env);
 		lappend(&decls, &ndecls, r);
 		break;
 	case Nfunc:
 		r->func.scope = mkstab(1);
 		r->func.scope->super = curstab();
+		r->func.env = n->func.env;
 		pushstab(r->func.scope);
+		pushenv(r->func.env);
 		r->func.type = tysubst(n->func.type, tsmap);
 		r->func.nargs = n->func.nargs;
 		r->func.args = xalloc(sizeof(Node *) * n->func.nargs);
@@ -455,6 +460,7 @@
 		for (i = 0; i < n->func.nargs; i++)
 			r->func.args[i] = specializenode(n->func.args[i], tsmap);
 		r->func.body = specializenode(n->func.body, tsmap);
+		popenv(r->func.env);
 		popstab();
 		break;
 	case Nimpl:
--- a/parse/type.c
+++ b/parse/type.c
@@ -834,7 +834,6 @@
 	switch (a->type) {
 	case Typaram:
 		ret = (a == b);
-		/* FIXME: this streq check needs to go */
 		ret = ret || streq(a->pname, b->pname);
 		break;
 	case Tyvar: