Skip to content

Commit

Permalink
Rollup merge of rust-lang#33406 - Manishearth:diag-improve-const-let,…
Browse files Browse the repository at this point in the history
… r=GuillaumeGomez

Improve diagnostics for constants being used in irrefutable patterns

It's pretty confusing and this error triggers in resolve only when "shadowing" a const, so let's make that clearer.

r? @steveklabnik
  • Loading branch information
Manishearth committed May 8, 2016
2 parents e596211 + 9f302b6 commit 30ce555
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 9 deletions.
64 changes: 63 additions & 1 deletion src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,69 @@ let Foo = 12i32; // ok!
The goal here is to avoid a conflict of names.
"##,

E0414: r##"
A variable binding in an irrefutable pattern is shadowing the name of a
constant. Example of erroneous code:
```compile_fail
const FOO: u8 = 7;
let FOO = 5; // error: variable bindings cannot shadow constants
// or
fn bar(FOO: u8) { // error: variable bindings cannot shadow constants
}
// or
for FOO in bar {
}
```
Introducing a new variable in Rust is done through a pattern. Thus you can have
`let` bindings like `let (a, b) = ...`. However, patterns also allow constants
in them, e.g. if you want to match over a constant:
```ignore
const FOO: u8 = 1;
match (x,y) {
(3, 4) => { .. }, // it is (3,4)
(FOO, 1) => { .. }, // it is (1,1)
(foo, 1) => { .. }, // it is (anything, 1)
// call the value in the first slot "foo"
_ => { .. } // it is anything
}
```
Here, the second arm matches the value of `x` against the constant `FOO`,
whereas the third arm will accept any value of `x` and call it `foo`.
This works for `match`, however in cases where an irrefutable pattern is
required, constants can't be used. An irrefutable pattern is one which always
matches, whose purpose is only to bind variable names to values. These are
required by let, for, and function argument patterns.
Refutable patterns in such a situation do not make sense, for example:
```ignore
let Some(x) = foo; // what if foo is None, instead?
let (1, x) = foo; // what if foo.0 is not 1?
let (SOME_CONST, x) = foo; // what if foo.0 is not SOME_CONST?
let SOME_CONST = foo; // what if foo is not SOME_CONST?
```
Thus, an irrefutable variable binding can't contain a constant.
To fix this error, just give the marked variable a different name.
"##,

E0415: r##"
More than one function parameter have the same name. Example of erroneous code:
Expand Down Expand Up @@ -1086,7 +1149,6 @@ register_diagnostics! {
E0409, // variable is bound with different mode in pattern # than in
// pattern #1
E0410, // variable from pattern is not bound in pattern 1
E0414, // only irrefutable patterns allowed here
E0418, // is not an enum variant, struct or const
E0420, // is not an associated const
E0421, // unresolved associated const
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ enum ResolutionError<'a> {
/// error E0413: declaration shadows an enum variant or unit-like struct in scope
DeclarationShadowsEnumVariantOrUnitLikeStruct(Name),
/// error E0414: only irrefutable patterns allowed here
OnlyIrrefutablePatternsAllowedHere(Name),
ConstantForIrrefutableBinding(Name),
/// error E0415: identifier is bound more than once in this parameter list
IdentifierBoundMoreThanOnceInParameterList(&'a str),
/// error E0416: identifier is bound more than once in the same pattern
Expand Down Expand Up @@ -323,11 +323,11 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
or unit-like struct in scope",
name)
}
ResolutionError::OnlyIrrefutablePatternsAllowedHere(name) => {
ResolutionError::ConstantForIrrefutableBinding(name) => {
let mut err = struct_span_err!(resolver.session,
span,
E0414,
"only irrefutable patterns allowed here");
"variable bindings cannot shadow constants");
err.span_note(span,
"there already is a constant in scope sharing the same \
name as this pattern");
Expand Down Expand Up @@ -2245,7 +2245,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
resolve_error(
self,
pattern.span,
ResolutionError::OnlyIrrefutablePatternsAllowedHere(name)
ResolutionError::ConstantForIrrefutableBinding(name)
);
self.record_def(pattern.id, err_path_resolution());
}
Expand Down
6 changes: 3 additions & 3 deletions src/test/compile-fail/const-pattern-irrefutable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ use foo::d; //~ NOTE constant imported here
const a: u8 = 2; //~ NOTE constant defined here

fn main() {
let a = 4; //~ ERROR only irrefutable
let a = 4; //~ ERROR variable bindings cannot
//~^ NOTE there already is a constant in scope
let c = 4; //~ ERROR only irrefutable
let c = 4; //~ ERROR variable bindings cannot
//~^ NOTE there already is a constant in scope
let d = 4; //~ ERROR only irrefutable
let d = 4; //~ ERROR variable bindings cannot
//~^ NOTE there already is a constant in scope
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-27033.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn main() {
};
const C: u8 = 1;
match 1 {
C @ 2 => { //~ ERROR only irrefutable patterns allowed here
C @ 2 => { //~ ERROR variable bindings cannot shadow constants
println!("{}", C);
}
_ => {}
Expand Down

0 comments on commit 30ce555

Please sign in to comment.