shithub: mc

Download patch

ref: e8121eb38f6c825fc4638d84521c51dc6cfe761b
parent: 76ce9de16baeec77b86ece6825b90715b08545ba
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Jul 13 20:07:31 EDT 2018

Push down named unions types into union tags

	Currently, union tags are given the type of their
	enclosing union, by default:

		type u = union
			`Foo
		;;

		var x = `Foo

	will currently infer the variable 'x' as having type
	'union `Foo ;;'. To make the type of 'x' infer as 'foo',
	the code needs to force 'x' to unify with something that is
	explicitly declared as a 'u'.

	This change makes it so that union tags declared in the manner
	above will default to type 'u', instead. This is a special case,
	but it makes the behavior less surprising.

--- a/doc/lang.txt
+++ b/doc/lang.txt
@@ -1,6 +1,6 @@
                     The Myrddin Programming Language
                               Jul 2012
-                          Updated Feb 2017
+                          Updated Jul 2018
                             Ori Bernstein
 
 TABLE OF CONTENTS:
@@ -784,6 +784,16 @@
             with type $t :: numeric $t, integral $t is replaced with int. An
             unconstrained type with $t :: numeric $t, floating $t is replaced with
             flt64.
+
+	    As a special case, a union type declared with the form
+
+	        type u = union
+                    `Foo
+		;;
+
+            will have the default type set to the named type, and not the
+            union itself. This is slightly inconsistent, but it makes the
+            behavior less surprising.
 
     4.6. Built In Traits:
 
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -36,6 +36,7 @@
 static void setwith(Type *ty, Traitspec **spec, size_t nspec);
 static void setupinit(Node *n);
 static void addinit(Node *blk, Node *dcl);
+static void setuname(Type *ty);
 
 %}
 
@@ -528,6 +529,7 @@
 			$$.type = mktyname($2.loc, mkname($2.loc, $2.name), $5);
 		else
 			$$.type = mktygeneric($2.loc, mkname($2.loc, $2.name), $2.params, $2.nparams, $5);
+		setuname($$.type);
 		setwith($$.type, $3.spec, $3.nspec);
 	}
 	;
@@ -1147,6 +1149,17 @@
 	n->decl.name->name.name = strdup(s);
 }
 
+static void
+setuname(Type *ty)
+{
+	size_t i;
+
+	if (ty->sub[0]->type != Tyunion)
+		return;
+	for (i = 0; i < ty->sub[0]->nmemb; i++)
+		ty->sub[0]->udecls[i]->utype = ty;
+}
+
 static Node *
 mkpseudodecl(Srcloc l, Type *t)
 {
@@ -1231,7 +1244,8 @@
 		break;
 	case Tyunion:
 		for (i = 0; i < b->nmemb; i++) {
-			b->udecls[i]->utype = b;
+			if (!b->udecls[i]->utype)
+				b->udecls[i]->utype = b;
 			b->udecls[i]->id = i;
 			putucon(st, b->udecls[i]);
 		}
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -514,7 +514,7 @@
 	case Tyunion:
 		inaggr++;
 		for (i = 0; i < t->nmemb; i++) {
-			t->udecls[i]->utype = t;
+			assert(t->udecls[i]->utype);
 			t->udecls[i]->utype = tf(t->udecls[i]->utype);
 			if (t->udecls[i]->etype) {
 				tyresolve(t->udecls[i]->etype);
@@ -1498,7 +1498,11 @@
 	 *
 	 * To make it compile, for now, we just bind the types in here.
 	 */
-	t = tysubst(tf(uc->utype), uc->utype);
+	t = uc->utype;
+	if (t->type != Tyunion)
+		t = t->sub[0];
+	assert(t->type == Tyunion);
+	t = tysubst(tf(t), t);
 	uc = tybase(t)->udecls[uc->id];
 	if (uc->etype) {
 		inferexpr(&n->expr.args[1], NULL, NULL);