Skip to content

Commit e1c6ead

Browse files
committed
move pattern migration setup/emitting to a separate module
1 parent 80c0919 commit e1c6ead

File tree

3 files changed

+104
-61
lines changed

3 files changed

+104
-61
lines changed

compiler/rustc_mir_build/src/errors.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1113,9 +1113,6 @@ pub(crate) struct Rust2024IncompatiblePatSugg {
11131113
pub(crate) suggestion: Vec<(Span, String)>,
11141114
pub(crate) ref_pattern_count: usize,
11151115
pub(crate) binding_mode_count: usize,
1116-
/// Internal state: the ref-mutability of the default binding mode at the subpattern being
1117-
/// lowered, with the span where it was introduced. `None` for a by-value default mode.
1118-
pub(crate) default_mode_span: Option<(Span, ty::Mutability)>,
11191116
/// Labels for where incompatibility-causing by-ref default binding modes were introduced.
11201117
pub(crate) default_mode_labels: FxIndexMap<Span, ty::Mutability>,
11211118
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! Automatic migration of Rust 2021 patterns to a form valid in both Editions 2021 and 2024.
2+
3+
use rustc_data_structures::fx::FxIndexMap;
4+
use rustc_errors::MultiSpan;
5+
use rustc_hir::HirId;
6+
use rustc_lint as lint;
7+
use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt};
8+
use rustc_span::Span;
9+
10+
use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg};
11+
use crate::fluent_generated as fluent;
12+
13+
/// For patterns flagged for migration during HIR typeck, this handles constructing and emitting
14+
/// a diagnostic suggestion.
15+
pub(super) struct PatMigration<'a> {
16+
pub(super) suggestion: Vec<(Span, String)>,
17+
pub(super) ref_pattern_count: usize,
18+
pub(super) binding_mode_count: usize,
19+
/// Internal state: the ref-mutability of the default binding mode at the subpattern being
20+
/// lowered, with the span where it was introduced. `None` for a by-value default mode.
21+
pub(super) default_mode_span: Option<(Span, ty::Mutability)>,
22+
/// Labels for where incompatibility-causing by-ref default binding modes were introduced.
23+
// FIXME(ref_pat_eat_one_layer_2024_structural): To track the default binding mode, we duplicate
24+
// logic from HIR typeck (in order to avoid needing to store all changes to the dbm in
25+
// TypeckResults). Since the default binding mode acts differently under this feature gate, the
26+
// labels will be wrong.
27+
pub(super) default_mode_labels: FxIndexMap<Span, Mutability>,
28+
/// Information collected from typeck, including spans for subpatterns invalid in Rust 2024.
29+
pub(super) info: &'a Rust2024IncompatiblePatInfo,
30+
}
31+
32+
impl<'a> PatMigration<'a> {
33+
pub(super) fn new(info: &'a Rust2024IncompatiblePatInfo) -> Self {
34+
PatMigration {
35+
suggestion: Vec::new(),
36+
ref_pattern_count: 0,
37+
binding_mode_count: 0,
38+
default_mode_span: None,
39+
default_mode_labels: Default::default(),
40+
info,
41+
}
42+
}
43+
44+
/// On Rust 2024, this emits a hard error. On earlier Editions, this emits the
45+
/// future-incompatibility lint `rust_2024_incompatible_pat`.
46+
pub(super) fn emit<'tcx>(self, tcx: TyCtxt<'tcx>, pat_id: HirId) {
47+
let mut spans =
48+
MultiSpan::from_spans(self.info.primary_labels.iter().map(|(span, _)| *span).collect());
49+
for (span, label) in self.info.primary_labels.iter() {
50+
spans.push_span_label(*span, label.clone());
51+
}
52+
let sugg = Rust2024IncompatiblePatSugg {
53+
suggest_eliding_modes: self.info.suggest_eliding_modes,
54+
suggestion: self.suggestion,
55+
ref_pattern_count: self.ref_pattern_count,
56+
binding_mode_count: self.binding_mode_count,
57+
default_mode_labels: self.default_mode_labels,
58+
};
59+
// If a relevant span is from at least edition 2024, this is a hard error.
60+
let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
61+
if is_hard_error {
62+
let mut err =
63+
tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
64+
if let Some(info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
65+
// provide the same reference link as the lint
66+
err.note(format!("for more information, see {}", info.reference));
67+
}
68+
err.arg("bad_modifiers", self.info.bad_modifiers);
69+
err.arg("bad_ref_pats", self.info.bad_ref_pats);
70+
err.arg("is_hard_error", true);
71+
err.subdiagnostic(sugg);
72+
err.emit();
73+
} else {
74+
tcx.emit_node_span_lint(
75+
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
76+
pat_id,
77+
spans,
78+
Rust2024IncompatiblePat {
79+
sugg,
80+
bad_modifiers: self.info.bad_modifiers,
81+
bad_ref_pats: self.info.bad_ref_pats,
82+
is_hard_error,
83+
},
84+
);
85+
}
86+
}
87+
}

compiler/rustc_mir_build/src/thir/pattern/mod.rs

+17-58
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@
22
33
mod check_match;
44
mod const_to_pat;
5+
mod migration;
56

67
use std::cmp::Ordering;
78
use std::sync::Arc;
89

910
use rustc_abi::{FieldIdx, Integer};
10-
use rustc_errors::MultiSpan;
1111
use rustc_errors::codes::*;
1212
use rustc_hir::def::{CtorOf, DefKind, Res};
1313
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
1414
use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
1515
use rustc_index::Idx;
16-
use rustc_lint as lint;
1716
use rustc_middle::mir::interpret::LitToConstInput;
1817
use rustc_middle::thir::{
1918
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
@@ -26,16 +25,16 @@ use rustc_span::{ErrorGuaranteed, Span};
2625
use tracing::{debug, instrument};
2726

2827
pub(crate) use self::check_match::check_match;
28+
use self::migration::PatMigration;
2929
use crate::errors::*;
30-
use crate::fluent_generated as fluent;
3130

3231
struct PatCtxt<'a, 'tcx> {
3332
tcx: TyCtxt<'tcx>,
3433
typing_env: ty::TypingEnv<'tcx>,
3534
typeck_results: &'a ty::TypeckResults<'tcx>,
3635

3736
/// Used by the Rust 2024 migration lint.
38-
rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
37+
rust_2024_migration: Option<PatMigration<'a>>,
3938
}
4039

4140
pub(super) fn pat_from_hir<'a, 'tcx>(
@@ -44,59 +43,19 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
4443
typeck_results: &'a ty::TypeckResults<'tcx>,
4544
pat: &'tcx hir::Pat<'tcx>,
4645
) -> Box<Pat<'tcx>> {
47-
let migration_info = typeck_results.rust_2024_migration_desugared_pats().get(pat.hir_id);
4846
let mut pcx = PatCtxt {
4947
tcx,
5048
typing_env,
5149
typeck_results,
52-
rust_2024_migration_suggestion: migration_info.and_then(|info| {
53-
Some(Rust2024IncompatiblePatSugg {
54-
suggest_eliding_modes: info.suggest_eliding_modes,
55-
suggestion: Vec::new(),
56-
ref_pattern_count: 0,
57-
binding_mode_count: 0,
58-
default_mode_span: None,
59-
default_mode_labels: Default::default(),
60-
})
61-
}),
50+
rust_2024_migration: typeck_results
51+
.rust_2024_migration_desugared_pats()
52+
.get(pat.hir_id)
53+
.map(PatMigration::new),
6254
};
6355
let result = pcx.lower_pattern(pat);
6456
debug!("pat_from_hir({:?}) = {:?}", pat, result);
65-
if let Some(info) = migration_info
66-
&& let Some(sugg) = pcx.rust_2024_migration_suggestion
67-
{
68-
let mut spans =
69-
MultiSpan::from_spans(info.primary_labels.iter().map(|(span, _)| *span).collect());
70-
for (span, label) in &info.primary_labels {
71-
spans.push_span_label(*span, label.clone());
72-
}
73-
// If a relevant span is from at least edition 2024, this is a hard error.
74-
let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
75-
if is_hard_error {
76-
let mut err =
77-
tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
78-
if let Some(lint_info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
79-
// provide the same reference link as the lint
80-
err.note(format!("for more information, see {}", lint_info.reference));
81-
}
82-
err.arg("bad_modifiers", info.bad_modifiers);
83-
err.arg("bad_ref_pats", info.bad_ref_pats);
84-
err.arg("is_hard_error", true);
85-
err.subdiagnostic(sugg);
86-
err.emit();
87-
} else {
88-
tcx.emit_node_span_lint(
89-
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
90-
pat.hir_id,
91-
spans,
92-
Rust2024IncompatiblePat {
93-
sugg,
94-
bad_modifiers: info.bad_modifiers,
95-
bad_ref_pats: info.bad_ref_pats,
96-
is_hard_error,
97-
},
98-
);
99-
}
57+
if let Some(m) = pcx.rust_2024_migration {
58+
m.emit(tcx, pat.hir_id);
10059
}
10160
result
10261
}
@@ -107,7 +66,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
10766
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
10867

10968
let mut opt_old_mode_span = None;
110-
if let Some(s) = &mut self.rust_2024_migration_suggestion
69+
if let Some(s) = &mut self.rust_2024_migration
11170
&& !adjustments.is_empty()
11271
{
11372
let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
@@ -117,7 +76,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
11776
mutbl
11877
});
11978

120-
if !s.suggest_eliding_modes {
79+
if !s.info.suggest_eliding_modes {
12180
let suggestion_str: String =
12281
implicit_deref_mutbls.clone().map(|mutbl| mutbl.ref_prefix_str()).collect();
12382
s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
@@ -169,7 +128,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
169128
})
170129
});
171130

172-
if let Some(s) = &mut self.rust_2024_migration_suggestion
131+
if let Some(s) = &mut self.rust_2024_migration
173132
&& let Some(old_mode_span) = opt_old_mode_span
174133
{
175134
s.default_mode_span = old_mode_span;
@@ -368,15 +327,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
368327
}
369328
hir::PatKind::Ref(subpattern, _) => {
370329
// Track the default binding mode for the Rust 2024 migration suggestion.
371-
let old_mode_span = self.rust_2024_migration_suggestion.as_mut().and_then(|s| {
330+
let old_mode_span = self.rust_2024_migration.as_mut().and_then(|s| {
372331
if let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span {
373332
// If this eats a by-ref default binding mode, label the binding mode.
374333
s.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
375334
}
376335
s.default_mode_span.take()
377336
});
378337
let subpattern = self.lower_pattern(subpattern);
379-
if let Some(s) = &mut self.rust_2024_migration_suggestion {
338+
if let Some(s) = &mut self.rust_2024_migration {
380339
s.default_mode_span = old_mode_span;
381340
}
382341
PatKind::Deref { subpattern }
@@ -408,19 +367,19 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
408367
.get(pat.hir_id)
409368
.expect("missing binding mode");
410369

411-
if let Some(s) = &mut self.rust_2024_migration_suggestion {
370+
if let Some(s) = &mut self.rust_2024_migration {
412371
if explicit_ba != hir::BindingMode::NONE
413372
&& let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span
414373
{
415374
// If this overrides a by-ref default binding mode, label the binding mode.
416375
s.default_mode_labels.insert(default_mode_span, default_ref_mutbl);
417376
// If our suggestion is to elide redundnt modes, this will be one of them.
418-
if s.suggest_eliding_modes {
377+
if s.info.suggest_eliding_modes {
419378
s.suggestion.push((pat.span.with_hi(ident.span.lo()), String::new()));
420379
s.binding_mode_count += 1;
421380
}
422381
}
423-
if !s.suggest_eliding_modes
382+
if !s.info.suggest_eliding_modes
424383
&& explicit_ba.0 == ByRef::No
425384
&& let ByRef::Yes(mutbl) = mode.0
426385
{

0 commit comments

Comments
 (0)