shithub: mc

Download patch

ref: 5711ab3b30b229b651424f7978bc39f0b044e193
parent: f363110a62803e055334516ba0e1899e62be65ac
author: Ori Bernstein <ori@markovcorp.com>
date: Wed Aug 23 07:46:44 EDT 2017

Check constraints correctly on typarams.

--- a/parse/infer.c
+++ b/parse/infer.c
@@ -33,6 +33,7 @@
 static void infernode(Node **np, Type *ret, int *sawret);
 static void inferexpr(Node **np, Type *ret, int *sawret);
 static void inferdecl(Node *n);
+static int tryconstrain(Type *ty, Trait *tr);
 
 static Type *tf(Type *t);
 
@@ -165,8 +166,12 @@
 	Node **args;
 	char buf[512];
 
+	if (!n)
+		return strdup("???");
 	switch (n->type) {
-	default: s = strdup(nodestr[n->type]); break;
+	default:
+		s = strdup(nodestr[n->type]);
+		break;
 	case Ndecl:
 		 d = declname(n);
 		 t = nodetystr(n);
@@ -749,13 +754,102 @@
 		bindtype(e, n->decl.init->expr.type);
 }
 
-/* Constrains a type to implement the required constraints. On
- * type variables, the constraint is added to the required
- * constraint list. Otherwise, the type is checked to see
- * if it has the required constraint */
-static void
-constrain(Node *ctx, Type *base, Trait *tr)
+/* this doesn't walk through named types, so it can't recurse infinitely. */
+int
+tymatchrank(Type *pat, Type *to)
 {
+	int match, q;
+	size_t i;
+	Ucon *puc, *tuc;
+
+	pat = tysearch(pat);
+	to = tysearch(to);
+	if (pat->type == Typaram) {
+		if (!pat->trneed)
+			return 0;
+		for (i = 0; bsiter(pat->trneed, &i); i++)
+			if (!tryconstrain(to, traittab[i]))
+				return -1;
+		return 0;
+	} else if (pat->type == Tyvar) {
+		return 1;
+	} else if (pat->type != to->type) {
+		return -1;
+	}
+
+	match = 0;
+	switch (pat->type) {
+	case Tystruct:
+		if (pat->nmemb != to->nmemb)
+			return -1;
+		for (i = 0; i < pat->nmemb; i++) {
+			if (!streq(declname(pat->sdecls[i]),declname( to->sdecls[i])))
+				return -1;
+			q = tymatchrank(decltype(pat->sdecls[i]), decltype(to->sdecls[i]));
+			if (q < 0)
+				return -1;
+			match += q;
+		}
+		break;
+	case Tyunion:
+		if (pat->nmemb != to->nmemb)
+			return -1;
+		for (i = 0; i < pat->nmemb; i++) {
+			if (!nameeq(pat->udecls[i], to->udecls[i]))
+				return -1;
+			puc = pat->udecls[i];
+			tuc = to->udecls[i];
+			if (puc->etype && tuc->etype) {
+				q = tymatchrank(puc->etype, tuc->etype);
+				if (q < 0)
+					return -1;
+				match += q;
+			} else if (puc->etype != tuc->etype) {
+				return -1;
+			}
+		}
+		break;
+	case Tyname:
+		if (!nameeq(pat->name, to->name))
+			return -1;
+		if (pat->narg != to->narg)
+			return -1;
+		for (i = 0; i < pat->narg; i++) {
+			q = tymatchrank(pat->arg[i], to->arg[i]);
+			if (q < 0)
+				return -1;
+			match += q;
+		}
+		break;
+	case Tyarray:
+		/* unsized arrays are ok */
+		if (pat->asize && to->asize) {
+			if (!!litvaleq(pat->asize->expr.args[0], to->asize->expr.args[0]))
+				return -1;
+		} else if (pat->asize != to->asize) {
+			return -1;
+		}
+		else return tymatchrank(pat->sub[0], to->sub[0]);
+		break;
+	default:
+		if (pat->nsub != to->nsub)
+			break;
+		if (pat->type == to->type)
+			match = 1;
+		for (i = 0; i < pat->nsub; i++) {
+			q = tymatchrank(pat->sub[i], to->sub[i]);
+			if (q < 0)
+				return -1;
+			match += q;
+		}
+		break;
+	}
+	return match;
+}
+
+static int
+tryconstrain(Type *base, Trait *tr)
+{
 	Traitmap *tm;
 	Bitset *bs;
 	Type *ty;
@@ -766,25 +860,25 @@
 		tm = traitmap->sub[ty->type];
 		while (1) {
 			if (ty->type == Typaram && bshas(ty->trneed, tr->uid))
-				return;
+				return 1;
 			if (ty->type == Tyvar) {
 				if (!ty->trneed)
 					ty->trneed = mkbs();
 				bsput(ty->trneed, tr->uid);
-				return;
+				return 1;
 			} 
 			if (bshas(tm->traits, tr->uid))
-				return;
+				return 1;
 			if (tm->name && ty->type == Tyname) {
 				bs = htget(tm->name, ty->name);
 				if (bs && bshas(bs, tr->uid))
-					return;
+					return 1;
 			}
 			for (i = 0; i < tm->nfilter; i++) {
 				if (tm->filtertr[i]->uid != tr->uid)
 					continue;
 				if (tymatchrank(tm->filter[i], ty) >= 0)
-					return;
+					return 1;
 			}
 			if (!tm->sub[ty->type])
 				break;
@@ -796,7 +890,18 @@
 			break;
 		base = base->sub[0];
 	}
-	fatal(ctx, "%s needs trait %s near %s", tystr(ty), namestr(tr->name), ctxstr(ctx));
+	return 0;
+}
+
+/* Constrains a type to implement the required constraints. On
+ * type variables, the constraint is added to the required
+ * constraint list. Otherwise, the type is checked to see
+ * if it has the required constraint */
+static void
+constrain(Node *ctx, Type *base, Trait *tr)
+{
+	if (!tryconstrain(base, tr))
+		fatal(ctx, "%s needs trait %s near %s", tystr(base), namestr(tr->name), ctxstr(ctx));
 }
 
 static void
--- a/parse/type.c
+++ b/parse/type.c
@@ -851,91 +851,6 @@
 	return eq;
 }
 
-/* this doesn't walk through named types, so it can't recurse infinitely. */
-int
-tymatchrank(Type *pat, Type *to)
-{
-	int match, q;
-	size_t i;
-	Ucon *puc, *tuc;
-
-	pat = tysearch(pat);
-	to = tysearch(to);
-	if (pat->type == Typaram)
-		return 0;
-	else if (pat->type != to->type)
-		return -1;
-
-	match = 0;
-	switch (pat->type) {
-	case Tystruct:
-		if (pat->nmemb != to->nmemb)
-			return -1;
-		for (i = 0; i < pat->nmemb; i++) {
-			if (!streq(declname(pat->sdecls[i]),declname( to->sdecls[i])))
-				return -1;
-			q = tymatchrank(decltype(pat->sdecls[i]), decltype(to->sdecls[i]));
-			if (q < 0)
-				return -1;
-			match += q;
-		}
-		break;
-	case Tyunion:
-		if (pat->nmemb != to->nmemb)
-			return -1;
-		for (i = 0; i < pat->nmemb; i++) {
-			if (!nameeq(pat->udecls[i], to->udecls[i]))
-				return -1;
-			puc = pat->udecls[i];
-			tuc = to->udecls[i];
-			if (puc->etype && tuc->etype) {
-				q = tymatchrank(puc->etype, tuc->etype);
-				if (q < 0)
-					return -1;
-				match += q;
-			} else if (puc->etype != tuc->etype) {
-				return -1;
-			}
-		}
-		break;
-	case Tyname:
-		if (!nameeq(pat->name, to->name))
-			return -1;
-		if (pat->narg != to->narg)
-			return -1;
-		for (i = 0; i < pat->narg; i++) {
-			q = tymatchrank(pat->arg[i], to->arg[i]);
-			if (q < 0)
-				return -1;
-			match += q;
-		}
-		break;
-	case Tyarray:
-		/* unsized arrays are ok */
-		if (pat->asize && to->asize) {
-			if (!!litvaleq(pat->asize->expr.args[0], to->asize->expr.args[0]))
-				return -1;
-		} else if (pat->asize != to->asize) {
-			return -1;
-		}
-		else return tymatchrank(pat->sub[0], to->sub[0]);
-		break;
-	default:
-		if (pat->nsub != to->nsub)
-			break;
-		if (pat->type == to->type)
-			match = 1;
-		for (i = 0; i < pat->nsub; i++) {
-			q = tymatchrank(pat->sub[i], to->sub[i]);
-			if (q < 0)
-				return -1;
-			match += q;
-		}
-		break;
-	}
-	return match;
-}
-
 size_t
 tyidfmt(char *buf, size_t sz, Type *ty)
 {