Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report duplicate alt patterns as errors #706

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
112 changes: 112 additions & 0 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -1975,6 +2056,37 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
check_pat(fcx, id_map, p, pattern_ty);
}
}

// Now check for any duplicate patterns

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;
}
}
}

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);
Expand Down