2019-11-27 11:39:25 -06:00
|
|
|
//! Borrow checker diagnostics.
|
|
|
|
|
2024-12-30 00:56:14 +00:00
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
2024-11-02 20:24:15 -07:00
|
|
|
use rustc_abi::{FieldIdx, VariantIdx};
|
2024-12-30 00:56:14 +00:00
|
|
|
use rustc_data_structures::fx::FxIndexMap;
|
2025-01-31 20:36:44 +00:00
|
|
|
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
|
2022-07-23 00:35:35 +03:00
|
|
|
use rustc_hir::def::{CtorKind, Namespace};
|
2024-06-14 14:46:32 -04:00
|
|
|
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
2023-04-19 10:57:17 +00:00
|
|
|
use rustc_index::IndexSlice;
|
2024-12-12 01:20:26 -08:00
|
|
|
use rustc_infer::infer::{
|
|
|
|
BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin,
|
|
|
|
};
|
2024-06-01 15:08:44 -04:00
|
|
|
use rustc_infer::traits::SelectionError;
|
2024-04-29 13:56:41 +10:00
|
|
|
use rustc_middle::bug;
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::mir::{
|
2024-12-12 01:20:26 -08:00
|
|
|
AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
|
Remove `rustc_middle::mir::tcx` module.
This is a really weird module. For example, what does `tcx` in
`rustc_middle::mir::tcx::PlaceTy` mean? The answer is "not much".
The top-level module comment says:
> Methods for the various MIR types. These are intended for use after
> building is complete.
Awfully broad for a module that has a handful of impl blocks for some
MIR types, none of which really relates to `TyCtxt`. `git blame`
indicates the comment is ancient, from 2015, and made sense then.
This module is now vestigial. This commit removes it and moves all the
code within into `rustc_middle::mir::statement`. Some specifics:
- `Place`, `PlaceRef`, `Rvalue`, `Operand`, `BorrowKind`: they all have `impl`
blocks in both the `tcx` and `statement` modules. The commit merges
the former into the latter.
- `BinOp`, `UnOp`: they only have `impl` blocks in `tcx`. The commit
moves these into `statement`.
- `PlaceTy`, `RvalueInitializationState`: they are defined in `tcx`.
This commit moves them into `statement` *and* makes them available in
`mir::*`, like many other MIR types.
2025-02-18 17:48:27 +11:00
|
|
|
LocalKind, Location, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement,
|
2025-01-31 09:55:55 +11:00
|
|
|
StatementKind, Terminator, TerminatorKind, find_self_call,
|
2018-09-09 19:34:39 +02:00
|
|
|
};
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::ty::print::Print;
|
2025-01-09 17:43:02 +00:00
|
|
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
2024-12-30 00:56:14 +00:00
|
|
|
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
|
2022-07-12 09:10:22 -05:00
|
|
|
use rustc_span::def_id::LocalDefId;
|
2024-01-12 08:21:42 +01:00
|
|
|
use rustc_span::source_map::Spanned;
|
2024-12-30 00:56:14 +00:00
|
|
|
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
2024-07-21 15:20:41 -04:00
|
|
|
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
2025-01-09 17:43:02 +00:00
|
|
|
use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
|
2023-11-21 21:24:51 +00:00
|
|
|
use rustc_trait_selection::infer::InferCtxtExt;
|
2024-06-01 15:08:44 -04:00
|
|
|
use rustc_trait_selection::traits::{
|
2025-01-31 20:36:44 +00:00
|
|
|
FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
|
2024-06-01 15:08:44 -04:00
|
|
|
};
|
2024-08-30 08:39:41 +10:00
|
|
|
use tracing::debug;
|
2017-12-10 21:15:52 +00:00
|
|
|
|
2019-10-10 22:20:57 +08:00
|
|
|
use super::MirBorrowckCtxt;
|
2018-06-19 21:22:52 -03:00
|
|
|
use super::borrow_set::BorrowData;
|
2024-12-12 01:20:26 -08:00
|
|
|
use crate::constraints::OutlivesConstraint;
|
2024-03-15 18:08:12 +00:00
|
|
|
use crate::fluent_generated as fluent;
|
2024-12-20 21:14:16 -08:00
|
|
|
use crate::nll::ConstraintDescription;
|
2023-02-10 16:58:32 +08:00
|
|
|
use crate::session_diagnostics::{
|
|
|
|
CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
|
|
|
|
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
|
2024-07-29 08:13:50 +10:00
|
|
|
};
|
2017-12-06 20:27:38 +02:00
|
|
|
|
2021-03-15 15:09:06 -07:00
|
|
|
mod find_all_local_uses;
|
2019-11-27 11:45:05 -06:00
|
|
|
mod find_use;
|
2019-11-27 12:22:17 -06:00
|
|
|
mod outlives_suggestion;
|
|
|
|
mod region_name;
|
|
|
|
mod var_name;
|
2019-11-27 11:45:05 -06:00
|
|
|
|
2021-03-07 14:41:45 +00:00
|
|
|
mod bound_region_errors;
|
2019-12-02 17:05:25 -06:00
|
|
|
mod conflict_errors;
|
|
|
|
mod explain_borrow;
|
|
|
|
mod move_errors;
|
|
|
|
mod mutability_errors;
|
2024-10-03 00:44:14 -04:00
|
|
|
mod opaque_suggestions;
|
2019-12-02 17:05:25 -06:00
|
|
|
mod region_errors;
|
2019-11-27 11:39:25 -06:00
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};
|
2023-09-30 20:23:34 +00:00
|
|
|
pub(crate) use move_errors::{IllegalMoveOriginKind, MoveError};
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) use mutability_errors::AccessKind;
|
|
|
|
pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;
|
|
|
|
pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
|
|
|
|
pub(crate) use region_name::{RegionName, RegionNameSource};
|
2025-01-09 17:43:02 +00:00
|
|
|
pub(crate) use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;
|
2019-11-27 12:22:17 -06:00
|
|
|
|
2022-07-23 00:35:35 +03:00
|
|
|
pub(super) struct DescribePlaceOpt {
|
2024-07-06 21:53:49 +10:00
|
|
|
including_downcast: bool,
|
2022-07-23 00:35:35 +03:00
|
|
|
|
|
|
|
/// Enable/Disable tuple fields.
|
|
|
|
/// For example `x` tuple. if it's `true` `x.0`. Otherwise `x`
|
2024-07-06 21:53:49 +10:00
|
|
|
including_tuple_field: bool,
|
2022-07-23 00:35:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) struct IncludingTupleField(pub(super) bool);
|
2018-09-23 16:07:45 +01:00
|
|
|
|
2024-12-30 00:56:14 +00:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-30 01:16:52 +00:00
|
|
|
#[derive(Default)]
|
|
|
|
pub(crate) struct BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
|
2024-12-30 00:56:14 +00:00
|
|
|
/// 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>>,
|
|
|
|
}
|
|
|
|
|
2024-12-30 01:16:52 +00:00
|
|
|
impl<'infcx, 'tcx> BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
|
2024-12-30 00:56:14 +00:00
|
|
|
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>) {
|
2024-12-30 01:21:48 +00:00
|
|
|
self.diags_buffer.buffered_diags.push(BufferedDiag::Error(diag));
|
2024-12-30 00:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
|
2024-12-30 01:21:48 +00:00
|
|
|
self.diags_buffer.buffer_non_error(diag);
|
2024-12-30 00:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)) =
|
2024-12-30 01:21:48 +00:00
|
|
|
self.diags_buffer.buffered_move_errors.insert(move_out_indices, place_and_err)
|
2024-12-30 00:56:14 +00:00
|
|
|
{
|
|
|
|
// 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?
|
2024-12-30 01:21:48 +00:00
|
|
|
self.diags_buffer.buffered_mut_errors.swap_remove(&span)
|
2024-12-30 00:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn buffer_mut_error(&mut self, span: Span, diag: Diag<'infcx>, count: usize) {
|
2024-12-30 01:21:48 +00:00
|
|
|
self.diags_buffer.buffered_mut_errors.insert(span, (diag, count));
|
2024-12-30 00:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2024-12-30 01:21:48 +00:00
|
|
|
for (_, (_, diag)) in std::mem::take(&mut self.diags_buffer.buffered_move_errors) {
|
2024-12-30 00:56:14 +00:00
|
|
|
// We have already set tainted for this error, so just buffer it.
|
2024-12-30 01:16:52 +00:00
|
|
|
self.buffer_error(diag);
|
2024-12-30 00:56:14 +00:00
|
|
|
}
|
2024-12-30 01:21:48 +00:00
|
|
|
for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
|
2024-12-30 00:56:14 +00:00
|
|
|
if count > 10 {
|
|
|
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
|
|
|
#[allow(rustc::untranslatable_diagnostic)]
|
|
|
|
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
|
|
|
|
}
|
2024-12-30 01:16:52 +00:00
|
|
|
self.buffer_error(diag);
|
2024-12-30 00:56:14 +00:00
|
|
|
}
|
|
|
|
|
2024-12-30 01:21:48 +00:00
|
|
|
if !self.diags_buffer.buffered_diags.is_empty() {
|
|
|
|
self.diags_buffer.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
|
|
|
|
for buffered_diag in self.diags_buffer.buffered_diags.drain(..) {
|
2024-12-30 00:56:14 +00:00
|
|
|
match buffered_diag {
|
|
|
|
BufferedDiag::Error(diag) => res = Some(diag.emit()),
|
|
|
|
BufferedDiag::NonError(diag) => diag.emit(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn has_buffered_diags(&self) -> bool {
|
2024-12-30 01:21:48 +00:00
|
|
|
self.diags_buffer.buffered_diags.is_empty()
|
2024-12-30 00:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn has_move_error(
|
|
|
|
&self,
|
|
|
|
move_out_indices: &[MoveOutIndex],
|
|
|
|
) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
|
2024-12-30 01:21:48 +00:00
|
|
|
self.diags_buffer.buffered_move_errors.get(move_out_indices)
|
2024-12-30 00:56:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-06 09:18:17 +10:00
|
|
|
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
2018-12-24 15:29:40 +01:00
|
|
|
/// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
|
|
|
|
/// is moved after being invoked.
|
2018-10-11 01:19:55 +02:00
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// note: closure cannot be invoked more than once because it moves the variable `dict` out of
|
|
|
|
/// its environment
|
|
|
|
/// --> $DIR/issue-42065.rs:16:29
|
|
|
|
/// |
|
|
|
|
/// LL | for (key, value) in dict {
|
|
|
|
/// | ^^^^
|
|
|
|
/// ```
|
2024-02-29 08:53:46 +11:00
|
|
|
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
|
2018-12-24 15:29:40 +01:00
|
|
|
pub(super) fn add_moved_or_invoked_closure_note(
|
2018-10-11 01:19:55 +02:00
|
|
|
&self,
|
|
|
|
location: Location,
|
2020-03-04 18:25:03 -03:00
|
|
|
place: PlaceRef<'tcx>,
|
2024-06-27 09:07:57 +00:00
|
|
|
diag: &mut Diag<'infcx>,
|
2022-11-15 19:43:33 -08:00
|
|
|
) -> bool {
|
2018-12-24 15:29:40 +01:00
|
|
|
debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
|
2019-05-27 23:37:18 +02:00
|
|
|
let mut target = place.local_or_deref_local();
|
2019-11-06 12:00:46 -05:00
|
|
|
for stmt in &self.body[location.block].statements[location.statement_index..] {
|
2018-12-24 15:29:40 +01:00
|
|
|
debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
|
2019-09-11 16:05:45 -03:00
|
|
|
if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
|
2018-12-24 15:29:40 +01:00
|
|
|
debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
|
2018-10-11 01:19:55 +02:00
|
|
|
match from {
|
2022-12-02 19:07:57 +00:00
|
|
|
Operand::Copy(place) | Operand::Move(place)
|
2019-05-27 23:37:18 +02:00
|
|
|
if target == place.local_or_deref_local() =>
|
2019-12-22 17:42:04 -05:00
|
|
|
{
|
2019-05-27 23:37:18 +02:00
|
|
|
target = into.local_or_deref_local()
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2018-10-11 01:19:55 +02:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-24 15:29:40 +01:00
|
|
|
// Check if we are attempting to call a closure after it has been invoked.
|
2019-11-06 12:00:46 -05:00
|
|
|
let terminator = self.body[location.block].terminator();
|
2018-12-24 15:29:40 +01:00
|
|
|
debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
|
2018-10-11 01:19:55 +02:00
|
|
|
if let TerminatorKind::Call {
|
2023-09-20 20:51:14 +02:00
|
|
|
func: Operand::Constant(box ConstOperand { const_, .. }),
|
2018-10-11 01:19:55 +02:00
|
|
|
args,
|
|
|
|
..
|
|
|
|
} = &terminator.kind
|
|
|
|
{
|
2023-09-20 20:51:14 +02:00
|
|
|
if let ty::FnDef(id, _) = *const_.ty().kind() {
|
2020-08-03 00:49:11 +02:00
|
|
|
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
|
2024-06-14 14:46:32 -04:00
|
|
|
if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
|
2020-08-03 00:49:11 +02:00
|
|
|
let closure = match args.first() {
|
2024-01-12 08:21:42 +01:00
|
|
|
Some(Spanned {
|
|
|
|
node: Operand::Copy(place) | Operand::Move(place), ..
|
|
|
|
}) if target == place.local_or_deref_local() => {
|
2020-08-03 00:49:11 +02:00
|
|
|
place.local_or_deref_local().unwrap()
|
|
|
|
}
|
2022-11-15 19:43:33 -08:00
|
|
|
_ => return false,
|
2020-08-03 00:49:11 +02:00
|
|
|
};
|
2018-10-11 01:19:55 +02:00
|
|
|
|
2020-08-03 00:49:11 +02:00
|
|
|
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
|
|
|
|
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
|
|
|
let did = did.expect_local();
|
2023-02-25 22:51:57 +00:00
|
|
|
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
2024-06-18 11:10:18 +00:00
|
|
|
diag.subdiagnostic(OnClosureNote::InvokedTwice {
|
|
|
|
place_name: &ty::place_to_string_for_capture(
|
|
|
|
self.infcx.tcx,
|
|
|
|
hir_place,
|
|
|
|
),
|
|
|
|
span: *span,
|
|
|
|
});
|
2022-11-15 19:43:33 -08:00
|
|
|
return true;
|
2020-08-03 00:49:11 +02:00
|
|
|
}
|
2018-10-16 19:37:01 +02:00
|
|
|
}
|
2018-10-11 01:19:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-24 15:29:40 +01:00
|
|
|
|
|
|
|
// Check if we are just moving a closure after it has been invoked.
|
|
|
|
if let Some(target) = target {
|
2020-08-03 00:49:11 +02:00
|
|
|
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
|
2020-04-17 15:17:01 +01:00
|
|
|
let did = did.expect_local();
|
2023-02-25 22:51:57 +00:00
|
|
|
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
2024-06-18 11:10:18 +00:00
|
|
|
diag.subdiagnostic(OnClosureNote::MovedTwice {
|
|
|
|
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
|
|
|
span: *span,
|
|
|
|
});
|
2022-11-15 19:43:33 -08:00
|
|
|
return true;
|
2018-12-24 15:29:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-15 19:43:33 -08:00
|
|
|
false
|
2018-10-11 01:19:55 +02:00
|
|
|
}
|
|
|
|
|
2020-03-25 11:17:06 +01:00
|
|
|
/// End-user visible description of `place` if one can be found.
|
2020-03-26 01:55:16 +01:00
|
|
|
/// If the place is a temporary for instance, `"value"` will be returned.
|
|
|
|
pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String {
|
2020-03-25 11:17:06 +01:00
|
|
|
match self.describe_place(place_ref) {
|
2020-03-26 01:55:16 +01:00
|
|
|
Some(mut descr) => {
|
|
|
|
// Surround descr with `backticks`.
|
|
|
|
descr.reserve(2);
|
2020-09-10 13:57:40 +02:00
|
|
|
descr.insert(0, '`');
|
|
|
|
descr.push('`');
|
2020-03-26 01:55:16 +01:00
|
|
|
descr
|
|
|
|
}
|
2020-03-25 11:17:06 +01:00
|
|
|
None => "value".to_string(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// End-user visible description of `place` if one can be found.
|
2022-05-06 12:11:42 +08:00
|
|
|
/// If the place is a temporary for instance, `None` will be returned.
|
2020-03-04 18:25:03 -03:00
|
|
|
pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
|
2022-07-23 00:35:35 +03:00
|
|
|
self.describe_place_with_options(
|
|
|
|
place_ref,
|
|
|
|
DescribePlaceOpt { including_downcast: false, including_tuple_field: true },
|
|
|
|
)
|
2018-06-20 23:51:18 -03:00
|
|
|
}
|
|
|
|
|
2022-05-06 12:11:42 +08:00
|
|
|
/// End-user visible description of `place` if one can be found. If the place is a temporary
|
|
|
|
/// for instance, `None` will be returned.
|
|
|
|
/// `IncludingDowncast` parameter makes the function return `None` if `ProjectionElem` is
|
2018-10-11 01:19:55 +02:00
|
|
|
/// `Downcast` and `IncludingDowncast` is true
|
2018-06-22 00:10:52 -03:00
|
|
|
pub(super) fn describe_place_with_options(
|
|
|
|
&self,
|
2020-03-04 18:25:03 -03:00
|
|
|
place: PlaceRef<'tcx>,
|
2022-07-23 00:35:35 +03:00
|
|
|
opt: DescribePlaceOpt,
|
2018-06-22 00:10:52 -03:00
|
|
|
) -> Option<String> {
|
2022-05-06 12:11:42 +08:00
|
|
|
let local = place.local;
|
|
|
|
let mut autoderef_index = None;
|
2017-12-06 20:27:38 +02:00
|
|
|
let mut buf = String::new();
|
2022-05-06 12:11:42 +08:00
|
|
|
let mut ok = self.append_local_to_string(local, &mut buf);
|
2017-12-06 20:27:38 +02:00
|
|
|
|
2022-05-06 12:11:42 +08:00
|
|
|
for (index, elem) in place.projection.into_iter().enumerate() {
|
|
|
|
match elem {
|
|
|
|
ProjectionElem::Deref => {
|
|
|
|
if index == 0 {
|
|
|
|
if self.body.local_decls[local].is_ref_for_guard() {
|
|
|
|
continue;
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2023-03-09 16:55:20 +00:00
|
|
|
if let LocalInfo::StaticRef { def_id, .. } =
|
|
|
|
*self.body.local_decls[local].local_info()
|
2022-05-06 12:11:42 +08:00
|
|
|
{
|
2023-03-09 16:55:20 +00:00
|
|
|
buf.push_str(self.infcx.tcx.item_name(def_id).as_str());
|
2022-05-06 12:11:42 +08:00
|
|
|
ok = Ok(());
|
|
|
|
continue;
|
2018-06-20 23:51:18 -03:00
|
|
|
}
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2022-05-06 12:11:42 +08:00
|
|
|
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
|
|
|
|
local,
|
|
|
|
projection: place.projection.split_at(index + 1).0,
|
|
|
|
}) {
|
|
|
|
let var_index = field.index();
|
2023-11-26 08:39:57 -05:00
|
|
|
buf = self.upvars[var_index].to_string(self.infcx.tcx);
|
2022-05-06 12:11:42 +08:00
|
|
|
ok = Ok(());
|
2023-11-26 08:39:57 -05:00
|
|
|
if !self.upvars[var_index].is_by_ref() {
|
2022-05-06 12:11:42 +08:00
|
|
|
buf.insert(0, '*');
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2022-05-06 12:11:42 +08:00
|
|
|
} else {
|
|
|
|
if autoderef_index.is_none() {
|
2024-03-23 17:24:13 -07:00
|
|
|
autoderef_index = match place.projection.iter().rposition(|elem| {
|
|
|
|
!matches!(
|
|
|
|
elem,
|
|
|
|
ProjectionElem::Deref | ProjectionElem::Downcast(..)
|
|
|
|
)
|
|
|
|
}) {
|
|
|
|
Some(index) => Some(index + 1),
|
|
|
|
None => Some(0),
|
|
|
|
};
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2022-05-06 12:11:42 +08:00
|
|
|
if index >= autoderef_index.unwrap() {
|
|
|
|
buf.insert(0, '*');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-23 00:35:35 +03:00
|
|
|
ProjectionElem::Downcast(..) if opt.including_downcast => return None,
|
2022-05-06 12:11:42 +08:00
|
|
|
ProjectionElem::Downcast(..) => (),
|
2022-07-27 11:58:34 +00:00
|
|
|
ProjectionElem::OpaqueCast(..) => (),
|
2023-08-16 08:43:30 +03:00
|
|
|
ProjectionElem::Subtype(..) => (),
|
2025-01-31 01:24:37 +00:00
|
|
|
ProjectionElem::UnwrapUnsafeBinder(_) => (),
|
2022-05-06 12:11:42 +08:00
|
|
|
ProjectionElem::Field(field, _ty) => {
|
|
|
|
// FIXME(project-rfc_2229#36): print capture precisely here.
|
|
|
|
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
|
|
|
|
local,
|
|
|
|
projection: place.projection.split_at(index + 1).0,
|
|
|
|
}) {
|
2023-11-26 08:39:57 -05:00
|
|
|
buf = self.upvars[field.index()].to_string(self.infcx.tcx);
|
2022-05-06 12:11:42 +08:00
|
|
|
ok = Ok(());
|
|
|
|
} else {
|
|
|
|
let field_name = self.describe_field(
|
|
|
|
PlaceRef { local, projection: place.projection.split_at(index).0 },
|
|
|
|
*field,
|
2022-07-23 00:35:35 +03:00
|
|
|
IncludingTupleField(opt.including_tuple_field),
|
2022-05-06 12:11:42 +08:00
|
|
|
);
|
2022-07-23 00:35:35 +03:00
|
|
|
if let Some(field_name_str) = field_name {
|
|
|
|
buf.push('.');
|
|
|
|
buf.push_str(&field_name_str);
|
|
|
|
}
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2022-05-06 12:11:42 +08:00
|
|
|
}
|
|
|
|
ProjectionElem::Index(index) => {
|
|
|
|
buf.push('[');
|
|
|
|
if self.append_local_to_string(*index, &mut buf).is_err() {
|
|
|
|
buf.push('_');
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2022-05-06 12:11:42 +08:00
|
|
|
buf.push(']');
|
|
|
|
}
|
|
|
|
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
|
|
|
|
// Since it isn't possible to borrow an element on a particular index and
|
|
|
|
// then use another while the borrow is held, don't output indices details
|
|
|
|
// to avoid confusing the end-user
|
|
|
|
buf.push_str("[..]");
|
|
|
|
}
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
|
|
|
}
|
2022-05-06 12:11:42 +08:00
|
|
|
ok.ok().map(|_| buf)
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
|
|
|
|
2022-07-23 00:35:35 +03:00
|
|
|
fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {
|
|
|
|
for elem in place.projection.into_iter() {
|
|
|
|
match elem {
|
|
|
|
ProjectionElem::Downcast(Some(name), _) => {
|
|
|
|
return Some(*name);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2018-10-11 01:19:55 +02:00
|
|
|
/// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
|
2019-05-03 22:24:52 +01:00
|
|
|
/// a name, or its name was generated by the compiler, then `Err` is returned
|
2018-05-16 18:58:54 +03:00
|
|
|
fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
|
2019-11-06 12:00:46 -05:00
|
|
|
let decl = &self.body.local_decls[local];
|
2018-05-16 18:58:54 +03:00
|
|
|
match self.local_names[local] {
|
|
|
|
Some(name) if !decl.from_compiler_desugaring() => {
|
2021-12-15 14:39:23 +11:00
|
|
|
buf.push_str(name.as_str());
|
2017-12-06 20:27:38 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-05-03 22:24:52 +01:00
|
|
|
_ => Err(()),
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-11 01:19:55 +02:00
|
|
|
/// End-user visible description of the `field`nth field of `base`
|
2022-07-23 00:35:35 +03:00
|
|
|
fn describe_field(
|
|
|
|
&self,
|
|
|
|
place: PlaceRef<'tcx>,
|
2023-03-28 12:32:57 -07:00
|
|
|
field: FieldIdx,
|
2022-07-23 00:35:35 +03:00
|
|
|
including_tuple_field: IncludingTupleField,
|
|
|
|
) -> Option<String> {
|
2022-04-25 16:09:36 +08:00
|
|
|
let place_ty = match place {
|
|
|
|
PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
|
2019-12-11 16:50:03 -03:00
|
|
|
PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
|
2022-04-25 16:09:36 +08:00
|
|
|
ProjectionElem::Deref
|
|
|
|
| ProjectionElem::Index(..)
|
2018-03-01 16:43:03 -03:00
|
|
|
| ProjectionElem::ConstantIndex { .. }
|
|
|
|
| ProjectionElem::Subslice { .. } => {
|
2022-04-25 16:09:36 +08:00
|
|
|
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2022-04-25 16:09:36 +08:00
|
|
|
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
|
2025-01-31 01:24:37 +00:00
|
|
|
ProjectionElem::Subtype(ty)
|
|
|
|
| ProjectionElem::OpaqueCast(ty)
|
|
|
|
| ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
|
2022-04-25 16:09:36 +08:00
|
|
|
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
|
2017-12-06 20:27:38 +02:00
|
|
|
},
|
2022-04-25 16:09:36 +08:00
|
|
|
};
|
2022-07-23 00:35:35 +03:00
|
|
|
self.describe_field_from_ty(
|
|
|
|
place_ty.ty,
|
|
|
|
field,
|
|
|
|
place_ty.variant_index,
|
|
|
|
including_tuple_field,
|
|
|
|
)
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
|
|
|
|
2018-10-11 01:19:55 +02:00
|
|
|
/// End-user visible description of the `field_index`nth field of `ty`
|
2019-03-28 18:00:17 -07:00
|
|
|
fn describe_field_from_ty(
|
|
|
|
&self,
|
2019-04-26 14:26:49 +02:00
|
|
|
ty: Ty<'_>,
|
2023-03-28 12:32:57 -07:00
|
|
|
field: FieldIdx,
|
2019-03-28 18:00:17 -07:00
|
|
|
variant_index: Option<VariantIdx>,
|
2022-07-23 00:35:35 +03:00
|
|
|
including_tuple_field: IncludingTupleField,
|
|
|
|
) -> Option<String> {
|
2024-09-05 00:34:04 +03:00
|
|
|
if let Some(boxed_ty) = ty.boxed_ty() {
|
2017-12-06 20:27:38 +02:00
|
|
|
// If the type is a box, the field is described from the boxed type
|
2024-09-05 00:34:04 +03:00
|
|
|
self.describe_field_from_ty(boxed_ty, field, variant_index, including_tuple_field)
|
2017-12-06 20:27:38 +02:00
|
|
|
} else {
|
2020-08-03 00:49:11 +02:00
|
|
|
match *ty.kind() {
|
2019-03-28 18:00:17 -07:00
|
|
|
ty::Adt(def, _) => {
|
|
|
|
let variant = if let Some(idx) = variant_index {
|
|
|
|
assert!(def.is_enum());
|
2023-11-21 20:07:32 +01:00
|
|
|
def.variant(idx)
|
2019-03-28 18:00:17 -07:00
|
|
|
} else {
|
|
|
|
def.non_enum_variant()
|
|
|
|
};
|
2022-10-25 20:15:15 +04:00
|
|
|
if !including_tuple_field.0 && variant.ctor_kind() == Some(CtorKind::Fn) {
|
2022-07-23 00:35:35 +03:00
|
|
|
return None;
|
|
|
|
}
|
2023-03-28 23:32:25 -07:00
|
|
|
Some(variant.fields[field].name.to_string())
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2022-07-23 00:35:35 +03:00
|
|
|
ty::Tuple(_) => Some(field.index().to_string()),
|
2024-03-21 17:11:06 -04:00
|
|
|
ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
|
2022-07-23 00:35:35 +03:00
|
|
|
self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2019-03-28 18:00:17 -07:00
|
|
|
ty::Array(ty, _) | ty::Slice(ty) => {
|
2022-07-23 00:35:35 +03:00
|
|
|
self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2023-12-21 01:52:10 +00:00
|
|
|
ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
|
2020-09-26 17:07:00 -04:00
|
|
|
// We won't be borrowck'ing here if the closure came from another crate,
|
|
|
|
// so it's safe to call `expect_local`.
|
|
|
|
//
|
|
|
|
// We know the field exists so it's safe to call operator[] and `unwrap` here.
|
2022-07-12 09:10:22 -05:00
|
|
|
let def_id = def_id.expect_local();
|
2023-02-25 22:51:57 +00:00
|
|
|
let var_id =
|
|
|
|
self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
|
2017-12-06 20:27:38 +02:00
|
|
|
|
2025-02-21 18:33:05 +11:00
|
|
|
Some(self.infcx.tcx.hir_name(var_id).to_string())
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// Might need a revision when the fields in trait RFC is implemented
|
|
|
|
// (https://github.com/rust-lang/rfcs/pull/1546)
|
|
|
|
bug!("End-user description not implemented for field access on `{:?}`", ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-07 14:00:59 +01:00
|
|
|
pub(super) fn borrowed_content_source(
|
|
|
|
&self,
|
2020-03-04 18:25:03 -03:00
|
|
|
deref_base: PlaceRef<'tcx>,
|
2019-07-07 14:00:59 +01:00
|
|
|
) -> BorrowedContentSource<'tcx> {
|
|
|
|
let tcx = self.infcx.tcx;
|
|
|
|
|
|
|
|
// Look up the provided place and work out the move path index for it,
|
|
|
|
// we'll use this to check whether it was originally from an overloaded
|
|
|
|
// operator.
|
2019-07-19 20:53:31 +02:00
|
|
|
match self.move_data.rev_lookup.find(deref_base) {
|
2019-07-07 14:00:59 +01:00
|
|
|
LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
|
|
|
|
debug!("borrowed_content_source: mpi={:?}", mpi);
|
|
|
|
|
|
|
|
for i in &self.move_data.init_path_map[mpi] {
|
|
|
|
let init = &self.move_data.inits[*i];
|
|
|
|
debug!("borrowed_content_source: init={:?}", init);
|
|
|
|
// We're only interested in statements that initialized a value, not the
|
|
|
|
// initializations from arguments.
|
2022-02-19 00:48:49 +01:00
|
|
|
let InitLocation::Statement(loc) = init.location else { continue };
|
2019-07-07 14:00:59 +01:00
|
|
|
|
2019-11-06 12:00:46 -05:00
|
|
|
let bbd = &self.body[loc.block];
|
2019-07-07 14:00:59 +01:00
|
|
|
let is_terminator = bbd.statements.len() == loc.statement_index;
|
|
|
|
debug!(
|
|
|
|
"borrowed_content_source: loc={:?} is_terminator={:?}",
|
|
|
|
loc, is_terminator,
|
|
|
|
);
|
|
|
|
if !is_terminator {
|
|
|
|
continue;
|
|
|
|
} else if let Some(Terminator {
|
2023-06-18 05:24:38 +00:00
|
|
|
kind:
|
|
|
|
TerminatorKind::Call {
|
|
|
|
func,
|
|
|
|
call_source: CallSource::OverloadedOperator,
|
|
|
|
..
|
|
|
|
},
|
2019-07-07 14:00:59 +01:00
|
|
|
..
|
2022-12-02 19:07:57 +00:00
|
|
|
}) = &bbd.terminator
|
2019-10-04 00:55:28 -04:00
|
|
|
{
|
2019-10-28 18:16:25 -04:00
|
|
|
if let Some(source) =
|
2020-04-12 10:28:41 -07:00
|
|
|
BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
|
2019-10-28 18:16:25 -04:00
|
|
|
{
|
2019-07-07 14:00:59 +01:00
|
|
|
return source;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Base is a `static` so won't be from an overloaded operator
|
|
|
|
_ => (),
|
|
|
|
};
|
|
|
|
|
|
|
|
// If we didn't find an overloaded deref or index, then assume it's a
|
|
|
|
// built in deref and check the type of the base.
|
2021-01-09 23:33:38 -06:00
|
|
|
let base_ty = deref_base.ty(self.body, tcx).ty;
|
2025-01-24 14:08:30 +00:00
|
|
|
if base_ty.is_raw_ptr() {
|
2019-07-07 14:00:59 +01:00
|
|
|
BorrowedContentSource::DerefRawPointer
|
2019-07-25 00:57:33 +02:00
|
|
|
} else if base_ty.is_mutable_ptr() {
|
2019-07-07 14:00:59 +01:00
|
|
|
BorrowedContentSource::DerefMutableRef
|
|
|
|
} else {
|
|
|
|
BorrowedContentSource::DerefSharedRef
|
|
|
|
}
|
|
|
|
}
|
2018-09-14 15:44:45 +02:00
|
|
|
|
2018-09-18 21:26:45 +02:00
|
|
|
/// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
|
|
|
|
/// name where required.
|
2019-05-04 08:40:07 +01:00
|
|
|
pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
|
2022-02-18 16:15:29 -05:00
|
|
|
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
2019-01-11 13:07:01 +02:00
|
|
|
|
2018-09-14 15:44:45 +02:00
|
|
|
// We need to add synthesized lifetimes where appropriate. We do
|
|
|
|
// this by hooking into the pretty printer and telling it to label the
|
|
|
|
// lifetimes without names with the value `'0`.
|
2022-01-28 11:25:15 +11:00
|
|
|
if let ty::Ref(region, ..) = ty.kind() {
|
|
|
|
match **region {
|
2023-11-13 14:00:05 +00:00
|
|
|
ty::ReBound(_, ty::BoundRegion { kind: br, .. })
|
2023-04-06 21:12:17 -04:00
|
|
|
| ty::RePlaceholder(ty::PlaceholderRegion {
|
|
|
|
bound: ty::BoundRegion { kind: br, .. },
|
|
|
|
..
|
|
|
|
}) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
|
2022-01-28 11:25:15 +11:00
|
|
|
_ => {}
|
|
|
|
}
|
2018-09-14 15:44:45 +02:00
|
|
|
}
|
2019-01-11 13:07:01 +02:00
|
|
|
|
2023-10-17 19:46:14 +02:00
|
|
|
ty.print(&mut printer).unwrap();
|
|
|
|
printer.into_buffer()
|
2018-09-14 15:44:45 +02:00
|
|
|
}
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Returns the name of the provided `Ty` (that must be a reference)'s region with a
|
2018-09-18 21:26:45 +02:00
|
|
|
/// synthesized lifetime name where required.
|
2019-05-04 08:40:07 +01:00
|
|
|
pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
|
2022-02-18 16:15:29 -05:00
|
|
|
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
2019-01-11 13:07:01 +02:00
|
|
|
|
2022-01-28 11:25:15 +11:00
|
|
|
let region = if let ty::Ref(region, ..) = ty.kind() {
|
|
|
|
match **region {
|
2023-11-13 14:00:05 +00:00
|
|
|
ty::ReBound(_, ty::BoundRegion { kind: br, .. })
|
2023-04-06 21:12:17 -04:00
|
|
|
| ty::RePlaceholder(ty::PlaceholderRegion {
|
|
|
|
bound: ty::BoundRegion { kind: br, .. },
|
|
|
|
..
|
|
|
|
}) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
|
2022-01-28 11:25:15 +11:00
|
|
|
_ => {}
|
2019-01-11 13:07:01 +02:00
|
|
|
}
|
2022-01-28 11:25:15 +11:00
|
|
|
region
|
|
|
|
} else {
|
|
|
|
bug!("ty for annotation of borrow region is not a reference");
|
2019-01-11 13:07:01 +02:00
|
|
|
};
|
|
|
|
|
2023-10-17 19:46:14 +02:00
|
|
|
region.print(&mut printer).unwrap();
|
|
|
|
printer.into_buffer()
|
2018-09-14 15:44:45 +02:00
|
|
|
}
|
2024-12-12 01:20:26 -08:00
|
|
|
|
|
|
|
/// Add a note to region errors and borrow explanations when higher-ranked regions in predicates
|
|
|
|
/// implicitly introduce an "outlives `'static`" constraint.
|
2025-01-06 03:25:45 +00:00
|
|
|
fn add_placeholder_from_predicate_note<G: EmissionGuarantee>(
|
2024-12-12 01:20:26 -08:00
|
|
|
&self,
|
2025-01-06 03:25:45 +00:00
|
|
|
err: &mut Diag<'_, G>,
|
2024-12-12 01:20:26 -08:00
|
|
|
path: &[OutlivesConstraint<'tcx>],
|
|
|
|
) {
|
|
|
|
let predicate_span = path.iter().find_map(|constraint| {
|
|
|
|
let outlived = constraint.sub;
|
|
|
|
if let Some(origin) = self.regioncx.var_infos.get(outlived)
|
|
|
|
&& let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(_)) =
|
|
|
|
origin.origin
|
|
|
|
&& let ConstraintCategory::Predicate(span) = constraint.category
|
|
|
|
{
|
|
|
|
Some(span)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(span) = predicate_span {
|
|
|
|
err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
|
|
|
|
}
|
|
|
|
}
|
2024-12-20 21:14:16 -08:00
|
|
|
|
|
|
|
/// Add a label to region errors and borrow explanations when outlives constraints arise from
|
|
|
|
/// proving a type implements `Sized` or `Copy`.
|
2025-01-06 03:25:45 +00:00
|
|
|
fn add_sized_or_copy_bound_info<G: EmissionGuarantee>(
|
2024-12-20 21:14:16 -08:00
|
|
|
&self,
|
2025-01-06 03:25:45 +00:00
|
|
|
err: &mut Diag<'_, G>,
|
2024-12-20 21:14:16 -08:00
|
|
|
blamed_category: ConstraintCategory<'tcx>,
|
|
|
|
path: &[OutlivesConstraint<'tcx>],
|
|
|
|
) {
|
|
|
|
for sought_category in [ConstraintCategory::SizedBound, ConstraintCategory::CopyBound] {
|
|
|
|
if sought_category != blamed_category
|
|
|
|
&& let Some(sought_constraint) = path.iter().find(|c| c.category == sought_category)
|
|
|
|
{
|
|
|
|
let label = format!(
|
|
|
|
"requirement occurs due to {}",
|
|
|
|
sought_category.description().trim_end()
|
|
|
|
);
|
|
|
|
err.span_label(sought_constraint.span, label);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-06 20:27:38 +02:00
|
|
|
}
|
2018-08-01 20:38:02 +01:00
|
|
|
|
2020-06-11 13:48:46 -04:00
|
|
|
/// The span(s) associated to a use of a place.
|
2018-08-01 20:38:02 +01:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
2020-07-25 07:04:13 -04:00
|
|
|
pub(super) enum UseSpans<'tcx> {
|
2020-06-11 13:48:46 -04:00
|
|
|
/// The access is caused by capturing a variable for a closure.
|
2018-08-01 20:38:02 +01:00
|
|
|
ClosureUse {
|
2023-10-19 21:46:28 +00:00
|
|
|
/// This is true if the captured variable was from a coroutine.
|
2023-12-22 21:29:12 +00:00
|
|
|
closure_kind: hir::ClosureKind,
|
2020-06-11 13:48:46 -04:00
|
|
|
/// The span of the args of the closure, including the `move` keyword if
|
|
|
|
/// it's present.
|
2018-08-01 20:38:02 +01:00
|
|
|
args_span: Span,
|
2021-03-17 02:51:27 -04:00
|
|
|
/// The span of the use resulting in capture kind
|
|
|
|
/// Check `ty::CaptureInfo` for more details
|
|
|
|
capture_kind_span: Span,
|
|
|
|
/// The span of the use resulting in the captured path
|
|
|
|
/// Check `ty::CaptureInfo` for more details
|
|
|
|
path_span: Span,
|
2020-06-11 13:48:46 -04:00
|
|
|
},
|
|
|
|
/// The access is caused by using a variable as the receiver of a method
|
|
|
|
/// that takes 'self'
|
|
|
|
FnSelfUse {
|
|
|
|
/// The span of the variable being moved
|
2018-08-30 15:06:27 -03:00
|
|
|
var_span: Span,
|
2020-06-11 13:48:46 -04:00
|
|
|
/// The span of the method call on the variable
|
|
|
|
fn_call_span: Span,
|
|
|
|
/// The definition span of the method being called
|
|
|
|
fn_span: Span,
|
2021-12-09 22:42:17 +08:00
|
|
|
kind: CallKind<'tcx>,
|
2018-08-01 20:38:02 +01:00
|
|
|
},
|
2020-06-19 22:45:09 -07:00
|
|
|
/// This access is caused by a `match` or `if let` pattern.
|
|
|
|
PatUse(Span),
|
|
|
|
/// This access has a single span associated to it: common case.
|
2018-08-01 20:38:02 +01:00
|
|
|
OtherUse(Span),
|
|
|
|
}
|
|
|
|
|
2020-07-25 07:04:13 -04:00
|
|
|
impl UseSpans<'_> {
|
2018-08-01 20:38:02 +01:00
|
|
|
pub(super) fn args_or_use(self) -> Span {
|
|
|
|
match self {
|
2020-06-19 22:45:09 -07:00
|
|
|
UseSpans::ClosureUse { args_span: span, .. }
|
|
|
|
| UseSpans::PatUse(span)
|
|
|
|
| UseSpans::OtherUse(span) => span,
|
2020-07-25 07:04:13 -04:00
|
|
|
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
2018-08-01 20:38:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-28 21:53:59 -04:00
|
|
|
/// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`
|
2021-03-17 02:51:27 -04:00
|
|
|
pub(super) fn var_or_use_path_span(self) -> Span {
|
|
|
|
match self {
|
|
|
|
UseSpans::ClosureUse { path_span: span, .. }
|
|
|
|
| UseSpans::PatUse(span)
|
|
|
|
| UseSpans::OtherUse(span) => span,
|
|
|
|
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-28 21:53:59 -04:00
|
|
|
/// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`
|
2018-08-01 20:38:02 +01:00
|
|
|
pub(super) fn var_or_use(self) -> Span {
|
|
|
|
match self {
|
2021-03-17 02:51:27 -04:00
|
|
|
UseSpans::ClosureUse { capture_kind_span: span, .. }
|
2020-06-19 22:45:09 -07:00
|
|
|
| UseSpans::PatUse(span)
|
|
|
|
| UseSpans::OtherUse(span) => span,
|
2020-07-25 07:04:13 -04:00
|
|
|
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
2018-08-01 20:38:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-22 21:29:12 +00:00
|
|
|
// FIXME(coroutines): Make this just return the `ClosureKind` directly?
|
2023-10-19 21:46:28 +00:00
|
|
|
pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
|
2019-10-10 22:20:57 +08:00
|
|
|
match self {
|
2023-12-22 21:29:12 +00:00
|
|
|
UseSpans::ClosureUse {
|
2023-12-25 16:56:12 +00:00
|
|
|
closure_kind: hir::ClosureKind::Coroutine(coroutine_kind),
|
2023-12-22 21:29:12 +00:00
|
|
|
..
|
|
|
|
} => Some(coroutine_kind),
|
2019-10-10 22:20:57 +08:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// Add a span label to the arguments of the closure, if it exists.
|
2024-02-29 08:53:46 +11:00
|
|
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
2024-06-18 11:10:18 +00:00
|
|
|
pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
|
2018-08-01 20:38:02 +01:00
|
|
|
if let UseSpans::ClosureUse { args_span, .. } = self {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(f(args_span));
|
2018-08-01 20:38:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-04 17:09:14 +08:00
|
|
|
/// Add a span label to the use of the captured variable, if it exists.
|
|
|
|
/// only adds label to the `path_span`
|
2024-02-29 08:53:46 +11:00
|
|
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
2022-11-04 17:09:14 +08:00
|
|
|
pub(super) fn var_path_only_subdiag(
|
|
|
|
self,
|
2024-02-23 10:20:45 +11:00
|
|
|
err: &mut Diag<'_>,
|
2022-11-04 17:09:14 +08:00
|
|
|
action: crate::InitializationRequiringAction,
|
|
|
|
) {
|
2023-02-10 16:58:32 +08:00
|
|
|
use CaptureVarPathUseCause::*;
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2022-11-04 17:09:14 +08:00
|
|
|
use crate::InitializationRequiringAction::*;
|
2023-12-22 21:29:12 +00:00
|
|
|
if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
|
|
|
|
match closure_kind {
|
2023-12-25 16:56:12 +00:00
|
|
|
hir::ClosureKind::Coroutine(_) => {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(match action {
|
|
|
|
Borrow => BorrowInCoroutine { path_span },
|
|
|
|
MatchOn | Use => UseInCoroutine { path_span },
|
|
|
|
Assignment => AssignInCoroutine { path_span },
|
|
|
|
PartialAssignment => AssignPartInCoroutine { path_span },
|
|
|
|
});
|
2022-11-04 17:09:14 +08:00
|
|
|
}
|
2024-01-24 17:30:02 +00:00
|
|
|
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(match action {
|
|
|
|
Borrow => BorrowInClosure { path_span },
|
|
|
|
MatchOn | Use => UseInClosure { path_span },
|
|
|
|
Assignment => AssignInClosure { path_span },
|
|
|
|
PartialAssignment => AssignPartInClosure { path_span },
|
|
|
|
});
|
2022-11-04 17:09:14 +08:00
|
|
|
}
|
|
|
|
}
|
2021-03-17 02:51:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-26 10:42:05 +08:00
|
|
|
/// Add a subdiagnostic to the use of the captured variable, if it exists.
|
2024-02-29 08:53:46 +11:00
|
|
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
2022-10-26 10:42:05 +08:00
|
|
|
pub(super) fn var_subdiag(
|
|
|
|
self,
|
2024-02-23 10:20:45 +11:00
|
|
|
err: &mut Diag<'_>,
|
2022-11-09 20:56:28 +08:00
|
|
|
kind: Option<rustc_middle::mir::BorrowKind>,
|
2023-12-22 21:29:12 +00:00
|
|
|
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
2022-10-26 10:42:05 +08:00
|
|
|
) {
|
2023-12-22 21:29:12 +00:00
|
|
|
if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
|
2022-11-09 20:56:28 +08:00
|
|
|
if capture_kind_span != path_span {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(match kind {
|
|
|
|
Some(kd) => match kd {
|
|
|
|
rustc_middle::mir::BorrowKind::Shared
|
|
|
|
| rustc_middle::mir::BorrowKind::Fake(_) => {
|
|
|
|
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
|
|
|
}
|
2022-11-09 20:56:28 +08:00
|
|
|
|
2024-06-18 11:10:18 +00:00
|
|
|
rustc_middle::mir::BorrowKind::Mut { .. } => {
|
|
|
|
CaptureVarKind::Mut { kind_span: capture_kind_span }
|
|
|
|
}
|
2022-11-09 20:56:28 +08:00
|
|
|
},
|
2024-06-18 11:10:18 +00:00
|
|
|
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
|
|
|
});
|
2022-11-09 20:56:28 +08:00
|
|
|
};
|
2023-12-22 21:29:12 +00:00
|
|
|
let diag = f(closure_kind, path_span);
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(diag);
|
2022-10-26 10:42:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Returns `false` if this place is not used in a closure.
|
2019-05-04 08:40:07 +01:00
|
|
|
pub(super) fn for_closure(&self) -> bool {
|
2018-10-10 21:56:17 +02:00
|
|
|
match *self {
|
2023-12-22 21:29:12 +00:00
|
|
|
UseSpans::ClosureUse { closure_kind, .. } => {
|
|
|
|
matches!(closure_kind, hir::ClosureKind::Closure)
|
|
|
|
}
|
2018-10-10 21:56:17 +02:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
/// Returns `false` if this place is not used in a coroutine.
|
|
|
|
pub(super) fn for_coroutine(&self) -> bool {
|
2018-10-10 21:56:17 +02:00
|
|
|
match *self {
|
2023-12-22 21:29:12 +00:00
|
|
|
// FIXME(coroutines): Do we want this to apply to synthetic coroutines?
|
|
|
|
UseSpans::ClosureUse { closure_kind, .. } => {
|
|
|
|
matches!(closure_kind, hir::ClosureKind::Coroutine(..))
|
|
|
|
}
|
2018-10-10 21:56:17 +02:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-01 20:38:02 +01:00
|
|
|
pub(super) fn or_else<F>(self, if_other: F) -> Self
|
|
|
|
where
|
|
|
|
F: FnOnce() -> Self,
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
closure @ UseSpans::ClosureUse { .. } => closure,
|
2020-06-19 22:45:09 -07:00
|
|
|
UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
|
2020-06-11 13:48:46 -04:00
|
|
|
fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
|
2018-08-01 20:38:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-07 14:00:59 +01:00
|
|
|
pub(super) enum BorrowedContentSource<'tcx> {
|
|
|
|
DerefRawPointer,
|
|
|
|
DerefMutableRef,
|
|
|
|
DerefSharedRef,
|
|
|
|
OverloadedDeref(Ty<'tcx>),
|
|
|
|
OverloadedIndex(Ty<'tcx>),
|
|
|
|
}
|
|
|
|
|
2021-12-15 08:38:12 +01:00
|
|
|
impl<'tcx> BorrowedContentSource<'tcx> {
|
2020-04-08 04:26:48 +03:00
|
|
|
pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
|
2019-07-07 14:00:59 +01:00
|
|
|
match *self {
|
2020-02-29 00:35:24 +01:00
|
|
|
BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
|
|
|
|
BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
|
|
|
|
BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
|
2021-11-16 13:12:38 -06:00
|
|
|
BorrowedContentSource::OverloadedDeref(ty) => ty
|
|
|
|
.ty_adt_def()
|
2022-03-05 07:28:41 +11:00
|
|
|
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
|
2023-01-06 19:34:45 -05:00
|
|
|
name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
|
2021-11-16 13:12:38 -06:00
|
|
|
_ => None,
|
|
|
|
})
|
2023-01-06 19:34:45 -05:00
|
|
|
.unwrap_or_else(|| format!("dereference of `{ty}`")),
|
|
|
|
BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"),
|
2019-07-07 14:00:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
|
|
|
|
match *self {
|
|
|
|
BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
|
|
|
|
BorrowedContentSource::DerefSharedRef => Some("shared reference"),
|
|
|
|
BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
|
|
|
|
// Overloaded deref and index operators should be evaluated into a
|
|
|
|
// temporary. So we don't need a description here.
|
|
|
|
BorrowedContentSource::OverloadedDeref(_)
|
|
|
|
| BorrowedContentSource::OverloadedIndex(_) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-08 04:26:48 +03:00
|
|
|
pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
|
2019-07-07 14:16:58 +01:00
|
|
|
match *self {
|
2020-02-29 00:35:24 +01:00
|
|
|
BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),
|
|
|
|
BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),
|
2019-07-07 14:16:58 +01:00
|
|
|
BorrowedContentSource::DerefMutableRef => {
|
|
|
|
bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
|
|
|
|
}
|
2021-11-16 13:12:38 -06:00
|
|
|
BorrowedContentSource::OverloadedDeref(ty) => ty
|
|
|
|
.ty_adt_def()
|
2022-03-05 07:28:41 +11:00
|
|
|
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
|
2023-01-06 19:34:45 -05:00
|
|
|
name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
|
2021-11-16 13:12:38 -06:00
|
|
|
_ => None,
|
|
|
|
})
|
2023-01-06 19:34:45 -05:00
|
|
|
.unwrap_or_else(|| format!("dereference of `{ty}`")),
|
|
|
|
BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"),
|
2019-07-07 14:16:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-07 14:00:59 +01:00
|
|
|
fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
|
2020-08-03 00:49:11 +02:00
|
|
|
match *func.kind() {
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::FnDef(def_id, args) => {
|
2019-07-07 14:00:59 +01:00
|
|
|
let trait_id = tcx.trait_of_item(def_id)?;
|
|
|
|
|
2024-06-14 14:46:32 -04:00
|
|
|
if tcx.is_lang_item(trait_id, LangItem::Deref)
|
|
|
|
|| tcx.is_lang_item(trait_id, LangItem::DerefMut)
|
2019-07-07 14:00:59 +01:00
|
|
|
{
|
2023-07-11 22:35:29 +01:00
|
|
|
Some(BorrowedContentSource::OverloadedDeref(args.type_at(0)))
|
2024-06-14 14:46:32 -04:00
|
|
|
} else if tcx.is_lang_item(trait_id, LangItem::Index)
|
|
|
|
|| tcx.is_lang_item(trait_id, LangItem::IndexMut)
|
2019-07-07 14:00:59 +01:00
|
|
|
{
|
2023-07-11 22:35:29 +01:00
|
|
|
Some(BorrowedContentSource::OverloadedIndex(args.type_at(0)))
|
2019-07-07 14:00:59 +01:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-04 10:24:34 +10:00
|
|
|
/// Helper struct for `explain_captures`.
|
2023-02-10 16:58:32 +08:00
|
|
|
struct CapturedMessageOpt {
|
|
|
|
is_partial_move: bool,
|
|
|
|
is_loop_message: bool,
|
|
|
|
is_move_msg: bool,
|
|
|
|
is_loop_move: bool,
|
2024-07-10 20:27:38 +08:00
|
|
|
has_suggest_reborrow: bool,
|
2023-02-10 16:58:32 +08:00
|
|
|
maybe_reinitialized_locations_is_empty: bool,
|
|
|
|
}
|
|
|
|
|
2024-09-06 09:18:17 +10:00
|
|
|
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
2018-08-01 20:38:02 +01:00
|
|
|
/// Finds the spans associated to a move or copy of move_place at location.
|
|
|
|
pub(super) fn move_spans(
|
|
|
|
&self,
|
2020-03-04 18:25:03 -03:00
|
|
|
moved_place: PlaceRef<'tcx>, // Could also be an upvar.
|
2018-08-01 20:38:02 +01:00
|
|
|
location: Location,
|
2020-07-25 07:04:13 -04:00
|
|
|
) -> UseSpans<'tcx> {
|
2018-08-01 20:38:02 +01:00
|
|
|
use self::UseSpans::*;
|
|
|
|
|
2022-02-19 00:48:49 +01:00
|
|
|
let Some(stmt) = self.body[location.block].statements.get(location.statement_index) else {
|
|
|
|
return OtherUse(self.body.source_info(location).span);
|
2018-08-01 20:38:02 +01:00
|
|
|
};
|
|
|
|
|
2018-10-10 21:56:17 +02:00
|
|
|
debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
|
2022-12-02 19:07:57 +00:00
|
|
|
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
|
2023-12-21 01:52:10 +00:00
|
|
|
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind
|
2022-12-02 19:07:57 +00:00
|
|
|
{
|
|
|
|
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
|
2023-01-23 22:15:33 +00:00
|
|
|
let def_id = def_id.expect_local();
|
2023-12-22 21:29:12 +00:00
|
|
|
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
2022-12-02 19:07:57 +00:00
|
|
|
self.closure_span(def_id, moved_place, places)
|
|
|
|
{
|
2023-12-22 21:29:12 +00:00
|
|
|
return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
|
2021-03-25 23:03:12 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// StatementKind::FakeRead only contains a def_id if they are introduced as a result
|
|
|
|
// of pattern matching within a closure.
|
2022-12-02 19:07:57 +00:00
|
|
|
if let StatementKind::FakeRead(box (cause, place)) = stmt.kind {
|
2021-03-25 23:03:12 -04:00
|
|
|
match cause {
|
|
|
|
FakeReadCause::ForMatchedPlace(Some(closure_def_id))
|
|
|
|
| FakeReadCause::ForLet(Some(closure_def_id)) => {
|
|
|
|
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
|
2022-12-02 19:07:57 +00:00
|
|
|
let places = &[Operand::Move(place)];
|
2023-12-22 21:29:12 +00:00
|
|
|
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
2023-04-01 20:11:38 -07:00
|
|
|
self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
|
2021-03-25 23:03:12 -04:00
|
|
|
{
|
2021-03-17 02:51:27 -04:00
|
|
|
return ClosureUse {
|
2023-12-22 21:29:12 +00:00
|
|
|
closure_kind,
|
2021-03-17 02:51:27 -04:00
|
|
|
args_span,
|
|
|
|
capture_kind_span,
|
|
|
|
path_span,
|
|
|
|
};
|
2020-06-11 13:48:46 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let normal_ret =
|
|
|
|
if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
|
|
|
|
PatUse(stmt.source_info.span)
|
|
|
|
} else {
|
|
|
|
OtherUse(stmt.source_info.span)
|
2020-06-21 16:28:19 -04:00
|
|
|
};
|
2020-06-11 13:48:46 -04:00
|
|
|
|
2020-06-11 13:48:46 -04:00
|
|
|
// We are trying to find MIR of the form:
|
|
|
|
// ```
|
|
|
|
// _temp = _moved_val;
|
|
|
|
// ...
|
|
|
|
// FnSelfCall(_temp, ...)
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// where `_moved_val` is the place we generated the move error for,
|
|
|
|
// `_temp` is some other local, and `FnSelfCall` is a function
|
|
|
|
// that has a `self` parameter.
|
|
|
|
|
|
|
|
let target_temp = match stmt.kind {
|
|
|
|
StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
|
|
|
|
temp.as_local().unwrap()
|
2020-06-11 13:48:46 -04:00
|
|
|
}
|
2020-06-11 13:48:46 -04:00
|
|
|
_ => return normal_ret,
|
|
|
|
};
|
2020-06-21 16:28:19 -04:00
|
|
|
|
2020-06-11 13:48:46 -04:00
|
|
|
debug!("move_spans: target_temp = {:?}", target_temp);
|
|
|
|
|
|
|
|
if let Some(Terminator {
|
2023-06-18 05:24:38 +00:00
|
|
|
kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
|
2020-06-11 13:48:46 -04:00
|
|
|
}) = &self.body[location.block].terminator
|
|
|
|
{
|
2025-01-31 09:55:55 +11:00
|
|
|
let Some((method_did, method_args)) =
|
|
|
|
find_self_call(self.infcx.tcx, self.body, target_temp, location.block)
|
|
|
|
else {
|
2020-08-10 07:16:30 -04:00
|
|
|
return normal_ret;
|
|
|
|
};
|
2020-06-11 13:48:46 -04:00
|
|
|
|
2021-12-09 22:42:17 +08:00
|
|
|
let kind = call_kind(
|
|
|
|
self.infcx.tcx,
|
2024-11-01 13:51:00 +11:00
|
|
|
self.infcx.typing_env(self.infcx.param_env),
|
2021-12-09 22:42:17 +08:00
|
|
|
method_did,
|
2023-07-11 22:35:29 +01:00
|
|
|
method_args,
|
2021-12-09 22:42:17 +08:00
|
|
|
*fn_span,
|
2023-06-18 05:24:38 +00:00
|
|
|
call_source.from_hir_call(),
|
2021-12-09 22:42:17 +08:00
|
|
|
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
|
2020-07-25 07:04:13 -04:00
|
|
|
);
|
|
|
|
|
2020-08-10 07:16:30 -04:00
|
|
|
return FnSelfUse {
|
|
|
|
var_span: stmt.source_info.span,
|
2021-12-09 22:42:17 +08:00
|
|
|
fn_call_span: *fn_span,
|
2022-07-04 17:23:24 +09:00
|
|
|
fn_span: self.infcx.tcx.def_span(method_did),
|
2020-08-10 07:16:30 -04:00
|
|
|
kind,
|
|
|
|
};
|
2020-06-19 22:45:09 -07:00
|
|
|
}
|
2025-01-06 03:25:45 +00:00
|
|
|
|
2020-08-08 00:39:38 +02:00
|
|
|
normal_ret
|
2018-08-01 20:38:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Finds the span of arguments of a closure (within `maybe_closure_span`)
|
|
|
|
/// and its usage of the local assigned at `location`.
|
|
|
|
/// This is done by searching in statements succeeding `location`
|
|
|
|
/// and originating from `maybe_closure_span`.
|
2020-07-25 07:04:13 -04:00
|
|
|
pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
|
2018-08-01 20:38:02 +01:00
|
|
|
use self::UseSpans::*;
|
2018-10-10 21:56:17 +02:00
|
|
|
debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
|
2018-08-01 20:38:02 +01:00
|
|
|
|
2019-11-06 12:00:46 -05:00
|
|
|
let target = match self.body[location.block].statements.get(location.statement_index) {
|
2022-12-02 19:07:57 +00:00
|
|
|
Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => {
|
2019-10-20 16:09:36 -04:00
|
|
|
if let Some(local) = place.as_local() {
|
|
|
|
local
|
|
|
|
} else {
|
|
|
|
return OtherUse(use_span);
|
|
|
|
}
|
|
|
|
}
|
2018-08-01 20:38:02 +01:00
|
|
|
_ => return OtherUse(use_span),
|
|
|
|
};
|
|
|
|
|
2019-11-06 12:00:46 -05:00
|
|
|
if self.body.local_kind(target) != LocalKind::Temp {
|
2018-08-01 20:38:02 +01:00
|
|
|
// operands are always temporaries.
|
|
|
|
return OtherUse(use_span);
|
|
|
|
}
|
|
|
|
|
2023-02-08 22:29:52 +01:00
|
|
|
// drop and replace might have moved the assignment to the next block
|
|
|
|
let maybe_additional_statement =
|
|
|
|
if let TerminatorKind::Drop { target: drop_target, .. } =
|
|
|
|
self.body[location.block].terminator().kind
|
|
|
|
{
|
|
|
|
self.body[drop_target].statements.first()
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
let statements =
|
|
|
|
self.body[location.block].statements[location.statement_index + 1..].iter();
|
|
|
|
|
|
|
|
for stmt in statements.chain(maybe_additional_statement) {
|
2022-12-02 19:07:57 +00:00
|
|
|
if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
|
2023-10-19 21:46:28 +00:00
|
|
|
let (&def_id, is_coroutine) = match kind {
|
2018-10-10 21:56:17 +02:00
|
|
|
box AggregateKind::Closure(def_id, _) => (def_id, false),
|
2023-12-21 01:52:10 +00:00
|
|
|
box AggregateKind::Coroutine(def_id, _) => (def_id, true),
|
2018-10-10 21:56:17 +02:00
|
|
|
_ => continue,
|
|
|
|
};
|
2023-01-23 22:15:33 +00:00
|
|
|
let def_id = def_id.expect_local();
|
2018-08-01 20:38:02 +01:00
|
|
|
|
2018-10-10 21:56:17 +02:00
|
|
|
debug!(
|
2023-10-19 21:46:28 +00:00
|
|
|
"borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
|
|
|
|
def_id, is_coroutine, places
|
2018-10-10 21:56:17 +02:00
|
|
|
);
|
2023-12-22 21:29:12 +00:00
|
|
|
if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
|
2022-07-12 09:10:22 -05:00
|
|
|
self.closure_span(def_id, Place::from(target).as_ref(), places)
|
2018-10-10 21:56:17 +02:00
|
|
|
{
|
2023-12-22 21:29:12 +00:00
|
|
|
return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
|
2018-10-10 21:56:17 +02:00
|
|
|
} else {
|
|
|
|
return OtherUse(use_span);
|
2018-08-01 20:38:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if use_span != stmt.source_info.span {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
OtherUse(use_span)
|
|
|
|
}
|
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
/// Finds the spans of a captured place within a closure or coroutine.
|
2021-03-17 02:51:27 -04:00
|
|
|
/// The first span is the location of the use resulting in the capture kind of the capture
|
|
|
|
/// The second span is the location the use resulting in the captured path of the capture
|
2018-10-10 21:56:17 +02:00
|
|
|
fn closure_span(
|
|
|
|
&self,
|
2022-07-12 09:10:22 -05:00
|
|
|
def_id: LocalDefId,
|
2020-03-04 18:25:03 -03:00
|
|
|
target_place: PlaceRef<'tcx>,
|
2023-04-01 20:11:38 -07:00
|
|
|
places: &IndexSlice<FieldIdx, Operand<'tcx>>,
|
2023-12-22 21:29:12 +00:00
|
|
|
) -> Option<(Span, hir::ClosureKind, Span, Span)> {
|
2018-10-10 21:56:17 +02:00
|
|
|
debug!(
|
|
|
|
"closure_span: def_id={:?} target_place={:?} places={:?}",
|
|
|
|
def_id, target_place, places
|
|
|
|
);
|
2023-11-24 19:28:19 +03:00
|
|
|
let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
|
2025-02-21 18:33:05 +11:00
|
|
|
let expr = &self.infcx.tcx.hir_expect_expr(hir_id).kind;
|
2019-03-04 09:00:30 +01:00
|
|
|
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
|
2025-02-20 18:28:48 +00:00
|
|
|
if let &hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr {
|
2022-07-12 09:10:22 -05:00
|
|
|
for (captured_place, place) in
|
2023-02-25 22:51:57 +00:00
|
|
|
self.infcx.tcx.closure_captures(def_id).iter().zip(places)
|
2021-03-17 02:51:27 -04:00
|
|
|
{
|
2019-05-04 03:47:16 +03:00
|
|
|
match place {
|
|
|
|
Operand::Copy(place) | Operand::Move(place)
|
2019-07-21 22:38:30 +02:00
|
|
|
if target_place == place.as_ref() =>
|
|
|
|
{
|
2019-05-04 03:47:16 +03:00
|
|
|
debug!("closure_span: found captured local {:?}", place);
|
2021-03-17 02:51:27 -04:00
|
|
|
return Some((
|
2022-07-11 23:39:53 +04:00
|
|
|
fn_decl_span,
|
2023-12-22 21:29:12 +00:00
|
|
|
kind,
|
2021-03-17 02:51:27 -04:00
|
|
|
captured_place.get_capture_kind_span(self.infcx.tcx),
|
|
|
|
captured_place.get_path_span(self.infcx.tcx),
|
|
|
|
));
|
2019-05-04 03:47:16 +03:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2018-10-10 21:56:17 +02:00
|
|
|
}
|
2019-05-04 03:47:16 +03:00
|
|
|
None
|
2018-10-10 21:56:17 +02:00
|
|
|
}
|
|
|
|
|
2018-08-01 20:38:02 +01:00
|
|
|
/// Helper to retrieve span(s) of given borrow from the current MIR
|
|
|
|
/// representation
|
2020-07-25 07:04:13 -04:00
|
|
|
pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
|
2019-11-06 12:00:46 -05:00
|
|
|
let span = self.body.source_info(borrow.reserve_location).span;
|
2018-08-01 20:38:02 +01:00
|
|
|
self.borrow_spans(span, borrow.reserve_location)
|
|
|
|
}
|
2022-03-02 04:30:16 +00:00
|
|
|
|
2024-02-29 08:53:46 +11:00
|
|
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
2024-02-20 14:12:50 +11:00
|
|
|
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
2022-03-02 04:30:16 +00:00
|
|
|
fn explain_captures(
|
|
|
|
&mut self,
|
2024-07-10 20:27:38 +08:00
|
|
|
err: &mut Diag<'infcx>,
|
2022-03-02 04:30:16 +00:00
|
|
|
span: Span,
|
|
|
|
move_span: Span,
|
|
|
|
move_spans: UseSpans<'tcx>,
|
|
|
|
moved_place: Place<'tcx>,
|
2023-02-10 16:58:32 +08:00
|
|
|
msg_opt: CapturedMessageOpt,
|
2022-03-02 04:30:16 +00:00
|
|
|
) {
|
2023-02-10 16:58:32 +08:00
|
|
|
let CapturedMessageOpt {
|
|
|
|
is_partial_move: is_partial,
|
|
|
|
is_loop_message,
|
|
|
|
is_move_msg,
|
|
|
|
is_loop_move,
|
2024-07-10 20:27:38 +08:00
|
|
|
has_suggest_reborrow,
|
2023-02-10 16:58:32 +08:00
|
|
|
maybe_reinitialized_locations_is_empty,
|
|
|
|
} = msg_opt;
|
2022-03-02 04:30:16 +00:00
|
|
|
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
|
|
|
|
let place_name = self
|
|
|
|
.describe_place(moved_place.as_ref())
|
2023-01-06 19:34:45 -05:00
|
|
|
.map(|n| format!("`{n}`"))
|
2022-03-02 04:30:16 +00:00
|
|
|
.unwrap_or_else(|| "value".to_owned());
|
|
|
|
match kind {
|
2024-03-15 18:08:12 +00:00
|
|
|
CallKind::FnCall { fn_trait_id, self_ty }
|
2024-06-14 14:46:32 -04:00
|
|
|
if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) =>
|
2022-03-02 04:30:16 +00:00
|
|
|
{
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonLabel::Call {
|
|
|
|
fn_call_span,
|
|
|
|
place_name: &place_name,
|
|
|
|
is_partial,
|
|
|
|
is_loop_message,
|
|
|
|
});
|
2024-04-12 20:57:07 +00:00
|
|
|
// Check if the move occurs on a value because of a call on a closure that comes
|
|
|
|
// from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`:
|
|
|
|
// ```
|
|
|
|
// error[E0382]: use of moved value: `blk`
|
|
|
|
// --> $DIR/once-cant-call-twice-on-heap.rs:8:5
|
|
|
|
// |
|
|
|
|
// LL | fn foo<F:FnOnce()>(blk: F) {
|
|
|
|
// | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
|
|
|
|
// LL | blk();
|
|
|
|
// | ----- `blk` moved due to this call
|
|
|
|
// LL | blk();
|
|
|
|
// | ^^^ value used here after move
|
|
|
|
// |
|
|
|
|
// note: `FnOnce` closures can only be called once
|
|
|
|
// --> $DIR/once-cant-call-twice-on-heap.rs:6:10
|
|
|
|
// |
|
|
|
|
// LL | fn foo<F:FnOnce()>(blk: F) {
|
|
|
|
// | ^^^^^^^^ `F` is made to be an `FnOnce` closure here
|
|
|
|
// LL | blk();
|
|
|
|
// | ----- this value implements `FnOnce`, which causes it to be moved when called
|
|
|
|
// ```
|
2024-04-19 21:09:51 -04:00
|
|
|
if let ty::Param(param_ty) = *self_ty.kind()
|
2024-03-15 18:08:12 +00:00
|
|
|
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
|
|
|
|
&& let param = generics.type_param(param_ty, self.infcx.tcx)
|
|
|
|
&& let Some(hir_generics) = self
|
|
|
|
.infcx
|
|
|
|
.tcx
|
|
|
|
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
|
|
|
.as_local()
|
2025-02-03 10:45:49 +11:00
|
|
|
.and_then(|def_id| self.infcx.tcx.hir_get_generics(def_id))
|
2024-03-15 18:08:12 +00:00
|
|
|
&& let spans = hir_generics
|
|
|
|
.predicates
|
|
|
|
.iter()
|
2024-11-25 16:38:35 +08:00
|
|
|
.filter_map(|pred| match pred.kind {
|
|
|
|
hir::WherePredicateKind::BoundPredicate(pred) => Some(pred),
|
2024-03-15 18:08:12 +00:00
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.filter(|pred| {
|
|
|
|
if let Some((id, _)) = pred.bounded_ty.as_generic_param() {
|
|
|
|
id == param.def_id
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.flat_map(|pred| pred.bounds)
|
|
|
|
.filter_map(|bound| {
|
|
|
|
if let Some(trait_ref) = bound.trait_ref()
|
|
|
|
&& let Some(trait_def_id) = trait_ref.trait_def_id()
|
|
|
|
&& trait_def_id == fn_trait_id
|
|
|
|
{
|
|
|
|
Some(bound.span())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect::<Vec<Span>>()
|
|
|
|
&& !spans.is_empty()
|
|
|
|
{
|
|
|
|
let mut span: MultiSpan = spans.clone().into();
|
|
|
|
for sp in spans {
|
|
|
|
span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def);
|
|
|
|
}
|
|
|
|
span.push_span_label(
|
|
|
|
fn_call_span,
|
|
|
|
fluent::borrowck_moved_a_fn_once_in_call,
|
|
|
|
);
|
|
|
|
err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
|
|
|
|
} else {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
|
2024-03-15 18:08:12 +00:00
|
|
|
}
|
2022-03-02 04:30:16 +00:00
|
|
|
}
|
2024-03-12 17:21:15 +00:00
|
|
|
CallKind::Operator { self_arg, trait_id, .. } => {
|
2022-03-02 04:30:16 +00:00
|
|
|
let self_arg = self_arg.unwrap();
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonLabel::OperatorUse {
|
|
|
|
fn_call_span,
|
|
|
|
place_name: &place_name,
|
|
|
|
is_partial,
|
|
|
|
is_loop_message,
|
|
|
|
});
|
2022-03-02 04:30:16 +00:00
|
|
|
if self.fn_self_span_reported.insert(fn_span) {
|
2024-03-12 17:21:15 +00:00
|
|
|
let lang = self.infcx.tcx.lang_items();
|
2024-02-14 14:17:27 +00:00
|
|
|
err.subdiagnostic(
|
2024-03-12 17:21:15 +00:00
|
|
|
if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
|
|
|
|
.contains(&Some(trait_id))
|
|
|
|
{
|
|
|
|
CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span }
|
|
|
|
} else {
|
|
|
|
CaptureReasonNote::LhsMoveByOperator { span: self_arg.span }
|
|
|
|
},
|
2024-02-14 14:17:27 +00:00
|
|
|
);
|
2022-03-02 04:30:16 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-11 22:35:29 +01:00
|
|
|
CallKind::Normal { self_arg, desugaring, method_did, method_args } => {
|
2022-03-02 04:30:16 +00:00
|
|
|
let self_arg = self_arg.unwrap();
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
let mut has_sugg = false;
|
2022-12-23 12:44:47 -08:00
|
|
|
let tcx = self.infcx.tcx;
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
// Avoid pointing to the same function in multiple different
|
|
|
|
// error messages.
|
|
|
|
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
|
|
|
|
self.explain_iterator_advancement_in_for_loop_if_applicable(
|
|
|
|
err,
|
|
|
|
span,
|
|
|
|
&move_spans,
|
|
|
|
);
|
|
|
|
|
|
|
|
let func = tcx.def_path_str(method_did);
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
|
|
|
|
func,
|
|
|
|
place_name: place_name.clone(),
|
|
|
|
span: self_arg.span,
|
|
|
|
});
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
}
|
|
|
|
let parent_did = tcx.parent(method_did);
|
|
|
|
let parent_self_ty =
|
|
|
|
matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
|
|
|
|
.then_some(parent_did)
|
|
|
|
.and_then(|did| match tcx.type_of(did).instantiate_identity().kind() {
|
|
|
|
ty::Adt(def, ..) => Some(def.did()),
|
|
|
|
_ => None,
|
|
|
|
});
|
|
|
|
let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
|
|
|
|
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
|
|
|
});
|
|
|
|
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
}
|
2022-03-02 04:30:16 +00:00
|
|
|
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
2022-12-23 12:44:47 -08:00
|
|
|
let ty = moved_place.ty(self.body, tcx).ty;
|
|
|
|
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
|
2023-04-17 16:38:30 +00:00
|
|
|
Some(def_id) => type_known_to_meet_bound_modulo_regions(
|
2023-11-21 20:07:32 +01:00
|
|
|
self.infcx,
|
2024-11-01 13:51:00 +11:00
|
|
|
self.infcx.param_env,
|
2023-07-05 20:13:26 +01:00
|
|
|
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
|
2023-04-17 16:38:30 +00:00
|
|
|
def_id,
|
|
|
|
),
|
2022-03-02 04:30:16 +00:00
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
if suggest {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
|
|
|
|
ty,
|
|
|
|
span: move_span.shrink_to_lo(),
|
|
|
|
});
|
2022-03-02 04:30:16 +00:00
|
|
|
}
|
|
|
|
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
|
|
|
|
fn_call_span,
|
|
|
|
place_name: &place_name,
|
|
|
|
is_partial,
|
|
|
|
is_loop_message,
|
|
|
|
});
|
2022-09-05 05:00:26 +00:00
|
|
|
// If the moved place was a `&mut` ref, then we can
|
|
|
|
// suggest to reborrow it where it was moved, so it
|
|
|
|
// will still be valid by the time we get to the usage.
|
|
|
|
if let ty::Ref(_, _, hir::Mutability::Mut) =
|
|
|
|
moved_place.ty(self.body, self.infcx.tcx).ty.kind()
|
2022-03-02 04:30:16 +00:00
|
|
|
{
|
2024-07-10 20:27:38 +08:00
|
|
|
// Suggest `reborrow` in other place for following situations:
|
|
|
|
// 1. If we are in a loop this will be suggested later.
|
|
|
|
// 2. If the moved value is a mut reference, it is used in a
|
|
|
|
// generic function and the corresponding arg's type is generic param.
|
|
|
|
if !is_loop_move && !has_suggest_reborrow {
|
|
|
|
self.suggest_reborrow(
|
|
|
|
err,
|
2022-03-02 04:30:16 +00:00
|
|
|
move_span.shrink_to_lo(),
|
2024-07-10 20:27:38 +08:00
|
|
|
moved_place.as_ref(),
|
2022-03-02 04:30:16 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2023-04-25 19:48:59 +00:00
|
|
|
if let Some((CallDesugaringKind::Await, _)) = desugaring {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonLabel::Await {
|
|
|
|
fn_call_span,
|
|
|
|
place_name: &place_name,
|
|
|
|
is_partial,
|
|
|
|
is_loop_message,
|
|
|
|
});
|
2023-04-25 19:48:59 +00:00
|
|
|
} else {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonLabel::MethodCall {
|
|
|
|
fn_call_span,
|
|
|
|
place_name: &place_name,
|
|
|
|
is_partial,
|
|
|
|
is_loop_message,
|
|
|
|
});
|
2023-04-25 19:48:59 +00:00
|
|
|
}
|
2023-01-28 20:43:16 +01:00
|
|
|
// Erase and shadow everything that could be passed to the new infcx.
|
2023-04-17 16:38:30 +00:00
|
|
|
let ty = moved_place.ty(self.body, tcx).ty;
|
2023-01-28 20:43:16 +01:00
|
|
|
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
if let ty::Adt(def, args) = ty.peel_refs().kind()
|
2024-06-14 14:46:32 -04:00
|
|
|
&& tcx.is_lang_item(def.did(), LangItem::Pin)
|
2023-07-11 22:35:29 +01:00
|
|
|
&& let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind()
|
2023-04-17 16:38:30 +00:00
|
|
|
&& let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
|
2022-12-26 13:35:35 -08:00
|
|
|
fn_call_span,
|
2023-11-13 14:01:16 +00:00
|
|
|
BoundRegionConversionTime::FnCall,
|
2023-07-11 22:35:29 +01:00
|
|
|
tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0),
|
2022-12-25 16:51:11 -08:00
|
|
|
)
|
2024-11-01 13:51:00 +11:00
|
|
|
&& self.infcx.can_eq(self.infcx.param_env, ty, self_ty)
|
2022-12-23 09:59:39 -08:00
|
|
|
{
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonSuggest::FreshReborrow {
|
|
|
|
span: move_span.shrink_to_hi(),
|
|
|
|
});
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
has_sugg = true;
|
2022-12-23 09:59:39 -08:00
|
|
|
}
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
if let Some(clone_trait) = tcx.lang_items().clone_trait() {
|
2023-11-19 23:53:31 +00:00
|
|
|
let sugg = if moved_place
|
|
|
|
.iter_projections()
|
|
|
|
.any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
|
|
|
|
{
|
2024-03-12 20:01:51 +00:00
|
|
|
let (start, end) = if let Some(expr) = self.find_expr(move_span)
|
|
|
|
&& let Some(_) = self.clone_on_reference(expr)
|
|
|
|
&& let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind
|
|
|
|
{
|
|
|
|
(move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi()))
|
|
|
|
} else {
|
|
|
|
(move_span.shrink_to_lo(), move_span.shrink_to_hi())
|
|
|
|
};
|
2023-11-19 23:53:31 +00:00
|
|
|
vec![
|
|
|
|
// We use the fully-qualified path because `.clone()` can
|
|
|
|
// sometimes choose `<&T as Clone>` instead of `<T as Clone>`
|
|
|
|
// when going through auto-deref, so this ensures that doesn't
|
|
|
|
// happen, causing suggestions for `.clone().clone()`.
|
2024-03-12 20:01:51 +00:00
|
|
|
(start, format!("<{ty} as Clone>::clone(&")),
|
|
|
|
(end, ")".to_string()),
|
2023-11-19 23:53:31 +00:00
|
|
|
]
|
|
|
|
} else {
|
|
|
|
vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
|
|
|
|
};
|
2024-01-13 17:09:33 +00:00
|
|
|
if let Some(errors) = self.infcx.type_implements_trait_shallow(
|
|
|
|
clone_trait,
|
|
|
|
ty,
|
2024-11-01 13:51:00 +11:00
|
|
|
self.infcx.param_env,
|
2024-01-13 17:09:33 +00:00
|
|
|
) && !has_sugg
|
2023-11-21 21:24:51 +00:00
|
|
|
{
|
|
|
|
let msg = match &errors[..] {
|
|
|
|
[] => "you can `clone` the value and consume it, but this \
|
2024-03-09 20:02:47 +00:00
|
|
|
might not be your desired behavior"
|
2023-11-21 21:24:51 +00:00
|
|
|
.to_string(),
|
|
|
|
[error] => {
|
|
|
|
format!(
|
2024-03-09 20:02:47 +00:00
|
|
|
"you could `clone` the value and consume it, if the \
|
|
|
|
`{}` trait bound could be satisfied",
|
2023-11-21 21:24:51 +00:00
|
|
|
error.obligation.predicate,
|
|
|
|
)
|
|
|
|
}
|
2025-01-31 20:36:44 +00:00
|
|
|
_ => {
|
2023-11-21 21:24:51 +00:00
|
|
|
format!(
|
2024-03-09 20:02:47 +00:00
|
|
|
"you could `clone` the value and consume it, if the \
|
2025-01-31 20:36:44 +00:00
|
|
|
following trait bounds could be satisfied: {}",
|
|
|
|
listify(&errors, |e: &FulfillmentError<'tcx>| format!(
|
|
|
|
"`{}`",
|
|
|
|
e.obligation.predicate
|
|
|
|
))
|
|
|
|
.unwrap(),
|
2023-11-21 21:24:51 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
err.multipart_suggestion_verbose(
|
|
|
|
msg,
|
2023-12-11 21:54:36 +01:00
|
|
|
sugg,
|
2023-11-21 21:24:51 +00:00
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
);
|
|
|
|
for error in errors {
|
2024-05-09 14:09:55 -04:00
|
|
|
if let FulfillmentErrorCode::Select(
|
2023-11-21 21:24:51 +00:00
|
|
|
SelectionError::Unimplemented,
|
|
|
|
) = error.code
|
|
|
|
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
|
|
|
|
pred,
|
|
|
|
)) = error.obligation.predicate.kind().skip_binder()
|
|
|
|
{
|
|
|
|
self.infcx.err_ctxt().suggest_derive(
|
|
|
|
&error.obligation,
|
|
|
|
err,
|
|
|
|
error.obligation.predicate.kind().rebind(pred),
|
|
|
|
);
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-21 21:24:51 +00:00
|
|
|
}
|
Suggest cloning and point out obligation errors on move error
When encountering a move error, look for implementations of `Clone` for
the moved type. If there is one, check if all its obligations are met.
If they are, we suggest cloning without caveats. If they aren't, we
suggest cloning while mentioning the unmet obligations, potentially
suggesting `#[derive(Clone)]` when appropriate.
```
error[E0507]: cannot move out of a shared reference
--> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28
|
LL | let mut copy: Vec<U> = map.clone().into_values().collect();
| ^^^^^^^^^^^ ------------- value moved due to this method call
| |
| move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait
|
note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL
help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied
|
LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect();
| ++++++++++++++++++++++++++++++++++++++++++++ +
help: consider annotating `Hash128_1` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | pub struct Hash128_1;
|
```
Fix #109429.
2023-11-20 22:51:52 +00:00
|
|
|
}
|
2022-08-16 03:02:04 +00:00
|
|
|
}
|
2022-03-02 04:30:16 +00:00
|
|
|
}
|
|
|
|
// Other desugarings takes &self, which cannot cause a move
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
} else {
|
2023-02-10 16:58:32 +08:00
|
|
|
if move_span != span || is_loop_message {
|
2024-06-18 11:10:18 +00:00
|
|
|
err.subdiagnostic(CaptureReasonLabel::MovedHere {
|
|
|
|
move_span,
|
|
|
|
is_partial,
|
|
|
|
is_move_msg,
|
|
|
|
is_loop_message,
|
|
|
|
});
|
2022-03-02 04:30:16 +00:00
|
|
|
}
|
|
|
|
// If the move error occurs due to a loop, don't show
|
|
|
|
// another message for the same span
|
2023-02-10 16:58:32 +08:00
|
|
|
if !is_loop_message {
|
2024-06-18 11:10:18 +00:00
|
|
|
move_spans.var_subdiag(err, None, |kind, var_span| match kind {
|
2023-12-25 16:56:12 +00:00
|
|
|
hir::ClosureKind::Coroutine(_) => {
|
2023-12-22 21:29:12 +00:00
|
|
|
CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
|
|
|
|
}
|
2024-01-24 17:30:02 +00:00
|
|
|
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
2023-12-22 21:29:12 +00:00
|
|
|
CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }
|
|
|
|
}
|
2023-02-10 16:58:32 +08:00
|
|
|
})
|
2022-03-02 04:30:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-01 20:38:02 +01:00
|
|
|
}
|