Skip to content

Commit 30ce555

Browse files
committed
Rollup merge of rust-lang#33406 - Manishearth:diag-improve-const-let, 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
2 parents e596211 + 9f302b6 commit 30ce555

File tree

4 files changed

+71
-9
lines changed

4 files changed

+71
-9
lines changed

src/librustc_resolve/diagnostics.rs

+63-1
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,69 @@ let Foo = 12i32; // ok!
623623
The goal here is to avoid a conflict of names.
624624
"##,
625625

626+
E0414: r##"
627+
A variable binding in an irrefutable pattern is shadowing the name of a
628+
constant. Example of erroneous code:
629+
630+
```compile_fail
631+
const FOO: u8 = 7;
632+
633+
let FOO = 5; // error: variable bindings cannot shadow constants
634+
635+
// or
636+
637+
fn bar(FOO: u8) { // error: variable bindings cannot shadow constants
638+
639+
}
640+
641+
// or
642+
643+
for FOO in bar {
644+
645+
}
646+
```
647+
648+
Introducing a new variable in Rust is done through a pattern. Thus you can have
649+
`let` bindings like `let (a, b) = ...`. However, patterns also allow constants
650+
in them, e.g. if you want to match over a constant:
651+
652+
```ignore
653+
const FOO: u8 = 1;
654+
655+
match (x,y) {
656+
(3, 4) => { .. }, // it is (3,4)
657+
(FOO, 1) => { .. }, // it is (1,1)
658+
(foo, 1) => { .. }, // it is (anything, 1)
659+
// call the value in the first slot "foo"
660+
_ => { .. } // it is anything
661+
}
662+
```
663+
664+
Here, the second arm matches the value of `x` against the constant `FOO`,
665+
whereas the third arm will accept any value of `x` and call it `foo`.
666+
667+
This works for `match`, however in cases where an irrefutable pattern is
668+
required, constants can't be used. An irrefutable pattern is one which always
669+
matches, whose purpose is only to bind variable names to values. These are
670+
required by let, for, and function argument patterns.
671+
672+
Refutable patterns in such a situation do not make sense, for example:
673+
674+
```ignore
675+
let Some(x) = foo; // what if foo is None, instead?
676+
677+
let (1, x) = foo; // what if foo.0 is not 1?
678+
679+
let (SOME_CONST, x) = foo; // what if foo.0 is not SOME_CONST?
680+
681+
let SOME_CONST = foo; // what if foo is not SOME_CONST?
682+
```
683+
684+
Thus, an irrefutable variable binding can't contain a constant.
685+
686+
To fix this error, just give the marked variable a different name.
687+
"##,
688+
626689
E0415: r##"
627690
More than one function parameter have the same name. Example of erroneous code:
628691
@@ -1086,7 +1149,6 @@ register_diagnostics! {
10861149
E0409, // variable is bound with different mode in pattern # than in
10871150
// pattern #1
10881151
E0410, // variable from pattern is not bound in pattern 1
1089-
E0414, // only irrefutable patterns allowed here
10901152
E0418, // is not an enum variant, struct or const
10911153
E0420, // is not an associated const
10921154
E0421, // unresolved associated const

src/librustc_resolve/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ enum ResolutionError<'a> {
141141
/// error E0413: declaration shadows an enum variant or unit-like struct in scope
142142
DeclarationShadowsEnumVariantOrUnitLikeStruct(Name),
143143
/// error E0414: only irrefutable patterns allowed here
144-
OnlyIrrefutablePatternsAllowedHere(Name),
144+
ConstantForIrrefutableBinding(Name),
145145
/// error E0415: identifier is bound more than once in this parameter list
146146
IdentifierBoundMoreThanOnceInParameterList(&'a str),
147147
/// error E0416: identifier is bound more than once in the same pattern
@@ -323,11 +323,11 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
323323
or unit-like struct in scope",
324324
name)
325325
}
326-
ResolutionError::OnlyIrrefutablePatternsAllowedHere(name) => {
326+
ResolutionError::ConstantForIrrefutableBinding(name) => {
327327
let mut err = struct_span_err!(resolver.session,
328328
span,
329329
E0414,
330-
"only irrefutable patterns allowed here");
330+
"variable bindings cannot shadow constants");
331331
err.span_note(span,
332332
"there already is a constant in scope sharing the same \
333333
name as this pattern");
@@ -2245,7 +2245,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
22452245
resolve_error(
22462246
self,
22472247
pattern.span,
2248-
ResolutionError::OnlyIrrefutablePatternsAllowedHere(name)
2248+
ResolutionError::ConstantForIrrefutableBinding(name)
22492249
);
22502250
self.record_def(pattern.id, err_path_resolution());
22512251
}

src/test/compile-fail/const-pattern-irrefutable.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ use foo::d; //~ NOTE constant imported here
1919
const a: u8 = 2; //~ NOTE constant defined here
2020

2121
fn main() {
22-
let a = 4; //~ ERROR only irrefutable
22+
let a = 4; //~ ERROR variable bindings cannot
2323
//~^ NOTE there already is a constant in scope
24-
let c = 4; //~ ERROR only irrefutable
24+
let c = 4; //~ ERROR variable bindings cannot
2525
//~^ NOTE there already is a constant in scope
26-
let d = 4; //~ ERROR only irrefutable
26+
let d = 4; //~ ERROR variable bindings cannot
2727
//~^ NOTE there already is a constant in scope
2828
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fn main() {
1414
};
1515
const C: u8 = 1;
1616
match 1 {
17-
C @ 2 => { //~ ERROR only irrefutable patterns allowed here
17+
C @ 2 => { //~ ERROR variable bindings cannot shadow constants
1818
println!("{}", C);
1919
}
2020
_ => {}

0 commit comments

Comments
 (0)