diff options
author | Michael Forney <mforney@mforney.org> | 2017-07-01 14:43:21 -0700 |
---|---|---|
committer | Ori Bernstein <ori@eigenstate.org> | 2017-07-03 23:27:02 -0700 |
commit | ca10a1ec838b7d468a2b43894af659c111a0e9b1 (patch) | |
tree | 16601ac01a6f644015188db074e1c2b69bdc5789 | |
parent | ddb327c92ebe3f96c5c816ec61996440551de401 (diff) | |
download | mc-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.txt | 10 | ||||
-rw-r--r-- | parse/gram.y | 6 | ||||
-rw-r--r-- | parse/infer.c | 24 | ||||
-rw-r--r-- | test/implexpr.myr | 18 | ||||
-rw-r--r-- | test/tests | 2 |
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[:])) +} @@ -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 |