Eigenstate: myrddin-dev mailing list

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 1/2] Add impl(type, name) to retrieve a particular implementation of a trait decl


This avoids having to create a temporary variable when you know what
implementation your want for a generic constant or function with generic return
value.

Re-use the impl keyword for this expression to avoid invalidating existing
programs.
---
 doc/lang.txt      | 10 ++++++++--
 parse/gram.y      |  6 +++++-
 parse/infer.c     | 24 ++++++++++++++++++------
 test/implexpr.myr | 18 ++++++++++++++++++
 test/tests        |  2 +-
 5 files changed, 50 insertions(+), 10 deletions(-)
 create mode 100644 test/implexpr.myr

diff --git a/doc/lang.txt b/doc/lang.txt
index 0f143224..3be5500f 100644
--- a/doc/lang.txt
+++ b/doc/lang.txt
@@ -1239,7 +1239,8 @@ TABLE OF CONTENTS:
         5.2.3. Atomic Expressions:
             
                 atomicexpr:     ident | gap | literal | "(" expr ")" | 
-                                "sizeof" "(" type ")" | castexpr
+                                "sizeof" "(" type ")" | castexpr |
+                                "impl" "(" name "," type ")"
                 castexpr:       "(" expr ":" type ")"
                 gap:            "_"
 
@@ -1265,6 +1266,10 @@ TABLE OF CONTENTS:
             match, again, given that it is never read from in the body of the
             match.
 
+            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.
+
         5.2.4. Cast Expressions:
 
             Cast expressions convert a value from one type to another.  Some
@@ -2012,7 +2017,8 @@ TABLE OF CONTENTS:
                 postepxr "#" |
                 atomicexpr
 
-    atomicexpr: ident | literal | "(" expr ")" | "sizeof" "(" type ")"
+    atomicexpr: ident | literal | "(" expr ")" | "sizeof" "(" type ")" |
+                "(" expr ":" type ")" | "impl" "(" name "," type ")"
 
     /* literals */
     literal:    funclit | seqlit | tuplit | simplelit
diff --git a/parse/gram.y b/parse/gram.y
index 3839a92c..bcf9713f 100644
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -380,7 +380,7 @@ typedeclcore
 
 name    : Tident {$$ = mkname($1->loc, $1->id);}
 	| Tident Tdot Tident {
-		$$ = mkname($3->loc, $3->id); setns($$, $1->id);
+		$$ = mknsname($3->loc, $1->id, $3->id);
 	}
 	;
 
@@ -755,6 +755,10 @@ atomicexpr
 	}
 	| Tsizeof Toparen type Tcparen
 	{$$ = mkexpr($1->loc, Osize, mkpseudodecl($1->loc, $3), NULL);}
+	| Timpl Toparen name Tcomma type Tcparen {
+		$$ = mkexpr($1->loc, Ovar, $3, NULL);
+		$$->expr.param = $5;
+	}
 	;
 
 tupbody : tuphead tuprest
diff --git a/parse/infer.c b/parse/infer.c
index dcaf1c40..445b34b4 100644
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1199,13 +1199,16 @@ static Type *initvar(Inferstate *st, Node *n, Node *s)
 	if (s->decl.ishidden)
 		fatal(n, "attempting to refer to hidden decl %s", ctxstr(st, n));
 
-	param = NULL;
+	param = n->expr.param;
 	if (s->decl.isgeneric) {
 		subst = mksubst();
+		if (param)
+			substput(subst, s->decl.trait->param, param);
 		t = tysubstmap(st, subst, tf(st, s->decl.type), s->decl.type);
-		if (s->decl.trait) {
+		if (s->decl.trait && !param) {
 			param = substget(subst, s->decl.trait->param);
-			delayedcheck(st, n, curstab());
+			if (!param)
+				fatal(n, "ambiguous trait decl %s", ctxstr(st, s));
 		}
 		substfree(subst);
 	} else {
@@ -1213,7 +1216,10 @@ static Type *initvar(Inferstate *st, Node *n, Node *s)
 	}
 	n->expr.did = s->decl.did;
 	n->expr.isconst = s->decl.isconst;
-	n->expr.param = param;
+	if (param) {
+		n->expr.param = param;
+		delayedcheck(st, n, curstab());
+	}
 	if (s->decl.isgeneric && !st->ingeneric) {
 		t = tyfreshen(st, NULL, t);
 		addspecialization(st, n, curstab());
@@ -1484,6 +1490,7 @@ static void inferexpr(Inferstate *st, Node **np, Type *ret, int *sawret)
 	Node *s, *n;
 	Type *t, *b;
 	int isconst;
+	Stab *ns;
 
 	n = *np;
 	assert(n->type == Nexpr);
@@ -1650,9 +1657,14 @@ static void inferexpr(Inferstate *st, Node **np, Type *ret, int *sawret)
 		 * already done with this node, we can just return. */
 		if (n->expr.type)
 			return;
-		s = getdcl(curstab(), args[0]);
+		ns = curstab();
+		if (args[0]->name.ns)
+			ns = getns(file, args[0]->name.ns);
+		s = getdcl(ns, args[0]);
 		if (!s)
 			fatal(n, "undeclared var %s", ctxstr(st, args[0]));
+		if (n->expr.param && !s->decl.trait)
+			fatal(n, "var %s must refer to a trait decl", ctxstr(st, args[0]));
 		initvar(st, n, s);
 		break;
 	case Ogap: /* _ -> @a */
@@ -1812,7 +1824,7 @@ static void specializeimpl(Inferstate *st, Node *n)
 		putdcl(file->file.globls, dcl);
 		htput(proto->decl.impls, n->impl.type, dcl);
 		dcl->decl.isconst = 1;
-		if (n->impl.type->type == Tygeneric || hasparams(n->impl.type)) {
+		if (ty->type == Tygeneric || hasparams(ty)) {
 			dcl->decl.isgeneric = 1;
 			lappend(&proto->decl.gimpl, &proto->decl.ngimpl, dcl);
 			lappend(&proto->decl.gtype, &proto->decl.ngtype, ty);
diff --git a/test/implexpr.myr b/test/implexpr.myr
new file mode 100644
index 00000000..d449a2af
--- /dev/null
+++ b/test/implexpr.myr
@@ -0,0 +1,18 @@
+use std
+
+trait favorite @a =
+	Fav : @a
+;;
+impl favorite int =
+	Fav = 12
+;;
+impl favorite char =
+	Fav = 'z'
+;;
+impl favorite byte[:] =
+	Fav = "hello"
+;;
+
+const main = {
+	std.put("{},{},{}\n", impl(Fav, int), impl(Fav, char), impl(Fav, byte[:]))
+}
diff --git a/test/tests b/test/tests
index ba4e0750..937828be 100644
--- a/test/tests
+++ b/test/tests
@@ -164,4 +164,4 @@ B destructuretup	E	0
 B nestedgoto	E	0
 B initializer	E	0
 B fmtalign	E	0
-
+B implexpr	P	12,z,hello
-- 
2.13.2


Follow-Ups:
Re: [RFC PATCH 1/2] Add impl(type, name) to retrieve a particular implementation of a trait declOri Bernstein <ori@xxxxxxxxxxxxxx>
References:
[RFC PATCH 0/2] impl specialization and lookup changesMichael Forney <mforney@xxxxxxxxxxx>