Skip to content

Commit a35a3ab

Browse files
committed
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
2 parents 75d25ac + 765076f commit a35a3ab

9 files changed

+126
-31
lines changed

src/librustc_const_eval/check_match.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,14 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
260260
"refutable pattern in {}: `{}` not covered",
261261
origin, pattern_string
262262
);
263-
diag.span_label(pat.span, format!("pattern `{}` not covered", pattern_string));
263+
let label_msg = match pat.node {
264+
PatKind::Path(hir::QPath::Resolved(None, ref path))
265+
if path.segments.len() == 1 && path.segments[0].parameters.is_none() => {
266+
format!("interpreted as a {} pattern, not new variable", path.def.kind_name())
267+
}
268+
_ => format!("pattern `{}` not covered", pattern_string),
269+
};
270+
diag.span_label(pat.span, label_msg);
264271
diag.emit();
265272
});
266273
}

src/librustc_resolve/lib.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -377,12 +377,6 @@ enum PatternSource {
377377
}
378378

379379
impl PatternSource {
380-
fn is_refutable(self) -> bool {
381-
match self {
382-
PatternSource::Match | PatternSource::IfLet | PatternSource::WhileLet => true,
383-
PatternSource::Let | PatternSource::For | PatternSource::FnParam => false,
384-
}
385-
}
386380
fn descr(self) -> &'static str {
387381
match self {
388382
PatternSource::Match => "match binding",
@@ -2388,20 +2382,24 @@ impl<'a> Resolver<'a> {
23882382
false, pat.span)
23892383
.and_then(LexicalScopeBinding::item);
23902384
let resolution = binding.map(NameBinding::def).and_then(|def| {
2391-
let ivmode = BindingMode::ByValue(Mutability::Immutable);
2392-
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
2393-
bmode != ivmode;
2385+
let is_syntactic_ambiguity = opt_pat.is_none() &&
2386+
bmode == BindingMode::ByValue(Mutability::Immutable);
23942387
match def {
23952388
Def::StructCtor(_, CtorKind::Const) |
23962389
Def::VariantCtor(_, CtorKind::Const) |
2397-
Def::Const(..) if !always_binding => {
2398-
// A unit struct/variant or constant pattern.
2390+
Def::Const(..) if is_syntactic_ambiguity => {
2391+
// Disambiguate in favor of a unit struct/variant
2392+
// or constant pattern.
23992393
self.record_use(ident.node, ValueNS, binding.unwrap(), ident.span);
24002394
Some(PathResolution::new(def))
24012395
}
24022396
Def::StructCtor(..) | Def::VariantCtor(..) |
24032397
Def::Const(..) | Def::Static(..) => {
2404-
// A fresh binding that shadows something unacceptable.
2398+
// This is unambiguously a fresh binding, either syntactically
2399+
// (e.g. `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves
2400+
// to something unusable as a pattern (e.g. constructor function),
2401+
// but we still conservatively report an error, see
2402+
// issues/33118#issuecomment-233962221 for one reason why.
24052403
resolve_error(
24062404
self,
24072405
ident.span,
@@ -2410,7 +2408,7 @@ impl<'a> Resolver<'a> {
24102408
);
24112409
None
24122410
}
2413-
Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => {
2411+
Def::Fn(..) | Def::Err => {
24142412
// These entities are explicitly allowed
24152413
// to be shadowed by fresh bindings.
24162414
None

src/test/compile-fail/blind-item-block-middle.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ mod foo { pub struct bar; }
1212

1313
fn main() {
1414
let bar = 5;
15-
//~^ ERROR let bindings cannot shadow unit structs
15+
//~^ ERROR mismatched types
1616
use foo::bar;
1717
}

src/test/compile-fail/issue-33504.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ struct Test;
1414

1515
fn main() {
1616
|| {
17-
let Test = 1; //~ ERROR let bindings cannot shadow unit structs
17+
let Test = 1; //~ ERROR mismatched types
1818
};
1919
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct UnitStruct;
12+
struct TupleStruct();
13+
struct BracedStruct{}
14+
15+
enum E {
16+
UnitVariant,
17+
TupleVariant(),
18+
BracedVariant{},
19+
}
20+
use E::*;
21+
22+
const CONST: () = ();
23+
static STATIC: () = ();
24+
25+
fn function() {}
26+
27+
fn main() {
28+
let doesnt_matter = 0;
29+
30+
match UnitStruct {
31+
UnitStruct => {} // OK, `UnitStruct` is a unit struct pattern
32+
}
33+
match doesnt_matter {
34+
TupleStruct => {} //~ ERROR match bindings cannot shadow tuple structs
35+
}
36+
match doesnt_matter {
37+
BracedStruct => {} // OK, `BracedStruct` is a fresh binding
38+
}
39+
match UnitVariant {
40+
UnitVariant => {} // OK, `UnitVariant` is a unit variant pattern
41+
}
42+
match doesnt_matter {
43+
TupleVariant => {} //~ ERROR match bindings cannot shadow tuple variants
44+
}
45+
match doesnt_matter {
46+
BracedVariant => {} //~ ERROR match bindings cannot shadow struct variants
47+
}
48+
match CONST {
49+
CONST => {} // OK, `CONST` is a const pattern
50+
}
51+
match doesnt_matter {
52+
STATIC => {} //~ ERROR match bindings cannot shadow statics
53+
}
54+
match doesnt_matter {
55+
function => {} // OK, `function` is a fresh binding
56+
}
57+
58+
let UnitStruct = UnitStruct; // OK, `UnitStruct` is a unit struct pattern
59+
let TupleStruct = doesnt_matter; //~ ERROR let bindings cannot shadow tuple structs
60+
let BracedStruct = doesnt_matter; // OK, `BracedStruct` is a fresh binding
61+
let UnitVariant = UnitVariant; // OK, `UnitVariant` is a unit variant pattern
62+
let TupleVariant = doesnt_matter; //~ ERROR let bindings cannot shadow tuple variants
63+
let BracedVariant = doesnt_matter; //~ ERROR let bindings cannot shadow struct variants
64+
let CONST = CONST; // OK, `CONST` is a const pattern
65+
let STATIC = doesnt_matter; //~ ERROR let bindings cannot shadow statics
66+
let function = doesnt_matter; // OK, `function` is a fresh binding
67+
}

src/test/compile-fail/const-pattern-irrefutable.rs renamed to src/test/ui/const-pattern-irrefutable.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,14 @@ mod foo {
1313
pub const d: u8 = 2;
1414
}
1515

16-
use foo::b as c; //~ NOTE is imported here
17-
use foo::d; //~ NOTE is imported here
16+
use foo::b as c;
17+
use foo::d;
1818

19-
const a: u8 = 2; //~ NOTE is defined here
19+
const a: u8 = 2;
2020

2121
fn main() {
22-
let a = 4; //~ ERROR let bindings cannot shadow constants
23-
//~^ NOTE cannot be named the same as a constant
24-
let c = 4; //~ ERROR let bindings cannot shadow constants
25-
//~^ NOTE cannot be named the same as a constant
26-
let d = 4; //~ ERROR let bindings cannot shadow constants
27-
//~^ NOTE cannot be named the same as a constant
22+
let a = 4; //~ ERROR refutable pattern in local binding: `_` not covered
23+
let c = 4; //~ ERROR refutable pattern in local binding: `_` not covered
24+
let d = 4; //~ ERROR refutable pattern in local binding: `_` not covered
2825
fn f() {} // Check that the `NOTE`s still work with an item here (c.f. issue #35115).
2926
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0005]: refutable pattern in local binding: `_` not covered
2+
--> $DIR/const-pattern-irrefutable.rs:22:9
3+
|
4+
22 | let a = 4; //~ ERROR refutable pattern in local binding: `_` not covered
5+
| ^ interpreted as a constant pattern, not new variable
6+
7+
error[E0005]: refutable pattern in local binding: `_` not covered
8+
--> $DIR/const-pattern-irrefutable.rs:23:9
9+
|
10+
23 | let c = 4; //~ ERROR refutable pattern in local binding: `_` not covered
11+
| ^ interpreted as a constant pattern, not new variable
12+
13+
error[E0005]: refutable pattern in local binding: `_` not covered
14+
--> $DIR/const-pattern-irrefutable.rs:24:9
15+
|
16+
24 | let d = 4; //~ ERROR refutable pattern in local binding: `_` not covered
17+
| ^ interpreted as a constant pattern, not new variable
18+
19+
error: aborting due to 3 previous errors
20+

src/test/compile-fail/name-clash-nullary.rs renamed to src/test/ui/resolve/name-clash-nullary.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::option::*;
12-
1311
fn main() {
14-
let None: isize = 42; //~ ERROR let bindings cannot shadow unit variants
15-
log(debug, None);
16-
//~^ ERROR cannot find function `log` in this scope
17-
//~| ERROR cannot find value `debug` in this scope
12+
let None: isize = 42; //~ ERROR mismatched types
1813
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/name-clash-nullary.rs:12:7
3+
|
4+
12 | let None: isize = 42; //~ ERROR mismatched types
5+
| ^^^^ expected isize, found enum `std::option::Option`
6+
|
7+
= note: expected type `isize`
8+
found type `std::option::Option<_>`
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)