From a9dc9c8867afc88d4a1fc6e66afccc6a2fd5787a Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 17 Jul 2011 17:12:46 -0400 Subject: [PATCH 1/3] Check for duplicate case patterns. --- src/comp/middle/typeck.rs | 111 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 9a7cf3579964d..f94f735e78328 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1975,6 +1975,117 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { check_pat(fcx, id_map, p, pattern_ty); } } + + // Now check for any duplicate patterns (boring old O(n!)) + + iter all_arm_pats(ast::arm[] arms, uint start) + -> tup(@ast::pat, uint) { + auto i = 0u; + for (ast::arm arm in arms) { + for (@ast::pat pat in arm.pats) { + if (i >= start) { + put tup(pat, i); + } + i += 1u; + } + } + } + fn pat_equiv(&@ast::pat p1, &@ast::pat p2) -> bool { + alt (p1.node) { + ast::pat_wild { + alt (p2.node) { + ast::pat_wild { ret true } + _ { ret false } + } + } + ast::pat_bind(_) { + alt (p2.node) { + ast::pat_bind(_) { ret true } + _ { ret false } + } + } + ast::pat_lit(?l1) { + alt (p2.node) { + ast::pat_lit(?l2) { ret lit_eq(l1, l2) } + _ { ret false } + } + } + ast::pat_tag(?path1, ?sub1) { + alt (p2.node) { + ast::pat_tag(?path2, ?sub2) { + if (ivec::len(path1.node.idents) != + ivec::len(path2.node.idents)) { + ret false; + } + auto i = 0u; + while (i < ivec::len(path1.node.idents)) { + if (path1.node.idents.(i) != + path2.node.idents.(i)) { + ret false; + } + i += 1u; + } + if (ivec::len(sub1) != ivec::len(sub2)) { + ret false; + } + i = 0u; + while (i < ivec::len(sub1)) { + if (!pat_equiv(sub1.(i), + sub2.(i))) { + ret false; + } + i += 1u; + } + ret true; + } + _ { ret false } + } + } + ast::pat_rec(?pats1, ?b1) { + alt (p2.node) { + ast::pat_rec(?pats2, ?b2) { + if (b1 != b2 || + ivec::len(pats1) != ivec::len(pats2)) { + ret false; + } + auto i = 0u; + while (i < ivec::len(pats1)) { + if (pats1.(i).ident != pats2.(i).ident || + !pat_equiv(pats1.(i).pat, + pats2.(i).pat)) { + ret false; + } + i += 1u; + } + ret true; + } + _ { ret false } + } + } + ast::pat_box(?pat1) { + alt (p2.node) { + ast::pat_box(?pat2) { ret pat_equiv(pat1, pat2); } + _ { ret false } + } + } + } + } + + for each (tup(@ast::pat, uint) _p1 in all_arm_pats(arms, 0u)) { + let uint i = _p1._1; + let @ast::pat p1 = _p1._0; + for each (tup(@ast::pat, uint) _p2 in all_arm_pats(arms, i)) { + let @ast::pat p2 = _p2._0; + if (p1.id != p2.id && pat_equiv(p1, p2)) { + fcx.ccx.tcx.sess.span_err(p2.span, + "duplicate matching pattern \ + found in alt block"); + fcx.ccx.tcx.sess.span_note(p1.span, + "earlier matching pattern:"); + } + } + } + // Now typecheck the blocks. auto result_ty = next_ty_var(fcx); From bf25c9170185dab08d76efae2b3ec2bfb57c004a Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 17 Jul 2011 17:14:08 -0400 Subject: [PATCH 2/3] Move the giant helper out of the giant enclosing function. --- src/comp/middle/typeck.rs | 161 +++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index f94f735e78328..c6ca36aa8495f 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1480,6 +1480,87 @@ fn require_pure_call(@crate_ctxt ccx, &ast::purity caller_purity, } } +fn pat_equiv(&@ast::pat p1, &@ast::pat p2) -> bool { + alt (p1.node) { + ast::pat_wild { + alt (p2.node) { + ast::pat_wild { ret true } + _ { ret false } + } + } + ast::pat_bind(_) { + alt (p2.node) { + ast::pat_bind(_) { ret true } + _ { ret false } + } + } + ast::pat_lit(?l1) { + alt (p2.node) { + ast::pat_lit(?l2) { ret lit_eq(l1, l2) } + _ { ret false } + } + } + ast::pat_tag(?path1, ?sub1) { + alt (p2.node) { + ast::pat_tag(?path2, ?sub2) { + if (ivec::len(path1.node.idents) != + ivec::len(path2.node.idents)) { + ret false; + } + auto i = 0u; + while (i < ivec::len(path1.node.idents)) { + if (path1.node.idents.(i) != + path2.node.idents.(i)) { + ret false; + } + i += 1u; + } + if (ivec::len(sub1) != ivec::len(sub2)) { + ret false; + } + i = 0u; + while (i < ivec::len(sub1)) { + if (!pat_equiv(sub1.(i), + sub2.(i))) { + ret false; + } + i += 1u; + } + ret true; + } + _ { ret false } + } + } + ast::pat_rec(?pats1, ?b1) { + alt (p2.node) { + ast::pat_rec(?pats2, ?b2) { + if (b1 != b2 || + ivec::len(pats1) != ivec::len(pats2)) { + ret false; + } + auto i = 0u; + while (i < ivec::len(pats1)) { + if (pats1.(i).ident != pats2.(i).ident || + !pat_equiv(pats1.(i).pat, + pats2.(i).pat)) { + ret false; + } + i += 1u; + } + ret true; + } + _ { ret false } + } + } + ast::pat_box(?pat1) { + alt (p2.node) { + ast::pat_box(?pat2) { ret pat_equiv(pat1, pat2); } + _ { ret false } + } + } + } +} + fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { // fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " + // syntax::print::pprust::expr_to_str(expr)); @@ -1990,86 +2071,6 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } } } - fn pat_equiv(&@ast::pat p1, &@ast::pat p2) -> bool { - alt (p1.node) { - ast::pat_wild { - alt (p2.node) { - ast::pat_wild { ret true } - _ { ret false } - } - } - ast::pat_bind(_) { - alt (p2.node) { - ast::pat_bind(_) { ret true } - _ { ret false } - } - } - ast::pat_lit(?l1) { - alt (p2.node) { - ast::pat_lit(?l2) { ret lit_eq(l1, l2) } - _ { ret false } - } - } - ast::pat_tag(?path1, ?sub1) { - alt (p2.node) { - ast::pat_tag(?path2, ?sub2) { - if (ivec::len(path1.node.idents) != - ivec::len(path2.node.idents)) { - ret false; - } - auto i = 0u; - while (i < ivec::len(path1.node.idents)) { - if (path1.node.idents.(i) != - path2.node.idents.(i)) { - ret false; - } - i += 1u; - } - if (ivec::len(sub1) != ivec::len(sub2)) { - ret false; - } - i = 0u; - while (i < ivec::len(sub1)) { - if (!pat_equiv(sub1.(i), - sub2.(i))) { - ret false; - } - i += 1u; - } - ret true; - } - _ { ret false } - } - } - ast::pat_rec(?pats1, ?b1) { - alt (p2.node) { - ast::pat_rec(?pats2, ?b2) { - if (b1 != b2 || - ivec::len(pats1) != ivec::len(pats2)) { - ret false; - } - auto i = 0u; - while (i < ivec::len(pats1)) { - if (pats1.(i).ident != pats2.(i).ident || - !pat_equiv(pats1.(i).pat, - pats2.(i).pat)) { - ret false; - } - i += 1u; - } - ret true; - } - _ { ret false } - } - } - ast::pat_box(?pat1) { - alt (p2.node) { - ast::pat_box(?pat2) { ret pat_equiv(pat1, pat2); } - _ { ret false } - } - } - } - } for each (tup(@ast::pat, uint) _p1 in all_arm_pats(arms, 0u)) { let uint i = _p1._1; From db35220bb5ce61c192735291b8e3589ff7dd8a7e Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 17 Jul 2011 17:19:49 -0400 Subject: [PATCH 3/3] Big-oh analysis is both incorrect and unneeded. --- src/comp/middle/typeck.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index c6ca36aa8495f..84af1b53e8061 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -2057,7 +2057,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } } - // Now check for any duplicate patterns (boring old O(n!)) + // Now check for any duplicate patterns iter all_arm_pats(ast::arm[] arms, uint start) -> tup(@ast::pat, uint) {