Skip to content

Commit 738b0f3

Browse files
committed
Clean up "pattern doesn't bind x" messages
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 ```
1 parent c49d102 commit 738b0f3

File tree

7 files changed

+131
-22
lines changed

7 files changed

+131
-22
lines changed

src/librustc_resolve/lib.rs

+71-17
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,10 @@ enum ResolutionError<'a> {
109109
TypeNotMemberOfTrait(Name, &'a str),
110110
/// error E0438: const is not a member of trait
111111
ConstNotMemberOfTrait(Name, &'a str),
112-
/// error E0408: variable `{}` from pattern #{} is not bound in pattern #{}
113-
VariableNotBoundInPattern(Name, usize, usize),
112+
/// error E0408: variable `{}` from pattern #{} is not bound in pattern #1
113+
VariableNotBoundInPattern(Name, Span, Vec<(Span, usize)>),
114+
/// error E0408: variable `{}` from pattern #1 is not bound in pattern #{}
115+
VariableNotBoundInFirstPattern(Span, Vec<(Name, usize, Span)>),
114116
/// error E0409: variable is bound with different mode in pattern #{} than in pattern #1
115117
VariableBoundWithDifferentMode(Name, usize, Span),
116118
/// error E0415: identifier is bound more than once in this parameter list
@@ -204,15 +206,53 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
204206
err.span_label(span, &format!("not a member of trait `{}`", trait_));
205207
err
206208
}
207-
ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => {
208-
let mut err = struct_span_err!(resolver.session,
209-
span,
210-
E0408,
211-
"variable `{}` from pattern #{} is not bound in pattern #{}",
212-
variable_name,
213-
from,
214-
to);
215-
err.span_label(span, &format!("pattern doesn't bind `{}`", variable_name));
209+
ResolutionError::VariableNotBoundInPattern(variable_name, sp, missing_vars) => {
210+
let spans: Vec<_> = missing_vars.iter().map(|x| x.0).collect();
211+
let msp = MultiSpan::from_spans(spans.clone());
212+
// "variable `a` from pattern #1 is not bound in patterns #2, #3"
213+
let msg = format!("variable `{}` from pattern #1 isn't bound in pattern{} {}",
214+
variable_name,
215+
if spans.len() > 1 {
216+
"s"
217+
} else {
218+
""
219+
},
220+
missing_vars.iter()
221+
.map(|x| format!("#{}", x.1))
222+
.collect::<Vec<_>>()
223+
.join(", "));
224+
let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408");
225+
for sp in spans {
226+
err.span_label(sp, &format!("pattern doesn't bind `{}`", variable_name));
227+
}
228+
err.span_label(sp, &"variable not in all patterns");
229+
err
230+
}
231+
ResolutionError::VariableNotBoundInFirstPattern(sp, extra_vars) => {
232+
let spans: Vec<_> = extra_vars.iter().map(|x| x.2).collect();
233+
let msp = MultiSpan::from_spans(spans.clone());
234+
// "variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern
235+
// #1"
236+
let msg = format!("{} {}n't bound in pattern #1",
237+
extra_vars.iter()
238+
.map(|x| format!("variable `{}` from pattern #{}", x.0, x.1))
239+
.collect::<Vec<_>>()
240+
.join(", "),
241+
if spans.len() > 1 {
242+
"are"
243+
} else {
244+
"is"
245+
});
246+
let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408");
247+
for sp in spans {
248+
err.span_label(sp, &"variable not in all patterns");
249+
}
250+
err.span_label(sp,
251+
&format!("pattern doesn't bind {}",
252+
extra_vars.iter()
253+
.map(|x| format!("`{}`", x.0))
254+
.collect::<Vec<_>>()
255+
.join(", ")));
216256
err
217257
}
218258
ResolutionError::VariableBoundWithDifferentMode(variable_name,
@@ -324,7 +364,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
324364
}
325365
}
326366

327-
#[derive(Copy, Clone)]
367+
#[derive(Copy, Clone, Debug)]
328368
struct BindingInfo {
329369
span: Span,
330370
binding_mode: BindingMode,
@@ -1867,14 +1907,20 @@ impl<'a> Resolver<'a> {
18671907
return;
18681908
}
18691909
let map_0 = self.binding_mode_map(&arm.pats[0]);
1910+
1911+
let mut missing_vars = FxHashMap();
1912+
let mut extra_vars = vec![];
1913+
18701914
for (i, p) in arm.pats.iter().enumerate() {
18711915
let map_i = self.binding_mode_map(&p);
18721916

18731917
for (&key, &binding_0) in &map_0 {
18741918
match map_i.get(&key) {
18751919
None => {
1876-
let error = ResolutionError::VariableNotBoundInPattern(key.name, 1, i + 1);
1877-
resolve_error(self, p.span, error);
1920+
let spans = missing_vars
1921+
.entry((key.name, binding_0.span))
1922+
.or_insert(vec![]);
1923+
spans.push((p.span, i + 1));
18781924
}
18791925
Some(binding_i) => {
18801926
if binding_0.binding_mode != binding_i.binding_mode {
@@ -1891,12 +1937,20 @@ impl<'a> Resolver<'a> {
18911937

18921938
for (&key, &binding) in &map_i {
18931939
if !map_0.contains_key(&key) {
1894-
resolve_error(self,
1895-
binding.span,
1896-
ResolutionError::VariableNotBoundInPattern(key.name, i + 1, 1));
1940+
extra_vars.push((key.name, i + 1, binding.span));
18971941
}
18981942
}
18991943
}
1944+
for (k, v) in missing_vars {
1945+
let (name, sp) = k;
1946+
resolve_error(self, sp, ResolutionError::VariableNotBoundInPattern(name, sp, v));
1947+
}
1948+
if extra_vars.len() > 0 {
1949+
resolve_error(self,
1950+
arm.pats[0].span,
1951+
ResolutionError::VariableNotBoundInFirstPattern(arm.pats[0].span,
1952+
extra_vars));
1953+
}
19001954
}
19011955

19021956
fn resolve_arm(&mut self, arm: &Arm) {

src/test/compile-fail/E0408.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ fn main() {
1212
let x = Some(0);
1313

1414
match x {
15-
Some(y) | None => {} //~ ERROR variable `y` from pattern #1 is not bound in pattern #2
15+
Some(y) | None => {} //~ ERROR variable `y` from pattern #1 isn't bound in pattern #2
1616
_ => () //~| NOTE pattern doesn't bind `y`
17+
//~| NOTE variable not in all patterns
1718
}
1819
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ mod bar {
1919
fn main() {
2020
use bar::foo::{alpha, charlie};
2121
match alpha {
22-
alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1
22+
alpha | beta => {} //~ ERROR variable `beta` from pattern #2 isn't bound in pattern #1
2323
charlie => {} //~| NOTE pattern doesn't bind `beta`
24+
//~| NOTE variable not in all patterns
2425
}
2526
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ enum foo { alpha, beta(isize) }
1313
fn main() {
1414
match foo::alpha {
1515
foo::alpha | foo::beta(i) => {}
16-
//~^ ERROR variable `i` from pattern #2 is not bound in pattern #1
16+
//~^ ERROR variable `i` from pattern #2 isn't bound in pattern #1
1717
}
1818
}

src/test/compile-fail/resolve-inconsistent-names.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
fn main() {
1212
let y = 1;
1313
match y {
14-
a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2
15-
//~^ ERROR variable `b` from pattern #2 is not bound in pattern #1
14+
a | b => {} //~ ERROR variable `a` from pattern #1 isn't bound in pattern #2
15+
//~^ ERROR variable `b` from pattern #2 isn't bound in pattern #1
1616
//~| NOTE pattern doesn't bind `a`
1717
//~| NOTE pattern doesn't bind `b`
18+
//~| NOTE variable not in all patterns
19+
//~| NOTE variable not in all patterns
1820
}
1921
}

src/test/ui/span/issue-39698.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
enum T {
12+
T1(i32, i32),
13+
T2(i32, i32),
14+
T3(i32),
15+
T4(i32),
16+
}
17+
18+
fn main() {
19+
match T::T1(123, 456) {
20+
T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
21+
}
22+
}

src/test/ui/span/issue-39698.stderr

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0408]: variable `d` from pattern #1 isn't bound in patterns #3, #4
2+
--> $DIR/issue-39698.rs:20:37
3+
|
4+
20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
5+
| - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d`
6+
| | |
7+
| | pattern doesn't bind `d`
8+
| variable not in all patterns
9+
10+
error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3
11+
--> $DIR/issue-39698.rs:20:23
12+
|
13+
20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
14+
| - ^^^^^^^^^^^ ^^^^^^^^ pattern doesn't bind `a`
15+
| | |
16+
| | pattern doesn't bind `a`
17+
| variable not in all patterns
18+
19+
error[E0408]: variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern #1
20+
--> $DIR/issue-39698.rs:20:32
21+
|
22+
20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); }
23+
| ----------- ^ ^ variable not in all patterns
24+
| | |
25+
| | variable not in all patterns
26+
| pattern doesn't bind `b`, `c`
27+
28+
error: aborting due to 3 previous errors
29+

0 commit comments

Comments
 (0)