Skip to content

Commit 0534655

Browse files
committed
Auto merge of #108504 - cjgillot:thir-pattern, r=compiler-errors,Nilstrieb
Check pattern refutability on THIR The current `check_match` query is based on HIR, but partially re-lowers HIR into THIR. This PR proposed to use the results of the `thir_body` query to check matches, instead of re-building THIR. Most of the diagnostic changes are spans getting shorter, or commas/semicolons not getting removed. This PR degrades the diagnostic for confusing constants in patterns (`let A = foo()` where `A` resolves to a `const A` somewhere): it does not point ot the definition of `const A` any more.
2 parents ce3cb03 + 1dde34b commit 0534655

File tree

106 files changed

+1041
-1482
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+1041
-1482
lines changed

Diff for: compiler/rustc_hir/src/pat_util.rs

-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::def::{CtorOf, DefKind, Res};
22
use crate::def_id::DefId;
33
use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind};
44
use rustc_data_structures::fx::FxHashSet;
5-
use rustc_span::hygiene::DesugaringKind;
65
use rustc_span::symbol::Ident;
76
use rustc_span::Span;
87

@@ -136,14 +135,4 @@ impl hir::Pat<'_> {
136135
});
137136
result
138137
}
139-
140-
/// If the pattern is `Some(<pat>)` from a desugared for loop, returns the inner pattern
141-
pub fn for_loop_some(&self) -> Option<&Self> {
142-
if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
143-
if let hir::PatKind::Struct(_, [pat_field], _) = self.kind {
144-
return Some(pat_field.pat);
145-
}
146-
}
147-
None
148-
}
149138
}

Diff for: compiler/rustc_interface/src/passes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
765765
parallel!(
766766
{
767767
sess.time("match_checking", || {
768-
tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id.to_def_id()))
768+
tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id))
769769
});
770770
},
771771
{

Diff for: compiler/rustc_middle/src/dep_graph/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
9494
}
9595

9696
#[inline]
97-
fn dep_kind_info(&self, dep_kind: DepKind) -> &DepKindStruct<'tcx> {
98-
&self.query_kinds[dep_kind as usize]
97+
fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> {
98+
&self.query_kinds[dk as usize]
9999
}
100100
}

Diff for: compiler/rustc_middle/src/mir/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,13 @@ impl<'tcx> Rvalue<'tcx> {
20012001
}
20022002

20032003
impl BorrowKind {
2004+
pub fn mutability(&self) -> Mutability {
2005+
match *self {
2006+
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => Mutability::Not,
2007+
BorrowKind::Mut { .. } => Mutability::Mut,
2008+
}
2009+
}
2010+
20042011
pub fn allows_two_phase_borrow(&self) -> bool {
20052012
match *self {
20062013
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false,

Diff for: compiler/rustc_middle/src/query/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1114,9 +1114,9 @@ rustc_queries! {
11141114
desc { "converting literal to mir constant" }
11151115
}
11161116

1117-
query check_match(key: DefId) {
1118-
desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
1119-
cache_on_disk_if { key.is_local() }
1117+
query check_match(key: LocalDefId) {
1118+
desc { |tcx| "match-checking `{}`", tcx.def_path_str(key.to_def_id()) }
1119+
cache_on_disk_if { true }
11201120
}
11211121

11221122
/// Performs part of the privacy check and computes effective visibilities.

Diff for: compiler/rustc_middle/src/thir.rs

+54-2
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ pub enum StmtKind<'tcx> {
227227

228228
/// The lint level for this `let` statement.
229229
lint_level: LintLevel,
230+
231+
/// Span of the `let <PAT> = <INIT>` part.
232+
span: Span,
230233
},
231234
}
232235

@@ -594,6 +597,55 @@ impl<'tcx> Pat<'tcx> {
594597
_ => None,
595598
}
596599
}
600+
601+
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
602+
/// `match foo() { Some(a) => (), None => () }`
603+
pub fn each_binding(&self, mut f: impl FnMut(Symbol, BindingMode, Ty<'tcx>, Span)) {
604+
self.walk_always(|p| {
605+
if let PatKind::Binding { name, mode, ty, .. } = p.kind {
606+
f(name, mode, ty, p.span);
607+
}
608+
});
609+
}
610+
611+
/// Walk the pattern in left-to-right order.
612+
///
613+
/// If `it(pat)` returns `false`, the children are not visited.
614+
pub fn walk(&self, mut it: impl FnMut(&Pat<'tcx>) -> bool) {
615+
self.walk_(&mut it)
616+
}
617+
618+
fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) {
619+
if !it(self) {
620+
return;
621+
}
622+
623+
use PatKind::*;
624+
match &self.kind {
625+
Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } => {}
626+
AscribeUserType { subpattern, .. }
627+
| Binding { subpattern: Some(subpattern), .. }
628+
| Deref { subpattern } => subpattern.walk_(it),
629+
Leaf { subpatterns } | Variant { subpatterns, .. } => {
630+
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
631+
}
632+
Or { pats } => pats.iter().for_each(|p| p.walk_(it)),
633+
Array { box ref prefix, ref slice, box ref suffix }
634+
| Slice { box ref prefix, ref slice, box ref suffix } => {
635+
prefix.iter().chain(slice.iter()).chain(suffix.iter()).for_each(|p| p.walk_(it))
636+
}
637+
}
638+
}
639+
640+
/// Walk the pattern in left-to-right order.
641+
///
642+
/// If you always want to recurse, prefer this method over `walk`.
643+
pub fn walk_always(&self, mut it: impl FnMut(&Pat<'tcx>)) {
644+
self.walk(|p| {
645+
it(p);
646+
true
647+
})
648+
}
597649
}
598650

599651
impl<'tcx> IntoDiagnosticArg for Pat<'tcx> {
@@ -879,7 +931,7 @@ mod size_asserts {
879931
static_assert_size!(ExprKind<'_>, 40);
880932
static_assert_size!(Pat<'_>, 72);
881933
static_assert_size!(PatKind<'_>, 56);
882-
static_assert_size!(Stmt<'_>, 48);
883-
static_assert_size!(StmtKind<'_>, 40);
934+
static_assert_size!(Stmt<'_>, 56);
935+
static_assert_size!(StmtKind<'_>, 48);
884936
// tidy-alphabetical-end
885937
}

Diff for: compiler/rustc_middle/src/thir/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm
175175
ref pattern,
176176
lint_level: _,
177177
else_block,
178+
span: _,
178179
} => {
179180
if let Some(init) = initializer {
180181
visitor.visit_expr(&visitor.thir()[*init]);

Diff for: compiler/rustc_mir_build/messages.ftl

+2-14
Original file line numberDiff line numberDiff line change
@@ -239,19 +239,9 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
239239
} into the body
240240
241241
mir_build_bindings_with_variant_name =
242-
pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}`
242+
pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
243243
.suggestion = to match on the variant, qualify the path
244244
245-
mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count ->
246-
[one] pattern
247-
*[other] patterns
248-
}
249-
.note = {$count ->
250-
[one] this pattern
251-
*[other] these patterns
252-
} will always match, so the `let` is useless
253-
.help = consider removing `let`
254-
255245
mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
256246
[one] pattern
257247
*[other] patterns
@@ -357,15 +347,13 @@ mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern",
357347
358348
mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
359349
360-
mir_build_res_defined_here = {$res} defined here
361-
362350
mir_build_adt_defined_here = `{$ty}` defined here
363351
364352
mir_build_variant_defined_here = not covered
365353
366354
mir_build_interpreted_as_const = introduce a variable instead
367355
368-
mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable
356+
mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
369357
370358
mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
371359
[one] variant that isn't

Diff for: compiler/rustc_mir_build/src/build/block.rs

+2
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
115115
initializer: Some(initializer),
116116
lint_level,
117117
else_block: Some(else_block),
118+
span: _,
118119
} => {
119120
// When lowering the statement `let <pat> = <expr> else { <else> };`,
120121
// the `<else>` block is nested in the parent scope enclosing this statement.
@@ -278,6 +279,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
278279
initializer,
279280
lint_level,
280281
else_block: None,
282+
span: _,
281283
} => {
282284
let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
283285
this.block_context.push(BlockFrame::Statement { ignores_expr_result });

Diff for: compiler/rustc_mir_build/src/build/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
5858
ty::WithOptConstParam { did, const_param_did: None } => {
5959
tcx.ensure_with_value().thir_check_unsafety(did);
6060
tcx.ensure_with_value().thir_abstract_const(did);
61+
tcx.ensure_with_value().check_match(did);
6162
}
6263
}
6364

Diff for: compiler/rustc_mir_build/src/errors.rs

+8-29
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use rustc_errors::{
66
error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
77
Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
88
};
9-
use rustc_hir::def::Res;
109
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
1110
use rustc_middle::thir::Pat;
1211
use rustc_middle::ty::{self, Ty};
13-
use rustc_span::{symbol::Ident, Span};
12+
use rustc_span::symbol::Symbol;
13+
use rustc_span::Span;
1414

1515
#[derive(LintDiagnostic)]
1616
#[diag(mir_build_unconditional_recursion)]
@@ -534,18 +534,10 @@ pub struct TrailingIrrefutableLetPatterns {
534534
#[derive(LintDiagnostic)]
535535
#[diag(mir_build_bindings_with_variant_name, code = "E0170")]
536536
pub struct BindingsWithVariantName {
537-
#[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")]
537+
#[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")]
538538
pub suggestion: Option<Span>,
539539
pub ty_path: String,
540-
pub ident: Ident,
541-
}
542-
543-
#[derive(LintDiagnostic)]
544-
#[diag(mir_build_irrefutable_let_patterns_generic_let)]
545-
#[note]
546-
#[help]
547-
pub struct IrrefutableLetPatternsGenericLet {
548-
pub count: usize,
540+
pub name: Symbol,
549541
}
550542

551543
#[derive(LintDiagnostic)]
@@ -584,13 +576,12 @@ pub struct IrrefutableLetPatternsWhileLet {
584576
#[diag(mir_build_borrow_of_moved_value)]
585577
pub struct BorrowOfMovedValue<'tcx> {
586578
#[primary_span]
587-
pub span: Span,
588579
#[label]
589580
#[label(mir_build_occurs_because_label)]
590581
pub binding_span: Span,
591582
#[label(mir_build_value_borrowed_label)]
592583
pub conflicts_ref: Vec<Span>,
593-
pub name: Ident,
584+
pub name: Symbol,
594585
pub ty: Ty<'tcx>,
595586
#[suggestion(code = "ref ", applicability = "machine-applicable")]
596587
pub suggest_borrowing: Option<Span>,
@@ -638,19 +629,19 @@ pub enum Conflict {
638629
Mut {
639630
#[primary_span]
640631
span: Span,
641-
name: Ident,
632+
name: Symbol,
642633
},
643634
#[label(mir_build_borrow)]
644635
Ref {
645636
#[primary_span]
646637
span: Span,
647-
name: Ident,
638+
name: Symbol,
648639
},
649640
#[label(mir_build_moved)]
650641
Moved {
651642
#[primary_span]
652643
span: Span,
653-
name: Ident,
644+
name: Symbol,
654645
},
655646
}
656647

@@ -802,8 +793,6 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
802793
pub let_suggestion: Option<SuggestLet>,
803794
#[subdiagnostic]
804795
pub misc_suggestion: Option<MiscPatternSuggestion>,
805-
#[subdiagnostic]
806-
pub res_defined_here: Option<ResDefinedHere>,
807796
}
808797

809798
#[derive(Subdiagnostic)]
@@ -837,14 +826,6 @@ impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
837826
}
838827
}
839828

840-
#[derive(Subdiagnostic)]
841-
#[label(mir_build_res_defined_here)]
842-
pub struct ResDefinedHere {
843-
#[primary_span]
844-
pub def_span: Span,
845-
pub res: Res,
846-
}
847-
848829
#[derive(Subdiagnostic)]
849830
#[suggestion(
850831
mir_build_interpreted_as_const,
@@ -855,9 +836,7 @@ pub struct ResDefinedHere {
855836
pub struct InterpretedAsConst {
856837
#[primary_span]
857838
pub span: Span,
858-
pub article: &'static str,
859839
pub variable: String,
860-
pub res: Res,
861840
}
862841

863842
#[derive(Subdiagnostic)]

Diff for: compiler/rustc_mir_build/src/thir/cx/block.rs

+5
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ impl<'tcx> Cx<'tcx> {
105105
}
106106
}
107107

108+
let span = match local.init {
109+
Some(init) => local.span.with_hi(init.span.hi()),
110+
None => local.span,
111+
};
108112
let stmt = Stmt {
109113
kind: StmtKind::Let {
110114
remainder_scope,
@@ -116,6 +120,7 @@ impl<'tcx> Cx<'tcx> {
116120
initializer: local.init.map(|init| self.mirror_expr(init)),
117121
else_block,
118122
lint_level: LintLevel::Explicit(local.hir_id),
123+
span,
119124
},
120125
opt_destruction_scope: opt_dxn_ext,
121126
};

0 commit comments

Comments
 (0)