shithub: mc

Download patch

ref: e79ca73515d029fa1a70a8cb0e9721bb8dc09194
parent: 95f4d0b36eb2d25889eed6ab48fb025d5b346b67
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Jul 9 09:45:06 EDT 2017

Inferstate is global.

	Fuck it, might as well treat it that way.

--- a/parse/infer.c
+++ b/parse/infer.c
@@ -15,57 +15,54 @@
 #include "util.h"
 #include "parse.h"
 
-typedef struct Inferstate Inferstate;
-struct Inferstate {
-	/* tracking where we are in the inference */
-	int ingeneric;
-	int inaggr;
-	int indentdepth;
-	Type *ret;
-	Srcloc *usrc;
-	size_t nusrc;
+/* tracking where we are in the inference */
+int ingeneric;
+int inaggr;
+int indentdepth;
+Type *ret;
+Srcloc *usrc;
+size_t nusrc;
 
-	/* post-inference checking/unification */
-	Htab *delayed;
-	Node **postcheck;
-	size_t npostcheck;
-	Stab **postcheckscope;
-	size_t npostcheckscope;
+/* post-inference checking/unification */
+Htab *delayed;
+Node **postcheck;
+size_t npostcheck;
+Stab **postcheckscope;
+size_t npostcheckscope;
 
-	/* generic declarations to be specialized */
-	Node **genericdecls;
-	size_t ngenericdecls;
-	Node **impldecl;
-	size_t nimpldecl;
+/* generic declarations to be specialized */
+Node **genericdecls;
+size_t ngenericdecls;
+Node **impldecl;
+size_t nimpldecl;
 
-	/* specializations of generics */
-	Node **specializations;
-	size_t nspecializations;
-	Stab **specializationscope;
-	size_t nspecializationscope;
-	Htab *seqbase;
-};
+/* specializations of generics */
+Node **specializations;
+size_t nspecializations;
+Stab **specializationscope;
+size_t nspecializationscope;
+Htab *seqbase;
 
 /* type params bound at the current point */
 Htab **tybindings;
 size_t ntybindings;
 
-static void infernode(Inferstate *st, Node **np, Type *ret, int *sawret);
-static void inferexpr(Inferstate *st, Node **np, Type *ret, int *sawret);
-static void inferdecl(Inferstate *st, Node *n);
+static void infernode(Node **np, Type *ret, int *sawret);
+static void inferexpr(Node **np, Type *ret, int *sawret);
+static void inferdecl(Node *n);
 
-static Type *tf(Inferstate *st, Type *t);
-static void tybind(Inferstate *st, Type *t);
-static void bind(Inferstate *st, Node *n);
-static void tyunbind(Inferstate *st);
-static void unbind(Inferstate *st, Node *n);
+static Type *tf(Type *t);
+static void tybind(Type *t);
+static void bind(Node *n);
+static void tyunbind();
+static void unbind(Node *n);
 
-static Type *unify(Inferstate *st, Node *ctx, Type *a, Type *b);
-static Type *tyfix(Inferstate *st, Node *ctx, Type *orig, int noerr);
-static void typesub(Inferstate *st, Node *n, int noerr);
+static Type *unify(Node *ctx, Type *a, Type *b);
+static Type *tyfix(Node *ctx, Type *orig, int noerr);
+static void typesub(Node *n, int noerr);
 
 static void
-ctxstrcall(char *buf, size_t sz, Inferstate *st, Node *n)
+ctxstrcall(char *buf, size_t sz, Node *n)
 {
 	char *p, *end, *sep, *t;
 	size_t nargs, i;
@@ -83,7 +80,7 @@
 	else
 		p += bprintf(p, end - p, "<e>(");
 	for (i = 1; i < nargs; i++) {
-		et = tyfix(st, NULL, exprtype(args[i]), 1);
+		et = tyfix(NULL, exprtype(args[i]), 1);
 		if (et != NULL)
 			t = tystr(et);
 		else
@@ -97,7 +94,7 @@
 		free(t);
 	}
 	if (exprtype(args[0])->nsub)
-		t = tystr(tyfix(st, NULL, exprtype(args[0])->sub[0], 1));
+		t = tystr(tyfix(NULL, exprtype(args[0])->sub[0], 1));
 	else
 		t = strdup("unknown");
 	p += bprintf(p, end - p, "): %s", t);
@@ -105,15 +102,15 @@
 }
 
 static char *
-nodetystr(Inferstate *st, Node *n)
+nodetystr(Node *n)
 {
 	Type *t;
 
 	t = NULL;
 	if (n->type == Nexpr && exprtype(n) != NULL)
-		t = tyfix(st, NULL, exprtype(n), 1);
+		t = tyfix(NULL, exprtype(n), 1);
 	else if (n->type == Ndecl && decltype(n) != NULL)
-		t = tyfix(st, n, decltype(n), 1);
+		t = tyfix(n, decltype(n), 1);
 
 	if (t && tybase(t)->type != Tyvar)
 		return tystr(t);
@@ -122,19 +119,19 @@
 }
 
 static void
-marksrc(Inferstate *st, Type *t, Srcloc l)
+marksrc(Type *t, Srcloc l)
 {
-	t = tf(st, t);
-	if (t->tid >= st->nusrc) {
-		st->usrc = zrealloc(st->usrc, st->nusrc*sizeof(Srcloc), (t->tid + 1)*sizeof(Srcloc));
-		st->nusrc = t->tid + 1;
+	t = tf(t);
+	if (t->tid >= nusrc) {
+		usrc = zrealloc(usrc, nusrc*sizeof(Srcloc), (t->tid + 1)*sizeof(Srcloc));
+		nusrc = t->tid + 1;
 	}
-	if (st->usrc[t->tid].line <= 0)
-		st->usrc[t->tid] = l;
+	if (usrc[t->tid].line <= 0)
+		usrc[t->tid] = l;
 }
 
 static char *
-srcstr(Inferstate *st, Type *ty)
+srcstr(Type *ty)
 {
 	char src[128];
 	Srcloc l;
@@ -141,8 +138,8 @@
 	char *s;
 
 	src[0] = 0;
-	if (st->nusrc > ty->tid && st->usrc[ty->tid].line > 0) {
-		l = st->usrc[ty->tid];
+	if (nusrc > ty->tid && usrc[ty->tid].line > 0) {
+		l = usrc[ty->tid];
 		s = tystr(ty);
 		snprintf(src, sizeof src, "\n\t%s from %s:%d", s, fname(l), lnum(l));
 		free(s);
@@ -153,7 +150,7 @@
 /* Tries to give a good string describing the context
  * for the sake of error messages. */
 static char *
-ctxstr(Inferstate *st, Node *n)
+ctxstr(Node *n)
 {
 	char *t, *t1, *t2, *t3;
 	char *s, *d;
@@ -165,7 +162,7 @@
 	default: s = strdup(nodestr[n->type]); break;
 	case Ndecl:
 		 d = declname(n);
-		 t = nodetystr(st, n);
+		 t = nodetystr(n);
 		 bprintf(buf, sizeof buf, "%s:%s", d, t);
 		 s = strdup(buf);
 		 free(t);
@@ -181,13 +178,13 @@
 			d = namestr(args[0]);
 		else
 			d = opstr[exprop(n)];
-		t = nodetystr(st, n);
+		t = nodetystr(n);
 		if (nargs >= 1)
-			t1 = nodetystr(st, args[0]);
+			t1 = nodetystr(args[0]);
 		if (nargs >= 2)
-			t2 = nodetystr(st, args[1]);
+			t2 = nodetystr(args[1]);
 		if (nargs >= 3)
-			t3 = nodetystr(st, args[2]);
+			t3 = nodetystr(args[2]);
 
 		switch (opclass[exprop(n)]) {
 		case OTpre:	bprintf(buf, sizeof buf, "%s<e:%s>", oppretty[exprop(n)], t1);	break;
@@ -199,7 +196,7 @@
 		case OTmisc:
 			switch (exprop(n)) {
 			case Ovar:	bprintf(buf, sizeof buf, "%s:%s", namestr(args[0]), t);	break;
-			case Ocall:	ctxstrcall(buf, sizeof buf, st, n);	break;
+			case Ocall:	ctxstrcall(buf, sizeof buf,n);	break;
 			case Oidx:
 				if (exprop(args[0]) == Ovar)
 					bprintf(buf, sizeof buf, "%s[<e1:%s>]", namestr(args[0]->expr.args[0]), t2);
@@ -233,18 +230,18 @@
 }
 
 static void
-addspecialization(Inferstate *st, Node *n, Stab *stab)
+addspecialization(Node *n, Stab *stab)
 {
 	Node *dcl;
 
 	dcl = decls[n->expr.did];
-	lappend(&st->specializationscope, &st->nspecializationscope, stab);
-	lappend(&st->specializations, &st->nspecializations, n);
-	lappend(&st->genericdecls, &st->ngenericdecls, dcl);
+	lappend(&specializationscope, &nspecializationscope, stab);
+	lappend(&specializations, &nspecializations, n);
+	lappend(&genericdecls, &ngenericdecls, dcl);
 }
 
 static void
-additerspecializations(Inferstate *st, Node *n, Stab *stab)
+additerspecializations(Node *n, Stab *stab)
 {
 	Trait *tr;
 	Type *ty;
@@ -260,29 +257,29 @@
 		ty = exprtype(n->iterstmt.seq);
 		if (hthas(tr->proto[i]->decl.impls, ty))
 			continue;
-		lappend(&st->specializationscope, &st->nspecializationscope, stab);
-		lappend(&st->specializations, &st->nspecializations, n);
-		lappend(&st->genericdecls, &st->ngenericdecls, tr->proto[i]);
+		lappend(&specializationscope, &nspecializationscope, stab);
+		lappend(&specializations, &nspecializations, n);
+		lappend(&genericdecls, &ngenericdecls, tr->proto[i]);
 	}
 }
 
 static void
-delayedcheck(Inferstate *st, Node *n, Stab *s)
+delayedcheck(Node *n, Stab *s)
 {
-	lappend(&st->postcheck, &st->npostcheck, n);
-	lappend(&st->postcheckscope, &st->npostcheckscope, s);
+	lappend(&postcheck, &npostcheck, n);
+	lappend(&postcheckscope, &npostcheckscope, s);
 }
 
 static void
-typeerror(Inferstate *st, Type *a, Type *b, Node *ctx, char *msg)
+typeerror(Type *a, Type *b, Node *ctx, char *msg)
 {
 	char *t1, *t2, *s1, *s2, *c;
 
-	t1 = tystr(tyfix(st, NULL, a, 1));
-	t2 = tystr(tyfix(st, NULL, b, 1));
-	s1 = srcstr(st, a);
-	s2 = srcstr(st, b);
-	c = ctxstr(st, ctx);
+	t1 = tystr(tyfix(NULL, a, 1));
+	t2 = tystr(tyfix(NULL, b, 1));
+	s1 = srcstr(a);
+	s2 = srcstr(b);
+	c = ctxstr(ctx);
 	if (msg)
 		fatal(ctx, "type \"%s\" incompatible with \"%s\" near %s: %s%s%s", t1, t2, c, msg, s1, s2);
 	else
@@ -310,7 +307,7 @@
 /* If the current environment binds a type,
  * we return true */
 static int
-isbound(Inferstate *st, Type *t)
+isbound(Type *t)
 {
 	ssize_t i;
 
@@ -326,7 +323,7 @@
  * pointers or slices are fine, but any other self-inclusion
  * would lead to a value of infinite size */
 static int
-occurs_rec(Inferstate *st, Type *sub, Bitset *bs)
+occurs_rec(Type *sub, Bitset *bs)
 {
 	size_t i;
 
@@ -339,7 +336,7 @@
 		break;
 	case Tystruct:
 		for (i = 0; i < sub->nmemb; i++)
-			if (occurs_rec(st, decltype(sub->sdecls[i]), bs))
+			if (occurs_rec(decltype(sub->sdecls[i]), bs))
 				return 1;
 		break;
 	case Tyunion:
@@ -346,13 +343,13 @@
 		for (i = 0; i < sub->nmemb; i++) {
 			if (!sub->udecls[i]->etype)
 				continue;
-			if (occurs_rec(st, sub->udecls[i]->etype, bs))
+			if (occurs_rec(sub->udecls[i]->etype, bs))
 				return 1;
 		}
 		break;
 	default:
 		for (i = 0; i < sub->nsub; i++)
-			if (occurs_rec(st, sub->sub[i], bs))
+			if (occurs_rec(sub->sub[i], bs))
 				return 1;
 		break;
 	}
@@ -361,7 +358,7 @@
 }
 
 static int
-occursin(Inferstate *st, Type *a, Type *b)
+occursin(Type *a, Type *b)
 {
 	Bitset *bs;
 	int r;
@@ -368,25 +365,25 @@
 
 	bs = mkbs();
 	bsput(bs, b->tid);
-	r = occurs_rec(st, a, bs);
+	r = occurs_rec(a, bs);
 	bsfree(bs);
 	return r;
 }
 
 static int
-occurs(Inferstate *st, Type *t)
+occurs(Type *t)
 {
 	Bitset *bs;
 	int r;
 
 	bs = mkbs();
-	r = occurs_rec(st, t, bs);
+	r = occurs_rec(t, bs);
 	bsfree(bs);
 	return r;
 }
 
 static int
-needfreshenrec(Inferstate *st, Type *t, Bitset *visited)
+needfreshenrec(Type *t, Bitset *visited)
 {
 	size_t i;
 
@@ -398,22 +395,22 @@
 	case Tygeneric: return 1;
 	case Tyname:
 		for (i = 0; i < t->narg; i++)
-			if (needfreshenrec(st, t->arg[i], visited))
+			if (needfreshenrec(t->arg[i], visited))
 				return 1;
-		return needfreshenrec(st, t->sub[0], visited);
+		return needfreshenrec(t->sub[0], visited);
 	case Tystruct:
 		for (i = 0; i < t->nmemb; i++)
-			if (needfreshenrec(st, decltype(t->sdecls[i]), visited))
+			if (needfreshenrec(decltype(t->sdecls[i]), visited))
 				return 1;
 		break;
 	case Tyunion:
 		for (i = 0; i < t->nmemb; i++)
-			if (t->udecls[i]->etype && needfreshenrec(st, t->udecls[i]->etype, visited))
+			if (t->udecls[i]->etype && needfreshenrec(t->udecls[i]->etype, visited))
 				return 1;
 		break;
 	default:
 		for (i = 0; i < t->nsub; i++)
-			if (needfreshenrec(st, t->sub[i], visited))
+			if (needfreshenrec(t->sub[i], visited))
 				return 1;
 		break;
 	}
@@ -421,13 +418,13 @@
 }
 
 static int
-needfreshen(Inferstate *st, Type *t)
+needfreshen(Type *t)
 {
 	Bitset *visited;
 	int ret;
 
 	visited = mkbs();
-	ret = needfreshenrec(st, t, visited);
+	ret = needfreshenrec(t, visited);
 	bsfree(visited);
 	return ret;
 }
@@ -434,29 +431,29 @@
 
 /* Freshens the type of a declaration. */
 static Type *
-tyfreshen(Inferstate *st, Tysubst *subst, Type *t)
+tyfreshen(Tysubst *subst, Type *t)
 {
-	if (!needfreshen(st, t)) {
+	if (!needfreshen(t)) {
 		if (debugopt['u'])
-			indentf(st->indentdepth, "%s isn't generic: skipping freshen\n", tystr(t));
+			indentf(indentdepth, "%s isn't generic: skipping freshen\n", tystr(t));
 		return t;
 	}
 
-	tybind(st, t);
+	tybind(t);
 	if (!subst) {
 		subst = mksubst();
-		t = tyspecialize(t, subst, st->delayed, st->seqbase);
+		t = tyspecialize(t, subst, delayed, seqbase);
 		substfree(subst);
 	} else {
-		t = tyspecialize(t, subst, st->delayed, st->seqbase);
+		t = tyspecialize(t, subst, delayed, seqbase);
 	}
-	tyunbind(st);
+	tyunbind();
 	return t;
 }
 
 /* Resolves a type and all its subtypes recursively. */
 static void
-tyresolve(Inferstate *st, Type *t)
+tyresolve(Type *t)
 {
 	size_t i;
 	Type *base;
@@ -467,41 +464,41 @@
 	/* type resolution should never throw errors about non-generic
 	 * showing up within a generic type, so we push and pop a generic
 	 * around resolution */
-	st->ingeneric++;
+	ingeneric++;
 	t->resolved = 1;
 	/* Walk through aggregate type members */
 	switch (t->type) {
 	case Tystruct:
-		st->inaggr++;
+		inaggr++;
 		for (i = 0; i < t->nmemb; i++)
-			infernode(st, &t->sdecls[i], NULL, NULL);
-		st->inaggr--;
+			infernode(&t->sdecls[i], NULL, NULL);
+		inaggr--;
 		break;
 	case Tyunion:
-		st->inaggr++;
+		inaggr++;
 		for (i = 0; i < t->nmemb; i++) {
 			t->udecls[i]->utype = t;
-			t->udecls[i]->utype = tf(st, t->udecls[i]->utype);
+			t->udecls[i]->utype = tf(t->udecls[i]->utype);
 			if (t->udecls[i]->etype) {
-				tyresolve(st, t->udecls[i]->etype);
-				t->udecls[i]->etype = tf(st, t->udecls[i]->etype);
+				tyresolve(t->udecls[i]->etype);
+				t->udecls[i]->etype = tf(t->udecls[i]->etype);
 			}
 		}
-		st->inaggr--;
+		inaggr--;
 		break;
 	case Tyarray:
-		if (!st->inaggr && !t->asize)
+		if (!inaggr && !t->asize)
 			lfatal(t->loc, "unsized array type outside of struct");
-		infernode(st, &t->asize, NULL, NULL);
+		infernode(&t->asize, NULL, NULL);
 		break;
 	case Typaram:
-		if (!isbound(st, t))
+		if (!isbound(t))
 			lfatal(t->loc, "type parameter %s is undefined in generic context", tystr(t));
 		break;
 	case Tyname:
 	case Tygeneric:
 		/* FIXME: this should not include the current type scope in the search. */
-		tybind(st, t);
+		tybind(t);
 		break;
 	default:
 		break;
@@ -508,7 +505,7 @@
 	}
 
 	for (i = 0; i < t->nsub; i++)
-		t->sub[i] = tf(st, t->sub[i]);
+		t->sub[i] = tf(t->sub[i]);
 	base = tybase(t);
 	/* no-ops if base == t */
 	if (t->traits && base->traits)
@@ -515,11 +512,11 @@
 		bsunion(t->traits, base->traits);
 	else if (base->traits)
 		t->traits = bsdup(base->traits);
-	if (occurs(st, t))
+	if (occurs(t))
 		lfatal(t->loc, "type %s includes itself", tystr(t));
 	if (t->type == Tygeneric || t->type == Tyname)
-		tyunbind(st);
-	st->ingeneric--;
+		tyunbind();
+	ingeneric--;
 }
 
 Type *
@@ -589,24 +586,24 @@
 }
 
 static Type *
-tysubstmap(Inferstate *st, Tysubst *subst, Type *t, Type *orig)
+tysubstmap(Tysubst *subst, Type *t, Type *orig)
 {
 	size_t i;
 
 	for (i = 0; i < t->ngparam; i++) {
-		substput(subst, t->gparam[i], tf(st, orig->arg[i]));
+		substput(subst, t->gparam[i], tf(orig->arg[i]));
 	}
-	t = tyfreshen(st, subst, t);
+	t = tyfreshen(subst, t);
 	return t;
 }
 
 static Type *
-tysubst(Inferstate *st, Type *t, Type *orig)
+tysubst(Type *t, Type *orig)
 {
 	Tysubst *subst;
 
 	subst = mksubst();
-	t = tysubstmap(st, subst, t, orig);
+	t = tysubstmap(subst, t, orig);
 	substfree(subst);
 	return t;
 }
@@ -615,7 +612,7 @@
 /* find the most accurate type mapping we have (ie,
  * the end of the unification chain */
 static Type *
-tf(Inferstate *st, Type *orig)
+tf(Type *orig)
 {
 	int isgeneric;
 	Type *t;
@@ -623,8 +620,8 @@
 	assert(orig != NULL);
 	t = tylookup(orig);
 	isgeneric = t->type == Tygeneric;
-	st->ingeneric += isgeneric;
-	tyresolve(st, t);
+	ingeneric += isgeneric;
+	tyresolve(t);
 	/* If this is an instantiation of a generic type, we want the params to
 	 * match the instantiation */
 	if (orig->type == Tyunres && t->type == Tygeneric) {
@@ -632,19 +629,19 @@
 			lfatal(orig->loc, "%s incompatibly specialized with %s, declared on %s:%d",
 					tystr(orig), tystr(t), file->file.files[t->loc.file], t->loc.line);
 		}
-		tybind(st, t);
-		t = tysubst(st, t, orig);
-		tyunbind(st);
+		tybind(t);
+		t = tysubst(t, orig);
+		tyunbind();
 	}
-	st->ingeneric -= isgeneric;
+	ingeneric -= isgeneric;
 	return t;
 }
 
 /* set the type of any typable node */
 static void
-settype(Inferstate *st, Node *n, Type *t)
+settype(Node *n, Type *t)
 {
-	t = tf(st, t);
+	t = tf(t);
 	switch (n->type) {
 	case Nexpr:	n->expr.type = t;	break;
 	case Ndecl:	n->decl.type = t;	break;
@@ -653,7 +650,7 @@
 	default: die("untypable node %s", nodestr[n->type]); break;
 	}
 	if (t->type != Tyvar)
-		marksrc(st, t, n->loc);
+		marksrc(t, n->loc);
 }
 
 /* Gets the type of a literal value */
@@ -680,7 +677,7 @@
 }
 
 static Type *
-delayeducon(Inferstate *st, Type *fallback)
+delayeducon(Type *fallback)
 {
 	Type *t;
 	char *from, *to;
@@ -688,11 +685,11 @@
 	if (fallback->type != Tyunion)
 		return fallback;
 	t = mktylike(fallback->loc, fallback->type);
-	htput(st->delayed, t, fallback);
+	htput(delayed, t, fallback);
 	if (debugopt['u']) {
 		from = tystr(t);
 		to = tystr(fallback);
-		indentf(st->indentdepth, "Delay %s -> %s\n", from, to);
+		indentf(indentdepth, "Delay %s -> %s\n", from, to);
 		free(from);
 		free(to);
 	}
@@ -701,7 +698,7 @@
 
 /* Finds the type of any typable node */
 static Type *
-type(Inferstate *st, Node *n)
+type(Node *n)
 {
 	Type *t;
 
@@ -715,11 +712,11 @@
 		die("untypeable node %s", nodestr[n->type]);
 		break;
 	};
-	return tf(st, t);
+	return tf(t);
 }
 
 static Ucon *
-uconresolve(Inferstate *st, Node *n)
+uconresolve(Node *n)
 {
 	Ucon *uc;
 	Node **args;
@@ -733,16 +730,16 @@
 		fatal(n, "no namespace %s\n", args[0]->name.ns);
 	uc = getucon(ns, args[0]);
 	if (!uc)
-		fatal(n, "no union constructor `%s", ctxstr(st, args[0]));
+		fatal(n, "no union constructor `%s", ctxstr(args[0]));
 	if (!uc->etype && n->expr.nargs > 1)
-		fatal(n, "nullary union constructor `%s passed arg ", ctxstr(st, args[0]));
+		fatal(n, "nullary union constructor `%s passed arg ", ctxstr(args[0]));
 	else if (uc->etype && n->expr.nargs != 2)
-		fatal(n, "union constructor `%s needs arg ", ctxstr(st, args[0]));
+		fatal(n, "union constructor `%s needs arg ", ctxstr(args[0]));
 	return uc;
 }
 
 static void
-putbindingsrec(Inferstate *st, Htab *bt, Type *t, Bitset *visited)
+putbindingsrec(Htab *bt, Type *t, Bitset *visited)
 {
 	size_t i;
 
@@ -753,34 +750,34 @@
 	switch (t->type) {
 	case Typaram:
 		if (hthas(bt, t->pname))
-			unify(st, NULL, htget(bt, t->pname), t);
-		else if (!isbound(st, t))
+			unify(NULL, htget(bt, t->pname), t);
+		else if (!isbound(t))
 			htput(bt, t->pname, t);
 		break;
 	case Tygeneric:
 		for (i = 0; i < t->ngparam; i++)
-			putbindingsrec(st, bt, t->gparam[i], visited);
+			putbindingsrec(bt, t->gparam[i], visited);
 		break;
 	case Tyname:
 		for (i = 0; i < t->narg; i++)
-			putbindingsrec(st, bt, t->arg[i], visited);
+			putbindingsrec(bt, t->arg[i], visited);
 		break;
 	case Tyunres:
 		for (i = 0; i < t->narg; i++)
-			putbindingsrec(st, bt, t->arg[i], visited);
+			putbindingsrec(bt, t->arg[i], visited);
 		break;
 	case Tystruct:
 		for (i = 0; i < t->nmemb; i++)
-			putbindingsrec(st, bt, t->sdecls[i]->decl.type, visited);
+			putbindingsrec(bt, t->sdecls[i]->decl.type, visited);
 		break;
 	case Tyunion:
 		for (i = 0; i < t->nmemb; i++)
 			if (t->udecls[i]->etype)
-				putbindingsrec(st, bt, t->udecls[i]->etype, visited);
+				putbindingsrec(bt, t->udecls[i]->etype, visited);
 		break;
 	default:
 		for (i = 0; i < t->nsub; i++)
-			putbindingsrec(st, bt, t->sub[i], visited);
+			putbindingsrec(bt, t->sub[i], visited);
 		break;
 	}
 }
@@ -788,7 +785,7 @@
 /* Binds the type parameters present in the
  * current type into the type environment */
 static void
-putbindings(Inferstate *st, Htab *bt, Type *t)
+putbindings(Htab *bt, Type *t)
 {
 	Bitset *visited;
 
@@ -795,22 +792,22 @@
 	if (!t)
 		return;
 	visited = mkbs();
-	putbindingsrec(st, bt, t, visited);
+	putbindingsrec(bt, t, visited);
 	bsfree(visited);
 }
 
 static void
-tybindall(Inferstate *st, Type *t)
+tybindall(Type *t)
 {
 	Htab *bt;
 
 	bt = mkht(strhash, streq);
 	lappend(&tybindings, &ntybindings, bt);
-	putbindings(st, bt, t);
+	putbindings(bt, t);
 }
 
 static void
-tybind(Inferstate *st, Type *t)
+tybind(Type *t)
 {
 	Htab *bt;
 	size_t i;
@@ -819,16 +816,16 @@
 	lappend(&tybindings, &ntybindings, bt);
 	if (t->type == Tygeneric)
 		for (i = 0; i < t->ngparam; i++)
-			putbindings(st, bt, t->gparam[i]);
+			putbindings(bt, t->gparam[i]);
 	else if (t->type == Tyname)
 		for (i = 0; i < t->narg; i++)
-			putbindings(st, bt, t->arg[i]);
+			putbindings(bt, t->arg[i]);
 }
 
 /* Binds the type parameters in the
  * declaration into the type environment */
 static void
-bind(Inferstate *st, Node *n)
+bind(Node *n)
 {
 	Htab *bt;
 
@@ -836,29 +833,29 @@
 
 	if(!n->decl.isgeneric)
 		return;
-	st->ingeneric++;
+	ingeneric++;
 	bt = mkht(strhash, streq);
 	lappend(&tybindings, &ntybindings, bt);
 
-	putbindings(st, bt, n->decl.type);
+	putbindings(bt, n->decl.type);
 	if (n->decl.init)
-		putbindings(st, bt, n->decl.init->expr.type);
+		putbindings(bt, n->decl.init->expr.type);
 }
 
 /* Rolls back the binding of type parameters in
  * the type environment */
 static void
-unbind(Inferstate *st, Node *n)
+unbind(Node *n)
 {
 	if(!n->decl.isgeneric)
 		return;
 	htfree(tybindings[ntybindings - 1]);
 	lpop(&tybindings, &ntybindings);
-	st->ingeneric--;
+	ingeneric--;
 }
 
 static void
-tyunbind(Inferstate *st)
+tyunbind()
 {
 	htfree(tybindings[ntybindings - 1]);
 	lpop(&tybindings, &ntybindings);
@@ -869,7 +866,7 @@
  * constraint list. Otherwise, the type is checked to see
  * if it has the required constraint */
 static void
-constrain(Inferstate *st, Node *ctx, Type *a, Trait *c)
+constrain(Node *ctx, Type *a, Trait *c)
 {
 	if (a->type == Tyvar) {
 		if (!a->traits)
@@ -876,7 +873,7 @@
 			a->traits = mkbs();
 		settrait(a, c);
 	} else if (!a->traits || !bshas(a->traits, c->uid)) {
-		fatal(ctx, "%s needs %s near %s", tystr(a), namestr(c->name), ctxstr(st, ctx));
+		fatal(ctx, "%s needs %s near %s", tystr(a), namestr(c->name), ctxstr(ctx));
 	}
 }
 
@@ -896,7 +893,7 @@
 }
 
 static void
-verifytraits(Inferstate *st, Node *ctx, Type *a, Type *b)
+verifytraits(Node *ctx, Type *a, Type *b)
 {
 	size_t i, n;
 	Srcloc l;
@@ -916,19 +913,19 @@
 		tyfmt(abuf, sizeof abuf, a);
 		tyfmt(bbuf, sizeof bbuf, b);
 		bsrc[0] = 0;
-		if (st->nusrc > b->tid && st->usrc[b->tid].line > 0) {
-			l = st->usrc[b->tid];
+		if (nusrc > b->tid && usrc[b->tid].line > 0) {
+			l = usrc[b->tid];
 			snprintf(bsrc, sizeof asrc, "\n\t%s from %s:%d", bbuf, fname(l), lnum(l));
 		}
 		fatal(ctx, "%s missing traits %s for %s near %s%s%s",
-				bbuf, traitbuf, abuf, ctxstr(st, ctx),
-				srcstr(st, a), srcstr(st, b));
+				bbuf, traitbuf, abuf, ctxstr(ctx),
+				srcstr(a), srcstr(b));
 	}
 }
 
 /* Merges the constraints on types */
 static void
-mergetraits(Inferstate *st, Node *ctx, Type *a, Type *b)
+mergetraits(Node *ctx, Type *a, Type *b)
 {
 	if (b->type == Tyvar) {
 		/* make sure that if a = b, both have same traits */
@@ -939,7 +936,7 @@
 		else if (b->traits)
 			a->traits = bsdup(b->traits);
 	} else {
-		verifytraits(st, ctx, a, b);
+		verifytraits(ctx, a, b);
 	}
 }
 
@@ -948,11 +945,11 @@
  * should be mapped to the higher ranked (ie, more
  * specific) type. */
 static int
-tyrank(Inferstate *st, Type *t)
+tyrank(Type *t)
 {
 	/* plain tyvar */
 	if (t->type == Tyvar) {
-		if (hthas(st->seqbase, t))
+		if (hthas(seqbase, t))
 			return 1;
 		else
 			return 0;
@@ -962,7 +959,7 @@
 }
 
 static void
-unionunify(Inferstate *st, Node *ctx, Type *u, Type *v)
+unionunify(Node *ctx, Type *u, Type *v)
 {
 	size_t i, j;
 	int found;
@@ -969,8 +966,8 @@
 
 	if (u->nmemb != v->nmemb)
 		fatal(ctx, "can't unify %s and %s near %s%s%s\n",
-			tystr(u), tystr(v), ctxstr(st, ctx),
-			srcstr(st, u), srcstr(st, v));
+			tystr(u), tystr(v), ctxstr(ctx),
+			srcstr(u), srcstr(v));
 
 	for (i = 0; i < u->nmemb; i++) {
 		found = 0;
@@ -981,21 +978,21 @@
 			if (u->udecls[i]->etype == NULL && v->udecls[j]->etype == NULL)
 				continue;
 			else if (u->udecls[i]->etype && v->udecls[j]->etype)
-				unify(st, ctx, u->udecls[i]->etype, v->udecls[j]->etype);
+				unify(ctx, u->udecls[i]->etype, v->udecls[j]->etype);
 			else
 				fatal(ctx, "can't unify %s and %s near %s%s%s",
-					tystr(u), tystr(v), ctxstr(st, ctx),
-					srcstr(st, u), srcstr(st, v));
+					tystr(u), tystr(v), ctxstr(ctx),
+					srcstr(u), srcstr(v));
 		}
 		if (!found)
 			fatal(ctx, "can't unify %s and %s near %s%s%s",
-				tystr(u), tystr(v), ctxstr(st, ctx),
-				srcstr(st, u), srcstr(st, v));
+				tystr(u), tystr(v), ctxstr(ctx),
+				srcstr(u), srcstr(v));
 	}
 }
 
 static void
-structunify(Inferstate *st, Node *ctx, Type *u, Type *v)
+structunify(Node *ctx, Type *u, Type *v)
 {
 	size_t i, j;
 	int found;
@@ -1003,8 +1000,8 @@
 
 	if (u->nmemb != v->nmemb)
 		fatal(ctx, "can't unify %s and %s near %s%s%s",
-			tystr(u), tystr(v), ctxstr(st, ctx),
-			srcstr(st, u), srcstr(st, v));
+			tystr(u), tystr(v), ctxstr(ctx),
+			srcstr(u), srcstr(v));
 
 	for (i = 0; i < u->nmemb; i++) {
 		found = 0;
@@ -1013,51 +1010,51 @@
 			vd = namestr(v->sdecls[j]->decl.name);
 			if (strcmp(ud, vd) == 0) {
 				found = 1;
-				unify(st, ctx, type(st, u->sdecls[i]), type(st, v->sdecls[j]));
+				unify(ctx, type(u->sdecls[i]), type(v->sdecls[j]));
 			}
 		}
 		/* we had at least one missing member */
 		if (!found)
 			fatal(ctx, "can't unify %s and %s near %s%s%s",
-				tystr(u), tystr(v), ctxstr(st, ctx),
-				srcstr(st, u), srcstr(st, v));
+				tystr(u), tystr(v), ctxstr(ctx),
+				srcstr(u), srcstr(v));
 	}
 }
 
 static void
-membunify(Inferstate *st, Node *ctx, Type *u, Type *v)
+membunify(Node *ctx, Type *u, Type *v)
 {
-	if (hthas(st->delayed, u))
-		u = htget(st->delayed, u);
+	if (hthas(delayed, u))
+		u = htget(delayed, u);
 	u = tybase(u);
-	if (hthas(st->delayed, v))
-		v = htget(st->delayed, v);
+	if (hthas(delayed, v))
+		v = htget(delayed, v);
 	v = tybase(v);
 	if (u->type == Tyunion && v->type == Tyunion && u != v)
-		unionunify(st, ctx, u, v);
+		unionunify(ctx, u, v);
 	else if (u->type == Tystruct && v->type == Tystruct && u != v)
-		structunify(st, ctx, u, v);
+		structunify(ctx, u, v);
 }
 
 static Type *
-basetype(Inferstate *st, Type *a)
+basetype(Type *a)
 {
 	Type *t;
 
-	t = htget(st->seqbase, a);
+	t = htget(seqbase, a);
         while (!t && a->type == Tyname) {
             a = a->sub[0];
-            t = htget(st->seqbase, a);
+            t = htget(seqbase, a);
         }
 	if (!t && (a->type == Tyslice || a->type == Tyarray || a->type == Typtr))
 		t = a->sub[0];
 	if (t)
-		t = tf(st, t);
+		t = tf(t);
 	return t;
 }
 
 static void
-checksize(Inferstate *st, Node *ctx, Type *a, Type *b)
+checksize(Node *ctx, Type *a, Type *b)
 {
 	if (a->asize)
 		a->asize = fold(a->asize, 1);
@@ -1065,10 +1062,10 @@
 		b->asize = fold(b->asize, 1);
 	if (a->asize && exprop(a->asize) != Olit)
 		lfatal(ctx->loc, "%s: array size is not constant near %s",
-				tystr(a), ctxstr(st, ctx));
+				tystr(a), ctxstr(ctx));
 	if (b->asize && exprop(b->asize) != Olit)
 		lfatal(ctx->loc, "%s: array size is not constant near %s",
-				tystr(b), ctxstr(st, ctx));
+				tystr(b), ctxstr(ctx));
 	if (!a->asize)
 		a->asize = b->asize;
 	else if (!b->asize)
@@ -1076,7 +1073,7 @@
 	else if (a->asize && b->asize)
 		if (!litvaleq(a->asize->expr.args[0], b->asize->expr.args[0]))
 			lfatal(ctx->loc, "array size of %s does not match %s near %s",
-				tystr(a), tystr(b), ctxstr(st, ctx));
+				tystr(a), tystr(b), ctxstr(ctx));
 }
 
 static int
@@ -1087,7 +1084,7 @@
 
 /* Unifies two types, or errors if the types are not unifiable. */
 static Type *
-unify(Inferstate *st, Node *ctx, Type *u, Type *v)
+unify(Node *ctx, Type *u, Type *v)
 {
 	Type *t, *r;
 	Type *a, *b;
@@ -1096,13 +1093,13 @@
 	size_t i;
 
 	/* a ==> b */
-	a = tf(st, u);
-	b = tf(st, v);
+	a = tf(u);
+	b = tf(v);
 	if (a->tid == b->tid)
 		return a;
 
 	/* we unify from lower to higher ranked types */
-	if (tyrank(st, b) < tyrank(st, a)) {
+	if (tyrank(b) < tyrank(a)) {
 		t = a;
 		a = b;
 		b = t;
@@ -1111,9 +1108,9 @@
 	if (debugopt['u']) {
 		from = tystr(a);
 		to = tystr(b);
-		indentf(st->indentdepth, "Unify %s => %s\n", from, to);
-		indentf(st->indentdepth + 1, "indexes: %s => %s\n",
-			tystr(htget(st->seqbase, a)), tystr(htget(st->seqbase, b)));
+		indentf(indentdepth, "Unify %s => %s\n", from, to);
+		indentf(indentdepth + 1, "indexes: %s => %s\n",
+			tystr(htget(seqbase, a)), tystr(htget(seqbase, b)));
 		free(from);
 		free(to);
 	}
@@ -1120,9 +1117,9 @@
 
 	/* Disallow recursive types */
 	if (a->type == Tyvar && b->type != Tyvar) {
-		if (occursin(st, a, b))
+		if (occursin(a, b))
 			fatal(ctx, "%s occurs within %s, leading to infinite type near %s\n",
-				tystr(a), tystr(b), ctxstr(st, ctx));
+				tystr(a), tystr(b), ctxstr(ctx));
 	}
 
 	r = NULL;
@@ -1129,20 +1126,20 @@
 	if (a->type == Tyvar || tyeq(a, b)) {
 		tytab[a->tid] = b;
 		if (ctx) {
-			marksrc(st, a, ctx->loc);
-			marksrc(st, b, ctx->loc);
+			marksrc(a, ctx->loc);
+			marksrc(b, ctx->loc);
 		}
 	}
 	if (a->type == Tyvar) {
-		ea = basetype(st, a);
-		eb = basetype(st, b);
+		ea = basetype(a);
+		eb = basetype(b);
 		if (ea && eb)
-			unify(st, ctx, ea, eb);
+			unify(ctx, ea, eb);
 		r = b;
 	}
 
 	if (a->type == Tyarray && b->type == Tyarray) {
-		checksize(st, ctx, a, b);
+		checksize(ctx, a, b);
 	}
 
 	/* if the tyrank of a is 0 (ie, a raw tyvar), just unify.
@@ -1150,47 +1147,47 @@
 	if (a->type == b->type && a->type != Tyvar) {
 		if (a->type == Tyname)
 			if (!nameeq(a->name, b->name))
-				typeerror(st, a, b, ctx, "incompatible types");
+				typeerror(a, b, ctx, "incompatible types");
 		if (hasargs(a) && hasargs(b)) {
 			/* Only Tygeneric and Tyname should be able to unify. And they
 			 * should have the same names for this to be true. */
 			if (!nameeq(a->name, b->name))
-				typeerror(st, a, b, ctx, NULL);
+				typeerror(a, b, ctx, NULL);
 			if (a->narg != b->narg)
-				typeerror(st, a, b, ctx, "incompatible parameter lists");
+				typeerror(a, b, ctx, "incompatible parameter lists");
 			for (i = 0; i < a->narg; i++)
-				unify(st, ctx, a->arg[i], b->arg[i]);
+				unify(ctx, a->arg[i], b->arg[i]);
 			r = b;
 		}
 		if (a->nsub != b->nsub) {
-			verifytraits(st, ctx, a, b);
+			verifytraits(ctx, a, b);
 			if (tybase(a)->type == Tyfunc)
-				typeerror(st, a, b, ctx, "function arity mismatch");
+				typeerror(a, b, ctx, "function arity mismatch");
 			else
-				typeerror(st, a, b, ctx, "subtype counts incompatible");
+				typeerror(a, b, ctx, "subtype counts incompatible");
 		}
 		for (i = 0; i < b->nsub; i++)
-			unify(st, ctx, a->sub[i], b->sub[i]);
+			unify(ctx, a->sub[i], b->sub[i]);
 		r = b;
 	} else if (a->type != Tyvar) {
-		typeerror(st, a, b, ctx, NULL);
+		typeerror(a, b, ctx, NULL);
 	}
-	mergetraits(st, ctx, a, b);
+	mergetraits(ctx, a, b);
 	if (a->isreflect || b->isreflect) {
 		tagreflect(r);
 		tagreflect(a);
 		tagreflect(b);
 	}
-	membunify(st, ctx, a, b);
+	membunify(ctx, a, b);
 
 	/* if we have delayed types for a tyvar, transfer it over. */
 	if (a->type == Tyvar && b->type == Tyvar) {
-		if (hthas(st->delayed, a) && !hthas(st->delayed, b))
-			htput(st->delayed, b, htget(st->delayed, a));
-		else if (hthas(st->delayed, b) && !hthas(st->delayed, a))
-			htput(st->delayed, a, htget(st->delayed, b));
-	} else if (hthas(st->delayed, a)) {
-		unify(st, ctx, htget(st->delayed, a), tybase(b));
+		if (hthas(delayed, a) && !hthas(delayed, b))
+			htput(delayed, b, htget(delayed, a));
+		else if (hthas(delayed, b) && !hthas(delayed, a))
+			htput(delayed, a, htget(delayed, b));
+	} else if (hthas(delayed, a)) {
+		unify(ctx, htget(delayed, a), tybase(b));
 	}
 
 	return r;
@@ -1200,18 +1197,18 @@
  * Funciton application requires a slightly
  * different approach to unification. */
 static void
-unifycall(Inferstate *st, Node *n)
+unifycall(Node *n)
 {
 	size_t i;
 	Type *ft;
 	char *ret, *ctx;
 
-	ft = type(st, n->expr.args[0]);
+	ft = type(n->expr.args[0]);
 
 	if (ft->type == Tyvar) {
 		/* the first arg is the function itself, so it shouldn't be counted */
 		ft = mktyfunc(n->loc, &n->expr.args[1], n->expr.nargs - 1, mktyvar(n->loc));
-		unify(st, n, ft, type(st, n->expr.args[0]));
+		unify(n, ft, type(n->expr.args[0]));
 	} else if (tybase(ft)->type != Tyfunc) {
 		fatal(n, "calling uncallable type %s", tystr(ft));
 	}
@@ -1219,29 +1216,29 @@
 	for (i = 1; i < n->expr.nargs; i++) {
 		if (i == ft->nsub)
 			fatal(n, "%s arity mismatch (expected %zd args, got %zd)",
-					ctxstr(st, n->expr.args[0]), ft->nsub - 1, n->expr.nargs - 1);
+					ctxstr(n->expr.args[0]), ft->nsub - 1, n->expr.nargs - 1);
 
 		if (ft->sub[i]->type == Tyvalist) {
 			break;
 		}
-		unify(st, n->expr.args[0], ft->sub[i], type(st, n->expr.args[i]));
+		unify(n->expr.args[0], ft->sub[i], type(n->expr.args[i]));
 	}
 	if (i < ft->nsub && ft->sub[i]->type != Tyvalist)
 		fatal(n, "%s arity mismatch (expected %zd args, got %zd)",
-				ctxstr(st, n->expr.args[0]), ft->nsub - 1, i - 1);
+				ctxstr(n->expr.args[0]), ft->nsub - 1, i - 1);
 	if (debugopt['u']) {
 		ret = tystr(ft->sub[0]);
-		ctx = ctxstr(st, n->expr.args[0]);
-		indentf(st->indentdepth, "Call of %s returns %s\n", ctx, ret);
+		ctx = ctxstr(n->expr.args[0]);
+		indentf(indentdepth, "Call of %s returns %s\n", ctx, ret);
 		free(ctx);
 		free(ret);
 	}
 
-	settype(st, n, ft->sub[0]);
+	settype(n, ft->sub[0]);
 }
 
 static void
-unifyparams(Inferstate *st, Node *ctx, Type *a, Type *b)
+unifyparams(Node *ctx, Type *a, Type *b)
 {
 	size_t i;
 
@@ -1257,9 +1254,9 @@
 
 	if (a->narg != b->narg)
 		fatal(ctx, "mismatched arg list sizes: %s with %s near %s", tystr(a), tystr(b),
-				ctxstr(st, ctx));
+				ctxstr(ctx));
 	for (i = 0; i < a->narg; i++)
-		unify(st, ctx, a->arg[i], b->arg[i]);
+		unify(ctx, a->arg[i], b->arg[i]);
 }
 
 static void
@@ -1273,27 +1270,27 @@
 }
 
 static Type *
-initvar(Inferstate *st, Node *n, Node *s)
+initvar(Node *n, Node *s)
 {
 	Type *t, *param;
 	Tysubst *subst;
 
 	if (s->decl.ishidden)
-		fatal(n, "attempting to refer to hidden decl %s", ctxstr(st, n));
+		fatal(n, "attempting to refer to hidden decl %s", ctxstr(n));
 
 	param = n->expr.param;
 	if (s->decl.isgeneric) {
 		subst = mksubst();
-		tybindall(st, s->decl.type);
+		tybindall(s->decl.type);
 		if (param)
 			substput(subst, s->decl.trait->param, param);
-		t = tysubstmap(st, subst, tf(st, s->decl.type), s->decl.type);
+		t = tysubstmap(subst, tf(s->decl.type), s->decl.type);
 		if (s->decl.trait && !param) {
 			param = substget(subst, s->decl.trait->param);
 			if (!param)
-				fatal(n, "ambiguous trait decl %s", ctxstr(st, s));
+				fatal(n, "ambiguous trait decl %s", ctxstr(s));
 		}
-		tyunbind(st);
+		tyunbind();
 		substfree(subst);
 	} else {
 		t = s->decl.type;
@@ -1302,19 +1299,19 @@
 	n->expr.isconst = s->decl.isconst;
 	if (param) {
 		n->expr.param = param;
-		delayedcheck(st, n, curstab());
+		delayedcheck(n, curstab());
 	}
-	if (s->decl.isgeneric && !st->ingeneric) {
-		t = tyfreshen(st, NULL, t);
-		addspecialization(st, n, curstab());
+	if (s->decl.isgeneric && !ingeneric) {
+		t = tyfreshen(NULL, t);
+		addspecialization(n, curstab());
 		if (t->type == Tyvar) {
-			settype(st, n, mktyvar(n->loc));
-			delayedcheck(st, n, curstab());
+			settype(n, mktyvar(n->loc));
+			delayedcheck(n, curstab());
 		} else {
-			settype(st, n, t);
+			settype(n, t);
 		}
 	} else {
-		settype(st, n, t);
+		settype(n, t);
 	}
 	return t;
 }
@@ -1325,7 +1322,7 @@
  * reference we should have, instead of the Omemb expr
  * that we do have */
 static Node *
-checkns(Inferstate *st, Node *n, Node **ret)
+checkns(Node *n, Node **ret)
 {
 	Node *var, *name, *nsname;
 	Node **args;
@@ -1354,29 +1351,29 @@
 		fatal(n, "undeclared var %s.%s", nsname->name.ns, nsname->name.name);
 	var = mkexpr(n->loc, Ovar, nsname, NULL);
 	var->expr.idx = n->expr.idx;
-	initvar(st, var, s);
+	initvar(var, s);
 	*ret = var;
 	return var;
 }
 
 static void
-inferstruct(Inferstate *st, Node *n, int *isconst)
+inferstruct(Node *n, int *isconst)
 {
 	size_t i;
 
 	*isconst = 1;
 	/* we want to check outer nodes before inner nodes when unifying nested structs */
-	delayedcheck(st, n, curstab());
+	delayedcheck(n, curstab());
 	for (i = 0; i < n->expr.nargs; i++) {
-		infernode(st, &n->expr.args[i], NULL, NULL);
+		infernode(&n->expr.args[i], NULL, NULL);
 		if (!n->expr.args[i]->expr.isconst)
 			*isconst = 0;
 	}
-	settype(st, n, mktyvar(n->loc));
+	settype(n, mktyvar(n->loc));
 }
 
 static int64_t
-arraysize(Inferstate *st, Node *n)
+arraysize(Node *n)
 {
 	int64_t sz, off, i;
 	Node **args, *idx;
@@ -1389,7 +1386,7 @@
 			idx = args[i]->expr.idx;
 			if (exprop(idx) != Olit)
 				fatal(idx, "nonconstant array initializer index near %s\n",
-					ctxstr(st, idx));
+					ctxstr(idx));
 			if (idx->expr.args[0]->lit.littype == Lchr)
 				off = idx->expr.args[0]->lit.chrval;
 			else if (idx->expr.args[0]->lit.littype == Lint)
@@ -1396,7 +1393,7 @@
 				off = idx->expr.args[0]->lit.intval;
 			else
 				fatal(idx, "noninteger array initializer index near %s\n",
-					ctxstr(st, idx));
+					ctxstr(idx));
 			if (off >= sz)
 				sz = off + 1;
 		} else {
@@ -1407,7 +1404,7 @@
 }
 
 static void
-inferarray(Inferstate *st, Node *n, int *isconst)
+inferarray(Node *n, int *isconst)
 {
 	size_t i;
 	Type *t;
@@ -1414,19 +1411,19 @@
 	Node *len;
 
 	*isconst = 1;
-	len = mkintlit(n->loc, arraysize(st, n));
+	len = mkintlit(n->loc, arraysize(n));
 	t = mktyarray(n->loc, mktyvar(n->loc), len);
 	for (i = 0; i < n->expr.nargs; i++) {
-		infernode(st, &n->expr.args[i], NULL, NULL);
-		unify(st, n, t->sub[0], type(st, n->expr.args[i]));
+		infernode(&n->expr.args[i], NULL, NULL);
+		unify(n, t->sub[0], type(n->expr.args[i]));
 		if (!n->expr.args[i]->expr.isconst)
 			*isconst = 0;
 	}
-	settype(st, n, t);
+	settype(n, t);
 }
 
 static void
-infertuple(Inferstate *st, Node *n, int *isconst)
+infertuple(Node *n, int *isconst)
 {
 	Type **types;
 	size_t i;
@@ -1434,22 +1431,22 @@
 	*isconst = 1;
 	types = xalloc(sizeof(Type *) * n->expr.nargs);
 	for (i = 0; i < n->expr.nargs; i++) {
-		infernode(st, &n->expr.args[i], NULL, NULL);
+		infernode(&n->expr.args[i], NULL, NULL);
 		n->expr.isconst = n->expr.isconst && n->expr.args[i]->expr.isconst;
-		types[i] = type(st, n->expr.args[i]);
+		types[i] = type(n->expr.args[i]);
 	}
 	*isconst = n->expr.isconst;
-	settype(st, n, mktytuple(n->loc, types, n->expr.nargs));
+	settype(n, mktytuple(n->loc, types, n->expr.nargs));
 }
 
 static void
-inferucon(Inferstate *st, Node *n, int *isconst)
+inferucon(Node *n, int *isconst)
 {
 	Ucon *uc;
 	Type *t;
 
 	*isconst = 1;
-	uc = uconresolve(st, n);
+	uc = uconresolve(n);
 	/* Hackety hack hack.
 	 * the types in a generic union may be bound from the tyname that
 	 * defined it, which is not accessible here.
@@ -1456,20 +1453,20 @@
 	 *
 	 * To make it compile, for now, we just bind the types in here.
 	 */
-	tybindall(st, uc->utype);
-	t = tysubst(st, tf(st, uc->utype), uc->utype);
+	tybindall(uc->utype);
+	t = tysubst(tf(uc->utype), uc->utype);
 	uc = tybase(t)->udecls[uc->id];
 	if (uc->etype) {
-		inferexpr(st, &n->expr.args[1], NULL, NULL);
-		unify(st, n, uc->etype, type(st, n->expr.args[1]));
+		inferexpr(&n->expr.args[1], NULL, NULL);
+		unify(n, uc->etype, type(n->expr.args[1]));
 		*isconst = n->expr.args[1]->expr.isconst;
 	}
-	settype(st, n, delayeducon(st, t));
-	tyunbind(st);
+	settype(n, delayeducon(t));
+	tyunbind();
 }
 
 static void
-inferpat(Inferstate *st, Node **np, Node *val, Node ***bind, size_t *nbind)
+inferpat(Node **np, Node *val, Node ***bind, size_t *nbind)
 {
 	size_t i;
 	Node **args;
@@ -1478,11 +1475,11 @@
 	Type *t;
 
 	n = *np;
-	n = checkns(st, n, np);
+	n = checkns(n, np);
 	args = n->expr.args;
 	for (i = 0; i < n->expr.nargs; i++)
 		if (args[i]->type == Nexpr)
-			inferpat(st, &args[i], val, bind, nbind);
+			inferpat(&args[i], val, bind, nbind);
 	switch (exprop(n)) {
 	case Otup:
 	case Ostruct:
@@ -1489,7 +1486,7 @@
 	case Oarr:
 	case Olit:
 	case Omemb:
-		infernode(st, np, NULL, NULL);
+		infernode(np, NULL, NULL);
 		break;
 		/* arithmetic expressions just need to be constant */
 	case Oneg:
@@ -1503,12 +1500,12 @@
 	case Obor:
 	case Obxor:
 	case Obnot:
-		infernode(st, np, NULL, NULL);
+		infernode(np, NULL, NULL);
 		if (!n->expr.isconst)
-			fatal(n, "matching against non-constant expression near %s", ctxstr(st, n));
+			fatal(n, "matching against non-constant expression near %s", ctxstr(n));
 		break;
 	case Oucon:
-		inferucon(st, n, &n->expr.isconst);
+		inferucon(n, &n->expr.isconst);
 		break;
 	case Ovar:
 		ns = curstab();
@@ -1517,34 +1514,34 @@
 		s = getdcl(ns, args[0]);
 		if (s && !s->decl.ishidden) {
 			if (s->decl.isgeneric)
-				t = tysubst(st, s->decl.type, s->decl.type);
+				t = tysubst(s->decl.type, s->decl.type);
 			else if (s->decl.isconst)
 				t = s->decl.type;
 			else
 				fatal(n, "pattern shadows variable declared on %s:%d near %s",
-						fname(s->loc), lnum(s->loc), ctxstr(st, s));
+						fname(s->loc), lnum(s->loc), ctxstr(s));
 		} else {
 			t = mktyvar(n->loc);
 			s = mkdecl(n->loc, n->expr.args[0], t);
 			s->decl.init = val;
-			settype(st, n, t);
+			settype(n, t);
 			lappend(bind, nbind, s);
 		}
-		settype(st, n, t);
+		settype(n, t);
 		n->expr.did = s->decl.did;
 		n->expr.isconst = s->decl.isconst;
 		break;
 	case Oaddr:
-		infernode(st, np, NULL, NULL);
+		infernode(np, NULL, NULL);
 		break;
 	case Ogap:
-		infernode(st, np, NULL, NULL);	break;
+		infernode(np, NULL, NULL);	break;
 	default: fatal(n, "invalid pattern"); break;
 	}
 }
 
 void
-addbindings(Inferstate *st, Node *n, Node **bind, size_t nbind)
+addbindings(Node *n, Node **bind, size_t nbind)
 {
 	size_t i;
 
@@ -1557,7 +1554,7 @@
 }
 
 static void
-infersub(Inferstate *st, Node *n, Type *ret, int *sawret, int *exprconst)
+infersub(Node *n, Type *ret, int *sawret, int *exprconst)
 {
 	Node **args;
 	size_t i, nargs;
@@ -1574,8 +1571,8 @@
 		if (args[i]->type == Nexpr) {
 			/* Omemb can sometimes resolve to a namespace. We have to check
 			 * this. Icky. */
-			checkns(st, args[i], &args[i]);
-			inferexpr(st, &args[i], ret, sawret);
+			checkns(args[i], &args[i]);
+			inferexpr(&args[i], ret, sawret);
 			isconst = isconst && args[i]->expr.isconst;
 		}
 	}
@@ -1585,7 +1582,7 @@
 }
 
 static void
-inferexpr(Inferstate *st, Node **np, Type *ret, int *sawret)
+inferexpr(Node **np, Type *ret, int *sawret)
 {
 	Node **args;
 	size_t i, nargs;
@@ -1598,8 +1595,8 @@
 	assert(n->type == Nexpr);
 	args = n->expr.args;
 	nargs = n->expr.nargs;
-	infernode(st, &n->expr.idx, NULL, NULL);
-	n = checkns(st, n, np);
+	infernode(&n->expr.idx, NULL, NULL);
+	n = checkns(n, np);
 	switch (exprop(n)) {
 		/* all operands are same type */
 	case Oadd: /* @a + @a -> @a */
@@ -1611,16 +1608,16 @@
 	case Osubeq:	/* @a -= @a -> @a */
 	case Omuleq:	/* @a *= @a -> @a */
 	case Odiveq:	/* @a /= @a -> @a */
-		infersub(st, n, ret, sawret, &isconst);
-		t = type(st, args[0]);
-		constrain(st, n, type(st, args[0]), traittab[Tcnum]);
+		infersub(n, ret, sawret, &isconst);
+		t = type(args[0]);
+		constrain(n, type(args[0]), traittab[Tcnum]);
 		isconst = args[0]->expr.isconst;
 		for (i = 1; i < nargs; i++) {
 			isconst = isconst && args[i]->expr.isconst;
-			t = unify(st, n, t, type(st, args[i]));
+			t = unify(n, t, type(args[i]));
 		}
 		n->expr.isconst = isconst;
-		settype(st, n, t);
+		settype(n, t);
 		break;
 	case Omod:	/* @a % @a -> @a */
 	case Obor:	/* @a | @a -> @a */
@@ -1639,26 +1636,26 @@
 	case Obxoreq:	/* @a ^= @a -> @a */
 	case Obsleq:	/* @a <<= @a -> @a */
 	case Obsreq:	/* @a >>= @a -> @a */
-		infersub(st, n, ret, sawret, &isconst);
-		t = type(st, args[0]);
-		constrain(st, n, type(st, args[0]), traittab[Tcnum]);
-		constrain(st, n, type(st, args[0]), traittab[Tcint]);
+		infersub(n, ret, sawret, &isconst);
+		t = type(args[0]);
+		constrain(n, type(args[0]), traittab[Tcnum]);
+		constrain(n, type(args[0]), traittab[Tcint]);
 		isconst = args[0]->expr.isconst;
 		for (i = 1; i < nargs; i++) {
 			isconst = isconst && args[i]->expr.isconst;
-			t = unify(st, n, t, type(st, args[i]));
+			t = unify(n, t, type(args[i]));
 		}
 		n->expr.isconst = isconst;
-		settype(st, n, t);
+		settype(n, t);
 		break;
 	case Oasn: /* @a = @a -> @a */
-		infersub(st, n, ret, sawret, &isconst);
-		t = type(st, args[0]);
+		infersub(n, ret, sawret, &isconst);
+		t = type(args[0]);
 		for (i = 1; i < nargs; i++)
-			t = unify(st, n, t, type(st, args[i]));
-		settype(st, n, t);
+			t = unify(n, t, type(args[i]));
+		settype(n, t);
 		if (args[0]->expr.isconst)
-			fatal(n, "attempting to assign constant \"%s\"", ctxstr(st, args[0]));
+			fatal(n, "attempting to assign constant \"%s\"", ctxstr(args[0]));
 		break;
 
 		/* operands same type, returning bool */
@@ -1670,90 +1667,90 @@
 	case Oge:   /* @a >= @a -> bool */
 	case Olt:   /* @a < @a -> bool */
 	case Ole:   /* @a <= @b -> bool */
-		infersub(st, n, ret, sawret, &isconst);
-		t = type(st, args[0]);
+		infersub(n, ret, sawret, &isconst);
+		t = type(args[0]);
 		for (i = 1; i < nargs; i++)
-			unify(st, n, t, type(st, args[i]));
-		settype(st, n, mktype(Zloc, Tybool));
+			unify(n, t, type(args[i]));
+		settype(n, mktype(Zloc, Tybool));
 		break;
 
 	case Olnot: /* !bool -> bool */
-		infersub(st, n, ret, sawret, &isconst);
-		t = unify(st, n, type(st, args[0]), mktype(Zloc, Tybool));
-		settype(st, n, t);
+		infersub(n, ret, sawret, &isconst);
+		t = unify(n, type(args[0]), mktype(Zloc, Tybool));
+		settype(n, t);
 		break;
 
 		/* reach into a type and pull out subtypes */
 	case Oaddr: /* &@a -> @a* */
-		infersub(st, n, ret, sawret, &isconst);
-		settype(st, n, mktyptr(n->loc, type(st, args[0])));
+		infersub(n, ret, sawret, &isconst);
+		settype(n, mktyptr(n->loc, type(args[0])));
 		break;
 	case Oderef: /* *@a* ->  @a */
-		infersub(st, n, ret, sawret, &isconst);
-		t = unify(st, n, type(st, args[0]), mktyptr(n->loc, mktyvar(n->loc)));
-		settype(st, n, t->sub[0]);
+		infersub(n, ret, sawret, &isconst);
+		t = unify(n, type(args[0]), mktyptr(n->loc, mktyvar(n->loc)));
+		settype(n, t->sub[0]);
 		break;
 	case Oidx: /* @a[@b::tcint] -> @a */
-		infersub(st, n, ret, sawret, &isconst);
+		infersub(n, ret, sawret, &isconst);
 		b = mktyvar(n->loc);
 		t = mktyvar(n->loc);
-		htput(st->seqbase, t, b);
-		unify(st, n, type(st, args[0]), t);
-		constrain(st, n, type(st, args[0]), traittab[Tcidx]);
-		constrain(st, n, type(st, args[1]), traittab[Tcint]);
-		settype(st, n, b);
+		htput(seqbase, t, b);
+		unify(n, type(args[0]), t);
+		constrain(n, type(args[0]), traittab[Tcidx]);
+		constrain(n, type(args[1]), traittab[Tcint]);
+		settype(n, b);
 		break;
 	case Oslice: /* @a[@b::tcint,@b::tcint] -> @a[,] */
-		infersub(st, n, ret, sawret, &isconst);
+		infersub(n, ret, sawret, &isconst);
 		b = mktyvar(n->loc);
 		t = mktyvar(n->loc);
-		htput(st->seqbase, t, b);
-		unify(st, n, type(st, args[0]), t);
-		constrain(st, n, type(st, args[1]), traittab[Tcint]);
-		constrain(st, n, type(st, args[2]), traittab[Tcint]);
-		settype(st, n, mktyslice(n->loc, b));
+		htput(seqbase, t, b);
+		unify(n, type(args[0]), t);
+		constrain(n, type(args[1]), traittab[Tcint]);
+		constrain(n, type(args[2]), traittab[Tcint]);
+		settype(n, mktyslice(n->loc, b));
 		break;
 
 		/* special cases */
 	case Omemb: /* @a.Ident -> @b, verify type(@a.Ident)==@b later */
-		infersub(st, n, ret, sawret, &isconst);
-		settype(st, n, mktyvar(n->loc));
-		delayedcheck(st, n, curstab());
+		infersub(n, ret, sawret, &isconst);
+		settype(n, mktyvar(n->loc));
+		delayedcheck(n, curstab());
 		break;
 	case Osize: /* sizeof(@a) -> size */
-		infersub(st, n, ret, sawret, &isconst);
-		settype(st, n, mktylike(n->loc, Tyuint));
+		infersub(n, ret, sawret, &isconst);
+		settype(n, mktylike(n->loc, Tyuint));
 		break;
 	case Ocall: /* (@a, @b, @c, ... -> @r)(@a, @b, @c, ...) -> @r */
-		infersub(st, n, ret, sawret, &isconst);
-		unifycall(st, n);
+		infersub(n, ret, sawret, &isconst);
+		unifycall(n);
 		break;
 	case Ocast: /* (@a : @b) -> @b */
-		infersub(st, n, ret, sawret, &isconst);
-		delayedcheck(st, n, curstab());
+		infersub(n, ret, sawret, &isconst);
+		delayedcheck(n, curstab());
 		break;
 	case Oret: /* -> @a -> void */
-		infersub(st, n, ret, sawret, &isconst);
+		infersub(n, ret, sawret, &isconst);
 		if (sawret)
 			*sawret = 1;
 		if (!ret)
-			fatal(n, "returns are not valid near %s", ctxstr(st, n));
-		t = unify(st, n, ret, type(st, args[0]));
-		settype(st, n, t);
+			fatal(n, "returns are not valid near %s", ctxstr(n));
+		t = unify(n, ret, type(args[0]));
+		settype(n, t);
 		break;
 	case Obreak:
 	case Ocontinue:
 		/* nullary: nothing to infer. */
-		settype(st, n, mktype(Zloc, Tyvoid));
+		settype(n, mktype(Zloc, Tyvoid));
 		break;
 	case Ojmp: /* goto void* -> void */
 		if (args[0]->type == Nlit && args[0]->lit.littype == Llbl)
 			args[0] = getlbl(curstab(), args[0]->loc, args[0]->lit.lblname);
-		infersub(st, n, ret, sawret, &isconst);
-		settype(st, n, mktype(Zloc, Tyvoid));
+		infersub(n, ret, sawret, &isconst);
+		settype(n, mktype(Zloc, Tyvoid));
 		break;
 	case Ovar: /* a:@a -> @a */
-		infersub(st, n, ret, sawret, &isconst);
+		infersub(n, ret, sawret, &isconst);
 		/* if we created this from a namespaced var, the type should be
 		 * set, and the normal lookup is expected to fail. Since we're
 		 * already done with this node, we can just return. */
@@ -1764,10 +1761,10 @@
 			ns = getns(file, args[0]->name.ns);
 		s = getdcl(ns, args[0]);
 		if (!s)
-			fatal(n, "undeclared var %s", ctxstr(st, args[0]));
+			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(st, args[0]));
-		initvar(st, n, s);
+			fatal(n, "var %s must refer to a trait decl", ctxstr(args[0]));
+		initvar(n, s);
 		break;
 	case Ogap: /* _ -> @a */
 		if (n->expr.type)
@@ -1774,17 +1771,17 @@
 			return;
 		n->expr.type = mktyvar(n->loc);
 		break;
-	case Oucon:	inferucon(st, n, &n->expr.isconst);	break;
-	case Otup:	infertuple(st, n, &n->expr.isconst);	break;
-	case Ostruct:	inferstruct(st, n, &n->expr.isconst);	break;
-	case Oarr:	inferarray(st, n, &n->expr.isconst);	break;
+	case Oucon:	inferucon(n, &n->expr.isconst);	break;
+	case Otup:	infertuple(n, &n->expr.isconst);	break;
+	case Ostruct:	inferstruct(n, &n->expr.isconst);	break;
+	case Oarr:	inferarray(n, &n->expr.isconst);	break;
 	case Olit: /* <lit>:@a::tyclass -> @a */
-		   infersub(st, n, ret, sawret, &isconst);
+		   infersub(n, ret, sawret, &isconst);
 		   switch (args[0]->lit.littype) {
 		   case Lfunc:
-			   tybindall(st, args[0]->lit.fnval->func.type);
-			   infernode(st, &args[0]->lit.fnval, NULL, NULL);
-			   tyunbind(st);
+			   tybindall(args[0]->lit.fnval->func.type);
+			   infernode(&args[0]->lit.fnval, NULL, NULL);
+			   tyunbind();
 
 			   /* FIXME: env capture means this is non-const */
 			   n->expr.isconst = 1;
@@ -1799,11 +1796,11 @@
 			   n->expr.isconst = 1;
 			   break;
 		   }
-		   settype(st, n, type(st, args[0]));
+		   settype(n, type(args[0]));
 		   break;
 	case Oundef:
-		   infersub(st, n, ret, sawret, &isconst);
-		   settype(st, n, mktype(n->loc, Tyvoid));
+		   infersub(n, ret, sawret, &isconst);
+		   settype(n, mktype(n->loc, Tyvoid));
 		   break;
 	case Odef:
 	case Odead:	n->expr.type = mktype(n->loc, Tyvoid);	break;
@@ -1849,7 +1846,7 @@
 }
 
 static void
-inferfunc(Inferstate *st, Node *n)
+inferfunc(Node *n)
 {
 	size_t i;
 	int sawret;
@@ -1856,15 +1853,15 @@
 
 	sawret = 0;
 	for (i = 0; i < n->func.nargs; i++)
-		infernode(st, &n->func.args[i], NULL, NULL);
-	infernode(st, &n->func.body, n->func.type->sub[0], &sawret);
+		infernode(&n->func.args[i], NULL, NULL);
+	infernode(&n->func.body, n->func.type->sub[0], &sawret);
 	/* if there's no return stmt in the function, assume void ret */
 	if (!sawret)
-		unify(st, n, type(st, n)->sub[0], mktype(Zloc, Tyvoid));
+		unify(n, type(n)->sub[0], mktype(Zloc, Tyvoid));
 }
 
 static void
-specializeimpl(Inferstate *st, Node *n)
+specializeimpl(Node *n)
 {
 	Node *dcl, *proto, *name, *sym;
 	Tysubst *subst;
@@ -1881,9 +1878,9 @@
 	if (n->impl.naux != t->naux)
 		fatal(n, "%s incompatibly specialized with %zd types instead of %zd types",
 			namestr(n->impl.traitname), n->impl.naux, t->naux);
-	n->impl.type = tf(st, n->impl.type);
+	n->impl.type = tf(n->impl.type);
 	for (i = 0; i < n->impl.naux; i++)
-		n->impl.aux[i] = tf(st, n->impl.aux[i]);
+		n->impl.aux[i] = tf(n->impl.aux[i]);
 	for (i = 0; i < n->impl.ndecls; i++) {
 		/* look up the prototype */
 		proto = NULL;
@@ -1906,19 +1903,19 @@
 		}
 		if (!proto)
 			fatal(n, "declaration %s missing in %s, near %s", namestr(dcl->decl.name),
-					namestr(t->name), ctxstr(st, n));
+					namestr(t->name), ctxstr(n));
 
 		/* infer and unify types */
-		verifytraits(st, n, t->param, n->impl.type);
+		verifytraits(n, t->param, n->impl.type);
 		subst = mksubst();
 		substput(subst, t->param, n->impl.type);
 		for (j = 0; j < t->naux; j++)
 			substput(subst, t->aux[j], n->impl.aux[j]);
-		ty = tyspecialize(type(st, proto), subst, st->delayed, NULL);
+		ty = tyspecialize(type(proto), subst, delayed, NULL);
 		substfree(subst);
 
-		inferdecl(st, dcl);
-		unify(st, n, type(st, dcl), ty);
+		inferdecl(dcl);
+		unify(n, type(dcl), ty);
 
 		/* and put the specialization into the global stab */
 		name = genericname(proto, n->impl.type, ty);
@@ -1938,34 +1935,34 @@
 		}
 		if (debugopt['S'])
 			printf("specializing trait [%d]%s:%s => %s:%s\n", n->loc.line,
-					namestr(proto->decl.name), tystr(type(st, proto)), namestr(name),
+					namestr(proto->decl.name), tystr(type(proto)), namestr(name),
 					tystr(ty));
 		dcl->decl.vis = t->vis;
-		lappend(&st->impldecl, &st->nimpldecl, dcl);
+		lappend(&impldecl, &nimpldecl, dcl);
 	}
 }
 
 static void
-inferdecl(Inferstate *st, Node *n)
+inferdecl(Node *n)
 {
 	Type *t;
 
-	t = tf(st, decltype(n));
+	t = tf(decltype(n));
 	if (t->type == Tygeneric && !n->decl.isgeneric) {
-		t = tyfreshen(st, NULL, t);
-		unifyparams(st, n, t, decltype(n));
+		t = tyfreshen(NULL, t);
+		unifyparams(n, t, decltype(n));
 	}
-	settype(st, n, t);
+	settype(n, t);
 	if (n->decl.init) {
-		inferexpr(st, &n->decl.init, NULL, NULL);
-		unify(st, n, type(st, n), type(st, n->decl.init));
+		inferexpr(&n->decl.init, NULL, NULL);
+		unify(n, type(n), type(n->decl.init));
 		if (n->decl.isconst && !n->decl.init->expr.isconst)
-			fatal(n, "non-const initializer for \"%s\"", ctxstr(st, n));
+			fatal(n, "non-const initializer for \"%s\"", ctxstr(n));
 	}
 }
 
 static void
-inferstab(Inferstate *st, Stab *s)
+inferstab(Stab *s)
 {
 	void **k;
 	size_t n, i;
@@ -1975,9 +1972,9 @@
 	k = htkeys(s->dcl, &n);
 	for (i = 0; i < n; i++) {
 		dcl = htget(s->dcl, k[i]);
-		bind(st, dcl);
-		tf(st, type(st, dcl));
-		unbind(st, dcl);
+		bind(dcl);
+		tf(type(dcl));
+		unbind(dcl);
 	}
 	free(k);
 
@@ -1987,9 +1984,9 @@
 		if (!t)
 			fatal(k[i], "undefined type %s", namestr(k[i]));
 		t = tysearch(t);
-		tybind(st, t);
-		tyresolve(st, t);
-		tyunbind(st);
+		tybind(t);
+		tyresolve(t);
+		tyunbind();
 		updatetype(s, k[i], t);
 	}
 	free(k);
@@ -1996,7 +1993,7 @@
 }
 
 static void
-infernode(Inferstate *st, Node **np, Type *ret, int *sawret)
+infernode(Node **np, Type *ret, int *sawret)
 {
 	size_t i, nbound;
 	Node **bound, *n, *pat;
@@ -2011,47 +2008,47 @@
 	switch (n->type) {
 	case Nfile:
 		pushstab(n->file.globls);
-		inferstab(st, n->file.globls);
+		inferstab(n->file.globls);
 		for (i = 0; i < n->file.nstmts; i++)
-			infernode(st, &n->file.stmts[i], NULL, sawret);
+			infernode(&n->file.stmts[i], NULL, sawret);
 		popstab();
 		break;
 	case Ndecl:
 		if (debugopt['u'])
-			indentf(st->indentdepth, "--- infer %s ---\n", declname(n));
-		st->indentdepth++;
-		bind(st, n);
-		inferdecl(st, n);
-		if (type(st, n)->type == Typaram && !st->ingeneric)
-			fatal(n, "generic type %s in non-generic near %s", tystr(type(st, n)),
-					ctxstr(st, n));
-		unbind(st, n);
-		st->indentdepth--;
+			indentf(indentdepth, "--- infer %s ---\n", declname(n));
+		indentdepth++;
+		bind(n);
+		inferdecl(n);
+		if (type(n)->type == Typaram && !ingeneric)
+			fatal(n, "generic type %s in non-generic near %s", tystr(type(n)),
+					ctxstr(n));
+		unbind(n);
+		indentdepth--;
 		if (debugopt['u'])
-			indentf(st->indentdepth, "--- done ---\n");
+			indentf(indentdepth, "--- done ---\n");
 		break;
 	case Nblock:
 		setsuper(n->block.scope, curstab());
 		pushstab(n->block.scope);
-		inferstab(st, n->block.scope);
+		inferstab(n->block.scope);
 		for (i = 0; i < n->block.nstmts; i++)
-			infernode(st, &n->block.stmts[i], ret, sawret);
+			infernode(&n->block.stmts[i], ret, sawret);
 		popstab();
 		break;
 	case Nifstmt:
-		infernode(st, &n->ifstmt.cond, NULL, sawret);
-		infernode(st, &n->ifstmt.iftrue, ret, sawret);
-		infernode(st, &n->ifstmt.iffalse, ret, sawret);
-		unify(st, n, type(st, n->ifstmt.cond), mktype(n->loc, Tybool));
+		infernode(&n->ifstmt.cond, NULL, sawret);
+		infernode(&n->ifstmt.iftrue, ret, sawret);
+		infernode(&n->ifstmt.iffalse, ret, sawret);
+		unify(n, type(n->ifstmt.cond), mktype(n->loc, Tybool));
 		break;
 	case Nloopstmt:
 		setsuper(n->loopstmt.scope, curstab());
 		pushstab(n->loopstmt.scope);
-		infernode(st, &n->loopstmt.init, ret, sawret);
-		infernode(st, &n->loopstmt.cond, NULL, sawret);
-		infernode(st, &n->loopstmt.step, ret, sawret);
-		infernode(st, &n->loopstmt.body, ret, sawret);
-		unify(st, n, type(st, n->loopstmt.cond), mktype(n->loc, Tybool));
+		infernode(&n->loopstmt.init, ret, sawret);
+		infernode(&n->loopstmt.cond, NULL, sawret);
+		infernode(&n->loopstmt.step, ret, sawret);
+		infernode(&n->loopstmt.body, ret, sawret);
+		unify(n, type(n->loopstmt.cond), mktype(n->loc, Tybool));
 		popstab();
 		break;
 	case Niterstmt:
@@ -2058,51 +2055,51 @@
 		bound = NULL;
 		nbound = 0;
 
-		inferpat(st, &n->iterstmt.elt, NULL, &bound, &nbound);
-		addbindings(st, n->iterstmt.body, bound, nbound);
+		inferpat(&n->iterstmt.elt, NULL, &bound, &nbound);
+		addbindings(n->iterstmt.body, bound, nbound);
 
-		infernode(st, &n->iterstmt.seq, NULL, sawret);
-		infernode(st, &n->iterstmt.body, ret, sawret);
+		infernode(&n->iterstmt.seq, NULL, sawret);
+		infernode(&n->iterstmt.body, ret, sawret);
 
 		b = mktyvar(n->loc);
 		t = mktyvar(n->loc);
-		htput(st->seqbase, t, b);
-		constrain(st, n, type(st, n->iterstmt.seq), traittab[Tciter]);
-		unify(st, n, type(st, n->iterstmt.seq), t);
-		unify(st, n, type(st, n->iterstmt.elt), b);
+		htput(seqbase, t, b);
+		constrain(n, type(n->iterstmt.seq), traittab[Tciter]);
+		unify(n, type(n->iterstmt.seq), t);
+		unify(n, type(n->iterstmt.elt), b);
 		break;
 	case Nmatchstmt:
-		infernode(st, &n->matchstmt.val, NULL, sawret);
+		infernode(&n->matchstmt.val, NULL, sawret);
 		for (i = 0; i < n->matchstmt.nmatches; i++) {
-			infernode(st, &n->matchstmt.matches[i], ret, sawret);
+			infernode(&n->matchstmt.matches[i], ret, sawret);
 			pat = n->matchstmt.matches[i]->match.pat;
-			unify(st, pat, type(st, n->matchstmt.val),
-					type(st, n->matchstmt.matches[i]->match.pat));
+			unify(pat, type(n->matchstmt.val),
+					type(n->matchstmt.matches[i]->match.pat));
 		}
 		break;
 	case Nmatch:
 		bound = NULL;
 		nbound = 0;
-		inferpat(st, &n->match.pat, NULL, &bound, &nbound);
-		addbindings(st, n->match.block, bound, nbound);
-		infernode(st, &n->match.block, ret, sawret);
+		inferpat(&n->match.pat, NULL, &bound, &nbound);
+		addbindings(n->match.block, bound, nbound);
+		infernode(&n->match.block, ret, sawret);
 		break;
 	case Nexpr:
-		inferexpr(st, np, ret, sawret);
+		inferexpr(np, ret, sawret);
 		break;
 	case Nfunc:
 		setsuper(n->func.scope, curstab());
 		if (ntybindings > 0)
 			for (i = 0; i < n->func.nargs; i++)
-				putbindings(st, tybindings[ntybindings - 1],
+				putbindings(tybindings[ntybindings - 1],
 					n->func.args[i]->decl.type);
 		pushstab(n->func.scope);
-		inferstab(st, n->func.scope);
-		inferfunc(st, n);
+		inferstab(n->func.scope);
+		inferfunc(n);
 		popstab();
 		break;
 	case Nimpl:
-		specializeimpl(st, n);
+		specializeimpl(n);
 		break;
 	case Nlit:
 	case Nname:
@@ -2117,10 +2114,10 @@
 /* returns the final type for t, after all unification
  * and default constraint selections */
 static Type *
-tyfix(Inferstate *st, Node *ctx, Type *orig, int noerr)
+tyfix(Node *ctx, Type *orig, int noerr)
 {
 	static Type *tyint, *tyflt;
-	Type *t, *delayed, *base;
+	Type *t, *d, *base;
 	char *from, *to;
 	size_t i;
 	char buf[1024];
@@ -2130,17 +2127,17 @@
 	if (!tyflt)
 		tyflt = mktype(Zloc, Tyflt64);
 
-	t = tysearch(tf(st, orig));
-	base = htget(st->seqbase, orig);
-	if (orig->type == Tyvar && hthas(st->delayed, orig)) {
-		delayed = htget(st->delayed, orig);
+	t = tysearch(tf(orig));
+	base = htget(seqbase, orig);
+	if (orig->type == Tyvar && hthas(delayed, orig)) {
+		d = htget(delayed, orig);
 		if (t->type == Tyvar) {
 			/* tyvar is guaranteed to unify error-free */
-			unify(st, ctx, t, delayed);
-			t = tf(st, t);
-		} else if (tybase(t)->type != delayed->type && !noerr) {
+			unify(ctx, t, d);
+			t = tf(t);
+		} else if (tybase(t)->type != d->type && !noerr) {
 			fatal(ctx, "type %s not compatible with %s near %s\n", tystr(t),
-					tystr(delayed), ctxstr(st, ctx));
+					tystr(d), ctxstr(ctx));
 		}
 	}
 	if (t->type == Tyvar) {
@@ -2151,48 +2148,48 @@
 	} else if (!t->fixed) {
 		t->fixed = 1;
 		if (t->type == Tyarray) {
-			typesub(st, t->asize, noerr);
+			typesub(t->asize, noerr);
 		} else if (t->type == Tystruct) {
-			st->inaggr++;
+			inaggr++;
 			for (i = 0; i < t->nmemb; i++)
-				typesub(st, t->sdecls[i], noerr);
-			st->inaggr--;
+				typesub(t->sdecls[i], noerr);
+			inaggr--;
 		} else if (t->type == Tyunion) {
 			for (i = 0; i < t->nmemb; i++) {
 				if (t->udecls[i]->etype) {
-					tyresolve(st, t->udecls[i]->etype);
+					tyresolve(t->udecls[i]->etype);
 					t->udecls[i]->etype =
-						tyfix(st, ctx, t->udecls[i]->etype, noerr);
+						tyfix(ctx, t->udecls[i]->etype, noerr);
 				}
 			}
 		} else if (t->type == Tyname) {
 			for (i = 0; i < t->narg; i++)
-				t->arg[i] = tyfix(st, ctx, t->arg[i], noerr);
+				t->arg[i] = tyfix(ctx, t->arg[i], noerr);
 		}
 		for (i = 0; i < t->nsub; i++)
-			t->sub[i] = tyfix(st, ctx, t->sub[i], noerr);
+			t->sub[i] = tyfix(ctx, t->sub[i], noerr);
 	}
 
 	if (t->type == Tyvar && !noerr) {
 		if (debugopt['T'])
 			dump(file, stdout);
-		fatal(ctx, "underconstrained type %s near %s", tyfmt(buf, 1024, t), ctxstr(st, ctx));
+		fatal(ctx, "underconstrained type %s near %s", tyfmt(buf, 1024, t), ctxstr(ctx));
 	}
 
 	if (debugopt['u'] && !tyeq(orig, t)) {
 		from = tystr(orig);
 		to = tystr(t);
-		indentf(st->indentdepth, "subst %s => %s\n", from, to);
+		indentf(indentdepth, "subst %s => %s\n", from, to);
 		free(from);
 		free(to);
 	}
 	if (base)
-		htput(st->seqbase, t, base);
+		htput(seqbase, t, base);
 	return t;
 }
 
 static void
-checkcast(Inferstate *st, Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+checkcast(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
 {
 	/* FIXME: actually verify the casts. Right now, it's ok to leave thi
 	 * unimplemented because bad casts get caught by the backend. */
@@ -2199,7 +2196,7 @@
 }
 
 static void
-infercompn(Inferstate *st, Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+infercompn(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
 {
 	Node *aggr;
 	Node *memb;
@@ -2212,12 +2209,12 @@
 	memb = n->expr.args[1];
 
 	found = 0;
-	t = tybase(tf(st, type(st, aggr)));
+	t = tybase(tf(type(aggr)));
 	/* all array-like types have a fake "len" member that we emulate */
 	if (t->type == Tyslice || t->type == Tyarray) {
 		if (!strcmp(namestr(memb), "len")) {
-			constrain(st, n, type(st, n), traittab[Tcnum]);
-			constrain(st, n, type(st, n), traittab[Tcint]);
+			constrain(n, type(n), traittab[Tcnum]);
+			constrain(n, type(n), traittab[Tcint]);
 			found = 1;
 		}
 	/*
@@ -2230,22 +2227,22 @@
 	 */
 	} else {
 		if (tybase(t)->type == Typtr)
-			t = tybase(tf(st, t->sub[0]));
+			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(st, n));
+						fname(t->loc), lnum(t->loc), ctxstr(n));
 			lappend(rem, nrem, n);
 			lappend(remscope, nremscope, curstab());
 			return;
 		} else if (tybase(t)->type != Tystruct) {
 			fatal(n, "type %s does not support member operators near %s",
-					tystr(t), ctxstr(st, n));
+					tystr(t), ctxstr(n));
 		}
 		nl = t->sdecls;
 		for (i = 0; i < t->nmemb; i++) {
 			if (!strcmp(namestr(memb), declname(nl[i]))) {
-				unify(st, n, type(st, n), decltype(nl[i]));
+				unify(n, type(n), decltype(nl[i]));
 				found = 1;
 				break;
 			}
@@ -2252,18 +2249,18 @@
 		}
 	}
 	if (!found)
-		fatal(aggr, "type %s has no member \"%s\" near %s", tystr(type(st, aggr)),
-				ctxstr(st, memb), ctxstr(st, aggr));
+		fatal(aggr, "type %s has no member \"%s\" near %s", tystr(type(aggr)),
+				ctxstr(memb), ctxstr(aggr));
 }
 
 static void
-checkstruct(Inferstate *st, Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+checkstruct(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
 {
 	Type *t, *et;
 	Node *val, *name;
 	size_t i, j;
 
-	t = tybase(tf(st, n->lit.type));
+	t = tybase(tf(n->lit.type));
 	/*
 	 * If we haven't inferred the type, and it's inside another struct,
 	 * we'll eventually get to it.
@@ -2282,7 +2279,7 @@
 		et = NULL;
 		for (j = 0; j < t->nmemb; j++) {
 			if (!strcmp(namestr(t->sdecls[j]->decl.name), namestr(name))) {
-				et = type(st, t->sdecls[j]);
+				et = type(t->sdecls[j]);
 				break;
 			}
 		}
@@ -2294,16 +2291,16 @@
 				return;
 			} else {
 				fatal(n, "could not find member %s in struct %s, near %s",
-						namestr(name), tystr(t), ctxstr(st, n));
+						namestr(name), tystr(t), ctxstr(n));
 			}
 		}
 
-		unify(st, val, et, type(st, val));
+		unify(val, et, type(val));
 	}
 }
 
 static void
-checkvar(Inferstate *st, Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+checkvar(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
 {
 	Node *proto, *dcl;
 	Type *ty;
@@ -2312,28 +2309,28 @@
 	ty = NULL;
 	dcl = NULL;
 	if (n->expr.param)
-		dcl = htget(proto->decl.impls, tf(st, n->expr.param));
+		dcl = htget(proto->decl.impls, tf(n->expr.param));
 	if (dcl)
 		ty = dcl->decl.type;
 	if (!ty)
-		ty = tyfreshen(st, NULL, type(st, proto));
-	unify(st, n, type(st, n), ty);
+		ty = tyfreshen(NULL, type(proto));
+	unify(n, type(n), ty);
 }
 
 static void
-postcheckpass(Inferstate *st, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
+postcheckpass(Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
 {
 	size_t i;
 	Node *n;
 
-	for (i = 0; i < st->npostcheck; i++) {
-		n = st->postcheck[i];
-		pushstab(st->postcheckscope[i]);
+	for (i = 0; i < npostcheck; i++) {
+		n = postcheck[i];
+		pushstab(postcheckscope[i]);
 		switch (exprop(n)) {
-		case Omemb:	infercompn(st, n, rem, nrem, remscope, nremscope);	break;
-		case Ocast:	checkcast(st, n, rem, nrem, remscope, nremscope);	break;
-		case Ostruct:	checkstruct(st, n, rem, nrem, remscope, nremscope);	break;
-		case Ovar:	checkvar(st, n, rem, nrem, remscope, nremscope);	break;
+		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)]);
 		}
 		popstab();
@@ -2341,7 +2338,7 @@
 }
 
 static void
-postcheck(Inferstate *st)
+postinfer(void)
 {
 	size_t nrem, nremscope;
 	Stab **remscope;
@@ -2352,16 +2349,16 @@
 		nremscope = 0;
 		rem = NULL;
 		nrem = 0;
-		postcheckpass(st, &rem, &nrem, &remscope, &nremscope);
-		if (nrem == st->npostcheck) {
+		postcheckpass(&rem, &nrem, &remscope, &nremscope);
+		if (nrem == npostcheck) {
 			break;
 		}
-		st->postcheck = rem;
-		st->npostcheck = nrem;
-		st->postcheckscope = remscope;
-		st->npostcheckscope = nremscope;
+		postcheck = rem;
+		npostcheck = nrem;
+		postcheckscope = remscope;
+		npostcheckscope = nremscope;
 	}
-	postcheckpass(st, NULL, NULL, NULL, NULL);
+	postcheckpass(NULL, NULL, NULL, NULL);
 }
 
 /* After inference, replace all
@@ -2368,7 +2365,7 @@
  * types in symbol tables with
  * the final computed types */
 static void
-stabsub(Inferstate *st, Stab *s)
+stabsub(Stab *s)
 {
 	void **k;
 	size_t n, i;
@@ -2380,7 +2377,7 @@
 	for (i = 0; i < n; i++) {
 		t = tysearch(gettype(s, k[i]));
 		updatetype(s, k[i], t);
-		tyfix(st, k[i], t, 0);
+		tyfix(k[i], t, 0);
 	}
 	free(k);
 
@@ -2387,9 +2384,9 @@
 	k = htkeys(s->dcl, &n);
 	for (i = 0; i < n; i++) {
 		d = getdcl(s, k[i]);
-		bind(st, d);
-		d->decl.type = tyfix(st, d, d->decl.type, 0);
-		unbind(st, d);
+		bind(d);
+		d->decl.type = tyfix(d, d->decl.type, 0);
+		unbind(d);
 		if (!d->decl.isconst && !d->decl.isgeneric)
 			continue;
 		if (d->decl.trait)
@@ -2398,13 +2395,13 @@
 		if (d->decl.isgeneric)
 			dt = "generic";
 		if (!d->decl.isimport && !d->decl.isextern && !d->decl.init)
-			fatal(d, "non-extern %s \"%s\" has no initializer", dt, ctxstr(st, d));
+			fatal(d, "non-extern %s \"%s\" has no initializer", dt, ctxstr(d));
 	}
 	free(k);
 }
 
 static void
-checkrange(Inferstate *st, Node *n)
+checkrange(Node *n)
 {
 	Type *t;
 	int64_t sval;
@@ -2425,7 +2422,7 @@
 	};
 
 	/* signed types */
-	t = type(st, n);
+	t = type(n);
 	if (t->type >= Tyint8 && t->type <= Tyint64) {
 		sval = n->lit.intval;
 		if (sval < svranges[t->type][0] || sval > svranges[t->type][1])
@@ -2471,7 +2468,7 @@
 }
 
 static void
-verifyop(Inferstate *st, Node *n)
+verifyop(Node *n)
 {
 	Type *ty;
 
@@ -2493,7 +2490,7 @@
 /* After type inference, replace all type
  * with the final computed type */
 static void
-typesub(Inferstate *st, Node *n, int noerr)
+typesub(Node *n, int noerr)
 {
 	size_t i;
 
@@ -2502,16 +2499,16 @@
 	switch (n->type) {
 	case Nfile:
 		pushstab(n->file.globls);
-		stabsub(st, n->file.globls);
+		stabsub(n->file.globls);
 		for (i = 0; i < n->file.nstmts; i++)
-			typesub(st, n->file.stmts[i], noerr);
+			typesub(n->file.stmts[i], noerr);
 		popstab();
 		break;
 	case Ndecl:
-		bind(st, n);
-		settype(st, n, tyfix(st, n, type(st, n), noerr));
+		bind(n);
+		settype(n, tyfix(n, type(n), noerr));
 		if (n->decl.init)
-			typesub(st, n->decl.init, noerr);
+			typesub(n->decl.init, noerr);
 		if (streq(declname(n), "main"))
 			if (!maincompatible(tybase(decltype(n))))
 				fatal(n, "main must be (->void) or (byte[:][:] -> void), got %s",
@@ -2519,69 +2516,69 @@
 		if (streq(declname(n), "__init__"))
 			if (!initcompatible(tybase(decltype(n))))
 				fatal(n, "__init__ must be (->void), got %s", tystr(decltype(n)));
-		unbind(st, n);
+		unbind(n);
 		break;
 	case Nblock:
 		pushstab(n->block.scope);
 		for (i = 0; i < n->block.nstmts; i++)
-			typesub(st, n->block.stmts[i], noerr);
+			typesub(n->block.stmts[i], noerr);
 		popstab();
 		break;
 	case Nifstmt:
-		typesub(st, n->ifstmt.cond, noerr);
-		typesub(st, n->ifstmt.iftrue, noerr);
-		typesub(st, n->ifstmt.iffalse, noerr);
+		typesub(n->ifstmt.cond, noerr);
+		typesub(n->ifstmt.iftrue, noerr);
+		typesub(n->ifstmt.iffalse, noerr);
 		break;
 	case Nloopstmt:
-		typesub(st, n->loopstmt.cond, noerr);
-		typesub(st, n->loopstmt.init, noerr);
-		typesub(st, n->loopstmt.step, noerr);
-		typesub(st, n->loopstmt.body, noerr);
+		typesub(n->loopstmt.cond, noerr);
+		typesub(n->loopstmt.init, noerr);
+		typesub(n->loopstmt.step, noerr);
+		typesub(n->loopstmt.body, noerr);
 		break;
 	case Niterstmt:
-		typesub(st, n->iterstmt.elt, noerr);
-		typesub(st, n->iterstmt.seq, noerr);
-		typesub(st, n->iterstmt.body, noerr);
-		additerspecializations(st, n, curstab());
+		typesub(n->iterstmt.elt, noerr);
+		typesub(n->iterstmt.seq, noerr);
+		typesub(n->iterstmt.body, noerr);
+		additerspecializations(n, curstab());
 		break;
 	case Nmatchstmt:
-		typesub(st, n->matchstmt.val, noerr);
+		typesub(n->matchstmt.val, noerr);
 		for (i = 0; i < n->matchstmt.nmatches; i++) {
-			typesub(st, n->matchstmt.matches[i], noerr);
+			typesub(n->matchstmt.matches[i], noerr);
 		}
 		break;
 	case Nmatch:
-		typesub(st, n->match.pat, noerr);
-		typesub(st, n->match.block, noerr);
+		typesub(n->match.pat, noerr);
+		typesub(n->match.block, noerr);
 		break;
 	case Nexpr:
-		settype(st, n, tyfix(st, n, type(st, n), 0));
+		settype(n, tyfix(n, type(n), 0));
 		if (n->expr.param)
-			n->expr.param = tyfix(st, n, n->expr.param, 0);
-		typesub(st, n->expr.idx, noerr);
+			n->expr.param = tyfix(n, n->expr.param, 0);
+		typesub(n->expr.idx, noerr);
 		if (exprop(n) == Ocast && exprop(n->expr.args[0]) == Olit &&
 				n->expr.args[0]->expr.args[0]->lit.littype == Lint) {
-			settype(st, n->expr.args[0], exprtype(n));
-			settype(st, n->expr.args[0]->expr.args[0], exprtype(n));
+			settype(n->expr.args[0], exprtype(n));
+			settype(n->expr.args[0]->expr.args[0], exprtype(n));
 		}
 		for (i = 0; i < n->expr.nargs; i++)
-			typesub(st, n->expr.args[i], noerr);
+			typesub(n->expr.args[i], noerr);
                 if (!noerr)
-                    verifyop(st, n);
+                    verifyop(n);
 		break;
 	case Nfunc:
 		pushstab(n->func.scope);
-		settype(st, n, tyfix(st, n, n->func.type, 0));
+		settype(n, tyfix(n, n->func.type, 0));
 		for (i = 0; i < n->func.nargs; i++)
-			typesub(st, n->func.args[i], noerr);
-		typesub(st, n->func.body, noerr);
+			typesub(n->func.args[i], noerr);
+		typesub(n->func.body, noerr);
 		popstab();
 		break;
 	case Nlit:
-		settype(st, n, tyfix(st, n, type(st, n), 0));
+		settype(n, tyfix(n, type(n), 0));
 		switch (n->lit.littype) {
-		case Lfunc:	typesub(st, n->lit.fnval, noerr);	break;
-		case Lint:	checkrange(st, n);
+		case Lfunc:	typesub(n->lit.fnval, noerr);	break;
+		case Lint:	checkrange(n);
 		default: break;
 		}
 		break;
@@ -2593,13 +2590,13 @@
 }
 
 static Type *
-itertype(Inferstate *st, Node *n, Type *ret)
+itertype(Node *n, Type *ret)
 {
 	Type *it, *val, *itp, *valp, *fn;
 
 	it = exprtype(n);
 	itp = mktyptr(n->loc, it);
-	val = basetype(st, it);
+	val = basetype(it);
 	if (!val)
 		die("FAIL! %s", tystr(it));
 	valp = mktyptr(n->loc, val);
@@ -2613,7 +2610,7 @@
  * with the type parameters replaced with the
  * specialized types */
 static void
-specialize(Inferstate *st, Node *f)
+specialize(Node *f)
 {
 	Node *d, *n, *name;
 	Type *ty, *it;
@@ -2620,33 +2617,33 @@
 	size_t i;
 	Trait *tr;
 
-	for (i = 0; i < st->nimpldecl; i++) {
-		d = st->impldecl[i];
+	for (i = 0; i < nimpldecl; i++) {
+		d = impldecl[i];
 		lappend(&file->file.stmts, &file->file.nstmts, d);
-		typesub(st, d, 0);
+		typesub(d, 0);
 	}
 
-	for (i = 0; i < st->nspecializations; i++) {
-		pushstab(st->specializationscope[i]);
-		n = st->specializations[i];
+	for (i = 0; i < nspecializations; i++) {
+		pushstab(specializationscope[i]);
+		n = specializations[i];
 		if (n->type == Nexpr) {
-			d = specializedcl(st->genericdecls[i], n->expr.param, n->expr.type, &name);
+			d = specializedcl(genericdecls[i], n->expr.param, n->expr.type, &name);
 			n->expr.args[0] = name;
 			n->expr.did = d->decl.did;
 
 			/* we need to sub in default types in the specialization, so call
 			 * typesub on the specialized function */
-			typesub(st, d, 0);
+			typesub(d, 0);
 		} else if (n->type == Niterstmt) {
 			tr = traittab[Tciter];
 			assert(tr->nproto == 2);
 			ty = exprtype(n->iterstmt.seq);
 
-			it = itertype(st, n->iterstmt.seq, mktype(n->loc, Tybool));
+			it = itertype(n->iterstmt.seq, mktype(n->loc, Tybool));
 			d = specializedcl(tr->proto[0], ty, it, &name);
 			htput(tr->proto[0]->decl.impls, ty, d);
 
-			it = itertype(st, n->iterstmt.seq, mktype(n->loc, Tyvoid));
+			it = itertype(n->iterstmt.seq, mktype(n->loc, Tyvoid));
 			d = specializedcl(tr->proto[1], ty, it, &name);
 			htput(tr->proto[1]->decl.impls, ty, d);
 		} else {
@@ -2657,7 +2654,7 @@
 }
 
 void
-applytraits(Inferstate *st, Node *f)
+applytraits(Node *f)
 {
 	size_t i, j;
 	Node *impl, *n;
@@ -2680,28 +2677,28 @@
 				tr = gettrait(ns, n);
 			if (!tr)
 				fatal(impl, "trait %s does not exist near %s",
-						namestr(impl->impl.traitname), ctxstr(st, impl));
+						namestr(impl->impl.traitname), ctxstr(impl));
 			if (tr->naux != impl->impl.naux)
 				fatal(impl, "incompatible implementation of %s: mismatched aux types",
-						namestr(impl->impl.traitname), ctxstr(st, impl));
+						namestr(impl->impl.traitname), ctxstr(impl));
 		}
-		tybindall(st, impl->impl.type);
+		tybindall(impl->impl.type);
 		for (j = 0; j < impl->impl.naux; j++)
-			tybindall(st, impl->impl.aux[j]);
-		ty = tf(st, impl->impl.type);
+			tybindall(impl->impl.aux[j]);
+		ty = tf(impl->impl.type);
 		settrait(ty, tr);
 		if (tr->uid == Tciter) {
-			htput(st->seqbase, tf(st, impl->impl.type), tf(st, impl->impl.aux[0]));
+			htput(seqbase, tf(impl->impl.type), tf(impl->impl.aux[0]));
 		}
-		tyunbind(st);
+		tyunbind();
 		for (j = 0; j < impl->impl.naux; j++)
-			tyunbind(st);
+			tyunbind();
 	}
 	popstab();
 }
 
 void
-verify(Inferstate *st, Node *f)
+verify(Node *f)
 {
 	Node *n;
 	size_t i;
@@ -2722,25 +2719,21 @@
 void
 infer(Node *file)
 {
-	Inferstate st = {
-		0,
-	};
-
 	assert(file->type == Nfile);
-	st.delayed = mkht(tyhash, tyeq);
-	st.seqbase = mkht(tyhash, tyeq);
+	delayed = mkht(tyhash, tyeq);
+	seqbase = mkht(tyhash, tyeq);
 	/* set up the symtabs */
 	loaduses(file);
 	// mergeexports(&st, file);
 
 	/* do the inference */
-	applytraits(&st, file);
-	infernode(&st, &file, NULL, NULL);
-	postcheck(&st);
+	applytraits(file);
+	infernode(&file, NULL, NULL);
+	postinfer();
 
 	/* and replace type vars with actual types */
 	assert(ntybindings == 0);
-	typesub(&st, file, 0);
-	specialize(&st, file);
-	verify(&st, file);
+	typesub(file, 0);
+	specialize(file);
+	verify(file);
 }