Skip to content

Commit

Permalink
Clean up "pattern doesn't bind x" messages
Browse files Browse the repository at this point in the history
Group "missing variable bind" spans in `or` matches and clarify wording
for the two possible cases: when a variable from the first pattern is
not in any of the subsequent patterns, and when a variable in any of the
other patterns is not in the first one.

Before:

```
error[E0408]: variable `a` from pattern #1 is not bound in pattern #2
  --> file.rs:10:23
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |                       ^^^^^^^^^^^ pattern doesn't bind `a`

error[E0408]: variable `b` from pattern #2 is not bound in pattern #1
  --> file.rs:10:32
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |                                ^ pattern doesn't bind `b`

error[E0408]: variable `a` from pattern #1 is not bound in pattern #3
  --> file.rs:10:37
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |                                     ^^^^^^^^ pattern doesn't bind `a`

error[E0408]: variable `d` from pattern #1 is not bound in pattern #3
  --> file.rs:10:37
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |                                     ^^^^^^^^ pattern doesn't bind `d`

error[E0408]: variable `c` from pattern #3 is not bound in pattern #1
  --> file.rs:10:43
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |                                           ^ pattern doesn't bind `c`

error[E0408]: variable `d` from pattern #1 is not bound in pattern #4
  --> file.rs:10:48
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |                                                ^^^^^^^^ pattern doesn't bind `d`

error: aborting due to 6 previous errors
```

After:

```
error[E0408]: variable `d` from pattern #1 isn't bound in patterns #3, #4
  --> file.rs:10:37
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |                  -                  ^^^^^^^^   ^^^^^^^^ pattern doesn't bind `d`
   |                  |                  |
   |                  missing variable   pattern doesn't bind `d`

error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3
  --> file.rs:10:23
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |               -       ^^^^^^^^^^^   ^^^^^^^^ pattern doesn't bind `a`
   |               |       |
   |               |       pattern doesn't bind `a`
   |               missing variable

error[E0408]: variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern #1
  --> file.rs:10:32
   |
10 |         T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
   |         -----------            ^          ^ missing variable
   |         |                      |
   |         |                      missing variable
   |         pattern does't bind `b`, `c`

error: aborting due to 3 previous errors
```
  • Loading branch information
estebank committed Feb 10, 2017
1 parent c49d102 commit 738b0f3
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 22 deletions.
88 changes: 71 additions & 17 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ enum ResolutionError<'a> {
TypeNotMemberOfTrait(Name, &'a str),
/// error E0438: const is not a member of trait
ConstNotMemberOfTrait(Name, &'a str),
/// error E0408: variable `{}` from pattern #{} is not bound in pattern #{}
VariableNotBoundInPattern(Name, usize, usize),
/// error E0408: variable `{}` from pattern #{} is not bound in pattern #1
VariableNotBoundInPattern(Name, Span, Vec<(Span, usize)>),
/// error E0408: variable `{}` from pattern #1 is not bound in pattern #{}
VariableNotBoundInFirstPattern(Span, Vec<(Name, usize, Span)>),
/// error E0409: variable is bound with different mode in pattern #{} than in pattern #1
VariableBoundWithDifferentMode(Name, usize, Span),
/// error E0415: identifier is bound more than once in this parameter list
Expand Down Expand Up @@ -204,15 +206,53 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
err.span_label(span, &format!("not a member of trait `{}`", trait_));
err
}
ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => {
let mut err = struct_span_err!(resolver.session,
span,
E0408,
"variable `{}` from pattern #{} is not bound in pattern #{}",
variable_name,
from,
to);
err.span_label(span, &format!("pattern doesn't bind `{}`", variable_name));
ResolutionError::VariableNotBoundInPattern(variable_name, sp, missing_vars) => {
let spans: Vec<_> = missing_vars.iter().map(|x| x.0).collect();
let msp = MultiSpan::from_spans(spans.clone());
// "variable `a` from pattern #1 is not bound in patterns #2, #3"
let msg = format!("variable `{}` from pattern #1 isn't bound in pattern{} {}",
variable_name,
if spans.len() > 1 {
"s"
} else {
""
},
missing_vars.iter()
.map(|x| format!("#{}", x.1))
.collect::<Vec<_>>()
.join(", "));
let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408");
for sp in spans {
err.span_label(sp, &format!("pattern doesn't bind `{}`", variable_name));
}
err.span_label(sp, &"variable not in all patterns");
err
}
ResolutionError::VariableNotBoundInFirstPattern(sp, extra_vars) => {
let spans: Vec<_> = extra_vars.iter().map(|x| x.2).collect();
let msp = MultiSpan::from_spans(spans.clone());
// "variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern
// #1"
let msg = format!("{} {}n't bound in pattern #1",
extra_vars.iter()
.map(|x| format!("variable `{}` from pattern #{}", x.0, x.1))
.collect::<Vec<_>>()
.join(", "),
if spans.len() > 1 {
"are"
} else {
"is"
});
let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408");
for sp in spans {
err.span_label(sp, &"variable not in all patterns");
}
err.span_label(sp,
&format!("pattern doesn't bind {}",
extra_vars.iter()
.map(|x| format!("`{}`", x.0))
.collect::<Vec<_>>()
.join(", ")));
err
}
ResolutionError::VariableBoundWithDifferentMode(variable_name,
Expand Down Expand Up @@ -324,7 +364,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
}
}

#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
struct BindingInfo {
span: Span,
binding_mode: BindingMode,
Expand Down Expand Up @@ -1867,14 +1907,20 @@ impl<'a> Resolver<'a> {
return;
}
let map_0 = self.binding_mode_map(&arm.pats[0]);

let mut missing_vars = FxHashMap();
let mut extra_vars = vec![];

for (i, p) in arm.pats.iter().enumerate() {
let map_i = self.binding_mode_map(&p);

for (&key, &binding_0) in &map_0 {
match map_i.get(&key) {
None => {
let error = ResolutionError::VariableNotBoundInPattern(key.name, 1, i + 1);
resolve_error(self, p.span, error);
let spans = missing_vars
.entry((key.name, binding_0.span))
.or_insert(vec![]);
spans.push((p.span, i + 1));
}
Some(binding_i) => {
if binding_0.binding_mode != binding_i.binding_mode {
Expand All @@ -1891,12 +1937,20 @@ impl<'a> Resolver<'a> {

for (&key, &binding) in &map_i {
if !map_0.contains_key(&key) {
resolve_error(self,
binding.span,
ResolutionError::VariableNotBoundInPattern(key.name, i + 1, 1));
extra_vars.push((key.name, i + 1, binding.span));
}
}
}
for (k, v) in missing_vars {
let (name, sp) = k;
resolve_error(self, sp, ResolutionError::VariableNotBoundInPattern(name, sp, v));
}
if extra_vars.len() > 0 {
resolve_error(self,
arm.pats[0].span,
ResolutionError::VariableNotBoundInFirstPattern(arm.pats[0].span,
extra_vars));
}
}

fn resolve_arm(&mut self, arm: &Arm) {
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/E0408.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ fn main() {
let x = Some(0);

match x {
Some(y) | None => {} //~ ERROR variable `y` from pattern #1 is not bound in pattern #2
Some(y) | None => {} //~ ERROR variable `y` from pattern #1 isn't bound in pattern #2
_ => () //~| NOTE pattern doesn't bind `y`
//~| NOTE variable not in all patterns
}
}
3 changes: 2 additions & 1 deletion src/test/compile-fail/issue-2848.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ mod bar {
fn main() {
use bar::foo::{alpha, charlie};
match alpha {
alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1
alpha | beta => {} //~ ERROR variable `beta` from pattern #2 isn't bound in pattern #1
charlie => {} //~| NOTE pattern doesn't bind `beta`
//~| NOTE variable not in all patterns
}
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-2849.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ enum foo { alpha, beta(isize) }
fn main() {
match foo::alpha {
foo::alpha | foo::beta(i) => {}
//~^ ERROR variable `i` from pattern #2 is not bound in pattern #1
//~^ ERROR variable `i` from pattern #2 isn't bound in pattern #1
}
}
6 changes: 4 additions & 2 deletions src/test/compile-fail/resolve-inconsistent-names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
fn main() {
let y = 1;
match y {
a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2
//~^ ERROR variable `b` from pattern #2 is not bound in pattern #1
a | b => {} //~ ERROR variable `a` from pattern #1 isn't bound in pattern #2
//~^ ERROR variable `b` from pattern #2 isn't bound in pattern #1
//~| NOTE pattern doesn't bind `a`
//~| NOTE pattern doesn't bind `b`
//~| NOTE variable not in all patterns
//~| NOTE variable not in all patterns
}
}
22 changes: 22 additions & 0 deletions src/test/ui/span/issue-39698.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

enum T {
T1(i32, i32),
T2(i32, i32),
T3(i32),
T4(i32),
}

fn main() {
match T::T1(123, 456) {
T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
}
}
29 changes: 29 additions & 0 deletions src/test/ui/span/issue-39698.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error[E0408]: variable `d` from pattern #1 isn't bound in patterns #3, #4
--> $DIR/issue-39698.rs:20:37
|
20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
| - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d`
| | |
| | pattern doesn't bind `d`
| variable not in all patterns

error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3
--> $DIR/issue-39698.rs:20:23
|
20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
| - ^^^^^^^^^^^ ^^^^^^^^ pattern doesn't bind `a`
| | |
| | pattern doesn't bind `a`
| variable not in all patterns

error[E0408]: variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern #1
--> $DIR/issue-39698.rs:20:32
|
20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
| ----------- ^ ^ variable not in all patterns
| | |
| | variable not in all patterns
| pattern doesn't bind `b`, `c`

error: aborting due to 3 previous errors

0 comments on commit 738b0f3

Please sign in to comment.