resolve: Use same rules for disambiguating fresh bindings in match and let
This commit is contained in:
parent
2278506f68
commit
db0be32fec
6 changed files with 90 additions and 25 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,6 @@ struct Test;
|
|||
|
||||
fn main() {
|
||||
|| {
|
||||
let Test = 1; //~ ERROR let bindings cannot shadow unit structs
|
||||
let Test = 1; //~ ERROR mismatched types
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
67
src/test/compile-fail/pattern-binding-disambiguation.rs
Normal file
67
src/test/compile-fail/pattern-binding-disambiguation.rs
Normal file
|
|
@ -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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue