shithub: mc

Download patch

ref: 871ef281aaf3c2e8bdff5d92355461bedfa5d933
parent: ca10a1ec838b7d468a2b43894af659c111a0e9b1
author: Michael Forney <mforney@mforney.org>
date: Sat Jul 1 10:43:22 EDT 2017

Specialize impl declarations on impl type in addition to decl type

This allows multiple specializations of a declarations with a concrete type,
which can be selected with the new impl expression if it can't be deduced by its
type alone.

For example

	trait hasname @t =
		Name: byte[:]
	;;
	impl hasname void =
		Name = "somename"
	;;
	impl hasname bool =
		Name = "othername"
	;;
	const boolname = impl(Name, void)

To do this, pass the param type through to genericname and specializedcl. Since
we now need the type parameter to look up trait decls, make sure n->expr.param
gets the necessary treatment in typesub, specializenode, pickle, and unpickle.

We also need to tag the param types for export.

--- a/doc/lang.txt
+++ b/doc/lang.txt
@@ -1268,7 +1268,9 @@
 
             An impl expression chooses the implementation of the given trait
             declaration for the given type. It is useful for refering to trait
-            declarations in a generic context.
+            declarations in a generic context. It also allows you to
+            disambiguate a trait declaration whose type does not refer to the
+            trait parameter.
 
         5.2.4. Cast Expressions:
 
--- a/mbld/deps.myr
+++ b/mbld/deps.myr
@@ -11,7 +11,7 @@
 	const myrdeps	: (b : build#, mt : myrtarg#, doclean : bool, addsrc : bool -> depgraph#)
 ;;
 
-const Abiversion = 12
+const Abiversion = 13
 
 var usepat	: regex.regex#
 var cflagpat	: regex.regex#
--- a/parse/export.c
+++ b/parse/export.c
@@ -150,6 +150,8 @@
 	case Nexpr:
 		tagnode(st, n->expr.idx, ingeneric, hidelocal);
 		tagtype(st, n->expr.type, ingeneric, hidelocal);
+		if (n->expr.param)
+			tagtype(st, n->expr.param, ingeneric, hidelocal);
 		for (i = 0; i < n->expr.nargs; i++)
 			tagnode(st, n->expr.args[i], ingeneric, hidelocal);
 		/* generics need to have the decls they refer to exported. */
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1814,7 +1814,7 @@
 		unify(st, n, type(st, dcl), ty);
 
 		/* and put the specialization into the global stab */
-		name = genericname(proto, ty);
+		name = genericname(proto, n->impl.type, ty);
 		sym = getdcl(file->file.globls, name);
 		if (sym)
 			fatal(n, "trait %s already specialized with %s on %s:%d",
@@ -2423,6 +2423,8 @@
 		break;
 	case Nexpr:
 		settype(st, n, tyfix(st, n, type(st, n), 0));
+		if (n->expr.param)
+			n->expr.param = tyfix(st, n, n->expr.param, 0);
 		typesub(st, n->expr.idx, noerr);
 		if (exprop(n) == Ocast && exprop(n->expr.args[0]) == Olit &&
 				n->expr.args[0]->expr.args[0]->lit.littype == Lint) {
@@ -2493,7 +2495,7 @@
 		pushstab(st->specializationscope[i]);
 		n = st->specializations[i];
 		if (n->type == Nexpr) {
-			d = specializedcl(st->genericdecls[i], n->expr.type, &name);
+			d = specializedcl(st->genericdecls[i], n->expr.param, n->expr.type, &name);
 			n->expr.args[0] = name;
 			n->expr.did = d->decl.did;
 
@@ -2506,11 +2508,11 @@
 			ty = exprtype(n->iterstmt.seq);
 
 			it = itertype(st, n->iterstmt.seq, mktype(n->loc, Tybool));
-			d = specializedcl(tr->proto[0], it, &name);
+			d = specializedcl(tr->proto[0], ty, it, &name);
 			htput(tr->proto[0]->decl.impls, ty, d);
 
 			it = itertype(st, n->iterstmt.seq, mktype(n->loc, Tyvoid));
-			d = specializedcl(tr->proto[1], it, &name);
+			d = specializedcl(tr->proto[1], ty, it, &name);
 			htput(tr->proto[1]->decl.impls, ty, d);
 		} else {
 			die("unknown node for specialization\n");
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -1,4 +1,4 @@
-#define Abiversion 12
+#define Abiversion 13
 
 typedef struct Srcloc Srcloc;
 typedef struct Tysubst Tysubst;
@@ -508,9 +508,9 @@
 Type *substget(Tysubst *subst, Type *from);
 void substpush(Tysubst *subst);
 void substpop(Tysubst *subst);
-Node *specializedcl(Node *n, Type *to, Node **name);
+Node *specializedcl(Node *n, Type *param, Type *to, Node **name);
 Type *tyspecialize(Type *t, Tysubst *tymap, Htab *delayed, Htab *tybase);
-Node *genericname(Node *n, Type *t);
+Node *genericname(Node *n, Type *param, Type *t);
 void geninit(Node *file);
 
 /* usefiles */
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -241,7 +241,7 @@
 			if (!d)
 				die("Missing decl %s", namestr(n->expr.args[0]));
 			if (d->decl.isgeneric)
-				d = specializedcl(d, n->expr.type, &n->expr.args[0]);
+				d = specializedcl(d, n->expr.param, n->expr.type, &n->expr.args[0]);
 			n->expr.did = d->decl.did;
 		}
 		break;
@@ -328,6 +328,8 @@
 	case Nexpr:
 		r->expr.op = n->expr.op;
 		r->expr.type = tysubst(n->expr.type, tsmap);
+		if (n->expr.param)
+			r->expr.param = tysubst(n->expr.param, tsmap);
 		r->expr.isconst = n->expr.isconst;
 		r->expr.nargs = n->expr.nargs;
 		r->expr.idx = specializenode(n->expr.idx, tsmap);
@@ -435,7 +437,7 @@
 	return r;
 }
 
-Node *genericname(Node *n, Type *t)
+Node *genericname(Node *n, Type *param, Type *t)
 {
 	char buf[1024];
 	char *p;
@@ -447,6 +449,10 @@
 	p = buf;
 	end = buf + sizeof buf;
 	p += bprintf(p, end - p, "%s", n->decl.name->name.name);
+	if (param) {
+		p += bprintf(p, end - p, "$");
+		p += tyidfmt(p, end - p, param);
+	}
 	p += bprintf(p, end - p, "$");
 	p += tyidfmt(p, end - p, t);
 	name = mkname(n->loc, buf);
@@ -574,7 +580,7 @@
  * duplicate of it with type 'to'. It also generates
  * a name for this specialized node, and returns it in '*name'.
  */
-Node *specializedcl(Node *gnode, Type *to, Node **name)
+Node *specializedcl(Node *gnode, Type *param, Type *to, Node **name)
 {
 	extern int stabstkoff;
 	Tysubst *tsmap;
@@ -584,7 +590,7 @@
 	assert(gnode->type == Ndecl);
 	assert(gnode->decl.isgeneric);
 
-	n = genericname(gnode, to);
+	n = genericname(gnode, param, to);
 	*name = n;
 	if (n->name.ns)
 		st = getns(file, n->name.ns);
@@ -598,7 +604,7 @@
 	if (gnode->decl.trait) {
 		g = bestimpl(gnode, to);
 		if (!g)
-			fatal(gnode, "no trait implemented for %s:%s", namestr(gnode->decl.name), tystr(to));
+			fatal(gnode, "type %s does not implement %s:%s", tystr(param), namestr(gnode->decl.name), tystr(to));
 	} else {
 		g = gnode;
 	}
--- a/parse/use.c
+++ b/parse/use.c
@@ -464,6 +464,9 @@
 	case Nexpr:
 		wrbyte(fd, n->expr.op);
 		wrtype(fd, n->expr.type);
+		wrbool(fd, n->expr.param != NULL);
+		if (n->expr.param)
+			wrtype(fd, n->expr.param);
 		wrbool(fd, n->expr.isconst);
 		pickle(fd, n->expr.idx);
 		wrint(fd, n->expr.nargs);
@@ -598,6 +601,8 @@
 	case Nexpr:
 		n->expr.op = rdbyte(fd);
 		rdtype(fd, &n->expr.type);
+		if (rdbool(fd))
+			rdtype(fd, &n->expr.param);
 		n->expr.isconst = rdbool(fd);
 		n->expr.idx = unpickle(fd);
 		n->expr.nargs = rdint(fd);
--- /dev/null
+++ b/test/implexpr-concrete.myr
@@ -1,0 +1,15 @@
+use std
+
+trait name @a =
+	Name: byte[:]
+;;
+impl name void =
+	Name = "zig"
+;;
+impl name int =
+	Name = "zag"
+;;
+
+const main = {
+	std.put("{}{}\n", impl(Name, void), impl(Name, int))
+}
--- a/test/tests
+++ b/test/tests
@@ -165,3 +165,4 @@
 B initializer	E	0
 B fmtalign	E	0
 B implexpr	P	12,z,hello
+B implexpr-concrete	P	zigzag