Do not report errors from move path builder.

This commit is contained in:
Camille GILLOT
2023-09-30 15:14:07 +00:00
parent a8e56d0b0b
commit 8d535070a2
11 changed files with 305 additions and 172 deletions

View File

@@ -1,9 +1,7 @@
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::mir::*;
use rustc_middle::ty;
use rustc_mir_dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
};
use rustc_mir_dataflow::move_paths::{IllegalMoveOriginKind, LookupResult, MovePathIndex};
use rustc_span::{BytePos, Span};
use crate::diagnostics::CapturedMessageOpt;
@@ -11,6 +9,23 @@ use crate::diagnostics::{DescribePlaceOpt, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
#[derive(Debug)]
pub(crate) struct MoveError<'tcx> {
place: Place<'tcx>,
location: Location,
kind: IllegalMoveOriginKind<'tcx>,
}
impl<'tcx> MoveError<'tcx> {
pub(crate) fn new(
place: Place<'tcx>,
location: Location,
kind: IllegalMoveOriginKind<'tcx>,
) -> Self {
MoveError { place, location, kind }
}
}
// Often when desugaring a pattern match we may have many individual moves in
// MIR that are all part of one operation from the user's point-of-view. For
// example:
@@ -53,20 +68,18 @@ enum GroupedMoveError<'tcx> {
}
impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
let grouped_errors = self.group_move_errors(move_errors);
pub(crate) fn report_move_errors(&mut self) {
let grouped_errors = self.group_move_errors();
for error in grouped_errors {
self.report(error);
}
}
fn group_move_errors(
&self,
errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
) -> Vec<GroupedMoveError<'tcx>> {
fn group_move_errors(&mut self) -> Vec<GroupedMoveError<'tcx>> {
let mut grouped_errors = Vec::new();
for (original_path, error) in errors {
self.append_to_grouped_errors(&mut grouped_errors, original_path, error);
let errors = std::mem::take(&mut self.move_errors);
for error in errors {
self.append_to_grouped_errors(&mut grouped_errors, error);
}
grouped_errors
}
@@ -74,66 +87,58 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn append_to_grouped_errors(
&self,
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
original_path: Place<'tcx>,
error: MoveError<'tcx>,
) {
match error {
MoveError::UnionMove { .. } => {
unimplemented!("don't know how to report union move errors yet.")
}
MoveError::IllegalMove { cannot_move_out_of: IllegalMoveOrigin { location, kind } } => {
// Note: that the only time we assign a place isn't a temporary
// to a user variable is when initializing it.
// If that ever stops being the case, then the ever initialized
// flow could be used.
if let Some(StatementKind::Assign(box (
place,
Rvalue::Use(Operand::Move(move_from)),
))) = self.body.basic_blocks[location.block]
.statements
.get(location.statement_index)
.map(|stmt| &stmt.kind)
{
if let Some(local) = place.as_local() {
let local_decl = &self.body.local_decls[local];
// opt_match_place is the
// match_span is the span of the expression being matched on
// match *x.y { ... } match_place is Some(*x.y)
// ^^^^ match_span is the span of *x.y
//
// opt_match_place is None for let [mut] x = ... statements,
// whether or not the right-hand side is a place expression
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
opt_match_place: Some((opt_match_place, match_span)),
binding_mode: _,
opt_ty_info: _,
pat_span: _,
})) = *local_decl.local_info()
{
let stmt_source_info = self.body.source_info(location);
self.append_binding_error(
grouped_errors,
kind,
original_path,
*move_from,
local,
opt_match_place,
match_span,
stmt_source_info.span,
);
return;
}
}
}
let MoveError { place: original_path, location, kind } = error;
let move_spans = self.move_spans(original_path.as_ref(), location);
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
use_spans: move_spans,
original_path,
kind,
});
// Note: that the only time we assign a place isn't a temporary
// to a user variable is when initializing it.
// If that ever stops being the case, then the ever initialized
// flow could be used.
if let Some(StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(move_from))))) =
self.body.basic_blocks[location.block]
.statements
.get(location.statement_index)
.map(|stmt| &stmt.kind)
{
if let Some(local) = place.as_local() {
let local_decl = &self.body.local_decls[local];
// opt_match_place is the
// match_span is the span of the expression being matched on
// match *x.y { ... } match_place is Some(*x.y)
// ^^^^ match_span is the span of *x.y
//
// opt_match_place is None for let [mut] x = ... statements,
// whether or not the right-hand side is a place expression
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
opt_match_place: Some((opt_match_place, match_span)),
binding_mode: _,
opt_ty_info: _,
pat_span: _,
})) = *local_decl.local_info()
{
let stmt_source_info = self.body.source_info(location);
self.append_binding_error(
grouped_errors,
kind,
original_path,
*move_from,
local,
opt_match_place,
match_span,
stmt_source_info.span,
);
return;
}
}
}
let move_spans = self.move_spans(original_path.as_ref(), location);
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
use_spans: move_spans,
original_path,
kind,
});
}
fn append_binding_error(