summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src/diagnostics
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/diagnostics')
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs34
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs64
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs160
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs156
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs18
9 files changed, 297 insertions, 158 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 1ef2b0ae9..b1def1892 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -484,9 +484,7 @@ fn try_extract_error_from_region_constraints<'tcx>(
};
nice_error.try_report_from_nll().or_else(|| {
if let SubregionOrigin::Subtype(trace) = cause {
- Some(
- infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
- )
+ Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch))
} else {
None
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 8bc8964bb..f2204c242 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -258,7 +258,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let ty = place.ty(self.body, self.infcx.tcx).ty;
// If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
- if is_loop_move & !in_pattern {
+ // Same for if we're in a loop, see #101119.
+ if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
err.span_suggestion_verbose(
@@ -451,7 +452,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn suggest_borrow_fn_like(
&self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ err: &mut Diagnostic,
ty: Ty<'tcx>,
move_sites: &[MoveSite],
value_name: &str,
@@ -526,12 +527,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
true
}
- fn suggest_adding_copy_bounds(
- &self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
- ty: Ty<'tcx>,
- span: Span,
- ) {
+ fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
let tcx = self.infcx.tcx;
let generics = tcx.generics_of(self.mir_def_id());
@@ -1124,6 +1120,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// short a lifetime. (But sometimes it is more useful to report
/// it as a more direct conflict between the execution of a
/// `Drop::drop` with an aliasing borrow.)
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn report_borrowed_value_does_not_live_long_enough(
&mut self,
location: Location,
@@ -1131,13 +1128,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
place_span: (Place<'tcx>, Span),
kind: Option<WriteKind>,
) {
- debug!(
- "report_borrowed_value_does_not_live_long_enough(\
- {:?}, {:?}, {:?}, {:?}\
- )",
- location, borrow, place_span, kind
- );
-
let drop_span = place_span.1;
let root_place =
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
@@ -1194,10 +1184,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
- debug!(
- "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
- place_desc, explanation
- );
+ debug!(?place_desc, ?explanation);
+
let err = match (place_desc, explanation) {
// If the outlives constraint comes from inside the closure,
// for example:
@@ -1469,6 +1457,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err
}
+ #[instrument(level = "debug", skip(self))]
fn report_temporary_value_does_not_live_long_enough(
&mut self,
location: Location,
@@ -1478,13 +1467,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
proper_span: Span,
explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
- debug!(
- "report_temporary_value_does_not_live_long_enough(\
- {:?}, {:?}, {:?}, {:?}\
- )",
- location, borrow, drop_span, proper_span
- );
-
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
explanation
{
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 72aee0267..1c01e78ab 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt};
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{sym, DesugaringKind, Span};
-use crate::region_infer::BlameConstraint;
+use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
WriteKind,
@@ -38,6 +38,7 @@ pub(crate) enum BorrowExplanation<'tcx> {
span: Span,
region_name: RegionName,
opt_place_desc: Option<String>,
+ extra_info: Vec<ExtraConstraintInfo>,
},
Unexplained,
}
@@ -243,6 +244,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
ref region_name,
ref opt_place_desc,
from_closure: _,
+ ref extra_info,
} => {
region_name.highlight_region_name(err);
@@ -268,18 +270,30 @@ impl<'tcx> BorrowExplanation<'tcx> {
);
};
+ for extra in extra_info {
+ match extra {
+ ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
+ err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+ }
+ }
+ }
+
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
}
_ => {}
}
}
- pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic(
+
+ fn add_lifetime_bound_suggestion_to_diagnostic(
&self,
err: &mut Diagnostic,
category: &ConstraintCategory<'tcx>,
span: Span,
region_name: &RegionName,
) {
+ if !span.is_desugaring(DesugaringKind::OpaqueTy) {
+ return;
+ }
if let ConstraintCategory::OpaqueType = category {
let suggestable_name =
if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime };
@@ -305,18 +319,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&self,
borrow_region: RegionVid,
outlived_region: RegionVid,
- ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>) {
- let BlameConstraint { category, from_closure, cause, variance_info: _ } =
- self.regioncx.best_blame_constraint(
- &self.body,
- borrow_region,
- NllRegionVariableOrigin::FreeRegion,
- |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
- );
+ ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
+ let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
+ borrow_region,
+ NllRegionVariableOrigin::FreeRegion,
+ |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
+ );
+ let BlameConstraint { category, from_closure, cause, .. } = blame_constraint;
let outlived_fr_name = self.give_region_a_name(outlived_region);
- (category, from_closure, cause.span, outlived_fr_name)
+ (category, from_closure, cause.span, outlived_fr_name, extra_info)
}
/// Returns structured explanation for *why* the borrow contains the
@@ -332,26 +345,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// - second half is the place being accessed
///
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn explain_why_borrow_contains_point(
&self,
location: Location,
borrow: &BorrowData<'tcx>,
kind_place: Option<(WriteKind, Place<'tcx>)>,
) -> BorrowExplanation<'tcx> {
- debug!(
- "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
- location, borrow, kind_place
- );
-
let regioncx = &self.regioncx;
let body: &Body<'_> = &self.body;
let tcx = self.infcx.tcx;
let borrow_region_vid = borrow.region;
- debug!("explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid);
+ debug!(?borrow_region_vid);
let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
- debug!("explain_why_borrow_contains_point: region_sub={:?}", region_sub);
+ debug!(?region_sub);
match find_use::find(body, regioncx, tcx, region_sub, location) {
Some(Cause::LiveVar(local, location)) => {
@@ -392,7 +401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None => {
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
- let (category, from_closure, span, region_name) =
+ let (category, from_closure, span, region_name, extra_info) =
self.free_region_constraint_info(borrow_region_vid, region);
if let Some(region_name) = region_name {
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
@@ -402,19 +411,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span,
region_name,
opt_place_desc,
+ extra_info,
}
} else {
- debug!(
- "explain_why_borrow_contains_point: \
- Could not generate a region name"
- );
+ debug!("Could not generate a region name");
BorrowExplanation::Unexplained
}
} else {
- debug!(
- "explain_why_borrow_contains_point: \
- Could not generate an error region vid"
- );
+ debug!("Could not generate an error region vid");
BorrowExplanation::Unexplained
}
}
@@ -455,7 +459,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return outmost_back_edge;
}
- let block = &self.body.basic_blocks()[location.block];
+ let block = &self.body.basic_blocks[location.block];
if location.statement_index < block.statements.len() {
let successor = location.successor_within_block();
@@ -514,7 +518,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
if loop_head.dominates(from, &self.dominators) {
- let block = &self.body.basic_blocks()[from.block];
+ let block = &self.body.basic_blocks[from.block];
if from.statement_index < block.statements.len() {
let successor = from.successor_within_block();
@@ -564,7 +568,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
UseSpans::PatUse(span)
| UseSpans::OtherUse(span)
| UseSpans::FnSelfUse { var_span: span, .. } => {
- let block = &self.body.basic_blocks()[location.block];
+ let block = &self.body.basic_blocks[location.block];
let kind = if let Some(&Statement {
kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 098e8de94..683084cf0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1086,14 +1086,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
),
);
}
- if is_option_or_result && maybe_reinitialized_locations_is_empty {
- err.span_suggestion_verbose(
- fn_call_span.shrink_to_lo(),
- "consider calling `.as_ref()` to borrow the type's contents",
- "as_ref().",
- Applicability::MachineApplicable,
- );
- }
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
@@ -1102,6 +1094,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
);
}
+ if is_option_or_result && maybe_reinitialized_locations_is_empty {
+ err.span_label(
+ var_span,
+ "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents",
+ );
+ }
}
// Other desugarings takes &self, which cannot cause a move
_ => {}
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index cb3cd479a..8d4c38d3a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -88,7 +88,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(StatementKind::Assign(box (
place,
Rvalue::Use(Operand::Move(move_from)),
- ))) = self.body.basic_blocks()[location.block]
+ ))) = self.body.basic_blocks[location.block]
.statements
.get(location.statement_index)
.map(|stmt| &stmt.kind)
@@ -360,7 +360,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
diag.span_label(upvar_span, "captured outer variable");
diag.span_label(
- self.body.span,
+ self.infcx.tcx.def_span(def_id),
format!("captured by this `{closure_kind}` closure"),
);
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 0ad4abbce..6b5014fa9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1,23 +1,23 @@
+use rustc_errors::{
+ Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed,
+};
use rustc_hir as hir;
+use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
use rustc_middle::hir::map::Map;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{
hir::place::PlaceBase,
- mir::{
- self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo,
- LocalKind, Location,
- },
+ mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{sym, BytePos, Span};
use crate::diagnostics::BorrowedContentSource;
use crate::MirBorrowckCtxt;
use rustc_const_eval::util::collect_writes::FindAssignments;
-use rustc_errors::{Applicability, Diagnostic};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum AccessKind {
@@ -309,7 +309,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&& !matches!(
decl.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
- ImplicitSelfKind::MutRef
+ hir::ImplicitSelfKind::MutRef
))))
)
{
@@ -364,7 +364,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
&& let hir::PatKind::Binding(
- hir::BindingAnnotation::Unannotated,
+ hir::BindingAnnotation::NONE,
_,
upvar_ident,
_,
@@ -614,6 +614,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
"trait `IndexMut` is required to modify indexed content, \
but it is not implemented for `{ty}`",
));
+ self.suggest_map_index_mut_alternatives(ty, &mut err, span);
}
_ => (),
}
@@ -627,6 +628,127 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.buffer_error(err);
}
+ fn suggest_map_index_mut_alternatives(
+ &self,
+ ty: Ty<'_>,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ span: Span,
+ ) {
+ let Some(adt) = ty.ty_adt_def() else { return };
+ let did = adt.did();
+ if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
+ || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
+ {
+ struct V<'a, 'b, 'tcx, G: EmissionGuarantee> {
+ assign_span: Span,
+ err: &'a mut DiagnosticBuilder<'b, G>,
+ ty: Ty<'tcx>,
+ suggested: bool,
+ }
+ impl<'a, 'b: 'a, 'hir, 'tcx, G: EmissionGuarantee> Visitor<'hir> for V<'a, 'b, 'tcx, G> {
+ fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) {
+ hir::intravisit::walk_stmt(self, stmt);
+ let expr = match stmt.kind {
+ hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
+ hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr,
+ _ => {
+ return;
+ }
+ };
+ if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
+ && let hir::ExprKind::Index(val, index) = place.kind
+ && (expr.span == self.assign_span || place.span == self.assign_span)
+ {
+ // val[index] = rv;
+ // ---------- place
+ self.err.multipart_suggestions(
+ &format!(
+ "to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
+ self.ty,
+ ),
+ vec![
+ vec![ // val.insert(index, rv);
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".insert(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(rv.span.lo()),
+ ", ".to_string(),
+ ),
+ (rv.span.shrink_to_hi(), ")".to_string()),
+ ],
+ vec![ // val.get_mut(index).map(|v| { *v = rv; });
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".get_mut(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(place.span.hi()),
+ ").map(|val| { *val".to_string(),
+ ),
+ (
+ rv.span.shrink_to_hi(),
+ "; })".to_string(),
+ ),
+ ],
+ vec![ // let x = val.entry(index).or_insert(rv);
+ (val.span.shrink_to_lo(), "let val = ".to_string()),
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".entry(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(rv.span.lo()),
+ ").or_insert(".to_string(),
+ ),
+ (rv.span.shrink_to_hi(), ")".to_string()),
+ ],
+ ].into_iter(),
+ Applicability::MachineApplicable,
+ );
+ self.suggested = true;
+ } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
+ && let hir::ExprKind::Index(val, index) = receiver.kind
+ && expr.span == self.assign_span
+ {
+ // val[index].path(args..);
+ self.err.multipart_suggestion(
+ &format!("to modify a `{}` use `.get_mut()`", self.ty),
+ vec![
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".get_mut(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(receiver.span.hi()),
+ ").map(|val| val".to_string(),
+ ),
+ (sp.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ self.suggested = true;
+ }
+ }
+ }
+ let hir_map = self.infcx.tcx.hir();
+ let def_id = self.body.source.def_id();
+ let hir_id = hir_map.local_def_id_to_hir_id(def_id.as_local().unwrap());
+ let node = hir_map.find(hir_id);
+ let Some(hir::Node::Item(item)) = node else { return; };
+ let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
+ let body = self.infcx.tcx.hir().body(body_id);
+ let mut v = V { assign_span: span, err, ty, suggested: false };
+ v.visit_body(body);
+ if !v.suggested {
+ err.help(&format!(
+ "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
+ ));
+ }
+ }
+ }
+
/// User cannot make signature of a trait mutable without changing the
/// trait. So we find if this error belongs to a trait and if so we move
/// suggestion to the trait or disable it if it is out of scope of this crate
@@ -786,11 +908,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
[
Expr {
kind:
- MethodCall(
- path_segment,
- _args,
- span,
- ),
+ MethodCall(path_segment, _, _, span),
hir_id,
..
},
@@ -810,10 +928,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
_,
) = hir_map.body(fn_body_id).value.kind
{
- let opt_suggestions = path_segment
- .hir_id
- .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
- .and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
+ let opt_suggestions = self
+ .infcx
+ .tcx
+ .typeck(path_segment.hir_id.owner)
+ .type_dependent_def_id(*hir_id)
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
.map(|def_id| self.infcx.tcx.associated_items(def_id))
.map(|assoc_items| {
@@ -851,6 +970,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let hir = self.infcx.tcx.hir();
let closure_id = self.mir_hir_id();
+ let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
let fn_call_id = hir.get_parent_node(closure_id);
let node = hir.get(fn_call_id);
let def_id = hir.enclosing_body_owner(fn_call_id);
@@ -902,7 +1022,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(span) = arg {
err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
err.span_label(func.span, "expects `Fn` instead of `FnMut`");
- err.span_label(self.body.span, "in this closure");
+ err.span_label(closure_span, "in this closure");
look_at_return = false;
}
}
@@ -928,7 +1048,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
sig.decl.output.span(),
"change this to return `FnMut` instead of `Fn`",
);
- err.span_label(self.body.span, "in this closure");
+ err.span_label(closure_span, "in this closure");
}
_ => {}
}
@@ -952,7 +1072,7 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
//
// Deliberately fall into this case for all implicit self types,
// so that we don't fall in to the next case with them.
- *kind == mir::ImplicitSelfKind::MutRef
+ *kind == hir::ImplicitSelfKind::MutRef
}
_ if Some(kw::SelfLower) == local_name => {
// Otherwise, check if the name is the `self` keyword - in which case
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index d359d7efb..35c3df768 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -6,7 +6,6 @@ use rustc_errors::Diagnostic;
use rustc_middle::ty::RegionVid;
use smallvec::SmallVec;
use std::collections::BTreeMap;
-use tracing::debug;
use crate::MirBorrowckCtxt;
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 176090c3b..34be2874f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
//! Error reporting machinery for lifetime errors.
use rustc_data_structures::fx::FxHashSet;
@@ -23,10 +25,13 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use crate::borrowck_errors;
-use crate::session_diagnostics::GenericDoesNotLiveLongEnough;
+use crate::session_diagnostics::{
+ FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
+ LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
+};
use super::{OutlivesSuggestionBuilder, RegionName};
-use crate::region_infer::BlameConstraint;
+use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
nll::ConstraintDescription,
region_infer::{values::RegionElement, TypeTest},
@@ -229,7 +234,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
let (_, cause) = self.regioncx.find_outlives_blame_span(
- &self.body,
longer_fr,
NllRegionVariableOrigin::Placeholder(placeholder),
error_vid,
@@ -350,10 +354,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
) {
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
- let BlameConstraint { category, cause, variance_info, from_closure: _ } =
- self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
+ let (blame_constraint, extra_info) =
+ self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
});
+ let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;
debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
@@ -462,6 +467,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
+ for extra in extra_info {
+ match extra {
+ ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
+ diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+ }
+ }
+ }
+
self.buffer_error(diag);
}
@@ -488,12 +501,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
- let mut diag = self
- .infcx
- .tcx
- .sess
- .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
-
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
if let ty::Opaque(def_id, _) = *output_ty.kind() {
output_ty = self.infcx.tcx.type_of(def_id)
@@ -501,19 +508,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
debug!("report_fnmut_error: output_ty={:?}", output_ty);
- let message = match output_ty.kind() {
- ty::Closure(_, _) => {
- "returns a closure that contains a reference to a captured variable, which then \
- escapes the closure body"
- }
- ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => {
- "returns an `async` block that contains a reference to a captured variable, which then \
- escapes the closure body"
- }
- _ => "returns a reference to a captured variable which escapes the closure body",
+ let err = FnMutError {
+ span: *span,
+ ty_err: match output_ty.kind() {
+ ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span },
+ ty::Adt(def, _)
+ if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) =>
+ {
+ FnMutReturnTypeErr::ReturnAsyncBlock { span: *span }
+ }
+ _ => FnMutReturnTypeErr::ReturnRef { span: *span },
+ },
};
- diag.span_label(*span, message);
+ let mut diag = self.infcx.tcx.sess.create_err(err);
if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty {
@@ -532,20 +540,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
let upvar_span = upvars_map.get(&def_hir).unwrap().span;
- diag.span_label(upvar_def_span, "variable defined here");
- diag.span_label(upvar_span, "variable captured here");
+ diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span });
+ diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span });
}
}
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
- diag.span_label(fr_span, "inferred to be a `FnMut` closure");
+ diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
}
- diag.note(
- "`FnMut` closures only have access to their captured variables while they are \
- executing...",
- );
- diag.note("...therefore, they cannot allow references to captured variables to escape");
+ self.suggest_move_on_borrowing_closure(&mut diag);
diag
}
@@ -562,6 +566,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// LL | ref_obj(x)
/// | ^^^^^^^^^^ `x` escapes the function body here
/// ```
+ #[instrument(level = "debug", skip(self))]
fn report_escaping_data_error(
&self,
errci: &ErrorConstraintInfo<'tcx>,
@@ -680,42 +685,37 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
..
} = errci;
- let mut diag =
- self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough");
-
let (_, mir_def_name) =
self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id());
+ let err = LifetimeOutliveErr { span: *span };
+ let mut diag = self.infcx.tcx.sess.create_err(err);
+
let fr_name = self.give_region_a_name(*fr).unwrap();
fr_name.highlight_region_name(&mut diag);
let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap();
outlived_fr_name.highlight_region_name(&mut diag);
- match (category, outlived_fr_is_local, fr_is_local) {
- (ConstraintCategory::Return(_), true, _) => {
- diag.span_label(
- *span,
- format!(
- "{mir_def_name} was supposed to return data with lifetime `{outlived_fr_name}` but it is returning \
- data with lifetime `{fr_name}`",
- ),
- );
- }
- _ => {
- diag.span_label(
- *span,
- format!(
- "{}requires that `{}` must outlive `{}`",
- category.description(),
- fr_name,
- outlived_fr_name,
- ),
- );
- }
- }
+ let err_category = match (category, outlived_fr_is_local, fr_is_local) {
+ (ConstraintCategory::Return(_), true, _) => LifetimeReturnCategoryErr::WrongReturn {
+ span: *span,
+ mir_def_name,
+ outlived_fr_name,
+ fr_name: &fr_name,
+ },
+ _ => LifetimeReturnCategoryErr::ShortReturn {
+ span: *span,
+ category_desc: category.description(),
+ free_region_name: &fr_name,
+ outlived_fr_name,
+ },
+ };
+
+ diag.subdiagnostic(err_category);
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
+ self.suggest_move_on_borrowing_closure(&mut diag);
diag
}
@@ -783,7 +783,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn maybe_suggest_constrain_dyn_trait_impl(
&self,
- diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ diag: &mut Diagnostic,
f: Region<'tcx>,
o: Region<'tcx>,
category: &ConstraintCategory<'tcx>,
@@ -860,7 +860,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
ident.span,
"calling this method introduces the `impl`'s 'static` requirement",
);
- err.span_note(multi_span, "the used `impl` has a `'static` requirement");
+ err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
err.span_suggestion_verbose(
span.shrink_to_hi(),
"consider relaxing the implicit `'static` requirement",
@@ -901,4 +901,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
}
+
+ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
+ let map = self.infcx.tcx.hir();
+ let body_id = map.body_owned_by(self.mir_def_id());
+ let expr = &map.body(body_id).value;
+ let mut closure_span = None::<rustc_span::Span>;
+ match expr.kind {
+ hir::ExprKind::MethodCall(.., args, _) => {
+ for arg in args {
+ if let hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ ..
+ }) = arg.kind
+ {
+ closure_span = Some(arg.span.shrink_to_lo());
+ break;
+ }
+ }
+ }
+ hir::ExprKind::Block(blk, _) => {
+ if let Some(ref expr) = blk.expr {
+ // only when the block is a closure
+ if let hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ ..
+ }) = expr.kind
+ {
+ closure_span = Some(expr.span.shrink_to_lo());
+ }
+ }
+ }
+ _ => {}
+ }
+ if let Some(closure_span) = closure_span {
+ diag.span_suggestion_verbose(
+ closure_span,
+ "consider adding 'move' keyword before the nested closure",
+ "move ",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index a87e8bd5b..6c1eaa809 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -265,7 +265,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// *user* has a name for. In that case, we'll be able to map
/// `fr` to a `Region<'tcx>`, and that region will be one of
/// named variants.
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?;
@@ -357,11 +357,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::BoundRegionKind::BrAnon(_) => None,
},
- ty::ReLateBound(..)
- | ty::ReVar(..)
- | ty::RePlaceholder(..)
- | ty::ReEmpty(_)
- | ty::ReErased => None,
+ ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
}
}
@@ -373,7 +369,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | fn foo(x: &u32) { .. }
/// ------- fully elaborated type of `x` is `&'1 u32`
/// ```
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_arguments(
&self,
fr: RegionVid,
@@ -662,7 +658,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | let x = Some(&22);
/// - fully elaborated type of `x` is `Option<&'1 u32>`
/// ```
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
@@ -682,7 +678,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// must be a closure since, in a free fn, such an argument would
/// have to either also appear in an argument (if using elision)
/// or be early bound (named, not in argument).
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
let tcx = self.infcx.tcx;
let hir = tcx.hir();
@@ -772,7 +768,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
let hir = self.infcx.tcx.hir();
- let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
+ let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else {
span_bug!(
hir_ty.span,
"lowered return type of async fn is not OpaqueDef: {:?}",
@@ -814,7 +810,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
}
}
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_yield_ty(
&self,
fr: RegionVid,