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: