Rollup merge of #134394 - dianne:clarify-pat-2024-migration, r=compiler-errors
Clarify the match ergonomics 2024 migration lint's output This makes a few changes: - Rather than using the whole pattern as a span for the lint, this collects spans for each problematic default binding mode reset and labels them with why they're problems. - The lint's suggestions are now verbose-styled, so that it's clear what's being suggested vs. what's problematic. - The wording is now less technical, and the hard error version of this diagnostic now links to the same reference material as the lint (currently an unwritten page of the edition guide). I'm not totally confident in the wording or formatting, so I'd appreciate feedback on that in particular. I tried to draw a connection with word choice between the labels and the suggestion, but it might be imprecise, unclear, or cluttered. If so, it might be worth making the labels more terse and adding notes that explain them, but that's harder to read in a way too. cc ```@Nadrieril``` ```@Jules-Bertholet``` Closes #133854. For reference, the error from that issue becomes: ``` error: pattern uses features incompatible with edition 2024 --> $DIR/remove-me.rs:6:25 | LL | map.iter().filter(|(&(_x, _y), &_c)| false); | ^ ^ cannot implicitly match against multiple layers of reference | | | cannot implicitly match against multiple layers of reference | help: make the implied reference pattern explicit | LL | map.iter().filter(|&(&(_x, _y), &_c)| false); | + ```
This commit is contained in:
commit
f3faaf524c
10 changed files with 315 additions and 189 deletions
|
@ -285,7 +285,7 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from
|
|||
|
||||
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
|
||||
|
||||
mir_build_rust_2024_incompatible_pat = patterns are not allowed to reset the default binding mode in edition 2024
|
||||
mir_build_rust_2024_incompatible_pat = this pattern relies on behavior which may change in edition 2024
|
||||
|
||||
mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
|
||||
.attributes = no other attributes may be applied
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
|
||||
MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
||||
MultiSpan, SubdiagMessageOp, Subdiagnostic, pluralize,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
@ -1088,18 +1088,20 @@ pub(crate) enum RustcBoxAttrReason {
|
|||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_rust_2024_incompatible_pat)]
|
||||
pub(crate) struct Rust2024IncompatiblePat {
|
||||
pub(crate) struct Rust2024IncompatiblePat<'a> {
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg: Rust2024IncompatiblePatSugg,
|
||||
pub(crate) sugg: Rust2024IncompatiblePatSugg<'a>,
|
||||
}
|
||||
|
||||
pub(crate) struct Rust2024IncompatiblePatSugg {
|
||||
pub(crate) struct Rust2024IncompatiblePatSugg<'a> {
|
||||
pub(crate) suggestion: Vec<(Span, String)>,
|
||||
/// Whether the incompatibility is a hard error because a relevant span is in edition 2024.
|
||||
pub(crate) is_hard_error: bool,
|
||||
pub(crate) ref_pattern_count: usize,
|
||||
pub(crate) binding_mode_count: usize,
|
||||
/// Labeled spans for subpatterns invalid in Rust 2024.
|
||||
pub(crate) labels: &'a [(Span, String)],
|
||||
}
|
||||
|
||||
impl Subdiagnostic for Rust2024IncompatiblePatSugg {
|
||||
impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
|
@ -1111,6 +1113,16 @@ impl Subdiagnostic for Rust2024IncompatiblePatSugg {
|
|||
} else {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
diag.multipart_suggestion("desugar the match ergonomics", self.suggestion, applicability);
|
||||
let plural_derefs = pluralize!(self.ref_pattern_count);
|
||||
let and_modes = if self.binding_mode_count > 0 {
|
||||
format!(" and variable binding mode{}", pluralize!(self.binding_mode_count))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("make the implied reference pattern{plural_derefs}{and_modes} explicit"),
|
||||
self.suggestion,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ mod const_to_pat;
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use rustc_abi::{FieldIdx, Integer};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
|
@ -34,7 +35,7 @@ struct PatCtxt<'a, 'tcx> {
|
|||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||
|
||||
/// Used by the Rust 2024 migration lint.
|
||||
rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
|
||||
rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg<'a>>,
|
||||
}
|
||||
|
||||
pub(super) fn pat_from_hir<'a, 'tcx>(
|
||||
|
@ -50,24 +51,36 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
|
|||
rust_2024_migration_suggestion: typeck_results
|
||||
.rust_2024_migration_desugared_pats()
|
||||
.get(pat.hir_id)
|
||||
.map(|&is_hard_error| Rust2024IncompatiblePatSugg {
|
||||
.map(|labels| Rust2024IncompatiblePatSugg {
|
||||
suggestion: Vec::new(),
|
||||
is_hard_error,
|
||||
ref_pattern_count: 0,
|
||||
binding_mode_count: 0,
|
||||
labels: labels.as_slice(),
|
||||
}),
|
||||
};
|
||||
let result = pcx.lower_pattern(pat);
|
||||
debug!("pat_from_hir({:?}) = {:?}", pat, result);
|
||||
if let Some(sugg) = pcx.rust_2024_migration_suggestion {
|
||||
if sugg.is_hard_error {
|
||||
let mut spans = MultiSpan::from_spans(sugg.labels.iter().map(|(span, _)| *span).collect());
|
||||
for (span, label) in sugg.labels {
|
||||
spans.push_span_label(*span, label.clone());
|
||||
}
|
||||
// If a relevant span is from at least edition 2024, this is a hard error.
|
||||
let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
|
||||
if is_hard_error {
|
||||
let mut err =
|
||||
tcx.dcx().struct_span_err(pat.span, fluent::mir_build_rust_2024_incompatible_pat);
|
||||
tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
|
||||
if let Some(info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
|
||||
// provide the same reference link as the lint
|
||||
err.note(format!("for more information, see {}", info.reference));
|
||||
}
|
||||
err.subdiagnostic(sugg);
|
||||
err.emit();
|
||||
} else {
|
||||
tcx.emit_node_span_lint(
|
||||
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
|
||||
pat.hir_id,
|
||||
pat.span,
|
||||
spans,
|
||||
Rust2024IncompatiblePat { sugg },
|
||||
);
|
||||
}
|
||||
|
@ -133,6 +146,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
})
|
||||
.collect();
|
||||
s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
|
||||
s.ref_pattern_count += adjustments.len();
|
||||
};
|
||||
|
||||
adjusted_pat
|
||||
|
@ -371,7 +385,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
s.suggestion.push((
|
||||
pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
|
||||
sugg_str.to_owned(),
|
||||
))
|
||||
));
|
||||
s.binding_mode_count += 1;
|
||||
}
|
||||
|
||||
// A ref x pattern is the same node used for x, and as such it has
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue