Skip to content

Commit 2061630

Browse files
committed
Auto merge of #134914 - lqd:polonius-next-episode-5, r=jackh726
A couple datalog/borrowck cleanups As discussed on zulip, here's a chill one in between slightly more interesting PRs: - I hadn't noticed there still were a couple of datalog-related modules outside of their dedicated `polonius` module (go to horn-clause jail, bonk!). - there somehow was both a `diags` module and a `diagnostics` module. - a couple other tiny things being renamed -- let me know what you think. As requested I've tried to have somewhat granular commits to ease review, but the last two or three could be squashed together, since they're all related to the `diags` module (but moving its contents is less tedious to check in its own commit). r? `@jackh726`
2 parents 93722f7 + 099b809 commit 2061630

File tree

14 files changed

+189
-210
lines changed

14 files changed

+189
-210
lines changed

Diff for: compiler/rustc_borrowck/src/consumers.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ use rustc_middle::ty::TyCtxt;
88
pub use super::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
99
pub use super::constraints::OutlivesConstraint;
1010
pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_at_location};
11-
pub use super::facts::{AllFacts as PoloniusInput, PoloniusRegionVid, RustcFacts};
12-
pub use super::location::{LocationTable, RichLocation};
13-
pub use super::nll::PoloniusOutput;
1411
pub use super::place_ext::PlaceExt;
1512
pub use super::places_conflict::{PlaceConflictBias, places_conflict};
13+
pub use super::polonius::legacy::{
14+
AllFacts as PoloniusInput, LocationTable, PoloniusOutput, PoloniusRegionVid, RichLocation,
15+
RustcFacts,
16+
};
1617
pub use super::region_infer::RegionInferenceContext;
1718

1819
/// Options determining the output behavior of [`get_body_with_borrowck_facts`].

Diff for: compiler/rustc_borrowck/src/diagnostics/mod.rs

+125-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! Borrow checker diagnostics.
22
3+
use std::collections::BTreeMap;
4+
35
use rustc_abi::{FieldIdx, VariantIdx};
6+
use rustc_data_structures::fx::FxIndexMap;
47
use rustc_errors::{Applicability, Diag, MultiSpan};
58
use rustc_hir::def::{CtorKind, Namespace};
69
use rustc_hir::{self as hir, CoroutineKind, LangItem};
@@ -17,10 +20,10 @@ use rustc_middle::mir::{
1720
use rustc_middle::ty::print::Print;
1821
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
1922
use rustc_middle::util::{CallDesugaringKind, call_kind};
20-
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
23+
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
2124
use rustc_span::def_id::LocalDefId;
2225
use rustc_span::source_map::Spanned;
23-
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
26+
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
2427
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
2528
use rustc_trait_selection::infer::InferCtxtExt;
2629
use rustc_trait_selection::traits::{
@@ -68,6 +71,126 @@ pub(super) struct DescribePlaceOpt {
6871

6972
pub(super) struct IncludingTupleField(pub(super) bool);
7073

74+
enum BufferedDiag<'infcx> {
75+
Error(Diag<'infcx>),
76+
NonError(Diag<'infcx, ()>),
77+
}
78+
79+
impl<'infcx> BufferedDiag<'infcx> {
80+
fn sort_span(&self) -> Span {
81+
match self {
82+
BufferedDiag::Error(diag) => diag.sort_span,
83+
BufferedDiag::NonError(diag) => diag.sort_span,
84+
}
85+
}
86+
}
87+
88+
#[derive(Default)]
89+
pub(crate) struct BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
90+
/// This field keeps track of move errors that are to be reported for given move indices.
91+
///
92+
/// There are situations where many errors can be reported for a single move out (see
93+
/// #53807) and we want only the best of those errors.
94+
///
95+
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
96+
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
97+
/// the `Place` of the previous most diagnostic. This happens instead of buffering the
98+
/// error. Once all move errors have been reported, any diagnostics in this map are added
99+
/// to the buffer to be emitted.
100+
///
101+
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
102+
/// when errors in the map are being re-added to the error buffer so that errors with the
103+
/// same primary span come out in a consistent order.
104+
buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'infcx>)>,
105+
106+
buffered_mut_errors: FxIndexMap<Span, (Diag<'infcx>, usize)>,
107+
108+
/// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.
109+
buffered_diags: Vec<BufferedDiag<'infcx>>,
110+
}
111+
112+
impl<'infcx, 'tcx> BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
113+
pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
114+
self.buffered_diags.push(BufferedDiag::NonError(diag));
115+
}
116+
}
117+
118+
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
119+
pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
120+
self.diags_buffer.buffered_diags.push(BufferedDiag::Error(diag));
121+
}
122+
123+
pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
124+
self.diags_buffer.buffer_non_error(diag);
125+
}
126+
127+
pub(crate) fn buffer_move_error(
128+
&mut self,
129+
move_out_indices: Vec<MoveOutIndex>,
130+
place_and_err: (PlaceRef<'tcx>, Diag<'infcx>),
131+
) -> bool {
132+
if let Some((_, diag)) =
133+
self.diags_buffer.buffered_move_errors.insert(move_out_indices, place_and_err)
134+
{
135+
// Cancel the old diagnostic so we don't ICE
136+
diag.cancel();
137+
false
138+
} else {
139+
true
140+
}
141+
}
142+
143+
pub(crate) fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'infcx>, usize)> {
144+
// FIXME(#120456) - is `swap_remove` correct?
145+
self.diags_buffer.buffered_mut_errors.swap_remove(&span)
146+
}
147+
148+
pub(crate) fn buffer_mut_error(&mut self, span: Span, diag: Diag<'infcx>, count: usize) {
149+
self.diags_buffer.buffered_mut_errors.insert(span, (diag, count));
150+
}
151+
152+
pub(crate) fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
153+
let mut res = self.infcx.tainted_by_errors();
154+
155+
// Buffer any move errors that we collected and de-duplicated.
156+
for (_, (_, diag)) in std::mem::take(&mut self.diags_buffer.buffered_move_errors) {
157+
// We have already set tainted for this error, so just buffer it.
158+
self.buffer_error(diag);
159+
}
160+
for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
161+
if count > 10 {
162+
#[allow(rustc::diagnostic_outside_of_impl)]
163+
#[allow(rustc::untranslatable_diagnostic)]
164+
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
165+
}
166+
self.buffer_error(diag);
167+
}
168+
169+
if !self.diags_buffer.buffered_diags.is_empty() {
170+
self.diags_buffer.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
171+
for buffered_diag in self.diags_buffer.buffered_diags.drain(..) {
172+
match buffered_diag {
173+
BufferedDiag::Error(diag) => res = Some(diag.emit()),
174+
BufferedDiag::NonError(diag) => diag.emit(),
175+
}
176+
}
177+
}
178+
179+
res
180+
}
181+
182+
pub(crate) fn has_buffered_diags(&self) -> bool {
183+
self.diags_buffer.buffered_diags.is_empty()
184+
}
185+
186+
pub(crate) fn has_move_error(
187+
&self,
188+
move_out_indices: &[MoveOutIndex],
189+
) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
190+
self.diags_buffer.buffered_move_errors.get(move_out_indices)
191+
}
192+
}
193+
71194
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
72195
/// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
73196
/// is moved after being invoked.

0 commit comments

Comments
 (0)