summaryrefslogtreecommitdiff
path: root/parse
diff options
context:
space:
mode:
Diffstat (limited to 'parse')
-rw-r--r--parse/export.c12
-rw-r--r--parse/gram.y220
-rw-r--r--parse/infer.c127
-rw-r--r--parse/node.c3
-rw-r--r--parse/parse.h17
-rw-r--r--parse/specialize.c39
-rw-r--r--parse/stab.c3
-rw-r--r--parse/type.c1
-rw-r--r--parse/use.c27
9 files changed, 348 insertions, 101 deletions
diff --git a/parse/export.c b/parse/export.c
index 68733fa..2d6e075 100644
--- a/parse/export.c
+++ b/parse/export.c
@@ -71,11 +71,15 @@ tagtype(Stab *st, Type *t, int ingeneric, int hidelocal)
{
size_t i;
- if (t->vis != Visintern)
+ if (!t || t->vis != Visintern)
return;
t->vis = Vishidden;
for (i = 0; i < t->nsub; i++)
tagtype(st, t->sub[i], ingeneric, hidelocal);
+ for (i = 0; i < t->nspec; i++) {
+ tagtype(st, t->spec[i]->param, ingeneric, hidelocal);
+ tagtype(st, t->spec[i]->aux, ingeneric, hidelocal);
+ }
switch (t->type) {
case Tystruct:
for (i = 0; i < t->nmemb; i++)
@@ -259,16 +263,18 @@ tagexports(int hidelocal)
free(k);
/* tag the traits */
- tr = NULL;
for (i = 0; i < ntraittab; i++) {
tr = traittab[i];
if (tr->vis != Visexport)
continue;
if (hidelocal && tr->ishidden)
tr->vis = Vishidden;
+ tagtype(st, tr->param, 0, hidelocal);
tr->param->vis = tr->vis;
- for (j = 0; j < tr->naux; j++)
+ for (j = 0; j < tr->naux; j++) {
+ tagtype(st, tr->aux[j], 0, hidelocal);
tr->aux[j]->vis = tr->vis;
+ }
for (j = 0; j < tr->nproto; j++) {
tr->proto[j]->decl.vis = tr->vis;
tagnode(st, tr->proto[j], 0, hidelocal);
diff --git a/parse/gram.y b/parse/gram.y
index dc17314..5c73295 100644
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -18,10 +18,11 @@
#include "parse.h"
-Stab *curscope;
#define LBLSTKSZ 64
static Node **lbls[LBLSTKSZ];
static size_t nlbls[LBLSTKSZ];
+Stab *curscope;
+
/* the first time we see a label, we increment to 0 */
static int lbldepth = -1;
@@ -32,6 +33,7 @@ static Op binop(int toktype);
static Node *mkpseudodecl(Srcloc l, Type *t);
static void installucons(Stab *st, Type *t);
static void setattrs(Node *dcl, char **attrs, size_t nattrs);
+static void setwith(Type *ty, Traitspec **spec, size_t nspec);
static void setupinit(Node *n);
%}
@@ -132,7 +134,9 @@ static void setupinit(Node *n);
%type <ty> type structdef uniondef tupledef compoundtype functype funcsig
%type <ty> generictype
%type <tylist> typelist typarams optauxtypes
-%type <nodelist> typaramlist
+%type <traitspecs> traitspec traits
+%type <traitspec> traitvar
+%type <nodelist> traitlist
%type <tok> asnop cmpop addop mulop shiftop optident obrace
@@ -207,6 +211,11 @@ but warnings suck.
Type **params;
size_t nparams;
} tydef;
+ struct {
+ Traitspec **spec;
+ size_t nspec;
+ } traitspecs;
+ Traitspec *traitspec;
Trait *trait;
Node *node;
Tok *tok;
@@ -254,14 +263,14 @@ toplev : package
| /* empty */
;
-decl : attrs Tvar decllist {
+decl : attrs Tvar decllist traitspec {
size_t i;
for (i = 0; i < $3.nn; i++)
setattrs($3.nl[i], $1.str, $1.nstr);
$$ = $3;
}
- | attrs Tconst decllist {
+ | attrs Tconst decllist traitspec {
size_t i;
for (i = 0; i < $3.nn; i++) {
setattrs($3.nl[i], $1.str, $1.nstr);
@@ -269,11 +278,12 @@ decl : attrs Tvar decllist {
}
$$ = $3;
}
- | attrs Tgeneric decllist {
+ | attrs Tgeneric decllist traitspec {
size_t i;
for (i = 0; i < $3.nn; i++) {
setattrs($3.nl[i], $1.str, $1.nstr);
+ setwith($3.nl[i]->decl.type, $4.spec, $4.nspec);
$3.nl[i]->decl.isconst = 1;
$3.nl[i]->decl.isgeneric = 1;
}
@@ -288,6 +298,50 @@ attrs : /* empty */ {$$.nstr = 0; $$.str = NULL;}
}
;
+traitspec
+ : Twith traits {$$ = $2;}
+ | /* nothing */ {$$.nspec = 0;}
+ ;
+
+traits : traitvar {
+ $$.spec = NULL;
+ $$.nspec = 0;
+ lappend(&$$.spec, &$$.nspec, $1);
+ }
+ | traits listsep traitvar {
+ $$ = $1;
+ lappend(&$$.spec, &$$.nspec, $3);
+ }
+ ;
+
+traitvar
+ : traitlist generictype {
+ $$ = calloc(sizeof(Traitspec), 1);
+ $$->trait = $1.nl;
+ $$->ntrait = $1.nn;
+ $$->param = $2;
+ $$->aux = NULL;
+ }
+ | traitlist generictype Tret type {
+ $$ = calloc(sizeof(Traitspec), 1);
+ $$->trait = $1.nl;
+ $$->ntrait = $1.nn;
+ $$->param = $2;
+ $$->aux = $4;
+ }
+ ;
+
+traitlist
+ : name {
+ $$.nl = 0;
+ $$.nn = 0;
+ lappend(&$$.nl, &$$.nn, $1);
+ }
+ | traitlist listsep name {
+ lappend(&$$.nl, &$$.nn, $3);
+ }
+ ;
+
decllist: declbody {
$$.loc = $1->loc; $$.nl = NULL; $$.nn = 0;
lappend(&$$.nl, &$$.nn, $1);
@@ -388,12 +442,22 @@ name : Tident {$$ = mkname($1->loc, $1->id);}
;
implstmt
- : Timpl name type optauxtypes {
+ : Timpl name type optauxtypes traitspec {
+ size_t i;
+
$$ = mkimplstmt($1->loc, $2, $3, $4.types, $4.ntypes, NULL, 0);
$$->impl.isproto = 1;
+ setwith($3, $5.spec, $5.nspec);
+ for (i = 0; i < $4.ntypes; i++)
+ setwith($4.types[i], $5.spec, $5.nspec);
}
- | Timpl name type optauxtypes Tasn Tendln implbody Tendblk {
- $$ = mkimplstmt($1->loc, $2, $3, $4.types, $4.ntypes, $7.nl, $7.nn);
+ | Timpl name type optauxtypes traitspec Tasn Tendln implbody Tendblk {
+ size_t i;
+
+ $$ = mkimplstmt($1->loc, $2, $3, $4.types, $4.ntypes, $8.nl, $8.nn);
+ setwith($3, $5.spec, $5.nspec);
+ for (i = 0; i < $4.ntypes; i++)
+ setwith($4.types[i], $5.spec, $5.nspec);
}
;
@@ -411,25 +475,32 @@ implbody
;
traitdef
- : Ttrait Tident generictype optauxtypes { /* trait prototype */
+ : Ttrait Tident generictype optauxtypes traitspec { /* trait prototype */
+ size_t i;
$$ = mktrait($1->loc,
mkname($2->loc, $2->id), $3,
$4.types, $4.ntypes,
NULL, 0,
1);
+ setwith($3, $5.spec, $5.nspec);
+ for (i = 0; i < $4.ntypes; i++)
+ setwith($4.types[i], $5.spec, $5.nspec);
}
- | Ttrait Tident generictype optauxtypes Tasn traitbody Tendblk /* trait definition */ {
+ | Ttrait Tident generictype optauxtypes traitspec Tasn traitbody Tendblk /* trait definition */ {
size_t i;
$$ = mktrait($1->loc,
mkname($2->loc, $2->id), $3,
$4.types, $4.ntypes,
- $6.nl, $6.nn,
+ $7.nl, $7.nn,
0);
- for (i = 0; i < $6.nn; i++) {
- $6.nl[i]->decl.trait = $$;
- $6.nl[i]->decl.impls = mkht(tyhash, tyeq);
- $6.nl[i]->decl.isgeneric = 1;
+ for (i = 0; i < $7.nn; i++) {
+ $7.nl[i]->decl.trait = $$;
+ $7.nl[i]->decl.impls = mkht(tyhash, tyeq);
+ $7.nl[i]->decl.isgeneric = 1;
}
+ setwith($3, $5.spec, $5.nspec);
+ for (i = 0; i < $4.ntypes; i++)
+ setwith($4.types[i], $5.spec, $5.nspec);
}
;
@@ -452,14 +523,14 @@ traitbody
;
-tydef : Ttype typeid {$$ = $2;}
- | Ttype typeid Tasn type {
+tydef : Ttype typeid traitspec {$$ = $2;}
+ | Ttype typeid traitspec Tasn type {
$$ = $2;
- if ($$.nparams == 0) {
- $$.type = mktyname($2.loc, mkname($2.loc, $2.name), $4);
- } else {
- $$.type = mktygeneric($2.loc, mkname($2.loc, $2.name), $2.params, $2.nparams, $4);
- }
+ if ($$.nparams == 0)
+ $$.type = mktyname($2.loc, mkname($2.loc, $2.name), $5);
+ else
+ $$.type = mktygeneric($2.loc, mkname($2.loc, $2.name), $2.params, $2.nparams, $5);
+ setwith($$.type, $3.spec, $3.nspec);
}
;
@@ -498,35 +569,17 @@ type : structdef
generictype
: Ttyparam {$$ = mktyparam($1->loc, $1->id);}
- | Ttyparam Twith name {
- $$ = mktyparam($1->loc, $1->id);
- lappend(&$$->traits, &$$->ntraits, $3);
- }
- | Ttyparam Twith Toparen typaramlist Tcparen {
- size_t i;
- $$ = mktyparam($1->loc, $1->id);
- for (i = 0; i < $4.nn; i++)
- lappend(&$$->traits, &$$->ntraits, $4.nl[i]);
- }
- ;
-
-typaramlist
- : name {
- $$.nl = NULL; $$.nn = 0;
- lappend(&$$.nl, &$$.nn, $1);
- }
- | typaramlist listsep name {lappend(&$$.nl, &$$.nn, $3);}
;
compoundtype
- : functype {$$ = $1;}
- | type Tosqbrac Tcolon Tcsqbrac {$$ = mktyslice($2->loc, $1);}
- | type Tosqbrac expr Tcsqbrac {$$ = mktyarray($2->loc, $1, $3);}
- | type Tosqbrac Tellipsis Tcsqbrac {$$ = mktyarray($2->loc, $1, NULL);}
- | name Toparen typelist Tcparen {$$ = mktyunres($1->loc, $1, $3.types, $3.ntypes);}
- | type Tderef {$$ = mktyptr($2->loc, $1);}
- | Tvoidlit {$$ = mktyunres($1->loc, mkname($1->loc, $1->id), NULL, 0);}
- | name {$$ = mktyunres($1->loc, $1, NULL, 0);}
+ : functype {$$ = $1;}
+ | type Tosqbrac Tcolon Tcsqbrac {$$ = mktyslice($2->loc, $1);}
+ | type Tosqbrac expr Tcsqbrac {$$ = mktyarray($2->loc, $1, $3);}
+ | type Tosqbrac Tellipsis Tcsqbrac {$$ = mktyarray($2->loc, $1, NULL);}
+ | name Toparen typelist Tcparen {$$ = mktyunres($1->loc, $1, $3.types, $3.ntypes);}
+ | type Tderef {$$ = mktyptr($2->loc, $1);}
+ | Tvoidlit {$$ = mktyunres($1->loc, mkname($1->loc, $1->id), NULL, 0);}
+ | name {$$ = mktyunres($1->loc, $1, NULL, 0);}
;
functype: Toparen funcsig Tcparen {$$ = $2;}
@@ -826,11 +879,13 @@ obrace : Tobrace {
}
;
-funclit : obrace params Tendln blkbody Tcbrace {
+funclit : obrace params traitspec Tendln blkbody Tcbrace {
size_t i;
Node *fn, *lit;
- $$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($3->loc), $4);
+ for (i = 0; i < $2.nn; i++)
+ setwith($2.nl[i]->decl.type, $3.spec, $3.nspec);
+ $$ = mkfunc($1->loc, $2.nl, $2.nn, mktyvar($4->loc), $5);
fn = $$->lit.fnval;
for (i = 0; i < nlbls[lbldepth]; i++) {
lit = lbls[lbldepth][i]->expr.args[0];
@@ -840,11 +895,14 @@ funclit : obrace params Tendln blkbody Tcbrace {
assert(lbldepth >= 0);
lbldepth--;
}
- | obrace params Tret type Tendln blkbody Tcbrace {
+ | obrace params Tret type traitspec Tendln blkbody Tcbrace {
size_t i;
Node *fn, *lit;
- $$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $6);
+ setwith($4, $5.spec, $5.nspec);
+ for (i = 0; i < $2.nn; i++)
+ setwith($2.nl[i]->decl.type, $5.spec, $5.nspec);
+ $$ = mkfunc($1->loc, $2.nl, $2.nn, $4, $7);
fn = $$->lit.fnval;
for (i = 0; i < nlbls[lbldepth]; i++) {
lit = lbls[lbldepth][i]->expr.args[0];
@@ -1056,7 +1114,8 @@ label : Tcolon Tident {
%%
-static void setupinit(Node *n)
+static void
+setupinit(Node *n)
{
char name[1024];
char *p, *s;
@@ -1078,7 +1137,8 @@ static void setupinit(Node *n)
n->decl.name->name.name = strdup(s);
}
-static Node *mkpseudodecl(Srcloc l, Type *t)
+static Node *
+mkpseudodecl(Srcloc l, Type *t)
{
static int nextpseudoid;
char buf[128];
@@ -1087,7 +1147,8 @@ static Node *mkpseudodecl(Srcloc l, Type *t)
return mkdecl(l, mkname(l, buf), t);
}
-static void setattrs(Node *dcl, char **attrs, size_t nattrs)
+static void
+setattrs(Node *dcl, char **attrs, size_t nattrs)
{
size_t i;
@@ -1101,7 +1162,51 @@ static void setattrs(Node *dcl, char **attrs, size_t nattrs)
}
}
-static void installucons(Stab *st, Type *t)
+static void
+setwith(Type *ty, Traitspec **ts, size_t nts)
+{
+ size_t i, j;
+
+ if (!ty)
+ return;
+ for (i = 0; i < nts; i++) {
+ switch (ty->type) {
+ case Typaram:
+ if (tyeq(ty, ts[i]->param))
+ lappend(&ty->spec, &ty->nspec, ts[i]);
+
+ break;
+ case Tyname:
+ case Tyunres:
+ for (j = 0; j < ty->ngparam; j++)
+ setwith(ty->gparam[j], ts, nts);
+ for (j = 0; j < ty->narg; j++)
+ setwith(ty->arg[j], ts, nts);
+ break;
+ case Tystruct:
+ for (j = 0; j < ty->nmemb; j++)
+ setwith(ty->sdecls[j]->decl.type, ts, nts);
+ break;
+ case Tyunion:
+ for (j = 0; j < ty->nmemb; j++)
+ setwith(ty->udecls[j]->etype, ts, nts);
+ break;
+ case Typtr:
+ case Tyarray:
+ case Tyslice:
+ case Tyfunc:
+ case Tytuple:
+ for (j = 0; j < ty->nsub; j++)
+ setwith(ty->sub[j], ts, nts);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+installucons(Stab *st, Type *t)
{
Type *b;
size_t i;
@@ -1127,7 +1232,8 @@ static void installucons(Stab *st, Type *t)
}
-static Op binop(int tt)
+static Op
+binop(int tt)
{
Op o;
diff --git a/parse/infer.c b/parse/infer.c
index 55628a5..daa071e 100644
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -35,7 +35,9 @@ static void inferexpr(Node **np, Type *ret, int *sawret);
static void inferdecl(Node *n);
static int tryconstrain(Type *ty, Trait *tr, int update);
+static Type *tyfreshen(Tysubst *subst, Type *orig);
static Type *tf(Type *t);
+static Type *basetype(Type *a);
static Type *unify(Node *ctx, Type *a, Type *b);
static Type *tyfix(Node *ctx, Type *orig, int noerr);
@@ -66,7 +68,6 @@ static Node **specializations;
static size_t nspecializations;
static Stab **specializationscope;
static size_t nspecializationscope;
-static Htab *seqbase;
static Traitmap *traitmap;
static void
@@ -279,6 +280,7 @@ additerspecialization(Node *n, Stab *stab)
ty = exprtype(n->iterstmt.seq);
if (ty->type == Tyslice || ty->type == Tyarray || ty->type == Typtr)
return;
+ ty = tyfreshen(NULL, ty);
for (i = 0; i < tr->nproto; i++) {
ty = exprtype(n->iterstmt.seq);
if (hthas(tr->proto[i]->decl.impls, ty))
@@ -462,27 +464,32 @@ needfreshen(Type *t)
static Type *
tyfreshen(Tysubst *subst, Type *orig)
{
- Type *t;
+ Type *ty, *base;
if (!needfreshen(orig))
return orig;
pushenv(orig->env);
if (!subst) {
subst = mksubst();
- t = tyspecialize(orig, subst, delayed, seqbase);
+ ty = tyspecialize(orig, subst, delayed, seqbase);
substfree(subst);
} else {
- t = tyspecialize(orig, subst, delayed, seqbase);
+ ty = tyspecialize(orig, subst, delayed, seqbase);
}
+ ty->spec = orig->spec;
+ ty->nspec = orig->nspec;
+ base = basetype(ty);
+ if (base)
+ htput(seqbase, ty, base);
popenv(orig->env);
- return t;
+ return ty;
}
/* Resolves a type and all its subtypes recursively. */
static void
tyresolve(Type *t)
{
- size_t i;
+ size_t i, j;
Trait *tr;
if (t->resolved)
@@ -526,13 +533,16 @@ tyresolve(Type *t)
break;
}
- for (i = 0; i < t->ntraits; i++) {
- tr = gettrait(curstab(), t->traits[i]);
- if (!tr)
- lfatal(t->loc, "trait %s does not exist", ctxstr(t->traits[i]));
- if (!t->trneed)
- t->trneed = mkbs();
- bsput(t->trneed, tr->uid);
+ for (i = 0; i < t->nspec; i++) {
+ for (j = 0; j < t->spec[i]->ntrait; j++) {
+ tr = gettrait(curstab(), t->spec[i]->trait[j]);
+ if (!tr)
+ lfatal(t->loc, "trait %s does not exist", ctxstr(t->spec[i]->trait[j]));
+ if (!t->trneed)
+ t->trneed = mkbs();
+ bsput(t->trneed, tr->uid);
+ htput(seqbase, t, t->spec[i]->aux);
+ }
}
for (i = 0; i < t->nsub; i++) {
@@ -597,9 +607,8 @@ tysubstmap(Tysubst *subst, Type *t, Type *orig)
{
size_t i;
- for (i = 0; i < t->ngparam; i++) {
+ for (i = 0; i < t->ngparam; i++)
substput(subst, t->gparam[i], tf(orig->arg[i]));
- }
t = tyfreshen(subst, t);
return t;
}
@@ -628,7 +637,9 @@ tf(Type *orig)
t = tylookup(orig);
isgeneric = t->type == Tygeneric;
ingeneric += isgeneric;
+ pushenv(orig->env);
tyresolve(t);
+ popenv(orig->env);
/* If this is an instantiation of a generic type, we want the params to
* match the instantiation */
if (orig->type == Tyunres && t->type == Tygeneric) {
@@ -1919,7 +1930,7 @@ specializeimpl(Node *n)
fatal(n, "%s incompatibly specialized with %zd types instead of %zd types",
namestr(n->impl.traitname), n->impl.naux, tr->naux);
n->impl.type = tf(n->impl.type);
- pushenv(n->impl.type->env);
+ pushenv(n->impl.env);
for (i = 0; i < n->impl.naux; i++)
n->impl.aux[i] = tf(n->impl.aux[i]);
for (i = 0; i < n->impl.ndecls; i++) {
@@ -1986,7 +1997,7 @@ specializeimpl(Node *n)
if (generic)
ingeneric--;
}
- popenv(n->impl.type->env);
+ popenv(n->impl.env);
}
static void
@@ -2049,7 +2060,7 @@ infernode(Node **np, Type *ret, int *sawret)
{
size_t i, nbound;
Node **bound, *n, *pat;
- Type *t, *b;
+ Type *t, *b, *e;
n = *np;
if (!n)
@@ -2115,12 +2126,15 @@ infernode(Node **np, Type *ret, int *sawret)
infernode(&n->iterstmt.seq, NULL, sawret);
infernode(&n->iterstmt.body, ret, sawret);
- b = mktyvar(n->loc);
- t = mktyvar(n->loc);
- htput(seqbase, t, b);
- constrain(n, type(n->iterstmt.seq), traittab[Tciter]);
- unify(n, type(n->iterstmt.seq), t);
- unify(n, type(n->iterstmt.elt), b);
+ e = type(n->iterstmt.elt);
+ t = type(n->iterstmt.seq);
+ constrain(n, t, traittab[Tciter]);
+ b = basetype(t);
+ if (b)
+ unify(n, e, b);
+ else
+ htput(seqbase, t, e);
+ delayedcheck(n, curstab());
break;
case Nmatchstmt:
infernode(&n->matchstmt.val, NULL, sawret);
@@ -2365,6 +2379,43 @@ checkvar(Node *n, Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope
}
static void
+fixiter(Node *n, Type *ty, Type *base)
+{
+ size_t i, bestidx;
+ int r, bestrank;
+ Type *b, *t, *orig;
+ Tysubst *ts;
+ Node *impl;
+
+ ty = tysearch(ty);
+ b = htget(seqbase, ty);
+ if (!b)
+ return;
+ bestrank = -1;
+ bestidx = 0;
+ for (i = 0; i < nimpltab; i++) {
+ if (impltab[i]->impl.trait != traittab[Tciter])
+ continue;
+ r = tymatchrank(impltab[i]->impl.type, ty);
+ if (r > bestrank) {
+ bestrank = r;
+ bestidx = i;
+ }
+ }
+ if (bestrank >= 0) {
+ impl = impltab[bestidx];
+ orig = impl->impl.type;
+ t = tf(impl->impl.aux[0]);
+ ts = mksubst();
+ for (i = 0; i < ty->narg; i++)
+ substput(ts, tf(orig->arg[i]), ty->arg[i]);
+ t = tyfreshen(ts, t);
+ substfree(ts);
+ unify(n, t, base);
+ }
+}
+
+static void
postcheckpass(Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
{
size_t i;
@@ -2373,12 +2424,16 @@ postcheckpass(Node ***rem, size_t *nrem, Stab ***remscope, size_t *nremscope)
for (i = 0; i < npostcheck; i++) {
n = postcheck[i];
pushstab(postcheckscope[i]);
- switch (exprop(n)) {
- case Omemb: infercompn(n, rem, nrem, remscope, nremscope); break;
- case Ocast: checkcast(n, rem, nrem, remscope, nremscope); break;
- case Ostruct: checkstruct(n, rem, nrem, remscope, nremscope); break;
- case Ovar: checkvar(n, rem, nrem, remscope, nremscope); break;
- default: die("should not see %s in postcheck\n", opstr[exprop(n)]);
+ if (n->type == Nexpr) {
+ switch (exprop(n)) {
+ case Omemb: infercompn(n, rem, nrem, remscope, nremscope); break;
+ case Ocast: checkcast(n, rem, nrem, remscope, nremscope); break;
+ case Ostruct: checkstruct(n, rem, nrem, remscope, nremscope); break;
+ case Ovar: checkvar(n, rem, nrem, remscope, nremscope); break;
+ default: die("should not see %s in postcheck\n", opstr[exprop(n)]);
+ }
+ } else if (n->type == Niterstmt) {
+ fixiter(n, type(n->iterstmt.seq), type(n->iterstmt.elt));
}
popstab();
}
@@ -2405,7 +2460,6 @@ postinfer(void)
postcheckscope = remscope;
npostcheckscope = nremscope;
}
- postcheckpass(NULL, NULL, NULL, NULL);
}
/* After inference, replace all
@@ -2588,7 +2642,8 @@ typesub(Node *n, int noerr)
typesub(n->iterstmt.elt, noerr);
typesub(n->iterstmt.seq, noerr);
typesub(n->iterstmt.body, noerr);
- additerspecialization(n, curstab());
+ if (!ingeneric)
+ additerspecialization(n, curstab());
break;
case Nmatchstmt:
typesub(n->matchstmt.val, noerr);
@@ -2687,6 +2742,8 @@ specialize(void)
tr = traittab[Tciter];
assert(tr->nproto == 2);
ty = exprtype(n->iterstmt.seq);
+ if (ty->type == Typaram)
+ continue;
it = itertype(n->iterstmt.seq, mktype(n->loc, Tybool));
d = specializedcl(tr->proto[0], ty, it, &name);
@@ -2782,10 +2839,10 @@ findtrait(Node *impl)
tr = gettrait(ns, n);
if (!tr)
fatal(impl, "trait %s does not exist near %s",
- namestr(impl->impl.traitname), ctxstr(impl));
+ namestr(impl->impl.traitname), ctxstr(impl));
if (tr->naux != impl->impl.naux)
fatal(impl, "incompatible implementation of %s: mismatched aux types",
- namestr(impl->impl.traitname), ctxstr(impl));
+ namestr(impl->impl.traitname), ctxstr(impl));
}
return tr;
}
@@ -2849,6 +2906,7 @@ initimpl(void)
Type *ty;
pushstab(file->file.globls);
+ seqbase = mkht(tyhash, tyeq);
traitmap = zalloc(sizeof(Traitmap));
builtintraits();
for (i = 0; i < nimpltab; i++) {
@@ -2898,7 +2956,6 @@ void
infer(void)
{
delayed = mkht(tyhash, tyeq);
- seqbase = mkht(tyhash, tyeq);
loaduses();
initimpl();
diff --git a/parse/node.c b/parse/node.c
index 6e9a8ce..e4332f9 100644
--- a/parse/node.c
+++ b/parse/node.c
@@ -264,6 +264,9 @@ mkimplstmt(Srcloc loc, Node *name, Type *t, Type **aux, size_t naux, Node **decl
n->impl.env = mkenv();
bindtype(n->impl.env, t);
}
+ for (i = 0; i < naux; i++)
+ if (hasparams(aux[i]))
+ bindtype(n->impl.env, aux[i]);
return n;
}
diff --git a/parse/parse.h b/parse/parse.h
index 0bae957..7ac4b05 100644
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -1,7 +1,8 @@
-#define Abiversion 14
+#define Abiversion 15
typedef struct Srcloc Srcloc;
typedef struct Tysubst Tysubst;
+typedef struct Traitspec Traitspec;
typedef struct Tok Tok;
typedef struct Node Node;
@@ -118,6 +119,13 @@ struct Tyenv {
Htab *tab;
};
+struct Traitspec {
+ Node **trait;
+ size_t ntrait;
+ Type *param;
+ Type *aux;
+};
+
struct Type {
Ty type;
uint32_t tid;
@@ -125,8 +133,10 @@ struct Type {
Vis vis;
- Node **traits; /* trait list */
- size_t ntraits; /* trait list size */
+ Traitspec **spec;
+ size_t nspec;
+ //Node **traits; /* trait list */
+ //size_t ntraits; /* trait list size */
Type **gparam; /* Tygeneric: type parameters that match the type args */
size_t ngparam; /* Tygeneric: count of type parameters */
@@ -367,6 +377,7 @@ extern Node **nodes; /* node id -> node map */
extern size_t ndecls;
extern Node **exportimpls;
extern size_t nexportimpls;
+extern Htab *seqbase;
/* property tables */
extern int opispure[];
diff --git a/parse/specialize.c b/parse/specialize.c
index 74af0e9..a9d8ee4 100644
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -14,6 +14,7 @@
#include "parse.h"
static Node *specializenode(Node *g, Tysubst *tsmap);
+static void fillsubst(Tysubst *tsmap, Type *to, Type *from);
static void
substpush(Tysubst *subst)
@@ -84,8 +85,9 @@ Type *
tyspecialize(Type *orig, Tysubst *tsmap, Htab *delayed, Htab *trbase)
{
Type *t, *ret, *tmp, *var, *base;
- Type **arg;
+ Traitspec *ts;
size_t i, narg;
+ Type **arg;
t = tysearch(orig);
tmp = substget(tsmap, t);
@@ -98,6 +100,20 @@ tyspecialize(Type *orig, Tysubst *tsmap, Htab *delayed, Htab *trbase)
ret = mktyvar(t->loc);
ret->trneed = bsdup(t->trneed);
substput(tsmap, t, ret);
+ for (i = 0; i < t->nspec; i++) {
+ ts = zalloc(sizeof(Traitspec));
+ ts->trait = t->spec[i]->trait;
+ ts->ntrait = t->spec[i]->ntrait;
+ ts->param = tyspecialize(t->spec[i]->param, tsmap, delayed, trbase);
+ if (t->spec[i]->aux)
+ ts->aux = tyspecialize(t->spec[i]->aux, tsmap, delayed, trbase);
+ lappend(&ret->spec, &ret->nspec, ts);
+ }
+ tmp = htget(seqbase, t);
+ if (tmp) {
+ tmp = tyspecialize(tmp, tsmap, delayed, trbase);
+ htput(trbase, ret, tmp);
+ }
break;
case Tygeneric:
var = mktyvar(t->loc);
@@ -186,6 +202,26 @@ tysubst(Type *t, Tysubst *tsmap)
return t;
}
+static void
+substputspec(Tysubst *tsmap, Type *from, Type *to)
+{
+ size_t ai, aj, bi, bj;
+
+ for (ai = 0; ai < from->nspec; ai++) {
+ for (aj = 0; aj < from->spec[ai]->ntrait; aj++) {
+ for (bi = 0; bi < to->nspec; bi++) {
+ for (bj = 0; bj < to->spec[bi]->ntrait; bj++) {
+ if (nameeq(from->spec[ai]->trait[aj], to->spec[bi]->trait[bj]))
+ fillsubst(tsmap, to->spec[ai]->aux, from->spec[bi]->aux);
+ }
+ }
+ if (nameeq(from->spec[ai]->trait[aj], traittab[Tciter]->name))
+ if (to->type == Tyslice || to->type == Tyarray)
+ fillsubst(tsmap, to->sub[0], from->spec[ai]->aux);
+ }
+ }
+}
+
/*
* Fills the substitution map with a mapping from
* the type parameter 'from' to it's substititon 'to'
@@ -199,6 +235,7 @@ fillsubst(Tysubst *tsmap, Type *to, Type *from)
if (debugopt['S'])
printf("mapping %s => %s\n", tystr(from), tystr(to));
substput(tsmap, from, to);
+ substputspec(tsmap, from, to);
return;
}
assert(to->nsub == from->nsub);
diff --git a/parse/stab.c b/parse/stab.c
index 1d89238..2d190d9 100644
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -671,6 +671,9 @@ bindtype_rec(Tyenv *e, Type *t, Bitset *visited)
tytab[t->tid] = tt;
else if (!boundtype(t))
htput(e->tab, t, t);
+ for (i = 0; i < t->nspec; i++)
+ if (t->spec[i]->aux)
+ bindtype_rec(e, t->spec[i]->aux, visited);
break;
case Tygeneric:
for (i = 0; i < t->ngparam; i++)
diff --git a/parse/type.c b/parse/type.c
index c31fbbe..de7237f 100644
--- a/parse/type.c
+++ b/parse/type.c
@@ -24,6 +24,7 @@ size_t ntraittab;
Node **impltab;
size_t nimpltab;
Htab *eqcache;
+Htab *seqbase;
struct Typair {
uint32_t atid;
diff --git a/parse/use.c b/parse/use.c
index 7c7d48b..906e59b 100644
--- a/parse/use.c
+++ b/parse/use.c
@@ -218,7 +218,7 @@ rdsym(FILE *fd, Trait *ctx)
static void
typickle(FILE *fd, Type *ty)
{
- size_t i;
+ size_t i, j;
if (!ty) {
die("trying to pickle null type\n");
@@ -226,6 +226,16 @@ typickle(FILE *fd, Type *ty)
}
wrbyte(fd, ty->type);
wrbyte(fd, ty->vis);
+ wrint(fd, ty->nspec);
+ for (i = 0; i < ty->nspec; i++) {
+ wrint(fd, ty->spec[i]->ntrait);
+ for (j = 0; j < ty->spec[i]->ntrait; j++)
+ pickle(fd, ty->spec[i]->trait[j]);
+ wrtype(fd, ty->spec[i]->param);
+ wrbool(fd, ty->spec[i]->aux != NULL);
+ if (ty->spec[i]->aux)
+ wrtype(fd, ty->spec[i]->aux);
+ }
wrint(fd, ty->nsub);
switch (ty->type) {
case Tyunres:
@@ -350,7 +360,7 @@ rdtrait(FILE *fd, Trait **dest, Type *ty)
static Type *
tyunpickle(FILE *fd)
{
- size_t i, n;
+ size_t i, j, n;
Type *ty;
Ty t;
@@ -359,6 +369,19 @@ tyunpickle(FILE *fd)
ty->isimport = 1;
if (rdbyte(fd) == Vishidden)
ty->ishidden = 1;
+ ty->nspec = rdint(fd);
+ ty->spec = malloc(ty->nspec * sizeof(Traitspec*));
+ for (i = 0; i < ty->nspec; i++) {
+ ty->spec[i] = zalloc(sizeof(Traitspec));
+ n = rdint(fd);
+ ty->spec[i]->ntrait = n;
+ ty->spec[i]->trait = malloc(n * sizeof(Node*));
+ for (j = 0; j < ty->spec[i]->ntrait; j++)
+ ty->spec[i]->trait[j] = unpickle(fd);
+ rdtype(fd, &ty->spec[i]->param);
+ if (rdbool(fd))
+ rdtype(fd, &ty->spec[i]->aux);
+ }
ty->nsub = rdint(fd);
if (ty->nsub > 0)
ty->sub = zalloc(ty->nsub * sizeof(Type *));