about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2016-05-07 22:08:13 -0700
committerManish Goregaokar <manishsmail@gmail.com>2016-05-08 07:00:11 -0700
commitdeb97fef214cf93a07f0b873e10b3dbb3c5d7058 (patch)
tree32d5db0e0d809a9bd72168a2198a117ab9cb7016
parent0cb966fa3b52ecb2d8b0da5419f8ba1c1a94b520 (diff)
parent9f302b6bcdc7b3d35a074ff565e17350f12038b7 (diff)
Rollup merge of #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
-rw-r--r--src/librustc_resolve/diagnostics.rs64
-rw-r--r--src/librustc_resolve/lib.rs8
-rw-r--r--src/test/compile-fail/const-pattern-irrefutable.rs6
-rw-r--r--src/test/compile-fail/issue-27033.rs2
4 files changed, 71 insertions, 9 deletions
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 56d3b927dc5..fda7c7aeb33 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -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:
 
@@ -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
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index ff412be323a..7c6c76f130e 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -139,7 +139,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
@@ -321,11 +321,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");
@@ -2248,7 +2248,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());
                         }
diff --git a/src/test/compile-fail/const-pattern-irrefutable.rs b/src/test/compile-fail/const-pattern-irrefutable.rs
index 825c39011fc..0be1e974e7d 100644
--- a/src/test/compile-fail/const-pattern-irrefutable.rs
+++ b/src/test/compile-fail/const-pattern-irrefutable.rs
@@ -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
 }
diff --git a/src/test/compile-fail/issue-27033.rs b/src/test/compile-fail/issue-27033.rs
index 051edfe5f45..a729cf95a7b 100644
--- a/src/test/compile-fail/issue-27033.rs
+++ b/src/test/compile-fail/issue-27033.rs
@@ -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);
         }
         _ => {}