ref: 7e7ef17a00025776a94f832d4f7fbd64e5687767
parent: 2652cf20199949dd23fc3e2d3327dd3f9e9be2ba
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Dec 26 15:01:13 EST 2016
Run postcheck until convergence. This should fix dangling type mismatches for struct members and such.
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1984,13 +1984,13 @@
return t;
}
-static void checkcast(Inferstate *st, Node *n)
+static void checkcast(Inferstate *st, Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
{
/* FIXME: actually verify the casts. Right now, it's ok to leave this
* unimplemented because bad casts get caught by the backend. */
}
-static void infercompn(Inferstate *st, Node *n)
+static void infercompn(Inferstate *st, Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
{
Node *aggr;
Node *memb;
@@ -2022,13 +2022,16 @@
} else {
if (tybase(t)->type == Typtr)
t = tybase(tf(st, t->sub[0]));
- if (tybase(t)->type != Tystruct) {
- if (tybase(t)->type == Tyvar)
+ 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));
- else
- fatal(n, "type %s does not support member operators near %s",
- tystr(t), ctxstr(st, 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));
}
nl = t->sdecls;
for (i = 0; i < t->nmemb; i++) {
@@ -2044,7 +2047,7 @@
ctxstr(st, memb), ctxstr(st, aggr));
}
-static void checkstruct(Inferstate *st, Node *n)
+static void checkstruct(Inferstate *st, Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
{
Type *t, *et;
Node *val, *name;
@@ -2074,15 +2077,22 @@
}
}
- if (!et)
- fatal(n, "could not find member %s in struct %s, near %s",
- namestr(name), tystr(t), ctxstr(st, n));
+ 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(st, n));
+ }
+ }
unify(st, val, et, type(st, val));
}
}
-static void checkvar(Inferstate *st, Node *n)
+static void checkvar(Inferstate *st, Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
{
Node *proto, *dcl;
Type *ty;
@@ -2099,7 +2109,7 @@
unify(st, n, type(st, n), ty);
}
-static void postcheck(Inferstate *st, Node *file)
+static void postcheckpass(Inferstate *st, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
{
size_t i;
Node *n;
@@ -2108,13 +2118,13 @@
n = st->postcheck[i];
pushstab(st->postcheckscope[i]);
if (n->type == Nexpr && exprop(n) == Omemb)
- infercompn(st, n);
+ infercompn(st, n, rem, nrem, remscope, nremscope);
else if (n->type == Nexpr && exprop(n) == Ocast)
- checkcast(st, n);
+ checkcast(st, n, rem, nrem, remscope, nremscope);
else if (n->type == Nexpr && exprop(n) == Ostruct)
- checkstruct(st, n);
+ checkstruct(st, n, rem, nrem, remscope, nremscope);
else if (n->type == Nexpr && exprop(n) == Ovar)
- checkvar(st, n);
+ checkvar(st, n, rem, nrem, remscope, nremscope);
else
die("Thing we shouldn't be checking in postcheck\n");
popstab();
@@ -2121,6 +2131,29 @@
}
}
+static void postcheck(Inferstate *st)
+{
+ size_t nrem, nremscope;
+ Stab **remscope;
+ Node **rem;
+
+ while (1) {
+ remscope = NULL;
+ nremscope = 0;
+ rem = NULL;
+ nrem = 0;
+ postcheckpass(st, &rem, &nrem, &remscope, &nremscope);
+ if (nrem == st->npostcheck) {
+ break;
+ }
+ st->postcheck = rem;
+ st->npostcheck = nrem;
+ st->postcheckscope = remscope;
+ st->npostcheckscope = nremscope;
+ }
+ postcheckpass(st, NULL, NULL, NULL, NULL);
+}
+
/* After inference, replace all
* types in symbol tables with
* the final computed types */
@@ -2466,7 +2499,7 @@
/* do the inference */
applytraits(&st, file);
infernode(&st, &file, NULL, NULL);
- postcheck(&st, file);
+ postcheck(&st);
/* and replace type vars with actual types */
typesub(&st, file, 0);