diff options
| author | 2022-08-04 15:46:32 +0200 | |
|---|---|---|
| committer | 2022-08-04 15:46:32 +0200 | |
| commit | d104761e3c213504f5a6dfb63059fc905fe6799f (patch) | |
| tree | 5b51d3147ce0506d331e89874033af0d4eb260e3 | |
| parent | 8a5bde697364ca301c14471196d137c3a53c25fa (diff) | |
enum
| -rw-r--r-- | bootstrap/all.h | 26 | ||||
| -rw-r--r-- | bootstrap/cgen.c | 30 | ||||
| -rw-r--r-- | bootstrap/dump.c | 1 | ||||
| -rw-r--r-- | bootstrap/fold.c | 48 | ||||
| -rw-r--r-- | bootstrap/parse.c | 210 | ||||
| -rw-r--r-- | bootstrap/test.cff | 25 | ||||
| -rw-r--r-- | bootstrap/types.c | 6 |
7 files changed, 303 insertions, 43 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h index 762e978..cb221da 100644 --- a/bootstrap/all.h +++ b/bootstrap/all.h @@ -30,12 +30,14 @@ struct span { /* must be alpha sorted */ #define LIST_KEYWORDS(_) \ _(and) \ + _(as) \ _(break) \ _(case) \ _(const) \ _(defmacro) \ _(do) \ _(else) \ + _(enum) \ _(extern) \ _(fn) \ _(for) \ @@ -45,9 +47,11 @@ struct span { _(or) \ _(return) \ _(static) \ + _(struct) \ _(switch) \ _(typedef) \ _(typeof) \ + _(union) \ _(while) enum toktype { @@ -64,7 +68,6 @@ enum toktype { TKmacident, TKgensym, TKeof, - NUM_LEXTOKENS }; #define NUM_KEYWORDS TKintlit @@ -119,6 +122,8 @@ struct parser { int idx; } *curexpan; // macro expansions int expanno; + const struct type *targty; + bool used_targetty; }; enum typetype { @@ -130,6 +135,7 @@ enum typetype { TYarr, TYslice, TYfn, + TYenum, }; struct type { @@ -147,8 +153,17 @@ struct type { const struct type *retty; bool variadic; } fn; + struct { + const struct type *intty; + const char *name; + slice_t(struct enumfield { + const char *name; + i64 i; + }) vals; + int id; + } enu; }; - // cgen.c (mutated later, not hashed or involved in equality) + // for cgen.c hack (mutated later, not hashed or involved in equality) const char *_cname; }; @@ -225,6 +240,8 @@ enum exprtype { Ecall, Eindex, Eblock, + Eas, + Eenumval, }; struct blockstmt { @@ -266,6 +283,11 @@ struct expr { struct expr *lhs, *rhs; } index; struct blockstmt block; + struct expr *child; // cast + struct { + i64 i; + const char *vname; + } enu; }; }; diff --git a/bootstrap/cgen.c b/bootstrap/cgen.c index 4bc6280..aac0893 100644 --- a/bootstrap/cgen.c +++ b/bootstrap/cgen.c @@ -27,13 +27,13 @@ gentype(const struct type *ty) { case TYarr: assert(ty->length >= 0); case TYslice: - assert(ty->_cname); - pri("%s", ty->_cname); - return; case TYfn: assert(ty->_cname); pri("%s", ty->_cname); return; + case TYenum: + gentype(ty->enu.intty); + break; } if (ty->konst) pri(" const"); @@ -97,7 +97,8 @@ pri(const char *fmt, ...) { fprintf(outfp, "%.20f", va_arg(ap, double)); break; case 's': - fprintf(outfp, "%s", va_arg(ap, const char *)); + S = va_arg(ap, const char *); + fprintf(outfp, "%s", S ? S : "(null)"); break; case 'w': ws = va_arg(ap, int); @@ -130,6 +131,7 @@ genexpr(struct expr *ex) { const struct type *ty = unconstify(ex->ty); switch (ex->t) { case Eintlit: + intlit: if (ty == ty_int) pri("%I", ex->i); else if (ty == ty_u64) @@ -184,8 +186,14 @@ genexpr(struct expr *ex) { genblock(ex->block); pri(")"); break; - default: - assert(0); + case Eas: + pri("((%t)%e)", ex->ty, ex->child); + break; + case Eenumval: + pri("/*%s:%s*/", ex->ty->enu.name, ex->enu.vname); + ty = ex->ty->enu.intty; + goto intlit; + break; } } @@ -292,6 +300,7 @@ liftnestedex(struct expr *ex) { switch (ex->t) { case Eintlit: case Eflolit: case Estrlit: case Eboolit: case Enullit: case Ename: + case Eenumval: break; case Eprefix: liftnestedex(ex->unop.child); @@ -320,8 +329,9 @@ liftnestedex(struct expr *ex) { case Eblock: liftnested(blocktostmt(ex->block)); break; - default: - assert(0); + case Eas: + liftnestedex(ex->child); + break; } } @@ -484,9 +494,9 @@ defctype(const struct type *ty, void *_) { if (ty->fn.variadic) pri("..."); pri(");\n"); - - break; + case TYenum: + *cname = xasprintf("__ty%d", id++); } } diff --git a/bootstrap/dump.c b/bootstrap/dump.c index 4b337b7..d01f4a7 100644 --- a/bootstrap/dump.c +++ b/bootstrap/dump.c @@ -41,6 +41,7 @@ pritype(const struct type *ty) { if (ty->fn.variadic) pri("..."); pri(") %t", ty->fn.retty); + case TYenum: } } diff --git a/bootstrap/fold.c b/bootstrap/fold.c index dfd6509..f7962d4 100644 --- a/bootstrap/fold.c +++ b/bootstrap/fold.c @@ -12,8 +12,8 @@ numcast(struct expr *ex, const struct type *to) { const struct type *ufrom = unconstify(from); int size = to->size; bool sgn = to->int_signed; - assert(t0 == TYint || t0 == TYfloat || t0 == TYbool); - assert(t1 == TYint || t1 == TYfloat || t1 == TYbool); + assert(t0 == TYint || t0 == TYfloat || t0 == TYbool || t0 == TYenum); + assert(t1 == TYint || t1 == TYfloat || t1 == TYbool || t1 == TYenum); if (ufrom == uto) /* pass */; @@ -201,13 +201,50 @@ findex(struct expr *ex) { free(r); } +static void +trysetenumvname(struct expr *ex) { + const struct type *t = ex->ty; + for (int i = 0; i < t->enu.vals.n; ++i) + if (ex->enu.i == t->enu.vals.d[i].i) { + ex->enu.vname = t->enu.vals.d[i].name; + break; + } +} + +static void +fas(struct expr *ex) { + struct expr *child = ex->child; + const struct type *to = ex->ty, + *from = child->ty; + + if (!fold(child)) + return; + if (!isnumtype(to) && to->t != TYenum) + return; + ex->i = child->i; + if (from->t == TYenum) { + child->ty = child->ty->enu.intty; + } + ex->ty = child->ty; + ex->i = child->i; + if (to->t == TYenum) { + numcast(ex, to->enu.intty); + ex->ty = to; + ex->t = Eenumval; + trysetenumvname(ex); + } else { + numcast(ex, to); + } + free(child); +} + int fold(struct expr *ex) { switch (ex->t) { case Eintlit: case Eflolit: case Eboolit: numcast(ex, ex->ty); return 1; - case Estrlit:case Enullit: + case Estrlit:case Enullit: case Eenumval: return 1; case Eprefix: funary(ex); @@ -221,13 +258,16 @@ fold(struct expr *ex) { case Eindex: findex(ex); break; + case Eas: + fas(ex); + break; default: break; } switch (ex->t) { case Eintlit: case Eflolit: case Estrlit: - case Eboolit: case Enullit: + case Eboolit: case Enullit: case Eenumval: return 1; default: return 0; diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 3cb6924..0804a73 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -1,4 +1,7 @@ #include "all.h" +#include "vec.h" +#include <stdint.h> +#include <strings.h> /***********/ /** Lexer **/ @@ -81,7 +84,7 @@ aissep(char c) { case ';': case '?': case '+': case '-': case '*': case '/': case '&': case '|': case '^': case '~': case '=': case '\'': - case '"': case '<': case '>': + case '"': case '<': case '>': case ':': return 1; return 0; } @@ -139,7 +142,7 @@ str2keyword(const char *s) { } static bool -str2number(struct tok *res, const char *s) { +readnumber(struct tok *res, const char *s) { char c; u64 acc = 0; double accf = 0.0; @@ -147,6 +150,7 @@ str2number(struct tok *res, const char *s) { int base = 10; bool flt = 0; int nused = 0; + const char *suffix = NULL; for (int i = 0; (c = s[i]); ++i) { extern int tolower(int); @@ -167,10 +171,11 @@ str2number(struct tok *res, const char *s) { if (nused > 0 && c == '_') continue; - if (base == 16 && !aisxdigit(c)) - return 0; - else if (base != 16 && (c < '0' || c > '0' + base - 1)) - return 0; + if ((base == 16 && !aisxdigit(c)) + || (base != 16 && (c < '0' || c > '0' + base - 1))) { + suffix = s + i; + break; + } ++nused; if (flt) { @@ -185,9 +190,29 @@ str2number(struct tok *res, const char *s) { if (flt) { res->t = TKflolit; res->flit.f = accf; + + if (!suffix) ; + else if (!strcasecmp(suffix, "f")) res->flit.ty = ty_f32; + else if (!strcasecmp(suffix, "f32")) res->flit.ty = ty_f32; + else if (!strcasecmp(suffix, "f64")) res->flit.ty = ty_f64; } else { res->t = TKintlit; res->ilit.i = acc; + + if (!suffix) ; + else if (!strcasecmp(suffix, "u")) res->ilit.ty = ty_uint; + else if (!strcasecmp(suffix , "u8")) res->ilit.ty = ty_u8; + else if (!strcasecmp(suffix , "i8")) res->ilit.ty = ty_i8; + else if (!strcasecmp(suffix, "u16")) res->ilit.ty = ty_u16; + else if (!strcasecmp(suffix, "i16")) res->ilit.ty = ty_i16; + else if (!strcasecmp(suffix, "u32")) res->ilit.ty = ty_u32; + else if (!strcasecmp(suffix, "i32")) res->ilit.ty = ty_i32; + else if (!strcasecmp(suffix, "u64")) res->ilit.ty = ty_u64; + else if (!strcasecmp(suffix, "i64")) res->ilit.ty = ty_i64; + else if (!strcasecmp(suffix, "z")) res->ilit.ty = ty_usize; + else if (!strcasecmp(suffix, "zs")) res->ilit.ty = ty_isize; + else if (!strcasecmp(suffix, "p")) res->ilit.ty = ty_uptrint; + else if (!strcasecmp(suffix, "ps")) res->ilit.ty = ty_iptrint; } return 1; } @@ -294,7 +319,7 @@ lex(struct parser *P) { if (readtilsep(P, s, sizeof s, 1) < 0) fatal(P, P->tokspan, "number literal too long"); - if (!str2number(&tok, s)) + if (!readnumber(&tok, s)) fatal(P, P->tokspan, "invalid number literal"); tok.span = P->tokspan; return tok; @@ -555,7 +580,7 @@ parsetype(struct parser *P) { } static const struct type * -ilittype(struct parser *P, u64 n) { +ilittype(u64 n) { if (n <= INT_MAX) return ty_int; if (n <= INT32_MAX) @@ -606,11 +631,13 @@ pexprimary(struct parser *P) { struct expr ex = {0}; struct tok tok; + P->used_targetty = 0; + if (lexmatch(P, &tok, TKintlit) || lexmatch(P, &tok, TKchrlit)) { ex.t = Eintlit; ex.span = tok.span; ex.i = tok.ilit.i; - ex.ty = tok.ilit.ty ? tok.ilit.ty : ilittype(P, ex.u); + ex.ty = tok.ilit.ty ? tok.ilit.ty : ilittype(ex.u); } else if (lexmatch(P, &tok, TKflolit)) { ex.t = Eflolit; ex.span = tok.span; @@ -647,10 +674,17 @@ pexprimary(struct parser *P) { if (!decl) fatal(P, tok.span, "%s is not defined", tok2str(tok)); if (decl->t == Dtype) { - assert(0); + const struct type *ty = decl->ty; + if (ty->t == TYenum) { + lexexpect(P, ':'); + P->targty = ty; + goto enumlit; + } else { + goto experr; + } } else if (decl->t == Dmacro) { parseexpandmacro(P, &decl->macro); - return parseexpr(P); + ex = parseexpr(P); } else { ex.t = Ename; ex.span = tok.span; @@ -685,9 +719,29 @@ pexprimary(struct parser *P) { ex = parseexpr(P); } lexexpect(P, ')'); + } else if (lexmatch(P, &tok, ':')) { + const char *vname; + int i; + enumlit: + vname = (tok = lexexpect(P, TKident)).str; + if (!(ex.ty = P->targty) || ex.ty->t != TYenum) + fatal(P, tok.span, "cannot infer type for enum literal `:%s'", vname); + for (i = 0; i < ex.ty->enu.vals.n; ++i) + if (!strcmp(ex.ty->enu.vals.d[i].name, vname)) + goto found; + fatal(P, tok.span, "enum `%s' contains no variant `%s'", + ex.ty->enu.name, vname); + found: + P->used_targetty = 1; + ex.t = Eenumval; + ex.enu.vname = vname; + ex.enu.i = ex.ty->enu.vals.d[i].i; } else { + experr: fatal(P, tok.span, "expected expression (near %s)", tok2str(tok)); } + + P->targty = NULL; return ex; } @@ -696,6 +750,8 @@ pexpostfix(struct parser *P) { struct expr ex = pexprimary(P); struct tok tok; + if (P->used_targetty) return ex; + for (;;) if (lexmatch(P, &tok, '(')) { vec_t(struct expr) args = {0}; int i = 0, n = ex.ty->fn.params.n; @@ -703,10 +759,13 @@ pexpostfix(struct parser *P) { if (ex.ty->t != TYfn) fatal(P, ex.span, "callee is not a function"); while (!lexmatch(P, NULL, ')')) { - struct expr arg = parseexpr(P); + struct expr arg; if (i == n && ! ex.ty->fn.variadic) fatal(P, arg.span, "too many args for call"); + if (i < n) + P->targty = ex.ty->fn.params.d[i]; + arg = parseexpr(P); if (i < n && !typeof2(arg.ty, ex.ty->fn.params.d[i++])) fatal(P, arg.span, "call argument #%d type mismatch", i); @@ -824,6 +883,30 @@ pexprefix(struct parser *P) { '&', exprdup(ex) } }; + } else if (lexmatch(P, &tok, TKkw_as)) { + const struct type *to, *from; + struct expr ex; + lexexpect(P, '('); + to = parsetype(P); + lexexpect(P, ')'); + P->targty = to; + ex = pexprefix(P); + from = ex.ty; + + if (typeof2(to, from)) ; + else if (to->t == TYint && from->t == TYptr && to->size == from->size) ; + else if (from->t == TYint && to->t == TYptr && to->size == from->size) ; + else if (from->t == TYbool && to->t == TYint) ; + else if (from->t == TYint && to->t == TYbool) ; + else if (from->t == TYenum && to->t == TYint) ; + else if (from->t == TYint && to->t == TYenum) ; + else + fatal(P, tok.span, "invalid cast"); // TODO better diagnostics... + + P->targty = to; + return (struct expr) { + Eas, tok.span, to, .child = exprdup(ex) + }; } return pexpostfix(P); @@ -855,6 +938,7 @@ pexbitarith(struct parser *P) { int oret; ex = pexprefix(P); + if (P->used_targetty) return ex; if (!(oret = peeksbitarithop(P, &tok))) return ex; tokt = tok.t; @@ -930,6 +1014,7 @@ pexcmp(struct parser *P) { struct tok tok; ex = pexbitarith(P); + if (P->used_targetty) return ex; if (matchcmpop(P, &tok)) { struct expr rhs = pexbitarith(P); if (!typeof2(ex.ty, rhs.ty)) @@ -954,6 +1039,7 @@ pexlog(struct parser *P) { int tokt; ex = pexcmp(P); + if (P->used_targetty) return ex; tok = lexpeek(P); tokt = tok.t; if (tokt != TKkw_and && tokt != TKkw_or) @@ -981,6 +1067,7 @@ pexcond(struct parser *P) { struct tok tok; ex = pexlog(P); + if (P->used_targetty) return ex; if (lexmatch(P, &tok, '?')) { struct expr ex2 = parseexpr(P); struct expr ex3; @@ -1025,6 +1112,7 @@ pexassign(struct parser *P) { int oret; ex = pexcond(P); + if (P->used_targetty) return ex; if ((oret = matchassignop(P, &tok))) { struct expr rhs = pexcond(P); if (!islvalue(&ex)) @@ -1081,6 +1169,7 @@ parsevardecl(struct parser *P, struct decl *decl) { } else { ty = parsetype(P); if (lexmatch(P, NULL, '=')) { + P->targty = ty; ini = exprdup(parseexpr(P)); } else if (decl->t == Dlet) { fatal(P, tok.span, "variable must be initialized"); @@ -1197,8 +1286,13 @@ pstiswitch(struct parser *P, const struct expr *test) { *f = parseblock0(P); } else { do { - struct expr ex = parseexpr(P); - assert(ex.ty->t == TYint); + struct expr ex; + P->targty = test->ty; + ex = parseexpr(P); + if (!fold(&ex)) + fatal(P, ex.span, "case expression is not constant"); + if (!typeof2(ex.ty, test->ty)) + fatal(P, ex.span, "case expression has incorrect type"); vec_push(&es, ex); if (!lexmatch(P, &tok, ',')) { lexexpect(P, TKkw_do); @@ -1224,7 +1318,7 @@ pstswitch(struct parser *P) { if (!lexmatch(P, &tok, '{')) { test = parseexpr(P); - if (test.ty->t == TYint) + if (test.ty->t == TYint || test.ty->t == TYenum) return pstiswitch(P, &test); else assert(0 && "NYI"); @@ -1239,7 +1333,8 @@ static bool isdecltokt(int tokt) { switch (tokt) case TKkw_extern: case TKkw_fn: case TKkw_typedef: - case TKkw_defmacro: case TKkw_static: + case TKkw_defmacro: case TKkw_static: case TKkw_enum: + case TKkw_struct: case TKkw_union: return 1; return 0; } @@ -1378,6 +1473,7 @@ parsestmt(struct parser *P) { st.t = Sreturn; st.span = tok.span; if (!lexmatch(P, &tok, ';')) { + P->targty = P->curfn->retty; st.retex = exprdup(parseexpr(P)); lexexpect(P, ';'); if (!typeof2(st.retex->ty, P->curfn->retty)) @@ -1470,7 +1566,7 @@ parsefn(struct decl *decl, struct parser *P) { fn->name = name; lexexpect(P, '('); - while (!lexmatch(P, NULL, ')')) { + while (!lexmatch(P, &tok, ')')) { struct fnparam param; if (lexmatch(P, NULL, '...')) { fn->variadic = 1; @@ -1479,7 +1575,7 @@ parsefn(struct decl *decl, struct parser *P) { param.ty = parsetype(P); vec_push(¶ms, param); } - if (!lexmatch(P, NULL, ',')) { + if (!lexmatch(P, &tok, ',')) { lexexpect(P, ')'); break; } else if (fn->variadic) { @@ -1630,17 +1726,78 @@ parsemacro(struct parser *P) { return macro; } +static const struct type * +parseenum(struct parser *P, const char *name) { + struct tok tok; + struct type ty = {TYenum}; + static int id = 0; + i64 iota = 0, max = 0, min = 0; + vec_t(struct enumfield) vals = {0}; + + if (lexmatch(P, &tok, ':')) { + ty.enu.intty = unconstify(parsetype(P)); + if (ty.enu.intty->t != TYint) + fatal(P, tok.span, "enum backing type is not integral"); + } + + lexexpect(P, '{'); + while (!lexmatch(P, &tok, '}')) { + const char *fnam = lexexpect(P, TKident).str; + i64 val; + + if (lexmatch(P, &tok, '=')) { + struct expr ex = parseexpr(P); + if (!fold(&ex) || ex.t != Eintlit) + fatal(P, ex.span, + "enum initializer must be compile-time integral constant"); + assert(ex.ty != ty_u64 || ex.u <= INT64_MAX); + val = ex.i; + } else { + val = iota; + } + if (val < min) + min = val; + if (val > max) + max = val; + iota = val + 1; + vec_push(&vals, ((struct enumfield) { fnam, val })); + + if (!lexmatch(P, &tok, ',')) { + lexexpect(P, '}'); + break; + } + } + + if (!ty.enu.intty) { + if (min >= 0) + ty.enu.intty = ilittype(max); + else { + if (min >= INT_MIN && max <= INT_MAX) ty.enu.intty = ty_int; + if (min >= INT32_MIN && max <= INT32_MAX) ty.enu.intty = ty_int; + if (min >= INT64_MIN && max <= INT64_MAX) ty.enu.intty = ty_int; + } + assert(ty.enu.intty); + } + + ty.enu.name = name; + ty.enu.id = id++; + vec_slice_cpy(&ty.enu.vals, &vals); + + return interntype(ty); +} + static void parsedecl(struct decl *decl, struct parser *P, bool toplevel) { struct tok tok = { .span = P->tokspan }; bool externp = 0; + const char *name ; memset(decl, 0, sizeof *decl); if (lexmatch(P, &tok, TKkw_extern)) externp = 1; if (lexmatch(P, &tok, TKkw_fn)) { - const char *name = lexexpects(P, TKident, "function name").str; + name = lexexpects(P, TKident, "function name").str; decl->t = Dfn; decl->name = decl->fn.name = name; @@ -1660,21 +1817,24 @@ parsedecl(struct decl *decl, struct parser *P, bool toplevel) { "extern static variable inside function cannot be initialized"); lexexpect(P, ';'); } else if (lexmatch(P, &tok, TKkw_typedef)) { - if (externp) - fatal(P, tok.span, "typedef cannot be `extern'"); + if (externp) fatal(P, tok.span, "typedef cannot be `extern'"); decl->t = Dtype; decl->name = lexexpects(P, TKident, "typedef name").str; decl->ty = parsetype(P); decl->_cname = xcalloc(1, sizeof(char *)); lexexpect(P, ';'); } else if (lexmatch(P, &tok, TKkw_defmacro)) { - if (externp) - fatal(P, tok.span, "macro cannot be `extern'"); - const char *name = lexexpects(P, TKident, "macro name").str; + if (externp) fatal(P, tok.span, "macro cannot be `extern'"); + name = lexexpects(P, TKident, "macro name").str; decl->t = Dmacro; decl->name = name; decl->macro = parsemacro(P); decl->macro.name = name; + } else if (lexmatch(P, &tok, TKkw_enum)) { + if (externp) fatal(P, tok.span, "enum cannot be `extern'"); + decl->name = lexexpects(P, TKident, "enum name").str; + decl->ty = parseenum(P, decl->name); + } else { fatal(P, tok.span, "expected declaration (near %s)", tok2str(tok)); @@ -1697,7 +1857,7 @@ parse(struct transunit *tu, struct parser *P) { void initparser(struct parser *P, const char *fname) { - assert(NUM_LEXTOKENS - 1 < '!'); + assert(NUM_KEYWORDS - 1 < '!'); memset(P, 0, sizeof *P); P->curfile = fname; if (!(P->fp = fopen(fname, "r"))) diff --git a/bootstrap/test.cff b/bootstrap/test.cff index ba47c6d..d962b16 100644 --- a/bootstrap/test.cff +++ b/bootstrap/test.cff @@ -1,7 +1,30 @@ -typedef v3f ["!"[~-1] - 30]f32; +typedef v3f ["!"[~-1] - as(int)30.0]f32; + +enum Color { + Red = 7, + Green = -10, + Blue, +} + +fn best() Color { + return :Green; +} + +fn hex(c Color) u32 { + switch (c) { + case :Red do return 0xFF0000; + case :Green do return 0x00FF00; + case :Blue do return 0x0000FF; + } +} extern fn main (argc int, argv **u8) void { extern fn printf(fmt *const u8, ...) int; + + printf("red %d\n", Color:Red); + printf("green %d\n", Color:Green); + printf("blue %d\n", Color:Blue); + printf("red ! %.8X\n", hex(:Red)); return; } diff --git a/bootstrap/types.c b/bootstrap/types.c index 401f9e6..0353041 100644 --- a/bootstrap/types.c +++ b/bootstrap/types.c @@ -52,7 +52,9 @@ hashtype(const struct type *ty) { h = jkhashv(h, ty->fn.params.n); for (int i = 0; i < ty->fn.params.n; ++i) h = jkhashv(h, ty->fn.params.d[i]); - + case TYenum: + h = jkhashv(h, ty->enu.id); + break; } return h; } @@ -82,6 +84,8 @@ typeeql(const struct type *lhs, const struct type *rhs) { if (!typeeql(lhs->fn.params.d[i], rhs->fn.params.d[i])) return 0; return 1; + case TYenum: + return 0; } assert(0 && "unreachable"); } |