Skip to content

Commit b6aadf5

Browse files
committed
In resolve, check for duplicate pattern-bound vars
Closes #3038
1 parent 300f54e commit b6aadf5

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

src/rustc/middle/resolve3.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import syntax::ast::{required, provided};
3232
import syntax::ast_util::{def_id_of_def, dummy_sp, local_def, new_def_hash};
3333
import syntax::ast_util::{walk_pat};
3434
import syntax::attr::{attr_metas, contains_name};
35-
import syntax::print::pprust::path_to_str;
35+
import syntax::print::pprust::{pat_to_str, path_to_str};
3636
import syntax::codemap::span;
3737
import syntax::visit::{default_visitor, fk_method, mk_vt, visit_block};
3838
import syntax::visit::{visit_crate, visit_expr, visit_expr_opt, visit_fn};
@@ -3658,9 +3658,12 @@ class Resolver {
36583658
fn resolve_pattern(pattern: @pat,
36593659
mode: PatternBindingMode,
36603660
mutability: Mutability,
3661-
bindings_list: option<hashmap<Atom,()>>,
3661+
// Maps idents to the node ID for the (outermost)
3662+
// pattern that binds them
3663+
bindings_list: option<hashmap<Atom,node_id>>,
36623664
visitor: ResolveVisitor) {
36633665

3666+
let pat_id = pattern.id;
36643667
do walk_pat(pattern) |pattern| {
36653668
alt pattern.node {
36663669
pat_ident(path, _)
@@ -3705,19 +3708,18 @@ class Resolver {
37053708

37063709
let is_mutable = mutability == Mutable;
37073710

3708-
let mut def;
3709-
alt mode {
3711+
let def = alt mode {
37103712
RefutableMode {
37113713
// For pattern arms, we must use
37123714
// `def_binding` definitions.
37133715

3714-
def = def_binding(pattern.id);
3716+
def_binding(pattern.id)
37153717
}
37163718
IrrefutableMode {
37173719
// But for locals, we use `def_local`.
3718-
def = def_local(pattern.id, is_mutable);
3720+
def_local(pattern.id, is_mutable)
37193721
}
3720-
}
3722+
};
37213723

37223724
// Record the definition so that later passes
37233725
// will be able to distinguish variants from
@@ -3737,10 +3739,19 @@ class Resolver {
37373739
let last_rib = (*self.value_ribs).last();
37383740
last_rib.bindings.insert(atom,
37393741
dl_def(def));
3740-
bindings_list.insert(atom, ());
3742+
bindings_list.insert(atom, pat_id);
37413743
}
3742-
some(_) {
3743-
// Do nothing.
3744+
some(b) {
3745+
if b.find(atom) == some(pat_id) {
3746+
// Then this is a duplicate variable
3747+
// in the same disjunct, which is an
3748+
// error
3749+
self.session.span_err(pattern.span,
3750+
#fmt("Identifier %s is bound more \
3751+
than once in the same pattern",
3752+
path_to_str(path)));
3753+
}
3754+
// Not bound in the same pattern: do nothing
37443755
}
37453756
none {
37463757
let last_rib = (*self.value_ribs).last();

src/test/compile-fail/issue-3038.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
enum f { g(int, int) }
2+
3+
enum h { i(j, k) }
4+
5+
enum j { l(int, int) }
6+
enum k { m(int, int) }
7+
8+
fn main()
9+
{
10+
11+
let _z = alt g(1, 2) {
12+
g(x, x) { log(debug, x + x); }
13+
//~^ ERROR Identifier x is bound more than once in the same pattern
14+
};
15+
16+
let _z = alt i(l(1, 2), m(3, 4)) {
17+
i(l(x, _), m(_, x)) //~ ERROR Identifier x is bound more than once in the same pattern
18+
{ log(error, x + x); }
19+
};
20+
21+
let _z = alt (1, 2) {
22+
(x, x) { x } //~ ERROR Identifier x is bound more than once in the same pattern
23+
};
24+
25+
}

0 commit comments

Comments
 (0)