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