about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-10 19:10:12 +0000
committerbors <bors@rust-lang.org>2017-11-10 19:10:12 +0000
commita35a3abcda67a729edbb7d649dbc663c6feabd4c (patch)
tree57774687c76fadcb30a945409bcc3738d40901a0 /src
parent75d25acd977085e6ae01d6a5c56cbbfc97463f89 (diff)
parent765076faabcceba7cc75ae78c4923f89bb34975b (diff)
downloadrust-a35a3abcda67a729edbb7d649dbc663c6feabd4c.tar.gz
rust-a35a3abcda67a729edbb7d649dbc663c6feabd4c.zip
Auto merge of #45050 - petrochenkov:ambind, r=nikomatsakis
resolve: Use same rules for disambiguating fresh bindings in `match` and `let`

Resolve `Unit` as a unit struct pattern in
```rust
struct Unit;

let Unit = x;
```
consistently with
```rust
match x {
    Unit => {}
}
```
It was previously an error.
(The change also applies to unit variants and constants.)

Fixes https://users.rust-lang.org/t/e0530-cannot-shadow-unit-structs-what-in-the-earthly-what/13054
(This particular change doesn't depend on a fix for the issue mentioned in https://users.rust-lang.org/t/e0530-cannot-shadow-unit-structs-what-in-the-earthly-what/13054/4)

cc @rust-lang/lang
r? @nikomatsakis
Diffstat (limited to 'src')
-rw-r--r--src/librustc_const_eval/check_match.rs9
-rw-r--r--src/librustc_resolve/lib.rs24
-rw-r--r--src/test/compile-fail/blind-item-block-middle.rs2
-rw-r--r--src/test/compile-fail/issue-33504.rs2
-rw-r--r--src/test/compile-fail/pattern-binding-disambiguation.rs67
-rw-r--r--src/test/ui/const-pattern-irrefutable.rs (renamed from src/test/compile-fail/const-pattern-irrefutable.rs)15
-rw-r--r--src/test/ui/const-pattern-irrefutable.stderr20
-rw-r--r--src/test/ui/resolve/name-clash-nullary.rs (renamed from src/test/compile-fail/name-clash-nullary.rs)7
-rw-r--r--src/test/ui/resolve/name-clash-nullary.stderr11
9 files changed, 126 insertions, 31 deletions
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index e6a04c9c57a..98ed8d99fda 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -260,7 +260,14 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                 "refutable pattern in {}: `{}` not covered",
                 origin, pattern_string
             );
-            diag.span_label(pat.span, format!("pattern `{}` not covered", pattern_string));
+            let label_msg = match pat.node {
+                PatKind::Path(hir::QPath::Resolved(None, ref path))
+                        if path.segments.len() == 1 && path.segments[0].parameters.is_none() => {
+                    format!("interpreted as a {} pattern, not new variable", path.def.kind_name())
+                }
+                _ => format!("pattern `{}` not covered", pattern_string),
+            };
+            diag.span_label(pat.span, label_msg);
             diag.emit();
         });
     }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 58bdf542fc9..8207057fd0a 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -377,12 +377,6 @@ enum PatternSource {
 }
 
 impl PatternSource {
-    fn is_refutable(self) -> bool {
-        match self {
-            PatternSource::Match | PatternSource::IfLet | PatternSource::WhileLet => true,
-            PatternSource::Let | PatternSource::For | PatternSource::FnParam  => false,
-        }
-    }
     fn descr(self) -> &'static str {
         match self {
             PatternSource::Match => "match binding",
@@ -2388,20 +2382,24 @@ impl<'a> Resolver<'a> {
                                                                       false, pat.span)
                                       .and_then(LexicalScopeBinding::item);
                     let resolution = binding.map(NameBinding::def).and_then(|def| {
-                        let ivmode = BindingMode::ByValue(Mutability::Immutable);
-                        let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
-                                             bmode != ivmode;
+                        let is_syntactic_ambiguity = opt_pat.is_none() &&
+                            bmode == BindingMode::ByValue(Mutability::Immutable);
                         match def {
                             Def::StructCtor(_, CtorKind::Const) |
                             Def::VariantCtor(_, CtorKind::Const) |
-                            Def::Const(..) if !always_binding => {
-                                // A unit struct/variant or constant pattern.
+                            Def::Const(..) if is_syntactic_ambiguity => {
+                                // Disambiguate in favor of a unit struct/variant
+                                // or constant pattern.
                                 self.record_use(ident.node, ValueNS, binding.unwrap(), ident.span);
                                 Some(PathResolution::new(def))
                             }
                             Def::StructCtor(..) | Def::VariantCtor(..) |
                             Def::Const(..) | Def::Static(..) => {
-                                // A fresh binding that shadows something unacceptable.
+                                // This is unambiguously a fresh binding, either syntactically
+                                // (e.g. `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
+                                // to something unusable as a pattern (e.g. constructor function),
+                                // but we still conservatively report an error, see
+                                // issues/33118#issuecomment-233962221 for one reason why.
                                 resolve_error(
                                     self,
                                     ident.span,
@@ -2410,7 +2408,7 @@ impl<'a> Resolver<'a> {
                                 );
                                 None
                             }
-                            Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => {
+                            Def::Fn(..) | Def::Err => {
                                 // These entities are explicitly allowed
                                 // to be shadowed by fresh bindings.
                                 None
diff --git a/src/test/compile-fail/blind-item-block-middle.rs b/src/test/compile-fail/blind-item-block-middle.rs
index 0db7eaf0ca7..a501a5cd3ec 100644
--- a/src/test/compile-fail/blind-item-block-middle.rs
+++ b/src/test/compile-fail/blind-item-block-middle.rs
@@ -12,6 +12,6 @@ mod foo { pub struct bar; }
 
 fn main() {
     let bar = 5;
-    //~^ ERROR let bindings cannot shadow unit structs
+    //~^ ERROR mismatched types
     use foo::bar;
 }
diff --git a/src/test/compile-fail/issue-33504.rs b/src/test/compile-fail/issue-33504.rs
index bc78d20745a..1e1994357c7 100644
--- a/src/test/compile-fail/issue-33504.rs
+++ b/src/test/compile-fail/issue-33504.rs
@@ -14,6 +14,6 @@ struct Test;
 
 fn main() {
     || {
-        let Test = 1; //~ ERROR let bindings cannot shadow unit structs
+        let Test = 1; //~ ERROR mismatched types
     };
 }
diff --git a/src/test/compile-fail/pattern-binding-disambiguation.rs b/src/test/compile-fail/pattern-binding-disambiguation.rs
new file mode 100644
index 00000000000..c740f6bb47c
--- /dev/null
+++ b/src/test/compile-fail/pattern-binding-disambiguation.rs
@@ -0,0 +1,67 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct UnitStruct;
+struct TupleStruct();
+struct BracedStruct{}
+
+enum E {
+    UnitVariant,
+    TupleVariant(),
+    BracedVariant{},
+}
+use E::*;
+
+const CONST: () = ();
+static STATIC: () = ();
+
+fn function() {}
+
+fn main() {
+    let doesnt_matter = 0;
+
+    match UnitStruct {
+        UnitStruct => {} // OK, `UnitStruct` is a unit struct pattern
+    }
+    match doesnt_matter {
+        TupleStruct => {} //~ ERROR match bindings cannot shadow tuple structs
+    }
+    match doesnt_matter {
+        BracedStruct => {} // OK, `BracedStruct` is a fresh binding
+    }
+    match UnitVariant {
+        UnitVariant => {} // OK, `UnitVariant` is a unit variant pattern
+    }
+    match doesnt_matter {
+        TupleVariant => {} //~ ERROR match bindings cannot shadow tuple variants
+    }
+    match doesnt_matter {
+        BracedVariant => {} //~ ERROR match bindings cannot shadow struct variants
+    }
+    match CONST {
+        CONST => {} // OK, `CONST` is a const pattern
+    }
+    match doesnt_matter {
+        STATIC => {} //~ ERROR match bindings cannot shadow statics
+    }
+    match doesnt_matter {
+        function => {} // OK, `function` is a fresh binding
+    }
+
+    let UnitStruct = UnitStruct; // OK, `UnitStruct` is a unit struct pattern
+    let TupleStruct = doesnt_matter; //~ ERROR let bindings cannot shadow tuple structs
+    let BracedStruct = doesnt_matter; // OK, `BracedStruct` is a fresh binding
+    let UnitVariant = UnitVariant; // OK, `UnitVariant` is a unit variant pattern
+    let TupleVariant = doesnt_matter; //~ ERROR let bindings cannot shadow tuple variants
+    let BracedVariant = doesnt_matter; //~ ERROR let bindings cannot shadow struct variants
+    let CONST = CONST; // OK, `CONST` is a const pattern
+    let STATIC = doesnt_matter; //~ ERROR let bindings cannot shadow statics
+    let function = doesnt_matter; // OK, `function` is a fresh binding
+}
diff --git a/src/test/compile-fail/const-pattern-irrefutable.rs b/src/test/ui/const-pattern-irrefutable.rs
index 11003067070..af0b95e002d 100644
--- a/src/test/compile-fail/const-pattern-irrefutable.rs
+++ b/src/test/ui/const-pattern-irrefutable.rs
@@ -13,17 +13,14 @@ mod foo {
     pub const d: u8 = 2;
 }
 
-use foo::b as c; //~ NOTE is imported here
-use foo::d; //~ NOTE is imported here
+use foo::b as c;
+use foo::d;
 
-const a: u8 = 2; //~ NOTE is defined here
+const a: u8 = 2;
 
 fn main() {
-    let a = 4; //~ ERROR let bindings cannot shadow constants
-               //~^ NOTE cannot be named the same as a constant
-    let c = 4; //~ ERROR let bindings cannot shadow constants
-               //~^ NOTE cannot be named the same as a constant
-    let d = 4; //~ ERROR let bindings cannot shadow constants
-               //~^ NOTE cannot be named the same as a constant
+    let a = 4; //~ ERROR refutable pattern in local binding: `_` not covered
+    let c = 4; //~ ERROR refutable pattern in local binding: `_` not covered
+    let d = 4; //~ ERROR refutable pattern in local binding: `_` not covered
     fn f() {} // Check that the `NOTE`s still work with an item here (c.f. issue #35115).
 }
diff --git a/src/test/ui/const-pattern-irrefutable.stderr b/src/test/ui/const-pattern-irrefutable.stderr
new file mode 100644
index 00000000000..af48b773638
--- /dev/null
+++ b/src/test/ui/const-pattern-irrefutable.stderr
@@ -0,0 +1,20 @@
+error[E0005]: refutable pattern in local binding: `_` not covered
+  --> $DIR/const-pattern-irrefutable.rs:22:9
+   |
+22 |     let a = 4; //~ ERROR refutable pattern in local binding: `_` not covered
+   |         ^ interpreted as a constant pattern, not new variable
+
+error[E0005]: refutable pattern in local binding: `_` not covered
+  --> $DIR/const-pattern-irrefutable.rs:23:9
+   |
+23 |     let c = 4; //~ ERROR refutable pattern in local binding: `_` not covered
+   |         ^ interpreted as a constant pattern, not new variable
+
+error[E0005]: refutable pattern in local binding: `_` not covered
+  --> $DIR/const-pattern-irrefutable.rs:24:9
+   |
+24 |     let d = 4; //~ ERROR refutable pattern in local binding: `_` not covered
+   |         ^ interpreted as a constant pattern, not new variable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/compile-fail/name-clash-nullary.rs b/src/test/ui/resolve/name-clash-nullary.rs
index bfcb0f4e863..adf52c6d8e6 100644
--- a/src/test/compile-fail/name-clash-nullary.rs
+++ b/src/test/ui/resolve/name-clash-nullary.rs
@@ -8,11 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::option::*;
-
 fn main() {
-  let None: isize = 42; //~ ERROR let bindings cannot shadow unit variants
-  log(debug, None);
-  //~^ ERROR cannot find function `log` in this scope
-  //~| ERROR cannot find value `debug` in this scope
+  let None: isize = 42; //~ ERROR mismatched types
 }
diff --git a/src/test/ui/resolve/name-clash-nullary.stderr b/src/test/ui/resolve/name-clash-nullary.stderr
new file mode 100644
index 00000000000..014b1fe1b5b
--- /dev/null
+++ b/src/test/ui/resolve/name-clash-nullary.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/name-clash-nullary.rs:12:7
+   |
+12 |   let None: isize = 42; //~ ERROR mismatched types
+   |       ^^^^ expected isize, found enum `std::option::Option`
+   |
+   = note: expected type `isize`
+              found type `std::option::Option<_>`
+
+error: aborting due to previous error
+