diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e6a04c9c57a6c..98ed8d99fda70 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 58bdf542fc9d4..8207057fd0aae 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 0db7eaf0ca7c3..a501a5cd3ec4c 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 bc78d20745a54..1e1994357c77a 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 0000000000000..c740f6bb47c3f --- /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 or the MIT license +// , 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 similarity index 55% rename from src/test/compile-fail/const-pattern-irrefutable.rs rename to src/test/ui/const-pattern-irrefutable.rs index 11003067070f4..af0b95e002d84 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 0000000000000..af48b7736381a --- /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 similarity index 68% rename from src/test/compile-fail/name-clash-nullary.rs rename to src/test/ui/resolve/name-clash-nullary.rs index bfcb0f4e86329..adf52c6d8e64d 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 0000000000000..014b1fe1b5b07 --- /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 +