shithub: mc

Download patch

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

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.

--- a/doc/lang.txt
+++ b/doc/lang.txt
@@ -1239,7 +1239,8 @@
         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 @@
             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 @@
                 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
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -380,7 +380,7 @@
 
 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 @@
 	}
 	| 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
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1199,13 +1199,16 @@
 	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 @@
 	}
 	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 @@
 	Node *s, *n;
 	Type *t, *b;
 	int isconst;
+	Stab *ns;
 
 	n = *np;
 	assert(n->type == Nexpr);
@@ -1650,9 +1657,14 @@
 		 * 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 @@
 		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);
--- /dev/null
+++ b/test/implexpr.myr
@@ -1,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[:]))
+}
--- a/test/tests
+++ b/test/tests
@@ -164,4 +164,4 @@
 B nestedgoto	E	0
 B initializer	E	0
 B fmtalign	E	0
-
+B implexpr	P	12,z,hello