summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs')
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs165
1 files changed, 126 insertions, 39 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 15d73ed73..c8c8b72b3 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1,6 +1,5 @@
-use std::iter;
-
use either::Either;
+use hir::PatField;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{
@@ -14,9 +13,10 @@ use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
- self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
- FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
- ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
+ self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
+ FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place,
+ PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
+ VarBindingForm,
};
use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
use rustc_middle::util::CallKind;
@@ -27,6 +27,7 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::ObligationCtxt;
+use std::iter;
use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
@@ -677,8 +678,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let tcx = self.infcx.tcx;
// Find out if the predicates show that the type is a Fn or FnMut
- let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
- if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
+ let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| {
+ if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
&& pred.self_ty() == ty
{
if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
@@ -704,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
.explicit_item_bounds(def_id)
.subst_iter_copied(tcx, substs)
- .find_map(find_fn_kind_from_did),
+ .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))),
ty::Closure(_, substs) => match substs.as_closure().kind() {
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
@@ -775,7 +776,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let predicates: Result<Vec<_>, _> = errors
.into_iter()
.map(|err| match err.obligation.predicate.kind().skip_binder() {
- PredicateKind::Clause(ty::Clause::Trait(predicate)) => {
+ PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
match predicate.self_ty().kind() {
ty::Param(param_ty) => Ok((
generics.type_param(param_ty, tcx),
@@ -926,7 +927,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// FIXME: supply non-"" `opt_via` when appropriate
let first_borrow_desc;
let mut err = match (gen_borrow_kind, issued_borrow.kind) {
- (BorrowKind::Shared, BorrowKind::Mut { .. }) => {
+ (
+ BorrowKind::Shared,
+ BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
+ ) => {
first_borrow_desc = "mutable ";
self.cannot_reborrow_already_borrowed(
span,
@@ -940,7 +944,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
)
}
- (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
+ (
+ BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
+ BorrowKind::Shared,
+ ) => {
first_borrow_desc = "immutable ";
let mut err = self.cannot_reborrow_already_borrowed(
span,
@@ -962,7 +969,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err
}
- (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
+ (
+ BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
+ BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
+ ) => {
first_borrow_desc = "first ";
let mut err = self.cannot_mutably_borrow_multiply(
span,
@@ -972,7 +982,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&msg_borrow,
None,
);
- self.suggest_split_at_mut_if_applicable(
+ self.suggest_slice_method_if_applicable(
&mut err,
place,
issued_borrow.borrowed_place,
@@ -982,15 +992,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
issued_borrow.borrowed_place,
&issued_spans,
);
+ self.explain_iterator_advancement_in_for_loop_if_applicable(
+ &mut err,
+ span,
+ &issued_spans,
+ );
err
}
- (BorrowKind::Unique, BorrowKind::Unique) => {
+ (
+ BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
+ BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
+ ) => {
first_borrow_desc = "first ";
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
}
- (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
+ (BorrowKind::Mut { .. }, BorrowKind::Shallow) => {
if let Some(immutable_section_description) =
self.classify_immutable_section(issued_borrow.assigned_place)
{
@@ -1004,7 +1022,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_spans.var_subdiag(
None,
&mut err,
- Some(BorrowKind::Unique),
+ Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),
|kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
@@ -1038,7 +1056,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
- (BorrowKind::Unique, _) => {
+ (BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => {
first_borrow_desc = "first ";
self.cannot_uniquely_borrow_by_one_closure(
span,
@@ -1052,7 +1070,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
- (BorrowKind::Shared, BorrowKind::Unique) => {
+ (BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
first_borrow_desc = "first ";
self.cannot_reborrow_already_uniquely_borrowed(
span,
@@ -1067,7 +1085,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
- (BorrowKind::Mut { .. }, BorrowKind::Unique) => {
+ (BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
first_borrow_desc = "first ";
self.cannot_reborrow_already_uniquely_borrowed(
span,
@@ -1085,10 +1103,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
| (
BorrowKind::Shallow,
- BorrowKind::Mut { .. }
- | BorrowKind::Unique
- | BorrowKind::Shared
- | BorrowKind::Shallow,
+ BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow,
) => unreachable!(),
};
@@ -1252,7 +1267,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
- fn suggest_split_at_mut_if_applicable(
+ fn suggest_slice_method_if_applicable(
&self,
err: &mut Diagnostic,
place: Place<'tcx>,
@@ -1264,7 +1279,75 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.help(
"consider using `.split_at_mut(position)` or similar method to obtain \
two mutable non-overlapping sub-slices",
- );
+ )
+ .help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
+ }
+ }
+
+ /// Suggest using `while let` for call `next` on an iterator in a for loop.
+ ///
+ /// For example:
+ /// ```ignore (illustrative)
+ ///
+ /// for x in iter {
+ /// ...
+ /// iter.next()
+ /// }
+ /// ```
+ pub(crate) fn explain_iterator_advancement_in_for_loop_if_applicable(
+ &self,
+ err: &mut Diagnostic,
+ span: Span,
+ issued_spans: &UseSpans<'tcx>,
+ ) {
+ let issue_span = issued_spans.args_or_use();
+ let tcx = self.infcx.tcx;
+ let hir = tcx.hir();
+
+ let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return };
+ let typeck_results = tcx.typeck(self.mir_def_id());
+
+ struct ExprFinder<'hir> {
+ issue_span: Span,
+ expr_span: Span,
+ body_expr: Option<&'hir hir::Expr<'hir>>,
+ loop_bind: Option<Symbol>,
+ }
+ impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
+ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
+ if let hir::ExprKind::Loop(hir::Block{ stmts: [stmt, ..], ..}, _, hir::LoopSource::ForLoop, _) = ex.kind &&
+ let hir::StmtKind::Expr(hir::Expr{ kind: hir::ExprKind::Match(call, [_, bind, ..], _), ..}) = stmt.kind &&
+ let hir::ExprKind::Call(path, _args) = call.kind &&
+ let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _, )) = path.kind &&
+ let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind &&
+ let hir::QPath::LangItem(LangItem::OptionSome, _, _) = path &&
+ let PatField { pat: hir::Pat{ kind: hir::PatKind::Binding(_, _, ident, ..), .. }, ..} = field &&
+ self.issue_span.source_equal(call.span) {
+ self.loop_bind = Some(ident.name);
+ }
+
+ if let hir::ExprKind::MethodCall(body_call, _recv, ..) = ex.kind &&
+ body_call.ident.name == sym::next && ex.span.source_equal(self.expr_span) {
+ self.body_expr = Some(ex);
+ }
+
+ hir::intravisit::walk_expr(self, ex);
+ }
+ }
+ let mut finder =
+ ExprFinder { expr_span: span, issue_span, loop_bind: None, body_expr: None };
+ finder.visit_expr(hir.body(body_id).value);
+
+ if let Some(loop_bind) = finder.loop_bind &&
+ let Some(body_expr) = finder.body_expr &&
+ let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) &&
+ let Some(trait_did) = tcx.trait_of_item(def_id) &&
+ tcx.is_diagnostic_item(sym::Iterator, trait_did) {
+ err.note(format!(
+ "a for loop advances the iterator for you, the result is stored in `{}`.",
+ loop_bind
+ ));
+ err.help("if you want to call `next` on a iterator within the loop, consider using `while let`.");
}
}
@@ -1720,18 +1803,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(
Some(name),
BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
- ) => self.report_escaping_closure_capture(
- borrow_spans,
- borrow_span,
- &RegionName {
- name: self.synthesize_region_name(),
- source: RegionNameSource::Static,
- },
- ConstraintCategory::CallArgument(None),
- var_or_use_span,
- &format!("`{}`", name),
- "block",
- ),
+ ) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
+ .report_escaping_closure_capture(
+ borrow_spans,
+ borrow_span,
+ &RegionName {
+ name: self.synthesize_region_name(),
+ source: RegionNameSource::Static,
+ },
+ ConstraintCategory::CallArgument(None),
+ var_or_use_span,
+ &format!("`{}`", name),
+ "block",
+ ),
(
Some(name),
BorrowExplanation::MustBeValidFor {
@@ -1744,7 +1828,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span,
..
},
- ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
+ ) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
borrow_span,
@@ -2579,7 +2663,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
let tcx = self.infcx.tcx;
if let (
- Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
+ Some(Terminator {
+ kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. },
+ ..
+ }),
Some((method_did, method_substs)),
) = (
&self.body[loan.reserve_location.block].terminator,