summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2017-07-01 14:43:21 -0700
committerOri Bernstein <ori@eigenstate.org>2017-07-03 23:27:02 -0700
commitca10a1ec838b7d468a2b43894af659c111a0e9b1 (patch)
tree16601ac01a6f644015188db074e1c2b69bdc5789
parentddb327c92ebe3f96c5c816ec61996440551de401 (diff)
downloadmc-ca10a1ec838b7d468a2b43894af659c111a0e9b1.tar.gz
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.
-rw-r--r--doc/lang.txt10
-rw-r--r--parse/gram.y6
-rw-r--r--parse/infer.c24
-rw-r--r--test/implexpr.myr18
-rw-r--r--test/tests2
5 files changed, 50 insertions, 10 deletions
diff --git a/doc/lang.txt b/doc/lang.txt
index 0f14322..3be5500 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 3839a92..bcf9713 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 fcf0161..164cbc8 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 0000000..d449a2a
--- /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 ba4e075..937828b 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