diff options
| author | 2022-08-25 06:34:22 +0200 | |
|---|---|---|
| committer | 2022-08-25 06:34:22 +0200 | |
| commit | a39378db8ce05f8ab45b5ae0f3252c0a5322fd70 (patch) | |
| tree | 06471804911a038529bb00e9b9cd0edee0dee3eb /src | |
| parent | a004d0f4033dab74a237d598c493228a7d107014 (diff) | |
switch check
Diffstat (limited to 'src')
| -rw-r--r-- | src/parse.cff | 23 | ||||
| -rw-r--r-- | src/set.hff | 6 |
2 files changed, 29 insertions, 0 deletions
diff --git a/src/parse.cff b/src/parse.cff index d0c3da7..2611906 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -2176,6 +2176,13 @@ fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt { let cs Vec<ISwitchCase> = {}; let f Block = {}; let elsep = #f; + + let seen Map<i64, Loc, struct { + fn hash(x i64) u32 { return x; } + fn eq(a i64, b i64) bool { return a == b;} + }> = {}; + defer seen->clear(); + while !lexmatch(P, &tok, '}') { lexexpect(P, :kw_case); if lexmatch(P, &tok, :kw_else) { @@ -2196,6 +2203,10 @@ fn pstiswitch(P *Parser, loc Loc, ex Expr) Stmt { if !typematchestarg(ex.ty, e.ty) { err(P, e.loc, "bad case expression (%t, expected %t)", e.ty, ex.ty); } + if seen->get(e.u.IntLit.i) { + err(P, e.loc, "duplicate case expression (previously seen at %l)", *seen->get(e.u.IntLit.i)); + } + seen->put(e.u.IntLit.i, e.loc); es->push(e); if !lexmatch(P, #null, ',') { lexexpect(P, ';'); @@ -2214,6 +2225,12 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt { let f Block = {}; let elsep = #f; + let seen Map<int, Loc, struct { + fn hash(x int) u32 { return x; } + fn eq(a int, b int) bool { return a == b;} + }> = {}; + defer seen->clear(); + while !lexmatch(P, &tok, '}') { let c EUSwitchCase = {}; lexexpect(P, :kw_case); @@ -2231,6 +2248,12 @@ fn psteuswitch(P *Parser, loc Loc, test Expr) Stmt { fatal(P, tok.loc, "%t has no such variant %qT", test.ty, tok); } c.variant = c.fld - test.ty.u.Agg.flds.#ptr; + + if seen->get(c.variant) { + err(P, tok.loc, "duplicate case expression (previously seen at %l)", *seen->get(c.variant)); + } + seen->put(c.variant, tok.loc); + if c.fld.ty != #null and lexmatch(P, &tok, '*') { if !islvalue(test) { fatal(P, tok.loc, "cannot capture by pointer, test expression is not lvalue"); diff --git a/src/set.hff b/src/set.hff index 6a03e52..212d578 100644 --- a/src/set.hff +++ b/src/set.hff @@ -74,6 +74,12 @@ struct Set<T, Traits> { fn put(self *Set, x T) void { self->intern(x); } + + fn clear(self *Set) void { + self.buf->clear(); + free(self.set); + *self = {}; + } } defmacro set_each(v, Set, &body) [ |