mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-31 05:26:23 +03:00
merge diags module into diagnostics
it's a more natural place for diagnostics-related structures and functions
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
//! Borrow checker diagnostics.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
||||
@@ -17,10 +20,10 @@
|
||||
use rustc_middle::ty::print::Print;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_middle::util::{CallDesugaringKind, call_kind};
|
||||
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
|
||||
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{
|
||||
@@ -68,6 +71,137 @@ pub(super) struct DescribePlaceOpt {
|
||||
|
||||
pub(super) struct IncludingTupleField(pub(super) bool);
|
||||
|
||||
enum BufferedDiag<'infcx> {
|
||||
Error(Diag<'infcx>),
|
||||
NonError(Diag<'infcx, ()>),
|
||||
}
|
||||
|
||||
impl<'infcx> BufferedDiag<'infcx> {
|
||||
fn sort_span(&self) -> Span {
|
||||
match self {
|
||||
BufferedDiag::Error(diag) => diag.sort_span,
|
||||
BufferedDiag::NonError(diag) => diag.sort_span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct BorrowckDiags<'infcx, 'tcx> {
|
||||
/// This field keeps track of move errors that are to be reported for given move indices.
|
||||
///
|
||||
/// There are situations where many errors can be reported for a single move out (see
|
||||
/// #53807) and we want only the best of those errors.
|
||||
///
|
||||
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
|
||||
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
|
||||
/// the `Place` of the previous most diagnostic. This happens instead of buffering the
|
||||
/// error. Once all move errors have been reported, any diagnostics in this map are added
|
||||
/// to the buffer to be emitted.
|
||||
///
|
||||
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
|
||||
/// when errors in the map are being re-added to the error buffer so that errors with the
|
||||
/// same primary span come out in a consistent order.
|
||||
buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'infcx>)>,
|
||||
|
||||
buffered_mut_errors: FxIndexMap<Span, (Diag<'infcx>, usize)>,
|
||||
|
||||
/// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.
|
||||
buffered_diags: Vec<BufferedDiag<'infcx>>,
|
||||
}
|
||||
|
||||
impl<'infcx, 'tcx> BorrowckDiags<'infcx, 'tcx> {
|
||||
pub(crate) fn new() -> Self {
|
||||
BorrowckDiags {
|
||||
buffered_move_errors: BTreeMap::new(),
|
||||
buffered_mut_errors: Default::default(),
|
||||
buffered_diags: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
|
||||
self.buffered_diags.push(BufferedDiag::Error(diag));
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
|
||||
self.buffered_diags.push(BufferedDiag::NonError(diag));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
|
||||
self.diags.buffer_error(diag);
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
|
||||
self.diags.buffer_non_error(diag);
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_move_error(
|
||||
&mut self,
|
||||
move_out_indices: Vec<MoveOutIndex>,
|
||||
place_and_err: (PlaceRef<'tcx>, Diag<'infcx>),
|
||||
) -> bool {
|
||||
if let Some((_, diag)) =
|
||||
self.diags.buffered_move_errors.insert(move_out_indices, place_and_err)
|
||||
{
|
||||
// Cancel the old diagnostic so we don't ICE
|
||||
diag.cancel();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'infcx>, usize)> {
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
self.diags.buffered_mut_errors.swap_remove(&span)
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_mut_error(&mut self, span: Span, diag: Diag<'infcx>, count: usize) {
|
||||
self.diags.buffered_mut_errors.insert(span, (diag, count));
|
||||
}
|
||||
|
||||
pub(crate) fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
|
||||
let mut res = self.infcx.tainted_by_errors();
|
||||
|
||||
// Buffer any move errors that we collected and de-duplicated.
|
||||
for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) {
|
||||
// We have already set tainted for this error, so just buffer it.
|
||||
self.diags.buffer_error(diag);
|
||||
}
|
||||
for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) {
|
||||
if count > 10 {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||
}
|
||||
self.diags.buffer_error(diag);
|
||||
}
|
||||
|
||||
if !self.diags.buffered_diags.is_empty() {
|
||||
self.diags.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
|
||||
for buffered_diag in self.diags.buffered_diags.drain(..) {
|
||||
match buffered_diag {
|
||||
BufferedDiag::Error(diag) => res = Some(diag.emit()),
|
||||
BufferedDiag::NonError(diag) => diag.emit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub(crate) fn has_buffered_diags(&self) -> bool {
|
||||
self.diags.buffered_diags.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn has_move_error(
|
||||
&self,
|
||||
move_out_indices: &[MoveOutIndex],
|
||||
) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
|
||||
self.diags.buffered_move_errors.get(move_out_indices)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
/// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
|
||||
/// is moved after being invoked.
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
|
||||
use diagnostics::BorrowckDiags;
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{BitSet, MixedBitSet};
|
||||
@@ -41,7 +40,7 @@
|
||||
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
||||
};
|
||||
use rustc_mir_dataflow::move_paths::{
|
||||
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
|
||||
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
|
||||
};
|
||||
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::UNUSED_MUT;
|
||||
@@ -217,7 +216,7 @@ fn do_mir_borrowck<'tcx>(
|
||||
|
||||
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
||||
// information.
|
||||
let diags = &mut diags::BorrowckDiags::new();
|
||||
let diags = &mut BorrowckDiags::new();
|
||||
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, &opaque_type_values, diags);
|
||||
|
||||
let movable_coroutine =
|
||||
@@ -566,7 +565,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<Box<PoloniusOutput>>,
|
||||
|
||||
diags: &'a mut diags::BorrowckDiags<'infcx, 'tcx>,
|
||||
diags: &'a mut BorrowckDiags<'infcx, 'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
}
|
||||
|
||||
@@ -2399,146 +2398,6 @@ fn lint_unused_mut(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
mod diags {
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
||||
use super::*;
|
||||
|
||||
enum BufferedDiag<'infcx> {
|
||||
Error(Diag<'infcx>),
|
||||
NonError(Diag<'infcx, ()>),
|
||||
}
|
||||
|
||||
impl<'infcx> BufferedDiag<'infcx> {
|
||||
fn sort_span(&self) -> Span {
|
||||
match self {
|
||||
BufferedDiag::Error(diag) => diag.sort_span,
|
||||
BufferedDiag::NonError(diag) => diag.sort_span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct BorrowckDiags<'infcx, 'tcx> {
|
||||
/// This field keeps track of move errors that are to be reported for given move indices.
|
||||
///
|
||||
/// There are situations where many errors can be reported for a single move out (see
|
||||
/// #53807) and we want only the best of those errors.
|
||||
///
|
||||
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
|
||||
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
|
||||
/// the `Place` of the previous most diagnostic. This happens instead of buffering the
|
||||
/// error. Once all move errors have been reported, any diagnostics in this map are added
|
||||
/// to the buffer to be emitted.
|
||||
///
|
||||
/// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
|
||||
/// when errors in the map are being re-added to the error buffer so that errors with the
|
||||
/// same primary span come out in a consistent order.
|
||||
buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'infcx>)>,
|
||||
|
||||
buffered_mut_errors: FxIndexMap<Span, (Diag<'infcx>, usize)>,
|
||||
|
||||
/// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.
|
||||
buffered_diags: Vec<BufferedDiag<'infcx>>,
|
||||
}
|
||||
|
||||
impl<'infcx, 'tcx> BorrowckDiags<'infcx, 'tcx> {
|
||||
pub(crate) fn new() -> Self {
|
||||
BorrowckDiags {
|
||||
buffered_move_errors: BTreeMap::new(),
|
||||
buffered_mut_errors: Default::default(),
|
||||
buffered_diags: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
|
||||
self.buffered_diags.push(BufferedDiag::Error(diag));
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
|
||||
self.buffered_diags.push(BufferedDiag::NonError(diag));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
|
||||
self.diags.buffer_error(diag);
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
|
||||
self.diags.buffer_non_error(diag);
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_move_error(
|
||||
&mut self,
|
||||
move_out_indices: Vec<MoveOutIndex>,
|
||||
place_and_err: (PlaceRef<'tcx>, Diag<'infcx>),
|
||||
) -> bool {
|
||||
if let Some((_, diag)) =
|
||||
self.diags.buffered_move_errors.insert(move_out_indices, place_and_err)
|
||||
{
|
||||
// Cancel the old diagnostic so we don't ICE
|
||||
diag.cancel();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_buffered_mut_error(
|
||||
&mut self,
|
||||
span: Span,
|
||||
) -> Option<(Diag<'infcx>, usize)> {
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
self.diags.buffered_mut_errors.swap_remove(&span)
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_mut_error(&mut self, span: Span, diag: Diag<'infcx>, count: usize) {
|
||||
self.diags.buffered_mut_errors.insert(span, (diag, count));
|
||||
}
|
||||
|
||||
pub(crate) fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
|
||||
let mut res = self.infcx.tainted_by_errors();
|
||||
|
||||
// Buffer any move errors that we collected and de-duplicated.
|
||||
for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) {
|
||||
// We have already set tainted for this error, so just buffer it.
|
||||
self.diags.buffer_error(diag);
|
||||
}
|
||||
for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) {
|
||||
if count > 10 {
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
||||
}
|
||||
self.diags.buffer_error(diag);
|
||||
}
|
||||
|
||||
if !self.diags.buffered_diags.is_empty() {
|
||||
self.diags.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
|
||||
for buffered_diag in self.diags.buffered_diags.drain(..) {
|
||||
match buffered_diag {
|
||||
BufferedDiag::Error(diag) => res = Some(diag.emit()),
|
||||
BufferedDiag::NonError(diag) => diag.emit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub(crate) fn has_buffered_diags(&self) -> bool {
|
||||
self.diags.buffered_diags.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn has_move_error(
|
||||
&self,
|
||||
move_out_indices: &[MoveOutIndex],
|
||||
) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
|
||||
self.diags.buffered_move_errors.get(move_out_indices)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The degree of overlap between 2 places for borrow-checking.
|
||||
enum Overlap {
|
||||
/// The places might partially overlap - in this case, we give
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::consumers::ConsumerOptions;
|
||||
use crate::diagnostics::RegionErrors;
|
||||
use crate::diagnostics::{BorrowckDiags, RegionErrors};
|
||||
use crate::polonius::LocalizedOutlivesConstraintSet;
|
||||
use crate::polonius::legacy::{AllFacts, AllFactsExt, LocationTable, PoloniusOutput};
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
@@ -298,7 +298,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||
diags: &mut crate::diags::BorrowckDiags<'infcx, 'tcx>,
|
||||
diags: &mut BorrowckDiags<'infcx, 'tcx>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||
|
||||
Reference in New Issue
Block a user