Skip to content

Commit 5850482

Browse files
authored
Rollup merge of rust-lang#68399 - Centril:check-match-unify, r=oli-obk
check_match: misc unifications and ICE fixes These are some unifications made as a by-product of working on `hir::ExprKind::Let`. Fixes rust-lang#68396. Fixes rust-lang#68394. Fixes rust-lang#68393. r? @oli-obk @matthewjasper
2 parents 3fa8cc3 + 58eb03d commit 5850482

13 files changed

+198
-95
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3763,6 +3763,7 @@ dependencies = [
37633763
"rustc_hir",
37643764
"rustc_index",
37653765
"rustc_macros",
3766+
"rustc_session",
37663767
"rustc_span",
37673768
"rustc_target",
37683769
"serialize",

src/librustc_mir_build/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ rustc_errors = { path = "../librustc_errors" }
2121
rustc_hir = { path = "../librustc_hir" }
2222
rustc_macros = { path = "../librustc_macros" }
2323
rustc_serialize = { path = "../libserialize", package = "serialize" }
24+
rustc_session = { path = "../librustc_session" }
2425
rustc_span = { path = "../librustc_span" }
2526
rustc_target = { path = "../librustc_target" }
2627
syntax = { path = "../libsyntax" }

src/librustc_mir_build/hair/pattern/_match.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -582,15 +582,12 @@ crate struct MatchCheckCtxt<'a, 'tcx> {
582582
}
583583

584584
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
585-
crate fn create_and_enter<F, R>(
585+
crate fn create_and_enter<R>(
586586
tcx: TyCtxt<'tcx>,
587587
param_env: ty::ParamEnv<'tcx>,
588588
module: DefId,
589-
f: F,
590-
) -> R
591-
where
592-
F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R,
593-
{
589+
f: impl for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R,
590+
) -> R {
594591
let pattern_arena = TypedArena::default();
595592

596593
f(MatchCheckCtxt { tcx, param_env, module, pattern_arena: &pattern_arena })

src/librustc_mir_build/hair/pattern/check_match.rs

+66-87
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}
55
use super::{PatCtxt, PatKind, PatternError};
66

77
use rustc::hir::map::Map;
8-
use rustc::lint;
9-
use rustc::session::parse::feature_err;
10-
use rustc::session::Session;
118
use rustc::ty::{self, Ty, TyCtxt};
129
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder};
1310
use rustc_hir as hir;
1411
use rustc_hir::def::*;
1512
use rustc_hir::def_id::DefId;
1613
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
1714
use rustc_hir::{HirId, Pat};
15+
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
16+
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
17+
use rustc_session::parse::feature_err;
18+
use rustc_session::Session;
1819
use rustc_span::symbol::sym;
1920
use rustc_span::{MultiSpan, Span};
2021
use syntax::ast::Mutability;
@@ -67,18 +68,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
6768
hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
6869
};
6970
self.check_irrefutable(&loc.pat, msg, sp);
70-
71-
// Check legality of move bindings and `@` patterns.
7271
self.check_patterns(false, &loc.pat);
7372
}
7473

75-
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
76-
intravisit::walk_body(self, body);
77-
78-
for param in body.params {
79-
self.check_irrefutable(&param.pat, "function argument", None);
80-
self.check_patterns(false, &param.pat);
81-
}
74+
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
75+
intravisit::walk_param(self, param);
76+
self.check_irrefutable(&param.pat, "function argument", None);
77+
self.check_patterns(false, &param.pat);
8278
}
8379
}
8480

@@ -123,6 +119,25 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
123119
if !self.tcx.features().bindings_after_at {
124120
check_legality_of_bindings_in_at_patterns(self, pat);
125121
}
122+
check_for_bindings_named_same_as_variants(self, pat);
123+
}
124+
125+
fn lower_pattern<'p>(
126+
&self,
127+
cx: &mut MatchCheckCtxt<'p, 'tcx>,
128+
pat: &'tcx hir::Pat<'tcx>,
129+
have_errors: &mut bool,
130+
) -> (&'p super::Pat<'tcx>, Ty<'tcx>) {
131+
let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
132+
patcx.include_lint_checks();
133+
let pattern = patcx.lower_pattern(pat);
134+
let pattern_ty = pattern.ty;
135+
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
136+
if !patcx.errors.is_empty() {
137+
*have_errors = true;
138+
patcx.report_inlining_errors(pat.span);
139+
}
140+
(pattern, pattern_ty)
126141
}
127142

128143
fn check_match(
@@ -132,11 +147,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
132147
source: hir::MatchSource,
133148
) {
134149
for arm in arms {
135-
// First, check legality of move bindings.
150+
// Check the arm for some things unrelated to exhaustiveness.
136151
self.check_patterns(arm.guard.is_some(), &arm.pat);
137-
138-
// Second, perform some lints.
139-
check_for_bindings_named_same_as_variants(self, &arm.pat);
140152
}
141153

142154
let module = self.tcx.hir().get_module_parent(scrut.hir_id);
@@ -145,16 +157,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
145157

146158
let inlined_arms: Vec<_> = arms
147159
.iter()
148-
.map(|arm| {
149-
let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
150-
patcx.include_lint_checks();
151-
let pattern = patcx.lower_pattern(&arm.pat);
152-
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
153-
if !patcx.errors.is_empty() {
154-
patcx.report_inlining_errors(arm.pat.span);
155-
have_errors = true;
156-
}
157-
(pattern, &*arm.pat, arm.guard.is_some())
160+
.map(|hir::Arm { pat, guard, .. }| {
161+
(self.lower_pattern(cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some())
158162
})
159163
.collect();
160164

@@ -178,11 +182,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
178182
fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
179183
let module = self.tcx.hir().get_module_parent(pat.hir_id);
180184
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
181-
let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
182-
patcx.include_lint_checks();
183-
let pattern = patcx.lower_pattern(pat);
184-
let pattern_ty = pattern.ty;
185-
let pattern = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
185+
let (pattern, pattern_ty) = self.lower_pattern(cx, pat, &mut false);
186186
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
187187

188188
let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
@@ -285,7 +285,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
285285
let ty_path = cx.tcx.def_path_str(edef.did);
286286
cx.tcx
287287
.struct_span_lint_hir(
288-
lint::builtin::BINDINGS_WITH_VARIANT_NAME,
288+
BINDINGS_WITH_VARIANT_NAME,
289289
p.hir_id,
290290
p.span,
291291
&format!(
@@ -310,79 +310,63 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
310310
}
311311

312312
/// Checks for common cases of "catchall" patterns that may not be intended as such.
313-
fn pat_is_catchall(pat: &Pat<'_>) -> bool {
314-
match pat.kind {
315-
hir::PatKind::Binding(.., None) => true,
316-
hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
317-
hir::PatKind::Ref(ref s, _) => pat_is_catchall(s),
318-
hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(&p)),
313+
fn pat_is_catchall(pat: &super::Pat<'_>) -> bool {
314+
use super::PatKind::*;
315+
match &*pat.kind {
316+
Binding { subpattern: None, .. } => true,
317+
Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s),
318+
Leaf { subpatterns: s } => s.iter().all(|p| pat_is_catchall(&p.pattern)),
319319
_ => false,
320320
}
321321
}
322322

323+
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
324+
let mut err = tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern");
325+
if let Some(catchall) = catchall {
326+
// We had a catchall pattern, hint at that.
327+
err.span_label(span, "unreachable pattern");
328+
err.span_label(catchall, "matches any value");
329+
}
330+
err.emit();
331+
}
332+
333+
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
334+
let msg = match source {
335+
hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
336+
hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
337+
_ => bug!(),
338+
};
339+
tcx.lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, msg);
340+
}
341+
323342
/// Check for unreachable patterns.
324343
fn check_arms<'p, 'tcx>(
325344
cx: &mut MatchCheckCtxt<'p, 'tcx>,
326-
arms: &[(&'p super::Pat<'tcx>, &hir::Pat<'_>, bool)],
345+
arms: &[(&'p super::Pat<'tcx>, HirId, bool)],
327346
source: hir::MatchSource,
328347
) -> Matrix<'p, 'tcx> {
329348
let mut seen = Matrix::empty();
330349
let mut catchall = None;
331-
for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
350+
for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() {
332351
let v = PatStack::from_pattern(pat);
333-
334-
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
352+
match is_useful(cx, &seen, &v, LeaveOutWitness, id, true) {
335353
NotUseful => {
336354
match source {
337355
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
338356

339357
hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
340-
// check which arm we're on.
358+
// Check which arm we're on.
341359
match arm_index {
342360
// The arm with the user-specified pattern.
343-
0 => {
344-
cx.tcx.lint_hir(
345-
lint::builtin::UNREACHABLE_PATTERNS,
346-
hir_pat.hir_id,
347-
pat.span,
348-
"unreachable pattern",
349-
);
350-
}
361+
0 => unreachable_pattern(cx.tcx, pat.span, id, None),
351362
// The arm with the wildcard pattern.
352-
1 => {
353-
let msg = match source {
354-
hir::MatchSource::IfLetDesugar { .. } => {
355-
"irrefutable if-let pattern"
356-
}
357-
hir::MatchSource::WhileLetDesugar => {
358-
"irrefutable while-let pattern"
359-
}
360-
_ => bug!(),
361-
};
362-
cx.tcx.lint_hir(
363-
lint::builtin::IRREFUTABLE_LET_PATTERNS,
364-
hir_pat.hir_id,
365-
pat.span,
366-
msg,
367-
);
368-
}
363+
1 => irrefutable_let_pattern(cx.tcx, pat.span, id, source),
369364
_ => bug!(),
370365
}
371366
}
372367

373368
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
374-
let mut err = cx.tcx.struct_span_lint_hir(
375-
lint::builtin::UNREACHABLE_PATTERNS,
376-
hir_pat.hir_id,
377-
pat.span,
378-
"unreachable pattern",
379-
);
380-
// if we had a catchall pattern, hint at that
381-
if let Some(catchall) = catchall {
382-
err.span_label(pat.span, "unreachable pattern");
383-
err.span_label(catchall, "matches any value");
384-
}
385-
err.emit();
369+
unreachable_pattern(cx.tcx, pat.span, id, catchall);
386370
}
387371

388372
// Unreachable patterns in try and await expressions occur when one of
@@ -392,19 +376,14 @@ fn check_arms<'p, 'tcx>(
392376
}
393377
Useful(unreachable_subpatterns) => {
394378
for pat in unreachable_subpatterns {
395-
cx.tcx.lint_hir(
396-
lint::builtin::UNREACHABLE_PATTERNS,
397-
hir_pat.hir_id,
398-
pat.span,
399-
"unreachable pattern",
400-
);
379+
unreachable_pattern(cx.tcx, pat.span, id, None);
401380
}
402381
}
403382
UsefulWithWitness(_) => bug!(),
404383
}
405384
if !has_guard {
406385
seen.push(v);
407-
if catchall.is_none() && pat_is_catchall(hir_pat) {
386+
if catchall.is_none() && pat_is_catchall(pat) {
408387
catchall = Some(pat.span);
409388
}
410389
}

src/test/ui/lint/lint-uppercase-variables.rs

+10
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ fn main() {
2525
//~^^^ WARN unused variable: `Foo`
2626
}
2727

28+
let Foo = foo::Foo::Foo;
29+
//~^ ERROR variable `Foo` should have a snake case name
30+
//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
31+
//~^^^ WARN unused variable: `Foo`
32+
33+
fn in_param(Foo: foo::Foo) {}
34+
//~^ ERROR variable `Foo` should have a snake case name
35+
//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
36+
//~^^^ WARN unused variable: `Foo`
37+
2838
test(1);
2939

3040
let _ = Something { X: 0 };

src/test/ui/lint/lint-uppercase-variables.stderr

+37-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ LL | Foo => {}
66
|
77
= note: `#[warn(bindings_with_variant_name)]` on by default
88

9+
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
10+
--> $DIR/lint-uppercase-variables.rs:28:9
11+
|
12+
LL | let Foo = foo::Foo::Foo;
13+
| ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
14+
15+
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
16+
--> $DIR/lint-uppercase-variables.rs:33:17
17+
|
18+
LL | fn in_param(Foo: foo::Foo) {}
19+
| ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
20+
921
warning: unused variable: `Foo`
1022
--> $DIR/lint-uppercase-variables.rs:22:9
1123
|
@@ -19,6 +31,18 @@ LL | #![warn(unused)]
1931
| ^^^^^^
2032
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
2133

34+
warning: unused variable: `Foo`
35+
--> $DIR/lint-uppercase-variables.rs:28:9
36+
|
37+
LL | let Foo = foo::Foo::Foo;
38+
| ^^^ help: consider prefixing with an underscore: `_Foo`
39+
40+
warning: unused variable: `Foo`
41+
--> $DIR/lint-uppercase-variables.rs:33:17
42+
|
43+
LL | fn in_param(Foo: foo::Foo) {}
44+
| ^^^ help: consider prefixing with an underscore: `_Foo`
45+
2246
error: structure field `X` should have a snake case name
2347
--> $DIR/lint-uppercase-variables.rs:10:5
2448
|
@@ -49,6 +73,18 @@ error: variable `Foo` should have a snake case name
4973
LL | Foo => {}
5074
| ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
5175

52-
error: aborting due to 4 previous errors
76+
error: variable `Foo` should have a snake case name
77+
--> $DIR/lint-uppercase-variables.rs:28:9
78+
|
79+
LL | let Foo = foo::Foo::Foo;
80+
| ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
81+
82+
error: variable `Foo` should have a snake case name
83+
--> $DIR/lint-uppercase-variables.rs:33:17
84+
|
85+
LL | fn in_param(Foo: foo::Foo) {}
86+
| ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
87+
88+
error: aborting due to 6 previous errors
5389

5490
For more information about this error, try `rustc --explain E0170`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
pub enum EFoo {
2+
A,
3+
}
4+
5+
pub trait Foo {
6+
const X: EFoo;
7+
}
8+
9+
struct Abc;
10+
11+
impl Foo for Abc {
12+
const X: EFoo = EFoo::A;
13+
}
14+
15+
struct Def;
16+
impl Foo for Def {
17+
const X: EFoo = EFoo::A;
18+
}
19+
20+
pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
21+
//~^ ERROR associated consts cannot be referenced in patterns
22+
let A::X = arg;
23+
//~^ ERROR associated consts cannot be referenced in patterns
24+
}
25+
26+
fn main() {}

0 commit comments

Comments
 (0)