shithub: mc

Download patch

ref: 19e261299a6f0105b5bfa919fc5401b0c6243ea2
parent: 2a75839b66139c8e402fe6e40992b0fd3c9b01c8
parent: 4519f3ff10c67f4f965433be4ec50e3552de276f
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Jul 20 15:30:12 EDT 2012

Merge branch 'master' of git+ssh://mimir.eigenstate.org/git/ori/mc2

Conflicts:
	parse/infer.c

--- a/8/Makefile
+++ b/8/Makefile
@@ -1,3 +1,4 @@
+INSTBIN=8m
 BIN=8m
 OBJ=isel.o \
     locs.o \
--- a/8/simp.c
+++ b/8/simp.c
@@ -519,10 +519,9 @@
     size_t i;
     size_t off;
 
-    if (aggr->expr.type->type == Typtr)
-        aggr = aggr->expr.args[0];
-    ty = aggr->expr.type;
-    ty = tybase(ty);
+    ty = tybase(exprtype(aggr));
+    if (ty->type == Typtr)
+        ty = tybase(ty->sub[0]);
 
     assert(ty->type == Tystruct);
     nl = ty->sdecls;
@@ -540,11 +539,12 @@
 {
     Node *t, *u, *r;
     Node **args;
+    Type *ty;
 
     args = n->expr.args;
-    if (n->expr.type->type == Typtr) {
+    ty = tybase(exprtype(args[0]));
+    if (ty->type == Typtr) {
         t = args[0];
-        t->expr.type = mktyptr(n->line, exprtype(n));
     } else {
         t = addr(args[0], exprtype(n));
     }
@@ -1167,6 +1167,7 @@
             lappend(fn, nfn, f);
         }
     } else {
+        dcl->decl.init = fold(dcl->decl.init);
         if (dcl->decl.init && exprop(dcl->decl.init) == Olit)
             lappend(&s.blobs, &s.nblobs, dcl);
         /* uninitialized global vars get zero-initialized decls */
--- a/mk/c.mk
+++ b/mk/c.mk
@@ -52,20 +52,32 @@
 
 
 install-bin: $(INSTBIN)
-	mkdir -p $(INST_ROOT)/bin
-	test -z "$(INSTBIN)" || install $(INSTBIN) $(INST_ROOT)/bin
+	@if [ ! -z "$(INSTBIN)" ]; then \
+		echo install $(INSTBIN) $(INST_ROOT)/bin; \
+		mkdir -p $(INST_ROOT)/bin; \
+		install $(INSTBIN) $(INST_ROOT)/bin; \
+	fi
 
 install-lib: $(INSTLIB)
-	mkdir -p $(INST_ROOT)/lib
-	test -z "$(INSTLIB)" || install $(INSTLIB) $(INST_ROOT)/lib
+	@if [ ! -z "$(INSTLIB)" ]; then \
+		echo install $(INSTLIB) $(INST_ROOT)/lib; \
+		mkdir -p $(INST_ROOT)/lib; \
+		install $(INSTLIB) $(INST_ROOT)/lib; \
+	fi
 
 install-hdr: $(INSTHDR)
-	mkdir -p $(INST_ROOT)/$(HDRDIR)/include
-	test -z "$(INSTHDR)" || install $(INSTHDR) $(INST_ROOT)/include
+	@if [ ! -z "$(INSTHDR)" ]; then \
+		echo install $(INSTHDR) $(INST_ROOT)/include; \
+		mkdir -p $(INST_ROOT)/include; \
+		install $(INSTHDR) $(INST_ROOT)/include; \
+	fi
 
 install-pc: $(INSTPKG)
-	mkdir -p $(INST_ROOT)/pkgconfig
-	test -z "$(INSTPC)" || install $(INSTPC) $(INST_ROOT)/pkgconfig
+	@if [ ! -z "$(INSTPKG)" ]; then \
+		echo install $(INSTPKG) $(INST_ROOT)/lib/pkgconfig; \
+		mkdir -p $(INST_ROOT)/lib/pkgconfig; \
+		install $(INSTPKG) $(INST_ROOT)/lib/pkgconfig; \
+	fi
 
 clean-backups:
 	find ./ -name .*.sw* -exec rm -f {} \;
--- a/opt/fold.c
+++ b/opt/fold.c
@@ -50,6 +50,8 @@
     vlong a, b;
     size_t i;
 
+    if (!n)
+        return NULL;
     assert(n->type == Nexpr);
     r = NULL;
     args = n->expr.args;
@@ -111,6 +113,12 @@
         case Oneg:
             if (islit(args[0], &a))
                 r = val(n->line, -a);
+            break;
+        case Ocast:
+            /* FIXME: we currentl assume that the bits of the
+             * val are close enough. */
+            r = args[0];
+            r->expr.type = exprtype(n);
             break;
         default:
             break;
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -14,10 +14,10 @@
 
 typedef struct Inferstate Inferstate;
 struct Inferstate {
-    /* what sort of constructs we're inside. incremented when we enter,
-     * decremented when we leave, in order to allow nesting */
     int inpat;
     int ingeneric;
+    int sawret;
+    Type *ret;
 
     /* bound by patterns turn into decls in the action block */
     Node **binds;
@@ -100,6 +100,45 @@
     return t;
 }
 
+/* prevents types that directly contain themselves. */
+static int tyinfinite(Inferstate *st, Type *t, Type *sub)
+{
+    size_t i;
+
+    assert(t != NULL);
+    if (t == sub) /* FIXME: is this actually right? */
+        return 1;
+    /* if we're on the first iteration, the subtype is the type
+     * itself. The assignment must come after the equality check
+     * for obvious reasons. */
+    if (!sub)
+        sub = t;
+
+    switch (sub->type) {
+        case Tystruct:
+            for (i = 0; i < sub->nmemb; i++)
+                if (tyinfinite(st, t, decltype(sub->sdecls[i])))
+                    return 1;
+            break;
+        case Tyunion:
+            for (i = 0; i < t->nmemb; i++) {
+                if (sub->udecls[i]->etype && tyinfinite(st, t, sub->udecls[i]->etype))
+                    return 1;
+            }
+            break;
+
+        case Typtr:
+        case Tyslice:
+            return 0;
+        default:
+            for (i = 0; i < sub->nsub; i++)
+                if (tyinfinite(st, t, sub->sub[i]))
+                    return 1;
+            break;
+    }
+    return 0;
+}
+
 static void tyresolve(Inferstate *st, Type *t)
 {
     size_t i;
@@ -132,6 +171,8 @@
         bsunion(t->cstrs, base->cstrs);
     else
         t->cstrs = bsdup(base->cstrs);
+    if (tyinfinite(st, t, NULL))
+        fatal(t->line, "Type %s includes itself", tystr(t));
 }
 
 /* fixd the most accurate type mapping we have */
@@ -144,7 +185,7 @@
     while (1) {
         if (!tytab[t->tid] && t->type == Tyname) {
             if (!(lu = gettype(curstab(), t->name)))
-                fatal(t->name->line, "Could not fixd type %s", namestr(t->name));
+                fatal(t->name->line, "Could not fixed type %s", namestr(t->name));
             tytab[t->tid] = lu;
         }
 
@@ -213,24 +254,45 @@
     return tf(st, t);
 }
 
-static char *ctxstr(Node *n)
+static char *ctxstr(Inferstate *st, Node *n)
 {
     char *s;
+    char *t;
+    char *u;
+    char buf[512];
+
     switch (n->type) {
-        default:        s = nodestr(n->type);   break;
-        case Ndecl:     s = declname(n);        break;
-        case Nname:     s = namestr(n);         break;
+        default:
+            s = nodestr(n->type);
+            break;
+        case Ndecl:
+            u = declname(n);
+            t = tystr(tf(st, decltype(n)));
+            snprintf(buf, 512, "%s:%s", u, t);
+            s = strdup(buf);
+            free(t);
+            break;
+        case Nname:
+            s = namestr(n);
+            break;
         case Nexpr:
             if (exprop(n) == Ovar)
-                s = namestr(n->expr.args[0]);
+                u = namestr(n->expr.args[0]);
             else
-                s = opstr(exprop(n));
+                u = opstr(exprop(n));
+            if (exprtype(n))
+                t = tystr(tf(st, exprtype(n)));
+            else
+                t = strdup("unknown");
+            snprintf(buf, 512, "%s:%s", u, t);
+            s = strdup(buf);
+            free(t);
             break;
     }
     return s;
 }
 
-static void constrain(Node *ctx, Type *a, Cstr *c)
+static void constrain(Inferstate *st, Node *ctx, Type *a, Cstr *c)
 {
     if (a->type == Tyvar) {
         if (!a->cstrs)
@@ -237,7 +299,7 @@
             a->cstrs = mkbs();
         setcstr(a, c);
     } else if (!bshas(a->cstrs, c->cid)) {
-            fatal(ctx->line, "%s needs %s near %s", tystr(a), c->name, ctxstr(ctx));
+            fatal(ctx->line, "%s needs %s near %s", tystr(a), c->name, ctxstr(st, ctx));
     }
 }
 
@@ -255,7 +317,7 @@
     return bsissubset(b->cstrs, a->cstrs);
 }
 
-static void mergecstrs(Node *ctx, Type *a, Type *b)
+static void mergecstrs(Inferstate *st, Node *ctx, Type *a, Type *b)
 {
     if (b->type == Tyvar) {
         /* make sure that if a = b, both have same cstrs */
@@ -268,7 +330,7 @@
     } else {
         if (!cstrcheck(a, b)) {
             dump(file, stdout);
-            fatal(ctx->line, "%s missing constraints for %s near %s", tystr(b), tystr(a), ctxstr(ctx));
+            fatal(ctx->line, "%s missing constraints for %s near %s", tystr(b), tystr(a), ctxstr(st, ctx));
         }
     }
 }
@@ -288,6 +350,8 @@
     return (a->type == Tyvar && a->nsub > 0) || a->type == Tyarray || a->type == Tyslice;
 }
 
+/* prevents types that contain themselves in the unification;
+ * eg @a U (@a -> foo) */
 static int occurs(Type *a, Type *b)
 {
     size_t i;
@@ -318,7 +382,7 @@
     }
 
     r = NULL;
-    mergecstrs(ctx, a, b);
+    mergecstrs(st, ctx, a, b);
     if (a->type == Tyvar) {
         tytab[a->tid] = b;
         r = b;
@@ -325,19 +389,19 @@
     }
     if (a->type == Tyvar && b->type != Tyvar) 
         if (occurs(a, b))
-            fatal(ctx->line, "Infinite type %s in %s near %s", tystr(a), tystr(b), ctxstr(ctx));
+            fatal(ctx->line, "Infinite type %s in %s near %s", tystr(a), tystr(b), ctxstr(st, ctx));
 
     if (a->type == b->type || idxhacked(&a, &b)) {
         for (i = 0; i < b->nsub; i++) {
             /* types must have same arity */
             if (i >= a->nsub)
-                fatal(ctx->line, "%s has wrong subtypes for %s near %s", tystr(a), tystr(b), ctxstr(ctx));
+                fatal(ctx->line, "%s has wrong subtypes for %s near %s", tystr(a), tystr(b), ctxstr(st, ctx));
 
             unify(st, ctx, a->sub[i], b->sub[i]);
         }
         r = b;
     } else if (a->type != Tyvar) {
-        fatal(ctx->line, "%s incompatible with %s near %s", tystr(a), tystr(b), ctxstr(ctx));
+        fatal(ctx->line, "%s incompatible with %s near %s", tystr(a), tystr(b), ctxstr(st, ctx));
     }
     return r;
 }
@@ -351,12 +415,13 @@
     if (ft->type == Tyvar) {
         /* the first arg is the function itself, so it shouldn't be counted */
         ft = mktyfunc(n->line, &n->expr.args[1], n->expr.nargs - 1, mktyvar(n->line));
+        unify(st, n, ft, type(st, n->expr.args[0]));
     }
     for (i = 1; i < n->expr.nargs; i++) {
         if (ft->sub[i]->type == Tyvalist)
             break;
         inferexpr(st, n->expr.args[i], NULL, NULL);
-        unify(st, n, ft->sub[i], type(st, n->expr.args[i]));
+        unify(st, n->expr.args[0], ft->sub[i], type(st, n->expr.args[i]));
     }
     settype(st, n, ft->sub[0]);
 }
@@ -484,7 +549,7 @@
         case Oidx:      /* @a[@b::tcint] -> @a */
             t = mktyidxhack(n->line, mktyvar(n->line));
             unify(st, n, type(st, args[0]), t);
-            constrain(n, type(st, args[1]), cstrtab[Tcint]);
+            constrain(st, n, type(st, args[1]), cstrtab[Tcint]);
             settype(st, n, tf(st, t->sub[0]));
             break;
         case Oslice:    /* @a[@b::tcint,@b::tcint] -> @a[,] */
@@ -499,7 +564,7 @@
             lappend(&st->postcheck, &st->npostcheck, n);
             break;
         case Osize:     /* sizeof @a -> size */
-            settype(st, n, mkty(n->line, Tyuint));
+            settype(st, n, tylike(mktyvar(n->line), Tyuint));
             break;
         case Ocall:     /* (@a, @b, @c, ... -> @r)(@a,@b,@c, ... -> @r) -> @r */
             unifycall(st, n);
@@ -529,7 +594,7 @@
                 return;
             s = getdcl(curstab(), args[0]);
             if (!s)
-                fatal(n->line, "Undeclared var %s", ctxstr(args[0]));
+                fatal(n->line, "Undeclared var %s", ctxstr(st, args[0]));
 
             if (s->decl.isgeneric)
                 t = freshen(st, s->decl.type);
@@ -546,11 +611,11 @@
         case Ocons:
             uc = getucon(curstab(), args[0]);
             if (!uc)
-                fatal(n->line, "No union constructor %s", ctxstr(args[0]));
+                fatal(n->line, "No union constructor %s", ctxstr(st, args[0]));
             if (!uc->etype && n->expr.nargs > 1)
-                fatal(n->line, "nullary union constructor %s passed arg ", ctxstr(args[0]));
+                fatal(n->line, "nullary union constructor %s passed arg ", ctxstr(st, args[0]));
             else if (uc->etype && n->expr.nargs != 2)
-                fatal(n->line, "union constructor %s needs arg ", ctxstr(args[0]));
+                fatal(n->line, "union constructor %s needs arg ", ctxstr(st, args[0]));
             else if (uc->etype)
                 unify(st, n, uc->etype, type(st, args[1]));
             settype(st, n, uc->utype);
@@ -610,7 +675,7 @@
         unify(st, n, type(st, n), type(st, n->decl.init));
     } else {
         if (n->decl.isconst && !n->decl.isextern)
-            fatal(n->line, "non-extern \"%s\" has no initializer", ctxstr(n));
+            fatal(n->line, "non-extern \"%s\" has no initializer", ctxstr(st, n));
     }
 }
 
@@ -704,7 +769,7 @@
             inferdecl(st, n);
             unbind(st, n);
             if (type(st, n)->type == Typaram && !st->ingeneric)
-                fatal(n->line, "Generic type %s in non-generic near %s\n", tystr(type(st, n)), ctxstr(n));
+                fatal(n->line, "Generic type %s in non-generic near %s\n", tystr(type(st, n)), ctxstr(st, n));
             if (n->decl.isgeneric)
                 st->ingeneric--;
             break;
@@ -722,7 +787,7 @@
             infernode(st, n->ifstmt.cond, NULL, sawret);
             infernode(st, n->ifstmt.iftrue, ret, sawret);
             infernode(st, n->ifstmt.iffalse, ret, sawret);
-            constrain(n, type(st, n->ifstmt.cond), cstrtab[Tctest]);
+            constrain(st, n, type(st, n->ifstmt.cond), cstrtab[Tctest]);
             break;
         case Nloopstmt:
             infernode(st, n->loopstmt.init, ret, sawret);
@@ -729,7 +794,7 @@
             infernode(st, n->loopstmt.cond, NULL, sawret);
             infernode(st, n->loopstmt.step, ret, sawret);
             infernode(st, n->loopstmt.body, ret, sawret);
-            constrain(n, type(st, n->loopstmt.cond), cstrtab[Tctest]);
+            constrain(st, n, type(st, n->loopstmt.cond), cstrtab[Tctest]);
             break;
         case Nmatchstmt:
             infernode(st, n->matchstmt.val, NULL, sawret);
@@ -770,6 +835,7 @@
 
 static void checkcast(Inferstate *st, Node *n)
 {
+    /* FIXME: actually verify the casts */
 }
 
 /* returns the final type for t, after all unifications
@@ -791,7 +857,8 @@
             return tyint;
         if (hascstr(t, cstrtab[Tcfloat]) && cstrcheck(t, tyflt))
             return tyint;
-    } else {
+    } else if (!t->fixed) {
+        t->fixed = 1;
         if (t->type == Tyarray) {
             typesub(st, t->asize);
         } else if (t->type == Tystruct) {
@@ -807,7 +874,7 @@
             t->sub[i] = tyfix(st, ctx, t->sub[i]);
     }
     if (t->type == Tyvar) {
-        fatal(t->line, "underconstrained type %s near %s", tyfmt(buf, 1024, t), ctxstr(ctx));
+        fatal(t->line, "underconstrained type %s near %s", tyfmt(buf, 1024, t), ctxstr(st, ctx));
     }
 
     return t;
@@ -833,18 +900,17 @@
         memb = st->postcheck[i]->expr.args[1];
 
         found = 0;
-        t = tf(st, type(st, aggr));
+        t = tybase(tf(st, type(st, aggr)));
         if (t->type == Tyslice || t->type == Tyarray) {
             if (!strcmp(namestr(memb), "len")) {
-                constrain(n, type(st, n), cstrtab[Tcnum]);
-                constrain(n, type(st, n), cstrtab[Tcint]);
-                constrain(n, type(st, n), cstrtab[Tctest]);
+                constrain(st, n, type(st, n), cstrtab[Tcnum]);
+                constrain(st, n, type(st, n), cstrtab[Tcint]);
+                constrain(st, n, type(st, n), cstrtab[Tctest]);
                 found = 1;
             }
         } else {
-            t = tybase(t);
             if (t->type == Typtr)
-                t = tf(st, t->sub[0]);
+                t = tybase(tf(st, t->sub[0]));
             nl = t->sdecls;
             for (j = 0; j < t->nmemb; j++) {
                 if (!strcmp(namestr(memb), declname(nl[j]))) {
@@ -856,7 +922,7 @@
         }
         if (!found)
             fatal(aggr->line, "Type %s has no member \"%s\" near %s",
-                  tystr(type(st, aggr)), ctxstr(memb), ctxstr(aggr));
+                  tystr(type(st, aggr)), ctxstr(st, memb), ctxstr(st, aggr));
     }
 }
 
@@ -877,7 +943,7 @@
     k = htkeys(s->dcl, &n);
     for (i = 0; i < n; i++) {
         d = getdcl(s, k[i]);
-        d->decl.type = tyfix(st, d->decl.name, d->decl.type);
+        d->decl.type = tyfix(st, d, d->decl.type);
     }
     free(k);
 }
@@ -984,10 +1050,10 @@
             if (!tg)
                 puttype(globls, nl, tl);
             else
-                fatal(nl->line, "Exported type %s double-declared on line %d", namestr(nl), tg->line);
+                fatal(nl->line, "Exported type %s already declared on line %d", namestr(nl), tg->line);
         } else {
             tg = gettype(globls, nl);
-            if (tg) 
+            if (tg)
                 updatetype(exports, nl, tf(st, tg));
             else
                 fatal(nl->line, "Exported type %s not declared", namestr(nl));
@@ -1002,7 +1068,7 @@
         /* if an export has an initializer, it shouldn't be declared in the
          * body */
         if (nl->decl.init && ng)
-            fatal(nl->line, "Export %s double-defined on line %d", ctxstr(nl), ng->line);
+            fatal(nl->line, "Export %s double-defined on line %d", ctxstr(st, nl), ng->line);
         if (!ng)
             putdcl(globls, nl);
         else
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -92,16 +92,19 @@
     Ty type;
     int tid;
     int line;
-    int resolved;     /* Have we resolved the subtypes? Idempotent, but slow to repeat. */
+
+    int resolved;     /* Have we resolved the subtypes? Prevents infinite recursion. */
+    int fixed;        /* Have we fixed the subtypes? Prevents infinite recursion. */
+
     Bitset *cstrs;    /* the type constraints matched on this type */
-    Node **cstrlist;  /* The names of the constraints on the type. Used to resolve/fill the bitset */
+    Node **cstrlist;  /* The names of the constraints on the type. Used to fill the bitset */
     size_t ncstrlist; /* The length of the constraint list above */
+
+    Type **sub;       /* sub-types; shared by all composite types */
     size_t nsub;      /* For compound types */
     size_t nmemb;     /* for aggregate types (struct, union) */
-    Type **sub;       /* sub-types; shared by all composite types */
     union {
-        Node *aname;   /* Tyalias: alias name */
-        Node *name;    /* Tyname: unresolved name */
+        Node *name;    /* Tyname: unresolved name. Tyalias: alias name */
         Node *asize;   /* array size */
         char *pname;   /* Typaram: name of type parameter */
         Node **sdecls; /* Tystruct: decls in struct */
--- a/parse/pickle.c
+++ b/parse/pickle.c
@@ -189,6 +189,10 @@
         case Tyvar:
             die("Attempting to pickle %s. This will not work.\n", tystr(ty));
             break;
+        case Tyalias:
+            pickle(ty->name, fd);
+            wrtype(fd, ty->sub[0]);
+            break;
         default:
             for (i = 0; i < ty->nsub; i++)
                 wrtype(fd, ty->sub[i]);
@@ -233,6 +237,10 @@
             ty->asize = unpickle(fd);
             break;
         case Tyslice:
+            ty->sub[0] = rdtype(fd);
+            break;
+        case Tyalias:
+            ty->name = unpickle(fd);
             ty->sub[0] = rdtype(fd);
             break;
         default:
--- a/parse/type.c
+++ b/parse/type.c
@@ -320,7 +320,7 @@
 
     p = buf;
     end = p + len;
-    p += snprintf(p, end - p, "struct ");
+    p += snprintf(p, end - p, "union ");
     for (i = 0; i < t->nmemb; i++) {
         name = namestr(t->udecls[i]->name);
         ty = tystr(t->udecls[i]->etype);
@@ -419,7 +419,7 @@
             p += namefmt(p, end - p, t->name);
             break;
         case Tyalias:  
-            p += snprintf(p, end - p, "%s", namestr(t->aname));
+            p += snprintf(p, end - p, "%s", namestr(t->name));
             break;
         case Tystruct:  p += fmtstruct(p, end - p, t);  break;
         case Tyunion:   p += fmtunion(p, end - p, t);   break;
--- a/test/tests
+++ b/test/tests
@@ -53,10 +53,12 @@
 B arraylit-ni	E	2
 B structlit	E	42
 B tuple		E	42
+B tyrec		E	42
 F declmismatch
 F infermismatch
 F flow
 F occur
+F tyoccur
 F union-extraarg
 F union-missingarg
 F match-badtypes
--- /dev/null
+++ b/test/tyoccur.myr
@@ -1,0 +1,5 @@
+type t = struct
+	memb : t
+;;
+
+var v : t
--- /dev/null
+++ b/test/tyrec.myr
@@ -1,0 +1,9 @@
+/* we just want to see if this file compiles */
+type foo = struct
+	v : foo*
+;;
+
+const main = {
+	var v : foo
+	-> 42
+}
--- a/util/Makefile
+++ b/util/Makefile
@@ -1,3 +1,4 @@
+INSTBIN=muse
 BIN=muse
 OBJ=muse.o