ref: beab0276a94c684f938ae5ea3d2c29c3dc331386
parent: 5d16f2c900fc1bc0b461878f5c936b969b7bee7d
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Jul 6 21:12:04 EDT 2018
Fix overlapping match statements (thanks Mako) We were overly aggressive in unifying wildcards.
--- a/mi/match.c
+++ b/mi/match.c
@@ -16,6 +16,7 @@
typedef struct Dtree Dtree;
struct Dtree {
int id;
+ int obscured;
Srcloc loc;
/* values for matching */
@@ -361,14 +362,13 @@
for (i = 0; i < ty->nmemb; i++) {
uc = ty->udecls[i];
next = dtbytag(start, uc);
- if (next) {
- if (uc->etype) {
- if (addwildrec(loc, uc->etype, next, accept, end, nend))
- ret = 1;
- } else {
- lappend(end, nend, next);
- }
- }
+ if (!next)
+ continue;
+
+ if (uc->etype && addwildrec(loc, uc->etype, next, accept, end, nend))
+ ret = 1;
+ else
+ lappend(end, nend, next);
}
if (!start->any) {
start->any = accept;
@@ -408,10 +408,8 @@
Dtree *next;
Ucon *uc;
- if (start->any) {
+ if (start->any)
lappend(end, nend, start->any);
- return 0;
- }
uc = finducon(tybase(exprtype(pat)), pat->expr.args[0]);
next = dtbytag(start, uc);
@@ -434,13 +432,15 @@
lappend(&start->pat, &start->npat, tagid);
if (uc->etype) {
next = mkdtree(pat->loc, genlbl(pat->loc));
+ next->obscured = (start->obscured || start->any != NULL);
lappend(&start->next, &start->nnext, next);
addpat(pat->expr.args[1], uvalue(val, uc->etype), next, accept, cap, ncap, end, nend);
} else {
+ accept->obscured = (start->obscured || start->any != NULL);
lappend(&start->next, &start->nnext, accept);
lappend(end, nend, accept);
}
- return 1;
+ return !start->obscured && start->any == NULL;
}
static int
@@ -502,12 +502,10 @@
if (pat->expr.args[0]->lit.littype == Lstr) {
return addstr(pat, val, start, accept, cap, ncap, end, nend);
} else {
- /* if we already have a match, we're not adding a new node */
- if (start->any) {
+ if (start->any)
lappend(end, nend, start->any);
- return 0;
- }
+ /* if we already have a match, we're not adding a new node */
for (i = 0; i < start->npat; i++) {
if (liteq(start->pat[i]->expr.args[0], pat->expr.args[0])) {
lappend(end, nend, start->next[i]);
@@ -520,10 +518,11 @@
start->load = val;
start->nconstructors = nconstructors(exprtype(pat));
}
+ accept->obscured = (start->obscured || start->any != NULL);
lappend(&start->pat, &start->npat, pat);
lappend(&start->next, &start->nnext, accept);
lappend(end, nend, accept);
- return 1;
+ return !start->obscured && start->any == NULL;
}
}
--- /dev/null
+++ b/test/matchoverwild.myr
@@ -1,0 +1,43 @@
+use std
+
+type ast = struct
+ body : op[:]
+;;
+type op = union
+ `Go int
+ `Set int
+ `Add int
+ `Mul (int, int)
+ `Read
+ `Write
+ `Loop ast
+;;
+
+const combine = {lhs : op, rhs : op
+ match (lhs, rhs)
+ | (`Add x, `Add y): -> `std.Some `Add (x + y)
+ | (`Go x, `Go y): -> `std.Some `Go (x + y)
+ | (`Go 0, _): -> `std.Some rhs
+ | (`Set x, `Add y): -> `std.Some `Set(x + y)
+ | (`Add _, `Set y): -> `std.Some rhs
+ | (`Add _, `Read): -> `std.Some rhs
+ | (`Set _, `Read): -> `std.Some rhs
+ | (`Loop _, `Loop _): -> `std.Some lhs
+ | _: -> `std.None
+ ;;
+}
+
+const main = {
+ match combine(`Add 123, `Set 246)
+ | `std.Some `Set 246:
+ /* ok */
+ | r:
+ std.fatal("bad combine {}\n", r)
+ ;;
+ match combine(`Add 123, `Add 246)
+ | `std.Some `Add 369:
+ /* ok */
+ | r:
+ std.fatal("bad combine {}\n", r)
+ ;;
+}
--- a/test/tests
+++ b/test/tests
@@ -110,6 +110,7 @@
B gsizeof E 5
B matchint E 84
B matchconst E 88
+B matchoverwild E 0
B matchnsconst P 'matched badchar'
B matchunion E 84
B matchtup E 42
@@ -148,6 +149,7 @@
B strjoin C
B exporttrait E 0
B local-labels E 10
+B empty-struct E 21
B empty-struct E 21
F declmismatch
F infermismatch