From db0be32fec539ab57c446433cb186f979af40413 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 5 Oct 2017 22:54:34 +0300 Subject: [PATCH] resolve: Use same rules for disambiguating fresh bindings in `match` and `let` --- src/librustc_resolve/lib.rs | 24 +++---- .../compile-fail/blind-item-block-middle.rs | 2 +- .../compile-fail/const-pattern-irrefutable.rs | 18 ++--- src/test/compile-fail/issue-33504.rs | 2 +- src/test/compile-fail/name-clash-nullary.rs | 2 +- .../pattern-binding-disambiguation.rs | 67 +++++++++++++++++++ 6 files changed, 90 insertions(+), 25 deletions(-) create mode 100644 src/test/compile-fail/pattern-binding-disambiguation.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c4f159544e40..930aebf25fb3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -376,12 +376,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", @@ -2378,20 +2372,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, @@ -2400,7 +2398,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 0db7eaf0ca7c..a501a5cd3ec4 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/const-pattern-irrefutable.rs b/src/test/compile-fail/const-pattern-irrefutable.rs index 11003067070f..5aa5a92c3a79 100644 --- a/src/test/compile-fail/const-pattern-irrefutable.rs +++ b/src/test/compile-fail/const-pattern-irrefutable.rs @@ -13,17 +13,17 @@ 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 + //~^ NOTE pattern `_` not covered + let c = 4; //~ ERROR refutable pattern in local binding: `_` not covered + //~^ NOTE pattern `_` not covered + let d = 4; //~ ERROR refutable pattern in local binding: `_` not covered + //~^ NOTE pattern `_` not covered fn f() {} // Check that the `NOTE`s still work with an item here (c.f. issue #35115). } diff --git a/src/test/compile-fail/issue-33504.rs b/src/test/compile-fail/issue-33504.rs index bc78d20745a5..1e1994357c77 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/name-clash-nullary.rs b/src/test/compile-fail/name-clash-nullary.rs index bfcb0f4e8632..1b6b47137030 100644 --- a/src/test/compile-fail/name-clash-nullary.rs +++ b/src/test/compile-fail/name-clash-nullary.rs @@ -11,7 +11,7 @@ use std::option::*; fn main() { - let None: isize = 42; //~ ERROR let bindings cannot shadow unit variants + let None: isize = 42; //~ ERROR mismatched types log(debug, None); //~^ ERROR cannot find function `log` in this scope //~| ERROR cannot find value `debug` in this scope 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 000000000000..c740f6bb47c3 --- /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 +}