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

Improve diagnostics for constants being used in irrefutable patterns #33406

Merged
merged 2 commits into from
May 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2233,7 +2233,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