summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:03 +0000
commit64d98f8ee037282c35007b64c2649055c56af1db (patch)
tree5492bcf97fce41ee1c0b1cc2add283f3e66cdab0 /compiler/rustc_borrowck
parentAdding debian version 1.67.1+dfsg1-1. (diff)
downloadrustc-64d98f8ee037282c35007b64c2649055c56af1db.tar.xz
rustc-64d98f8ee037282c35007b64c2649055c56af1db.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_borrowck')
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs35
-rw-r--r--compiler/rustc_borrowck/src/constraints/graph.rs2
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs10
-rw-r--r--compiler/rustc_borrowck/src/consumers.rs8
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs5
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs304
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs53
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs115
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs100
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs162
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs18
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs233
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/var_name.rs25
-rw-r--r--compiler/rustc_borrowck/src/facts.rs2
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs104
-rw-r--r--compiler/rustc_borrowck/src/location.rs5
-rw-r--r--compiler/rustc_borrowck/src/member_constraints.rs9
-rw-r--r--compiler/rustc_borrowck/src/nll.rs2
-rw-r--r--compiler/rustc_borrowck/src/place_ext.rs2
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs113
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs26
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs6
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs13
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs84
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs19
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs127
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs115
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs2
35 files changed, 993 insertions, 732 deletions
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 01be37912..a4943d112 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -12,7 +12,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
place: &str,
borrow_place: &str,
value_place: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
place,
span,
@@ -28,7 +28,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
desc: &str,
borrow_span: Span,
borrow_desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
@@ -50,7 +50,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let via =
|msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
let mut err = struct_span_err!(
@@ -98,7 +98,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
new_loan_span,
@@ -269,7 +269,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
&self,
span: Span,
desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
}
@@ -348,7 +348,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
span: Span,
path: &str,
reason: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
}
@@ -359,7 +359,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
immutable_place: &str,
immutable_section: &str,
action: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
mutate_span,
@@ -378,7 +378,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
&self,
span: Span,
yield_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
@@ -392,7 +392,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
pub(crate) fn cannot_borrow_across_destructor(
&self,
borrow_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(
self,
borrow_span,
@@ -405,7 +405,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
&self,
span: Span,
path: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
}
@@ -415,7 +415,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
return_kind: &str,
reference_desc: &str,
path_desc: &str,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
span,
@@ -440,15 +440,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
closure_kind: &str,
borrowed_path: &str,
capture_span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ scope: &str,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!(
self,
closure_span,
E0373,
- "{} may outlive the current function, but it borrows {}, which is owned by the current \
- function",
- closure_kind,
- borrowed_path,
+ "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
+ which is owned by the current {scope}",
);
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
.span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
@@ -458,14 +457,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
pub(crate) fn thread_local_value_does_not_live_long_enough(
&self,
span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
}
pub(crate) fn temporary_value_borrowed_for_too_long(
&self,
span: Span,
- ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
}
diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index 385f15317..c780d0479 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -148,7 +148,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> {
if let Some(p) = self.pointer {
self.pointer = self.graph.next_constraints[p];
- Some(self.constraints[p].clone())
+ Some(self.constraints[p])
} else if let Some(next_static_idx) = self.next_static_idx {
self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) {
None
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 84a93e5f7..1f0b8adea 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -115,13 +115,11 @@ impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
}
rustc_index::newtype_index! {
- pub struct OutlivesConstraintIndex {
- DEBUG_FORMAT = "OutlivesConstraintIndex({})"
- }
+ #[debug_format = "OutlivesConstraintIndex({})"]
+ pub struct OutlivesConstraintIndex {}
}
rustc_index::newtype_index! {
- pub struct ConstraintSccIndex {
- DEBUG_FORMAT = "ConstraintSccIndex({})"
- }
+ #[debug_format = "ConstraintSccIndex({})"]
+ pub struct ConstraintSccIndex {}
}
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index 86da767f3..055b281bc 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -25,13 +25,13 @@ pub use super::{
/// can, for example, happen when requesting a body of a `const` function
/// because they are evaluated during typechecking. The panic can be avoided
/// by overriding the `mir_borrowck` query. You can find a complete example
-/// that shows how to do this at `src/test/run-make/obtain-borrowck/`.
+/// that shows how to do this at `tests/run-make/obtain-borrowck/`.
///
/// * Polonius is highly unstable, so expect regular changes in its signature or other details.
-pub fn get_body_with_borrowck_facts<'tcx>(
- tcx: TyCtxt<'tcx>,
+pub fn get_body_with_borrowck_facts(
+ tcx: TyCtxt<'_>,
def: ty::WithOptConstParam<LocalDefId>,
-) -> BodyWithBorrowckFacts<'tcx> {
+) -> BodyWithBorrowckFacts<'_> {
let (input_body, promoted) = tcx.mir_promoted(def);
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).build();
let input_body: &Body<'_> = &input_body.borrow();
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index f825b1d8f..8c4885770 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -108,9 +108,8 @@ impl_visitable! {
}
rustc_index::newtype_index! {
- pub struct BorrowIndex {
- DEBUG_FORMAT = "bw{}"
- }
+ #[debug_format = "bw{}"]
+ pub struct BorrowIndex {}
}
/// `Borrows` stores the data used in the analyses that track the flow
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 5e3745f17..e5a36259f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -6,6 +6,7 @@ use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
+use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
use rustc_infer::infer::TyCtxtInferExt;
@@ -20,7 +21,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
@@ -29,6 +30,7 @@ use crate::borrowck_errors;
use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
use crate::diagnostics::find_all_local_uses;
+use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
@@ -156,7 +158,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_note(
MultiSpan::from_spans(reinit_spans),
&if reinits <= 3 {
- format!("these {} reinitializations might get skipped", reinits)
+ format!("these {reinits} reinitializations might get skipped")
} else {
format!(
"these 3 reinitializations and {} other{} might get skipped",
@@ -194,7 +196,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if !seen_spans.contains(&move_span) {
if !closure {
- self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern);
+ self.suggest_ref_or_clone(
+ mpi,
+ move_span,
+ &mut err,
+ &mut in_pattern,
+ move_spans,
+ );
}
self.explain_captures(
@@ -219,9 +227,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label(
span,
format!(
- "value {} here after {}move",
+ "value {} here after {partial_str}move",
desired_action.as_verb_in_past_tense(),
- partial_str
),
);
}
@@ -251,7 +258,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&format!(
"consider creating a fresh reborrow of {} here",
self.describe_place(moved_place)
- .map(|n| format!("`{}`", n))
+ .map(|n| format!("`{n}`"))
.unwrap_or_else(|| "the mutable reference".to_string()),
),
"&mut *",
@@ -265,7 +272,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
);
let note_msg = match opt_name {
- Some(name) => format!("`{}`", name),
+ Some(name) => format!("`{name}`"),
None => "value".to_owned(),
};
if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg) {
@@ -291,9 +298,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} = use_spans
{
err.note(&format!(
- "{} occurs due to deref coercion to `{}`",
+ "{} occurs due to deref coercion to `{deref_target_ty}`",
desired_action.as_noun(),
- deref_target_ty
));
// Check first whether the source is accessible (issue #87060)
@@ -312,6 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_span: Span,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
in_pattern: &mut bool,
+ move_spans: UseSpans<'_>,
) {
struct ExpressionFinder<'hir> {
expr_span: Span,
@@ -351,7 +358,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_, _, body_id),
..
- })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
+ })) = hir.find(self.mir_hir_id())
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
{
let place = &self.move_data.move_paths[mpi].place;
@@ -387,7 +394,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
- let hir_id = hir.get_parent_node(expr.hir_id);
+ let hir_id = hir.parent_id(expr.hir_id);
if let Some(parent) = hir.find(hir_id) {
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
@@ -440,6 +447,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) = call_expr.kind
{
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
+ } else if let UseSpans::FnSelfUse {
+ kind: CallKind::Normal { .. },
+ ..
+ } = move_spans {
+ // We already suggest cloning for these cases in `explain_captures`.
} else {
self.suggest_cloning(err, ty, move_span);
}
@@ -515,26 +527,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// that are *partially* initialized by assigning to a field of an uninitialized
// binding. We differentiate between them for more accurate wording here.
"isn't fully initialized"
- } else if spans
- .iter()
- .filter(|i| {
- // We filter these to avoid misleading wording in cases like the following,
- // where `x` has an `init`, but it is in the same place we're looking at:
- // ```
- // let x;
- // x += 1;
- // ```
- !i.contains(span)
- // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
- && !visitor
- .errors
- .iter()
- .map(|(sp, _)| *sp)
- .any(|sp| span < sp && !sp.contains(span))
- })
- .count()
- == 0
- {
+ } else if !spans.iter().any(|i| {
+ // We filter these to avoid misleading wording in cases like the following,
+ // where `x` has an `init`, but it is in the same place we're looking at:
+ // ```
+ // let x;
+ // x += 1;
+ // ```
+ !i.contains(span)
+ // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
+ && !visitor
+ .errors
+ .iter()
+ .map(|(sp, _)| *sp)
+ .any(|sp| span < sp && !sp.contains(span))
+ }) {
show_assign_sugg = true;
"isn't initialized"
} else {
@@ -649,7 +656,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if !assign_value.is_empty() {
err.span_suggestion_verbose(
sugg_span.shrink_to_hi(),
- format!("consider assigning a value"),
+ "consider assigning a value",
format!(" = {}", assign_value),
Applicability::MaybeIncorrect,
);
@@ -666,40 +673,34 @@ 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 = |predicates: ty::EarlyBinder<
- &[(ty::Predicate<'tcx>, Span)],
- >,
- substs| {
- predicates.0.iter().find_map(|(pred, _)| {
- let pred = if let Some(substs) = substs {
- predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
- } else {
- pred.kind().skip_binder()
- };
- if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred && pred.self_ty() == ty {
- if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
- return Some(hir::Mutability::Not);
- } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
- return Some(hir::Mutability::Mut);
- }
+ let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
+ && pred.self_ty() == ty
+ {
+ if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
+ return Some(hir::Mutability::Not);
+ } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
+ return Some(hir::Mutability::Mut);
}
- None
- })
+ }
+ None
};
// If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
// borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
// These types seem reasonably opaque enough that they could be substituted with their
// borrowed variants in a function body when we see a move error.
- let borrow_level = match ty.kind() {
- ty::Param(_) => find_fn_kind_from_did(
- tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
- .map_bound(|p| p.predicates),
- None,
- ),
- ty::Opaque(did, substs) => {
- find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*did), Some(*substs))
- }
+ let borrow_level = match *ty.kind() {
+ ty::Param(_) => tcx
+ .explicit_predicates_of(self.mir_def_id().to_def_id())
+ .predicates
+ .iter()
+ .copied()
+ .find_map(find_fn_kind_from_did),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
+ .bound_explicit_item_bounds(def_id)
+ .subst_iter_copied(tcx, substs)
+ .find_map(find_fn_kind_from_did),
ty::Closure(_, substs) => match substs.as_closure().kind() {
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
@@ -745,7 +746,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_suggestion_verbose(
span.shrink_to_hi(),
"consider cloning the value if the performance cost is acceptable",
- ".clone()".to_string(),
+ ".clone()",
Applicability::MachineApplicable,
);
}
@@ -943,7 +944,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
first_borrow_desc = "immutable ";
- self.cannot_reborrow_already_borrowed(
+ let mut err = self.cannot_reborrow_already_borrowed(
span,
&desc_place,
&msg_place,
@@ -953,7 +954,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"immutable",
&msg_borrow,
None,
- )
+ );
+ self.suggest_binding_for_closure_capture_self(
+ &mut err,
+ issued_borrow.borrowed_place,
+ &issued_spans,
+ );
+ err
}
(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
@@ -1235,6 +1242,138 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
+ fn suggest_binding_for_closure_capture_self(
+ &self,
+ err: &mut Diagnostic,
+ borrowed_place: Place<'tcx>,
+ issued_spans: &UseSpans<'tcx>,
+ ) {
+ let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
+ let hir = self.infcx.tcx.hir();
+
+ // check whether the borrowed place is capturing `self` by mut reference
+ let local = borrowed_place.local;
+ let Some(_) = self
+ .body
+ .local_decls
+ .get(local)
+ .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
+
+ struct ExpressionFinder<'hir> {
+ capture_span: Span,
+ closure_change_spans: Vec<Span>,
+ closure_arg_span: Option<Span>,
+ in_closure: bool,
+ suggest_arg: String,
+ hir: rustc_middle::hir::map::Map<'hir>,
+ closure_local_id: Option<hir::HirId>,
+ closure_call_changes: Vec<(Span, String)>,
+ }
+ impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
+ fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
+ if e.span.contains(self.capture_span) {
+ if let hir::ExprKind::Closure(&hir::Closure {
+ movability: None,
+ body,
+ fn_arg_span,
+ fn_decl: hir::FnDecl{ inputs, .. },
+ ..
+ }) = e.kind &&
+ let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
+ self.suggest_arg = "this: &Self".to_string();
+ if inputs.len() > 0 {
+ self.suggest_arg.push_str(", ");
+ }
+ self.in_closure = true;
+ self.closure_arg_span = fn_arg_span;
+ self.visit_expr(body);
+ self.in_closure = false;
+ }
+ }
+ if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
+ if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
+ seg.ident.name == kw::SelfLower && self.in_closure {
+ self.closure_change_spans.push(e.span);
+ }
+ }
+ hir::intravisit::walk_expr(self, e);
+ }
+
+ fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
+ if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
+ let Some(init) = local.init
+ {
+ if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
+ movability: None,
+ ..
+ }), .. } = init &&
+ init.span.contains(self.capture_span) {
+ self.closure_local_id = Some(*hir_id);
+ }
+ }
+ hir::intravisit::walk_local(self, local);
+ }
+
+ fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
+ if let hir::StmtKind::Semi(e) = s.kind &&
+ let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
+ let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
+ let Res::Local(hir_id) = seg.res &&
+ Some(hir_id) == self.closure_local_id {
+ let (span, arg_str) = if args.len() > 0 {
+ (args[0].span.shrink_to_lo(), "self, ".to_string())
+ } else {
+ let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
+ (span, "(self)".to_string())
+ };
+ self.closure_call_changes.push((span, arg_str));
+ }
+ hir::intravisit::walk_stmt(self, s);
+ }
+ }
+
+ if let Some(hir::Node::ImplItem(
+ hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
+ )) = hir.find(self.mir_hir_id()) &&
+ let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
+ let mut finder = ExpressionFinder {
+ capture_span: *capture_kind_span,
+ closure_change_spans: vec![],
+ closure_arg_span: None,
+ in_closure: false,
+ suggest_arg: String::new(),
+ closure_local_id: None,
+ closure_call_changes: vec![],
+ hir,
+ };
+ finder.visit_expr(expr);
+
+ if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
+ return;
+ }
+
+ let mut sugg = vec![];
+ let sm = self.infcx.tcx.sess.source_map();
+
+ if let Some(span) = finder.closure_arg_span {
+ sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
+ }
+ for span in finder.closure_change_spans {
+ sugg.push((span, "this".to_string()));
+ }
+
+ for (span, suggest) in finder.closure_call_changes {
+ sugg.push((span, suggest));
+ }
+
+ err.multipart_suggestion_verbose(
+ "try explicitly pass `&Self` into the Closure as an argument",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
/// Returns the description of the root place for a conflicting borrow and the full
/// descriptions of the places that caused the conflict.
///
@@ -1418,6 +1557,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// and `move` will not help here.
(
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",
+ ),
+ (
+ Some(name),
BorrowExplanation::MustBeValidFor {
category:
category @ (ConstraintCategory::Return(_)
@@ -1436,6 +1590,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
category,
span,
&format!("`{}`", name),
+ "function",
),
(
name,
@@ -1716,7 +1871,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// We check that there's a single level of block nesting to ensure always correct
/// suggestions. If we don't, then we only provide a free-form message to avoid
- /// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`.
+ /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
/// We could expand the analysis to suggest hoising all of the relevant parts of
/// the users' code to make the code compile, but that could be too much.
struct NestedStatementVisitor {
@@ -1888,6 +2043,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some(err)
}
+ #[instrument(level = "debug", skip(self))]
fn report_escaping_closure_capture(
&mut self,
use_span: UseSpans<'tcx>,
@@ -1896,6 +2052,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
category: ConstraintCategory<'tcx>,
constraint_span: Span,
captured_var: &str,
+ scope: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use();
@@ -1926,8 +2083,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None => "closure",
};
- let mut err =
- self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
+ let mut err = self.cannot_capture_in_long_lived_closure(
+ args_span,
+ kind,
+ captured_var,
+ var_span,
+ scope,
+ );
err.span_suggestion_verbose(
sugg_span,
&format!(
@@ -1949,10 +2111,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
err.note(
"async blocks are not executed immediately and must either take a \
- reference or ownership of outside variables they use",
+ reference or ownership of outside variables they use",
);
} else {
- let msg = format!("function requires argument type to outlive `{}`", fr_name);
+ let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
err.span_note(constraint_span, &msg);
}
}
@@ -2031,7 +2193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut back_edge_stack = Vec::new();
predecessor_locations(self.body, location).for_each(|predecessor| {
- if location.dominates(predecessor, &self.dominators) {
+ if location.dominates(predecessor, self.dominators()) {
back_edge_stack.push(predecessor)
} else {
stack.push(predecessor);
@@ -2143,7 +2305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut has_predecessor = false;
predecessor_locations(self.body, location).for_each(|predecessor| {
- if location.dominates(predecessor, &self.dominators) {
+ if location.dominates(predecessor, self.dominators()) {
back_edge_stack.push(predecessor)
} else {
stack.push(predecessor);
@@ -2669,7 +2831,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Need to use the `rustc_middle::ty` types to compare against the
// `return_region`. Then use the `rustc_hir` type to get only
// the lifetime span.
- if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
+ if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind {
// With access to the lifetime, we can get
// the span of it.
arguments.push((*argument, lifetime.ident.span));
@@ -2690,7 +2852,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let return_ty = sig.output().skip_binder();
let mut return_span = fn_decl.output.span();
if let hir::FnRetTy::Return(ty) = &fn_decl.output {
- if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
+ if let hir::TyKind::Ref(lifetime, _) = ty.kind {
return_span = lifetime.ident.span;
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 304683618..209574709 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -77,7 +77,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
err.span_label(
var_or_use_span,
- format!("{}borrow later {}", borrow_desc, message),
+ format!("{borrow_desc}borrow later {message}"),
);
}
} else {
@@ -90,7 +90,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
let capture_kind_label = message;
err.span_label(
var_or_use_span,
- format!("{}borrow later {}", borrow_desc, capture_kind_label),
+ format!("{borrow_desc}borrow later {capture_kind_label}"),
);
err.span_label(path_span, path_label);
}
@@ -110,7 +110,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
};
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
- err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+ err.span_label(var_or_use_span, format!("{borrow_desc}{message}"));
} else {
// path_span must be `Some` as otherwise the if condition is true
let path_span = path_span.unwrap();
@@ -121,7 +121,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
let capture_kind_label = message;
err.span_label(
var_or_use_span,
- format!("{}borrow later {}", borrow_desc, capture_kind_label),
+ format!("{borrow_desc}borrow later {capture_kind_label}"),
);
err.span_label(path_span, path_label);
}
@@ -160,12 +160,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
match local_names[dropped_local] {
Some(local_name) if !local_decl.from_compiler_desugaring() => {
let message = format!(
- "{B}borrow might be used here, when `{LOC}` is dropped \
- and runs the {DTOR} for {TYPE}",
- B = borrow_desc,
- LOC = local_name,
- TYPE = type_desc,
- DTOR = dtor_desc
+ "{borrow_desc}borrow might be used here, when `{local_name}` is dropped \
+ and runs the {dtor_desc} for {type_desc}",
);
err.span_label(body.source_info(drop_loc).span, message);
@@ -180,18 +176,14 @@ impl<'tcx> BorrowExplanation<'tcx> {
err.span_label(
local_decl.source_info.span,
format!(
- "a temporary with access to the {B}borrow \
+ "a temporary with access to the {borrow_desc}borrow \
is created here ...",
- B = borrow_desc
),
);
let message = format!(
- "... and the {B}borrow might be used here, \
+ "... and the {borrow_desc}borrow might be used here, \
when that temporary is dropped \
- and runs the {DTOR} for {TYPE}",
- B = borrow_desc,
- TYPE = type_desc,
- DTOR = dtor_desc
+ and runs the {dtor_desc} for {type_desc}",
);
err.span_label(body.source_info(drop_loc).span, message);
@@ -249,20 +241,16 @@ impl<'tcx> BorrowExplanation<'tcx> {
err.span_label(
span,
format!(
- "{}requires that `{}` is borrowed for `{}`",
+ "{}requires that `{desc}` is borrowed for `{region_name}`",
category.description(),
- desc,
- region_name,
),
);
} else {
err.span_label(
span,
format!(
- "{}requires that {}borrow lasts for `{}`",
+ "{}requires that {borrow_desc}borrow lasts for `{region_name}`",
category.description(),
- borrow_desc,
- region_name,
),
);
};
@@ -270,7 +258,7 @@ 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"));
+ err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
}
}
}
@@ -296,15 +284,14 @@ impl<'tcx> BorrowExplanation<'tcx> {
if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime };
let msg = format!(
- "you can add a bound to the {}to make it last less than `'static` and match `{}`",
+ "you can add a bound to the {}to make it last less than `'static` and match `{region_name}`",
category.description(),
- region_name,
);
err.span_suggestion_verbose(
span.shrink_to_hi(),
&msg,
- format!(" + {}", suggestable_name),
+ format!(" + {suggestable_name}"),
Applicability::Unspecified,
);
}
@@ -444,6 +431,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// First span returned points to the location of the conflicting use
/// Second span if `Some` is returned in the case of closures and points
/// to the use of the path
+ #[instrument(level = "debug", skip(self))]
fn later_use_kind(
&self,
borrow: &BorrowData<'tcx>,
@@ -461,11 +449,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let block = &self.body.basic_blocks[location.block];
let kind = if let Some(&Statement {
- kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
+ kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)),
..
}) = block.statements.get(location.statement_index)
{
- LaterUseKind::FakeLetRead
+ if let Some(l) = place.as_local()
+ && let local_decl = &self.body.local_decls[l]
+ && local_decl.ty.is_closure()
+ {
+ LaterUseKind::ClosureCapture
+ } else {
+ LaterUseKind::FakeLetRead
+ }
} else if self.was_captured_by_trait_object(borrow) {
LaterUseKind::TraitCapture
} else if location.statement_index == block.statements.len() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
index 498e98343..2c4d953f0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::{Body, Local, Location};
/// Find all uses of (including assignments to) a [`Local`].
///
/// Uses `BTreeSet` so output is deterministic.
-pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet<Location> {
+pub(super) fn find(body: &Body<'_>, local: Local) -> BTreeSet<Location> {
let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() };
visitor.visit_body(body);
visitor.uses
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 4e2271a30..1b40b7143 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -6,7 +6,7 @@ use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::GeneratorKind;
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{LateBoundRegionConversionTime, TyCtxtInferExt};
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
@@ -18,7 +18,10 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
use rustc_span::def_id::LocalDefId;
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{
+ type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
+};
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
@@ -400,8 +403,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_prefix: &str,
) {
let message = format!(
- "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait",
- move_prefix, place_desc, ty,
+ "{move_prefix}move occurs because {place_desc} has type `{ty}`, which does not implement the `Copy` trait",
);
if let Some(span) = span {
err.span_label(span, message);
@@ -736,11 +738,11 @@ impl<'tcx> BorrowedContentSource<'tcx> {
BorrowedContentSource::OverloadedDeref(ty) => ty
.ty_adt_def()
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
- name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
_ => None,
})
- .unwrap_or_else(|| format!("dereference of `{}`", ty)),
- BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
+ .unwrap_or_else(|| format!("dereference of `{ty}`")),
+ BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"),
}
}
@@ -766,11 +768,11 @@ impl<'tcx> BorrowedContentSource<'tcx> {
BorrowedContentSource::OverloadedDeref(ty) => ty
.ty_adt_def()
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
- name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
_ => None,
})
- .unwrap_or_else(|| format!("dereference of `{}`", ty)),
- BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
+ .unwrap_or_else(|| format!("dereference of `{ty}`")),
+ BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"),
}
}
@@ -1030,7 +1032,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
let place_name = self
.describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
+ .map(|n| format!("`{n}`"))
.unwrap_or_else(|| "value".to_owned());
match kind {
CallKind::FnCall { fn_trait_id, .. }
@@ -1039,8 +1041,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label(
fn_call_span,
&format!(
- "{} {}moved due to this call{}",
- place_name, partially_str, loop_message
+ "{place_name} {partially_str}moved due to this call{loop_message}",
),
);
err.span_note(
@@ -1053,36 +1054,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label(
fn_call_span,
&format!(
- "{} {}moved due to usage in operator{}",
- place_name, partially_str, loop_message
+ "{place_name} {partially_str}moved due to usage in operator{loop_message}",
),
);
if self.fn_self_span_reported.insert(fn_span) {
err.span_note(
- // Check whether the source is accessible
- if self.infcx.tcx.sess.source_map().is_span_accessible(self_arg.span) {
- self_arg.span
- } else {
- fn_call_span
- },
+ self_arg.span,
"calling this operator moves the left-hand side",
);
}
}
- CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
+ CallKind::Normal { self_arg, desugaring, method_did } => {
let self_arg = self_arg.unwrap();
+ let tcx = self.infcx.tcx;
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
- let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
- let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
+ let ty = moved_place.ty(self.body, tcx).ty;
+ let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
Some(def_id) => {
let infcx = self.infcx.tcx.infer_ctxt().build();
type_known_to_meet_bound_modulo_regions(
&infcx,
self.param_env,
- infcx.tcx.mk_imm_ref(
- infcx.tcx.lifetimes.re_erased,
- infcx.tcx.erase_regions(ty),
- ),
+ tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
def_id,
DUMMY_SP,
)
@@ -1093,9 +1086,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_suggestion_verbose(
move_span.shrink_to_lo(),
&format!(
- "consider iterating over a slice of the `{}`'s content to \
+ "consider iterating over a slice of the `{ty}`'s content to \
avoid moving into the `for` loop",
- ty,
),
"&",
Applicability::MaybeIncorrect,
@@ -1105,8 +1097,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label(
fn_call_span,
&format!(
- "{} {}moved due to this implicit call to `.into_iter()`{}",
- place_name, partially_str, loop_message
+ "{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}",
),
);
// If the moved place was a `&mut` ref, then we can
@@ -1122,7 +1113,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&format!(
"consider creating a fresh reborrow of {} here",
self.describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
+ .map(|n| format!("`{n}`"))
.unwrap_or_else(|| "the mutable reference".to_string()),
),
"&mut *",
@@ -1134,19 +1125,67 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label(
fn_call_span,
&format!(
- "{} {}moved due to this method call{}",
- place_name, partially_str, loop_message
+ "{place_name} {partially_str}moved due to this method call{loop_message}",
),
);
+ let infcx = tcx.infer_ctxt().build();
+ let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
+ if let ty::Adt(def, substs) = ty.kind()
+ && Some(def.did()) == tcx.lang_items().pin_type()
+ && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
+ && let self_ty = infcx.replace_bound_vars_with_fresh_vars(
+ fn_call_span,
+ LateBoundRegionConversionTime::FnCall,
+ tcx.fn_sig(method_did).input(0),
+ )
+ && infcx.can_eq(self.param_env, ty, self_ty).is_ok()
+ {
+ err.span_suggestion_verbose(
+ fn_call_span.shrink_to_lo(),
+ "consider reborrowing the `Pin` instead of moving it",
+ "as_mut().".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if let Some(clone_trait) = tcx.lang_items().clone_trait()
+ && let trait_ref = tcx.mk_trait_ref(clone_trait, [ty])
+ && let o = Obligation::new(
+ tcx,
+ ObligationCause::dummy(),
+ self.param_env,
+ ty::Binder::dummy(trait_ref),
+ )
+ && infcx.predicate_must_hold_modulo_regions(&o)
+ {
+ err.span_suggestion_verbose(
+ fn_call_span.shrink_to_lo(),
+ "you can `clone` the value and consume it, but this might not be \
+ your desired behavior",
+ "clone().".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
+ let func = tcx.def_path_str(method_did);
err.span_note(
self_arg.span,
- &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
+ &format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}")
);
}
+ let parent_did = tcx.parent(method_did);
+ let parent_self_ty = (tcx.def_kind(parent_did)
+ == rustc_hir::def::DefKind::Impl)
+ .then_some(parent_did)
+ .and_then(|did| match tcx.type_of(did).kind() {
+ ty::Adt(def, ..) => Some(def.did()),
+ _ => None,
+ });
+ let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
+ matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
+ });
if is_option_or_result && maybe_reinitialized_locations_is_empty {
err.span_label(
var_span,
@@ -1161,7 +1200,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if move_span != span || !loop_message.is_empty() {
err.span_label(
move_span,
- format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
+ format!("value {partially_str}moved{move_msg} here{loop_message}"),
);
}
// If the move error occurs due to a loop, don't show
@@ -1169,7 +1208,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if loop_message.is_empty() {
move_spans.var_span_label(
err,
- format!("variable {}moved due to use{}", partially_str, move_spans.describe()),
+ format!("variable {partially_str}moved due to use{}", move_spans.describe()),
"moved",
);
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 5a47f4567..6db3c858a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -4,7 +4,7 @@ use rustc_middle::ty;
use rustc_mir_dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
};
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
use crate::prefixes::PrefixSet;
@@ -148,7 +148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
match_span: Span,
statement_span: Span,
) {
- debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span);
+ debug!(?match_place, ?match_span, "append_binding_error");
let from_simple_let = match_place.is_none();
let match_place = match_place.unwrap_or(move_from);
@@ -160,7 +160,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge
&& match_span == *span
{
- debug!("appending local({:?}) to list", bind_to);
+ debug!("appending local({bind_to:?}) to list");
if !binds_to.is_empty() {
binds_to.push(bind_to);
}
@@ -198,7 +198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} = ge
{
if match_span == *span && mpi == *other_mpi {
- debug!("appending local({:?}) to list", bind_to);
+ debug!("appending local({bind_to:?}) to list");
binds_to.push(bind_to);
return;
}
@@ -410,15 +410,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) {
match error {
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
- if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
- err.span_suggestion(
- span,
- "consider borrowing here",
- format!("&{snippet}"),
- Applicability::Unspecified,
- );
- }
-
+ self.add_borrow_suggestions(err, span);
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(move_from.as_ref()) {
@@ -461,39 +453,75 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
+ fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) {
+ match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
+ Ok(snippet) if snippet.starts_with('*') => {
+ err.span_suggestion_verbose(
+ span.with_hi(span.lo() + BytePos(1)),
+ "consider removing the dereference here",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ "consider borrowing here",
+ "&".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+
fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
- let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
+ let mut suggestions: Vec<(Span, String, String)> = Vec::new();
for local in binds_to {
let bind_to = &self.body.local_decls[*local];
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { pat_span, .. },
)))) = bind_to.local_info
{
- if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
+ let Ok(pat_snippet) =
+ self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };
+ let Some(stripped) = pat_snippet.strip_prefix('&') else {
+ suggestions.push((
+ bind_to.source_info.span.shrink_to_lo(),
+ "consider borrowing the pattern binding".to_string(),
+ "ref ".to_string(),
+ ));
+ continue;
+ };
+ let inner_pat_snippet = stripped.trim_start();
+ let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut")
+ && inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
{
- if let Some(stripped) = pat_snippet.strip_prefix('&') {
- let pat_snippet = stripped.trim_start();
- let (suggestion, to_remove) = if pat_snippet.starts_with("mut")
- && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
- {
- (pat_snippet["mut".len()..].trim_start(), "&mut")
- } else {
- (pat_snippet, "&")
- };
- suggestions.push((pat_span, to_remove, suggestion.to_owned()));
- }
- }
+ let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start();
+ let pat_span = pat_span.with_hi(
+ pat_span.lo()
+ + BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32),
+ );
+ (pat_span, String::new(), "mutable borrow")
+ } else {
+ let pat_span = pat_span.with_hi(
+ pat_span.lo()
+ + BytePos(
+ (pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32,
+ ),
+ );
+ (pat_span, String::new(), "borrow")
+ };
+ suggestions.push((
+ pat_span,
+ format!("consider removing the {to_remove}"),
+ suggestion.to_string(),
+ ));
}
}
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
suggestions.dedup_by_key(|&mut (span, _, _)| span);
- for (span, to_remove, suggestion) in suggestions {
- err.span_suggestion(
- span,
- &format!("consider removing the `{to_remove}`"),
- suggestion,
- Applicability::MachineApplicable,
- );
+ for (span, msg, suggestion) in suggestions {
+ err.span_suggestion_verbose(span, &msg, suggestion, Applicability::MachineApplicable);
}
}
@@ -521,8 +549,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if binds_to.len() > 1 {
err.note(
- "move occurs because these variables have types that \
- don't implement the `Copy` trait",
+ "move occurs because these variables have types that don't implement the `Copy` \
+ trait",
);
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 3319a8068..45b15c2c5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -180,6 +180,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// the verbs used in some diagnostic messages.
let act;
let acted_on;
+ let mut suggest = true;
+ let mut mut_error = None;
+ let mut count = 1;
let span = match error_access {
AccessKind::Mutate => {
@@ -194,15 +197,50 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let borrow_spans = self.borrow_spans(span, location);
let borrow_span = borrow_spans.args_or_use();
- err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason);
- borrow_spans.var_span_label(
- &mut err,
- format!(
- "mutable borrow occurs due to use of {} in closure",
- self.describe_any_place(access_place.as_ref()),
- ),
- "mutable",
- );
+ match the_place_err {
+ PlaceRef { local, projection: [] }
+ if self.body.local_decls[local].can_be_made_mutable() =>
+ {
+ let span = self.body.local_decls[local].source_info.span;
+ mut_error = Some(span);
+ if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
+ // We've encountered a second (or more) attempt to mutably borrow an
+ // immutable binding, so the likely problem is with the binding
+ // declaration, not the use. We collect these in a single diagnostic
+ // and make the binding the primary span of the error.
+ err = buffer;
+ count = c + 1;
+ if count == 2 {
+ err.replace_span_with(span, false);
+ err.span_label(span, "not mutable");
+ }
+ suggest = false;
+ } else {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ _ => {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ if suggest {
+ borrow_spans.var_span_label(
+ &mut err,
+ format!(
+ "mutable borrow occurs due to use of {} in closure",
+ self.describe_any_place(access_place.as_ref()),
+ ),
+ "mutable",
+ );
+ }
borrow_span
}
};
@@ -226,7 +264,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
ProjectionElem::Deref,
],
} => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
if let Some(span) = get_mut_span_in_struct_field(
self.infcx.tcx,
@@ -252,7 +290,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.unwrap_or(false) =>
{
let decl = &self.body.local_decls[local];
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
if let Some(mir::Statement {
source_info,
kind:
@@ -276,7 +314,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
pat_span: _,
},
)))) => {
- err.span_note(sp, "the binding is already a mutable borrow");
+ if suggest {
+ err.span_note(sp, "the binding is already a mutable borrow");
+ }
}
_ => {
err.span_note(
@@ -304,20 +344,25 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} else {
err.span_help(source_info.span, "try removing `&mut` here");
}
- } else if decl.mutability == Mutability::Not
- && !matches!(
+ } else if decl.mutability == Mutability::Not {
+ if matches!(
decl.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
hir::ImplicitSelfKind::MutRef
- ))))
- )
- {
- err.span_suggestion_verbose(
- decl.source_info.span.shrink_to_lo(),
- "consider making the binding mutable",
- "mut ",
- Applicability::MachineApplicable,
- );
+ ),)))
+ ) {
+ err.note(
+ "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
+ );
+ err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably");
+ } else {
+ err.span_suggestion_verbose(
+ decl.source_info.span.shrink_to_lo(),
+ "consider making the binding mutable",
+ "mut ",
+ Applicability::MachineApplicable,
+ );
+ };
}
}
@@ -333,16 +378,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let local_decl = &self.body.local_decls[local];
assert_eq!(local_decl.mutability, Mutability::Not);
- err.span_label(span, format!("cannot {ACT}", ACT = act));
- err.span_suggestion(
- local_decl.source_info.span,
- "consider changing this to be mutable",
- format!("mut {}", self.local_names[local].unwrap()),
- Applicability::MachineApplicable,
- );
- let tcx = self.infcx.tcx;
- if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
- self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ if count < 10 {
+ err.span_label(span, format!("cannot {act}"));
+ }
+ if suggest {
+ err.span_suggestion_verbose(
+ local_decl.source_info.span.shrink_to_lo(),
+ "consider changing this to be mutable",
+ "mut ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ let tcx = self.infcx.tcx;
+ if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
+ self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ }
}
}
@@ -357,7 +406,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let captured_place = &self.upvars[upvar_index.index()].place;
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
let upvar_hir_id = captured_place.get_root_variable();
@@ -397,7 +446,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.span_to_snippet(span)
.map_or(false, |snippet| snippet.starts_with("&mut ")) =>
{
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
err.span_suggestion(
span,
"try removing `&mut` here",
@@ -409,7 +458,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[local].is_ref_for_guard() =>
{
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
err.note(
"variables bound in patterns are immutable until the end of the pattern guard",
);
@@ -537,7 +586,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Some((true, err_help_span, suggested_code)) => {
let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
if !is_trait_sig {
- err.span_suggestion(
+ err.span_suggestion_verbose(
err_help_span,
&format!(
"consider changing this to be a mutable {pointer_desc}"
@@ -546,7 +595,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Applicability::MachineApplicable,
);
} else if let Some(x) = local_trait {
- err.span_suggestion(
+ err.span_suggestion_verbose(
x,
&format!(
"consider changing that to be a mutable {pointer_desc}"
@@ -569,24 +618,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.span_label(
span,
format!(
- "`{NAME}` is a `{SIGIL}` {DESC}, \
- so the data it refers to cannot be {ACTED_ON}",
- NAME = name,
- SIGIL = pointer_sigil,
- DESC = pointer_desc,
- ACTED_ON = acted_on
+ "`{name}` is a `{pointer_sigil}` {pointer_desc}, \
+ so the data it refers to cannot be {acted_on}",
),
);
}
_ => {
err.span_label(
span,
- format!(
- "cannot {ACT} through `{SIGIL}` {DESC}",
- ACT = act,
- SIGIL = pointer_sigil,
- DESC = pointer_desc
- ),
+ format!("cannot {act} through `{pointer_sigil}` {pointer_desc}"),
);
}
}
@@ -599,19 +639,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
match opt_source {
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
err.help(&format!(
"trait `DerefMut` is required to modify through a dereference, \
- but it is not implemented for `{ty}`",
+ but it is not implemented for `{ty}`",
));
}
Some(BorrowedContentSource::OverloadedIndex(ty)) => {
err.help(&format!(
"trait `IndexMut` is required to modify indexed content, \
- but it is not implemented for `{ty}`",
+ but it is not implemented for `{ty}`",
));
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
}
@@ -620,11 +660,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
_ => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
}
}
- self.buffer_error(err);
+ if let Some(span) = mut_error {
+ self.buffer_mut_error(span, err, count);
+ } else {
+ self.buffer_error(err);
+ }
}
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
@@ -965,7 +1009,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 fn_call_id = hir.parent_id(closure_id);
let node = hir.get(fn_call_id);
let def_id = hir.enclosing_body_owner(fn_call_id);
let mut look_at_return = true;
@@ -1050,7 +1094,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
-fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
+pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
match local_decl.local_info.as_deref() {
@@ -1168,7 +1212,7 @@ fn suggest_ampmut<'tcx>(
{
let lt_name = &src[1..ws_pos];
let ty = &src[ws_pos..];
- return (true, highlight_span, format!("&{} mut{}", lt_name, ty));
+ return (true, highlight_span, format!("&{lt_name} mut{ty}"));
}
let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
@@ -1209,7 +1253,7 @@ fn get_mut_span_in_struct_field<'tcx>(
// Now we're dealing with the actual struct that we're going to suggest a change to,
// we can expect a field that is an immutable reference to a type.
&& let hir::Node::Field(field) = node
- && let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
+ && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
{
return Some(lt.ident.span.between(ty.span));
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 35c3df768..1eaf0a2f1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -209,14 +209,14 @@ impl OutlivesSuggestionBuilder {
let mut diag = if suggested.len() == 1 {
mbcx.infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() {
SuggestedConstraint::Outlives(a, bs) => {
- let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect();
- format!("add bound `{}: {}`", a, bs.join(" + "))
+ let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
+ format!("add bound `{a}: {}`", bs.join(" + "))
}
SuggestedConstraint::Equal(a, b) => {
- format!("`{}` and `{}` must be the same: replace one with the other", a, b)
+ format!("`{a}` and `{b}` must be the same: replace one with the other")
}
- SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a),
+ SuggestedConstraint::Static(a) => format!("replace `{a}` with `'static`"),
})
} else {
// Create a new diagnostic.
@@ -231,18 +231,16 @@ impl OutlivesSuggestionBuilder {
for constraint in suggested {
match constraint {
SuggestedConstraint::Outlives(a, bs) => {
- let bs: SmallVec<[String; 2]> =
- bs.iter().map(|r| format!("{}", r)).collect();
- diag.help(&format!("add bound `{}: {}`", a, bs.join(" + ")));
+ let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
+ diag.help(&format!("add bound `{a}: {}`", bs.join(" + ")));
}
SuggestedConstraint::Equal(a, b) => {
diag.help(&format!(
- "`{}` and `{}` must be the same: replace one with the other",
- a, b
+ "`{a}` and `{b}` must be the same: replace one with the other",
));
}
SuggestedConstraint::Static(a) => {
- diag.help(&format!("replace `{}` with `'static`", a));
+ diag.help(&format!("replace `{a}` with `'static`"));
}
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 9bc2e79e2..187861ba1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -4,9 +4,14 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def::Res::Def;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, Item, ItemKind, Node};
+use rustc_hir::GenericBound::Trait;
+use rustc_hir::QPath::Resolved;
+use rustc_hir::WherePredicate::BoundPredicate;
+use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
use rustc_infer::infer::{
error_reporting::nice_region_error::{
self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
@@ -18,11 +23,11 @@ use rustc_infer::infer::{
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::Region;
use rustc_middle::ty::TypeVisitor;
use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_middle::ty::{Region, TyCtxt};
use rustc_span::symbol::{kw, Ident};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use crate::borrowck_errors;
use crate::session_diagnostics::{
@@ -70,7 +75,25 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
///
/// Usually we expect this to either be empty or contain a small number of items, so we can avoid
/// allocation most of the time.
-pub(crate) type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;
+pub(crate) struct RegionErrors<'tcx>(Vec<RegionErrorKind<'tcx>>, TyCtxt<'tcx>);
+
+impl<'tcx> RegionErrors<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+ Self(vec![], tcx)
+ }
+ #[track_caller]
+ pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
+ let val = val.into();
+ self.1.sess.delay_span_bug(DUMMY_SP, format!("{val:?}"));
+ self.0.push(val);
+ }
+ pub fn is_empty(&self) -> bool {
+ self.0.is_empty()
+ }
+ pub fn into_iter(self) -> impl Iterator<Item = RegionErrorKind<'tcx>> {
+ self.0.into_iter()
+ }
+}
#[derive(Clone, Debug)]
pub(crate) enum RegionErrorKind<'tcx> {
@@ -168,12 +191,109 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
false
}
+ // For generic associated types (GATs) which implied 'static requirement
+ // from higher-ranked trait bounds (HRTB). Try to locate span of the trait
+ // and the span which bounded to the trait for adding 'static lifetime suggestion
+ fn suggest_static_lifetime_for_gat_from_hrtb(
+ &self,
+ diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ lower_bound: RegionVid,
+ ) {
+ let mut suggestions = vec![];
+ let hir = self.infcx.tcx.hir();
+
+ // find generic associated types in the given region 'lower_bound'
+ let gat_id_and_generics = self
+ .regioncx
+ .placeholders_contained_in(lower_bound)
+ .map(|placeholder| {
+ if let Some(id) = placeholder.name.get_id()
+ && let Some(placeholder_id) = id.as_local()
+ && let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id)
+ && let Some(generics_impl) = hir.get_parent(gat_hir_id).generics()
+ {
+ Some((gat_hir_id, generics_impl))
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>();
+ debug!(?gat_id_and_generics);
+
+ // find higher-ranked trait bounds bounded to the generic associated types
+ let mut hrtb_bounds = vec![];
+ gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| {
+ for pred in generics.predicates {
+ let BoundPredicate(
+ WhereBoundPredicate {
+ bound_generic_params,
+ bounds,
+ ..
+ }) = pred else { continue; };
+ if bound_generic_params
+ .iter()
+ .rfind(|bgp| hir.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
+ .is_some()
+ {
+ for bound in *bounds {
+ hrtb_bounds.push(bound);
+ }
+ }
+ }
+ });
+ debug!(?hrtb_bounds);
+
+ hrtb_bounds.iter().for_each(|bound| {
+ let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
+ diag.span_note(
+ *trait_span,
+ format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")
+ );
+ let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; };
+ let Def(_, trait_res_defid) = trait_ref.path.res else { return; };
+ debug!(?generics_fn);
+ generics_fn.predicates.iter().for_each(|predicate| {
+ let BoundPredicate(
+ WhereBoundPredicate {
+ span: bounded_span,
+ bounded_ty,
+ bounds,
+ ..
+ }
+ ) = predicate else { return; };
+ bounds.iter().for_each(|bd| {
+ if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }, _) = bd
+ && let Def(_, res_defid) = tr_ref.path.res
+ && res_defid == trait_res_defid // trait id matches
+ && let TyKind::Path(Resolved(_, path)) = bounded_ty.kind
+ && let Def(_, defid) = path.res
+ && generics_fn.params
+ .iter()
+ .rfind(|param| param.def_id.to_def_id() == defid)
+ .is_some() {
+ suggestions.push((bounded_span.shrink_to_hi(), format!(" + 'static")));
+ }
+ });
+ });
+ });
+ if suggestions.len() > 0 {
+ suggestions.dedup();
+ diag.multipart_suggestion_verbose(
+ format!("consider restricting the type parameter to the `'static` lifetime"),
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
/// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
// Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
// buffered in the `MirBorrowckCtxt`.
let mut outlives_suggestion = OutlivesSuggestionBuilder::default();
+ let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> =
+ None;
for nll_error in nll_errors.into_iter() {
match nll_error {
@@ -203,12 +323,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// to report it; we could probably handle it by
// iterating over the universal regions and reporting
// an error that multiple bounds are required.
- self.buffer_error(self.infcx.tcx.sess.create_err(
- GenericDoesNotLiveLongEnough {
+ let mut diag =
+ self.infcx.tcx.sess.create_err(GenericDoesNotLiveLongEnough {
kind: type_test.generic_kind.to_string(),
span: type_test_span,
- },
- ));
+ });
+
+ // Add notes and suggestions for the case of 'static lifetime
+ // implied but not specified when a generic associated types
+ // are from higher-ranked trait bounds
+ self.suggest_static_lifetime_for_gat_from_hrtb(
+ &mut diag,
+ type_test.lower_bound,
+ );
+
+ self.buffer_error(diag);
}
}
@@ -216,13 +345,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
- self.buffer_error(unexpected_hidden_region_diagnostic(
+ let mut diag = unexpected_hidden_region_diagnostic(
self.infcx.tcx,
span,
named_ty,
named_region,
named_key,
- ));
+ );
+ if last_unexpected_hidden_region != Some((span, named_ty, named_key)) {
+ self.buffer_error(diag);
+ last_unexpected_hidden_region = Some((span, named_ty, named_key));
+ } else {
+ diag.delay_as_bug();
+ }
}
RegionErrorKind::BoundUniversalRegionError {
@@ -273,71 +408,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
outlives_suggestion.add_suggestion(self);
}
- fn get_impl_ident_and_self_ty_from_trait(
- &self,
- def_id: DefId,
- trait_objects: &FxIndexSet<DefId>,
- ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
- let tcx = self.infcx.tcx;
- match tcx.hir().get_if_local(def_id) {
- Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
- {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) => Some((impl_item.ident, self_ty)),
- _ => None,
- }
- }
- Some(Node::TraitItem(trait_item)) => {
- let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did.def_id) {
- Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
- // The method being called is defined in the `trait`, but the `'static`
- // obligation comes from the `impl`. Find that `impl` so that we can point
- // at it in the suggestion.
- let trait_did = trait_did.to_def_id();
- match tcx
- .hir()
- .trait_impls(trait_did)
- .iter()
- .filter_map(|&impl_did| {
- match tcx.hir().get_if_local(impl_did.to_def_id()) {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) if trait_objects.iter().all(|did| {
- // FIXME: we should check `self_ty` against the receiver
- // type in the `UnifyReceiver` context, but for now, use
- // this imperfect proxy. This will fail if there are
- // multiple `impl`s for the same trait like
- // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
- // In that case, only the first one will get suggestions.
- let mut traits = vec![];
- let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
- hir_v.visit_ty(self_ty);
- !traits.is_empty()
- }) =>
- {
- Some(self_ty)
- }
- _ => None,
- }
- })
- .next()
- {
- Some(self_ty) => Some((trait_item.ident, self_ty)),
- _ => None,
- }
- }
- _ => None,
- }
- }
- _ => None,
- }
- }
-
/// Report an error because the universal region `fr` was required to outlive
/// `outlived_fr` but it is not known to do so. For example:
///
@@ -461,7 +531,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
);
(desc, note)
}
- _ => panic!("Unexpected type {:?}", ty),
+ _ => panic!("Unexpected type {ty:?}"),
};
diag.note(&format!("requirement occurs because of {desc}",));
diag.note(&note);
@@ -472,7 +542,7 @@ 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"));
+ diag.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
}
}
}
@@ -504,7 +574,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
- if let ty::Opaque(def_id, _) = *output_ty.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() {
output_ty = self.infcx.tcx.type_of(def_id)
};
@@ -764,10 +834,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let lifetime = if f.has_name() { fr_name.name } else { kw::UnderscoreLifetime };
let arg = match param.param.pat.simple_ident() {
- Some(simple_ident) => format!("argument `{}`", simple_ident),
+ Some(simple_ident) => format!("argument `{simple_ident}`"),
None => "the argument".to_string(),
};
- let captures = format!("captures data from {}", arg);
+ let captures = format!("captures data from {arg}");
return nice_region_error::suggest_new_region_bound(
self.infcx.tcx,
@@ -777,6 +847,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Some(arg),
captures,
Some((param.param_ty_span, param.param_ty.to_string())),
+ self.infcx.tcx.is_suitable_region(f).map(|r| r.def_id),
);
}
}
@@ -832,7 +903,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
visitor.visit_ty(param.param_ty);
let Some((ident, self_ty)) =
- self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return};
+ NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &visitor.0) else { return; };
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 171e62d91..9233287cf 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -200,9 +200,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// increment the counter.
///
/// This is _not_ idempotent. Call `give_region_a_name` when possible.
- fn synthesize_region_name(&self) -> Symbol {
+ pub(crate) fn synthesize_region_name(&self) -> Symbol {
let c = self.next_region_name.replace_with(|counter| *counter + 1);
- Symbol::intern(&format!("'{:?}", c))
+ Symbol::intern(&format!("'{c:?}"))
}
/// Maps from an internal MIR region vid to something that we can
@@ -493,10 +493,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
//
// &
// - let's call the lifetime of this reference `'1`
- (
- ty::Ref(region, referent_ty, _),
- hir::TyKind::Rptr(_lifetime, referent_hir_ty),
- ) => {
+ (ty::Ref(region, referent_ty, _), hir::TyKind::Ref(_lifetime, referent_hir_ty)) => {
if region.to_region_vid() == needle_fr {
// Just grab the first character, the `&`.
let source_map = self.infcx.tcx.sess.source_map();
@@ -622,7 +619,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
// programs, so we need to use delay_span_bug here. See #82126.
self.infcx.tcx.sess.delay_span_bug(
hir_arg.span(),
- &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg),
+ &format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"),
);
}
}
@@ -786,8 +783,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
} else {
span_bug!(
hir_ty.span,
- "bounds from lowered return type of async fn did not match expected format: {:?}",
- opaque_ty
+ "bounds from lowered return type of async fn did not match expected format: {opaque_ty:?}",
);
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index b385f95b6..ada3310d8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -18,7 +18,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
upvars: &[Upvar<'tcx>],
fr: RegionVid,
) -> Option<(Option<Symbol>, Span)> {
- debug!("get_var_name_and_span_for_region(fr={:?})", fr);
+ debug!("get_var_name_and_span_for_region(fr={fr:?})");
assert!(self.universal_regions().is_universal_region(fr));
debug!("get_var_name_and_span_for_region: attempting upvar");
@@ -44,10 +44,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
) -> Option<usize> {
let upvar_index =
self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| {
- debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
+ debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}");
tcx.any_free_region_meets(&upvar_ty, |r| {
let r = r.to_region_vid();
- debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr);
+ debug!("get_upvar_index_for_region: r={r:?} fr={fr:?}");
r == fr
})
})?;
@@ -55,8 +55,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index);
debug!(
- "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}",
- fr, upvar_index, upvar_ty,
+ "get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}",
);
Some(upvar_index)
@@ -71,13 +70,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
upvar_index: usize,
) -> (Symbol, Span) {
let upvar_hir_id = upvars[upvar_index].place.get_root_variable();
- debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id);
+ debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}");
let upvar_name = tcx.hir().name(upvar_hir_id);
let upvar_span = tcx.hir().span(upvar_hir_id);
debug!(
- "get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}",
- upvar_name, upvar_span
+ "get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}",
);
(upvar_name, upvar_span)
@@ -97,15 +95,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let argument_index =
self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position(
|arg_ty| {
- debug!("get_argument_index_for_region: arg_ty = {:?}", arg_ty);
+ debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}");
tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
},
)?;
debug!(
- "get_argument_index_for_region: found {:?} in argument {} which has type {:?}",
- fr,
- argument_index,
+ "get_argument_index_for_region: found {fr:?} in argument {argument_index} which has type {:?}",
self.universal_regions().unnormalized_input_tys[argument_index],
);
@@ -122,13 +118,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
) -> (Option<Symbol>, Span) {
let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs();
let argument_local = Local::new(implicit_inputs + argument_index + 1);
- debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
+ debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}");
let argument_name = local_names[argument_local];
let argument_span = body.local_decls[argument_local].source_info.span;
debug!(
- "get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
- argument_name, argument_span
+ "get_argument_name_and_span_for_region: argument_name={argument_name:?} argument_span={argument_span:?}",
);
(argument_name, argument_span)
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index 51ed27c16..02ffb51fb 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -192,7 +192,7 @@ fn write_row(
) -> Result<(), Box<dyn Error>> {
for (index, c) in columns.iter().enumerate() {
let tail = if index == columns.len() - 1 { "\n" } else { "\t" };
- write!(out, "{:?}{}", c.to_string(location_table), tail)?;
+ write!(out, "{:?}{tail}", c.to_string(location_table))?;
}
Ok(())
}
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index f66a7ab3c..6fd929005 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -106,7 +106,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
self.check_activations(location);
match &terminator.kind {
- TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => {
+ TerminatorKind::SwitchInt { discr, targets: _ } => {
self.consume_operand(location, discr);
}
TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 74b4e4a0c..73ea7314b 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -5,6 +5,7 @@
#![feature(let_chains)]
#![feature(min_specialization)]
#![feature(never_type)]
+#![feature(once_cell)]
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
#![feature(trusted_step)]
@@ -39,6 +40,7 @@ use rustc_span::{Span, Symbol};
use either::Either;
use smallvec::SmallVec;
+use std::cell::OnceCell;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
@@ -124,10 +126,7 @@ pub fn provide(providers: &mut Providers) {
};
}
-fn mir_borrowck<'tcx>(
- tcx: TyCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx BorrowCheckResult<'tcx> {
+fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &BorrowCheckResult<'_> {
let (input_body, promoted) = tcx.mir_promoted(def);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
@@ -336,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
borrow_set: Rc::clone(&borrow_set),
- dominators: Dominators::dummy(), // not used
+ dominators: Default::default(),
upvars: Vec::new(),
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
region_names: RefCell::default(),
@@ -349,8 +348,6 @@ fn do_mir_borrowck<'tcx>(
};
}
- let dominators = body.basic_blocks.dominators();
-
let mut mbcx = MirBorrowckCtxt {
infcx,
param_env,
@@ -367,7 +364,7 @@ fn do_mir_borrowck<'tcx>(
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
borrow_set: Rc::clone(&borrow_set),
- dominators,
+ dominators: Default::default(),
upvars,
local_names,
region_names: RefCell::default(),
@@ -537,7 +534,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
borrow_set: Rc<BorrowSet<'tcx>>,
/// Dominators for MIR
- dominators: Dominators<BasicBlock>,
+ dominators: OnceCell<Dominators<BasicBlock>>,
/// Information about upvars not necessarily preserved in types or MIR
upvars: Vec<Upvar<'tcx>>,
@@ -644,7 +641,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
self.check_activations(loc, span, flow_state);
match &term.kind {
- TerminatorKind::SwitchInt { discr, switch_ty: _, targets: _ } => {
+ TerminatorKind::SwitchInt { discr, targets: _ } => {
self.consume_operand(loc, (discr, span), flow_state);
}
TerminatorKind::Drop { place, target: _, unwind: _ } => {
@@ -866,7 +863,6 @@ enum WriteKind {
/// local place can be mutated.
//
// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications:
-// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`.
// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and
// `is_declared_mutable()`.
// - Take flow state into consideration in `is_assignable()` for local variables.
@@ -1055,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
- if !is_active(&this.dominators, borrow, location) {
+ if !is_active(this.dominators(), borrow, location) {
assert!(allow_two_phase_borrow(borrow.kind));
return Control::Continue;
}
@@ -1135,20 +1131,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Write of P[i] or *P requires P init'd.
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
- // Special case: you can assign an immutable local variable
- // (e.g., `x = ...`) so long as it has never been initialized
- // before (at this point in the flow).
- if let Some(local) = place_span.0.as_local() {
- if let Mutability::Not = self.body.local_decls[local].mutability {
- // check for reassignments to immutable local variables
- self.check_if_reassignment_to_immutable_state(
- location, local, place_span, flow_state,
- );
- return;
- }
- }
-
- // Otherwise, use the normal access permission rules.
self.access_place(
location,
place_span,
@@ -1557,24 +1539,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
- fn check_if_reassignment_to_immutable_state(
- &mut self,
- location: Location,
- local: Local,
- place_span: (Place<'tcx>, Span),
- flow_state: &Flows<'cx, 'tcx>,
- ) {
- debug!("check_if_reassignment_to_immutable_state({:?})", local);
-
- // Check if any of the initializations of `local` have happened yet:
- if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
- // And, if so, report an error.
- let init = &self.move_data.inits[init_index];
- let span = init.span(&self.body);
- self.report_illegal_reassignment(location, place_span, span, place_span.0);
- }
- }
-
fn check_if_full_path_is_moved(
&mut self,
location: Location,
@@ -2040,12 +2004,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// partial initialization, do not complain about mutability
// errors except for actual mutation (as opposed to an attempt
// to do a partial initialization).
- let previously_initialized =
- self.is_local_ever_initialized(place.local, flow_state).is_some();
+ let previously_initialized = self.is_local_ever_initialized(place.local, flow_state);
// at this point, we have set up the error reporting state.
- if previously_initialized {
- self.report_mutability_error(place, span, the_place_err, error_access, location);
+ if let Some(init_index) = previously_initialized {
+ if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
+ // If this is a mutate access to an immutable local variable with no projections
+ // report the error as an illegal reassignment
+ let init = &self.move_data.inits[init_index];
+ let assigned_span = init.span(&self.body);
+ self.report_illegal_reassignment(location, (place, span), assigned_span, place);
+ } else {
+ self.report_mutability_error(place, span, the_place_err, error_access, location)
+ }
true
} else {
false
@@ -2059,12 +2030,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) -> Option<InitIndex> {
let mpi = self.move_data.rev_lookup.find_local(local);
let ii = &self.move_data.init_path_map[mpi];
- for &index in ii {
- if flow_state.ever_inits.contains(index) {
- return Some(index);
- }
- }
- None
+ ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied()
}
/// Adds the place into the used mutable variables set
@@ -2207,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// `self.foo` -- we want to double
// check that the location `*self`
// is mutable (i.e., this is not a
- // `Fn` closure). But if that
+ // `Fn` closure). But if that
// check succeeds, we want to
// *blame* the mutability on
// `place` (that is,
@@ -2253,6 +2219,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
}
+
+ fn dominators(&self) -> &Dominators<BasicBlock> {
+ self.dominators.get_or_init(|| self.body.basic_blocks.dominators())
+ }
}
mod error {
@@ -2278,6 +2248,7 @@ mod error {
/// same primary span come out in a consistent order.
buffered_move_errors:
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
+ buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
/// Diagnostics to be reported buffer.
buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck
@@ -2289,6 +2260,7 @@ mod error {
BorrowckErrors {
tcx,
buffered_move_errors: BTreeMap::new(),
+ buffered_mut_errors: Default::default(),
buffered: Default::default(),
tainted_by_errors: None,
}
@@ -2339,12 +2311,34 @@ mod error {
}
}
+ pub fn get_buffered_mut_error(
+ &mut self,
+ span: Span,
+ ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
+ self.errors.buffered_mut_errors.remove(&span)
+ }
+
+ pub fn buffer_mut_error(
+ &mut self,
+ span: Span,
+ t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ count: usize,
+ ) {
+ self.errors.buffered_mut_errors.insert(span, (t, count));
+ }
+
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it.
diag.buffer(&mut self.errors.buffered);
}
+ for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
+ if count > 10 {
+ diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+ }
+ diag.buffer(&mut self.errors.buffered);
+ }
if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs
index 9fa7e218b..288b7d85b 100644
--- a/compiler/rustc_borrowck/src/location.rs
+++ b/compiler/rustc_borrowck/src/location.rs
@@ -20,9 +20,8 @@ pub struct LocationTable {
}
rustc_index::newtype_index! {
- pub struct LocationIndex {
- DEBUG_FORMAT = "LocationIndex({})"
- }
+ #[debug_format = "LocationIndex({})"]
+ pub struct LocationIndex {}
}
#[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
index b5e00f471..4af324f74 100644
--- a/compiler/rustc_borrowck/src/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -55,9 +55,8 @@ pub(crate) struct NllMemberConstraint<'tcx> {
}
rustc_index::newtype_index! {
- pub(crate) struct NllMemberConstraintIndex {
- DEBUG_FORMAT = "MemberConstraintIndex({})"
- }
+ #[debug_format = "MemberConstraintIndex({})"]
+ pub(crate) struct NllMemberConstraintIndex {}
}
impl Default for MemberConstraintSet<'_, ty::RegionVid> {
@@ -110,7 +109,7 @@ where
R1: Copy + Hash + Eq,
{
/// Remap the "member region" key using `map_fn`, producing a new
- /// member constraint set. This is used in the NLL code to map from
+ /// member constraint set. This is used in the NLL code to map from
/// the original `RegionVid` to an scc index. In some cases, we
/// may have multiple `R1` values mapping to the same `R2` key -- that
/// is ok, the two sets will be merged.
@@ -159,7 +158,7 @@ where
}
/// Iterate down the constraint indices associated with a given
- /// peek-region. You can then use `choice_regions` and other
+ /// peek-region. You can then use `choice_regions` and other
/// methods to access data.
pub(crate) fn indices(
&self,
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index e379e6470..b2d92d0db 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -385,7 +385,7 @@ pub(super) fn dump_annotation<'tcx>(
// When the enclosing function is tagged with `#[rustc_regions]`,
// we dump out various bits of state as warnings. This is useful
- // for verifying that the compiler is behaving as expected. These
+ // for verifying that the compiler is behaving as expected. These
// warnings focus on the closure region requirements -- for
// viewing the intraprocedural state, the -Zdump-mir output is
// better.
diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs
index 9f6b1fdfc..85d207b2f 100644
--- a/compiler/rustc_borrowck/src/place_ext.rs
+++ b/compiler/rustc_borrowck/src/place_ext.rs
@@ -63,7 +63,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Not) => {
// For both derefs of raw pointers and `&T`
// references, the original path is `Copy` and
- // therefore not significant. In particular,
+ // therefore not significant. In particular,
// there is nothing the user can do to the
// original path that would invalidate the
// newly created reference -- and if there
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 89ac0dfa4..918fb2d69 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -209,7 +209,7 @@ fn place_components_conflict<'tcx>(
match (elem, &base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
- // The array length is like additional fields on the
+ // The array length is like additional fields on the
// type; it does not overlap any existing data there.
// Furthermore, if cannot actually be a prefix of any
// borrowed place (at least in MIR as it is currently.)
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 90e2b6b69..238172ea3 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -527,6 +527,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.scc_values.region_value_str(scc)
}
+ pub(crate) fn placeholders_contained_in<'a>(
+ &'a self,
+ r: RegionVid,
+ ) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
+ let scc = self.constraint_sccs.scc(r.to_region_vid());
+ self.scc_values.placeholders_contained_in(scc)
+ }
+
/// Returns access to the value of `r` for debugging purposes.
pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex {
let scc = self.constraint_sccs.scc(r.to_region_vid());
@@ -562,7 +570,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let mir_def_id = body.source.def_id();
self.propagate_constraints(body);
- let mut errors_buffer = RegionErrors::new();
+ let mut errors_buffer = RegionErrors::new(infcx.tcx);
// If this is a closure, we can propagate unsatisfied
// `outlives_requirements` to our creator, so create a vector
@@ -680,7 +688,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// enforce the constraint).
///
/// The current value of `scc` at the time the method is invoked
- /// is considered a *lower bound*. If possible, we will modify
+ /// is considered a *lower bound*. If possible, we will modify
/// the constraint to set it equal to one of the option regions.
/// If we make any changes, returns true, else false.
#[instrument(skip(self, member_constraint_index), level = "debug")]
@@ -747,27 +755,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Otherwise, we need to find the minimum remaining choice, if
// any, and take that.
debug!("choice_regions remaining are {:#?}", choice_regions);
- let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
- let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
- let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
- match (r1_outlives_r2, r2_outlives_r1) {
- (true, true) => Some(r1.min(r2)),
- (true, false) => Some(r2),
- (false, true) => Some(r1),
- (false, false) => None,
- }
+ let Some(&min_choice) = choice_regions.iter().find(|&r1| {
+ choice_regions.iter().all(|&r2| {
+ self.universal_region_relations.outlives(r2, *r1)
+ })
+ }) else {
+ debug!("no choice region outlived by all others");
+ return false;
};
- let mut min_choice = choice_regions[0];
- for &other_option in &choice_regions[1..] {
- debug!(?min_choice, ?other_option,);
- match min(min_choice, other_option) {
- Some(m) => min_choice = m,
- None => {
- debug!(?min_choice, ?other_option, "incomparable; no min choice",);
- return false;
- }
- }
- }
let min_choice_scc = self.constraint_sccs.scc(min_choice);
debug!(?min_choice, ?min_choice_scc);
@@ -844,7 +839,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if self.eval_verify_bound(
infcx,
param_env,
- body,
generic_ty,
type_test.lower_bound,
&type_test.verify_bound,
@@ -973,16 +967,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
//
// This is needed because -- particularly in the case
// where `ur` is a local bound -- we are sometimes in a
- // position to prove things that our caller cannot. See
+ // position to prove things that our caller cannot. See
// #53570 for an example.
- if self.eval_verify_bound(
- infcx,
- param_env,
- body,
- generic_ty,
- ur,
- &type_test.verify_bound,
- ) {
+ if self.eval_verify_bound(infcx, param_env, generic_ty, ur, &type_test.verify_bound) {
continue;
}
@@ -1203,7 +1190,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self,
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body: &Body<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
verify_bound: &VerifyBound<'tcx>,
@@ -1226,25 +1212,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
- self.eval_verify_bound(
- infcx,
- param_env,
- body,
- generic_ty,
- lower_bound,
- verify_bound,
- )
+ self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
}),
VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
- self.eval_verify_bound(
- infcx,
- param_env,
- body,
- generic_ty,
- lower_bound,
- verify_bound,
- )
+ self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
}),
}
}
@@ -1683,26 +1655,29 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,);
- // If we have some bound universal region `'a`, then the only
- // elements it can contain is itself -- we don't know anything
- // else about it!
- let Some(error_element) = ({
- self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element {
- RegionElement::Location(_) => true,
- RegionElement::RootUniversalRegion(_) => true,
- RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
- })
- }) else {
- return;
- };
- debug!("check_bound_universal_region: error_element = {:?}", error_element);
+ for error_element in self.scc_values.elements_contained_in(longer_fr_scc) {
+ match error_element {
+ RegionElement::Location(_) | RegionElement::RootUniversalRegion(_) => {}
+ // If we have some bound universal region `'a`, then the only
+ // elements it can contain is itself -- we don't know anything
+ // else about it!
+ RegionElement::PlaceholderRegion(placeholder1) => {
+ if placeholder == placeholder1 {
+ continue;
+ }
+ }
+ }
- // Find the region that introduced this `error_element`.
- errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
- longer_fr,
- error_element,
- placeholder,
- });
+ errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
+ longer_fr,
+ error_element,
+ placeholder,
+ });
+
+ // Stop after the first error, it gets too noisy otherwise, and does not provide more information.
+ break;
+ }
+ debug!("check_bound_universal_region: all bounds satisfied");
}
#[instrument(level = "debug", skip(self, infcx, errors_buffer))]
@@ -2068,7 +2043,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// '5: '6 ('6 is the target)
//
// Some of those regions are unified with `'6` (in the same
- // SCC). We want to screen those out. After that point, the
+ // SCC). We want to screen those out. After that point, the
// "closest" constraint we have to the end is going to be the
// most likely to be the point where the value escapes -- but
// we still want to screen for an "interesting" point to
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 516a08077..db5a67a8b 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -12,6 +12,8 @@ use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::ObligationCtxt;
+use crate::session_diagnostics::NonGenericOpaqueTypeParam;
+
use super::RegionInferenceContext;
impl<'tcx> RegionInferenceContext<'tcx> {
@@ -235,7 +237,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// # Parameters
///
/// - `def_id`, the `impl Trait` type
- /// - `substs`, the substs used to instantiate this opaque type
+ /// - `substs`, the substs used to instantiate this opaque type
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
/// `opaque_defn.concrete_ty`
#[instrument(level = "debug", skip(self))]
@@ -262,7 +264,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
return self.tcx.ty_error();
}
- // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
+ // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
let OpaqueTyOrigin::TyAlias = origin else {
return definition_ty;
@@ -318,7 +320,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
// tests to pass
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ let _ = infcx.take_opaque_types();
if errors.is_empty() {
definition_ty
@@ -389,17 +391,13 @@ fn check_opaque_type_parameter_valid(
} else {
// Prevent `fn foo() -> Foo<u32>` from being defining.
let opaque_param = opaque_generics.param_at(i, tcx);
- tcx.sess
- .struct_span_err(span, "non-defining opaque type use in defining scope")
- .span_note(
- tcx.def_span(opaque_param.def_id),
- &format!(
- "used non-generic {} `{}` for generic parameter",
- opaque_param.kind.descr(),
- arg,
- ),
- )
- .emit();
+ let kind = opaque_param.kind.descr();
+ tcx.sess.emit_err(NonGenericOpaqueTypeParam {
+ ty: arg,
+ kind,
+ span,
+ param_span: tcx.def_span(opaque_param.def_id),
+ });
return false;
}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 7498ddccf..c3dfeedc2 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -90,12 +90,14 @@ impl RegionValueElements {
rustc_index::newtype_index! {
/// A single integer representing a `Location` in the MIR control-flow
/// graph. Constructed efficiently from `RegionValueElements`.
- pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" }
+ #[debug_format = "PointIndex({})"]
+ pub struct PointIndex {}
}
rustc_index::newtype_index! {
/// A single integer representing a `ty::Placeholder`.
- pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
+ #[debug_format = "PlaceholderIndex({})"]
+ pub struct PlaceholderIndex {}
}
/// An individual element in a region value -- the value of a
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 577332c07..23acf1592 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -1,6 +1,6 @@
use rustc_errors::{IntoDiagnosticArg, MultiSpan};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{GenericArg, Ty};
use rustc_span::Span;
use crate::diagnostics::RegionName;
@@ -240,3 +240,14 @@ pub(crate) struct MoveBorrow<'a> {
#[label]
pub borrow_span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")]
+pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
+ pub ty: GenericArg<'tcx>,
+ pub kind: &'a str,
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub param_span: Span,
+}
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 3617bf58b..11729e2c8 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -1,13 +1,13 @@
use std::fmt;
-use rustc_infer::infer::canonical::Canonical;
-use rustc_infer::traits::query::NoSolution;
+use rustc_infer::infer::{canonical::Canonical, InferOk};
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
use rustc_span::def_id::DefId;
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
-use rustc_trait_selection::traits::query::Fallible;
+use rustc_trait_selection::traits::query::{Fallible, NoSolution};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
@@ -107,11 +107,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
locations: Locations,
) {
- for (predicate, span) in instantiated_predicates
- .predicates
- .into_iter()
- .zip(instantiated_predicates.spans.into_iter())
- {
+ for (predicate, span) in instantiated_predicates {
debug!(?predicate);
let category = ConstraintCategory::Predicate(span);
let predicate = self.normalize_with_category(predicate, locations, category);
@@ -177,4 +173,74 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
value
})
}
+
+ #[instrument(skip(self), level = "debug")]
+ pub(super) fn ascribe_user_type(
+ &mut self,
+ mir_ty: Ty<'tcx>,
+ user_ty: ty::UserType<'tcx>,
+ span: Span,
+ ) {
+ // FIXME: Ideally MIR types are normalized, but this is not always true.
+ let mir_ty = self.normalize(mir_ty, Locations::All(span));
+
+ self.fully_perform_op(
+ Locations::All(span),
+ ConstraintCategory::Boring,
+ self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
+ )
+ .unwrap_or_else(|err| {
+ span_mirbug!(
+ self,
+ span,
+ "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
+ );
+ });
+ }
+
+ /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
+ ///
+ /// FIXME(#104478, #104477): This is a hack for backward-compatibility.
+ #[instrument(skip(self), level = "debug")]
+ pub(super) fn ascribe_user_type_skip_wf(
+ &mut self,
+ mir_ty: Ty<'tcx>,
+ user_ty: ty::UserType<'tcx>,
+ span: Span,
+ ) {
+ let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
+
+ // A fast path for a common case with closure input/output types.
+ if let ty::Infer(_) = user_ty.kind() {
+ self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring)
+ .unwrap();
+ return;
+ }
+
+ let mir_ty = self.normalize(mir_ty, Locations::All(span));
+ let cause = ObligationCause::dummy_with_span(span);
+ let param_env = self.param_env;
+ let op = |infcx: &'_ _| {
+ let ocx = ObligationCtxt::new_in_snapshot(infcx);
+ let user_ty = ocx.normalize(&cause, param_env, user_ty);
+ ocx.eq(&cause, param_env, user_ty, mir_ty)?;
+ if !ocx.select_all_or_error().is_empty() {
+ return Err(NoSolution);
+ }
+ Ok(InferOk { value: (), obligations: vec![] })
+ };
+
+ self.fully_perform_op(
+ Locations::All(span),
+ ConstraintCategory::Boring,
+ type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()),
+ )
+ .unwrap_or_else(|err| {
+ span_mirbug!(
+ self,
+ span,
+ "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
+ );
+ });
+ }
}
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index ce7f857e2..e15d1b99a 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -107,7 +107,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
closure_substs: ty::SubstsRef<'tcx>,
) {
// Extract the values of the free regions in `closure_substs`
- // into a vector. These are the regions that we will be
+ // into a vector. These are the regions that we will be
// relating to one another.
let closure_mapping = &UniversalRegions::closure_mapping(
self.tcx,
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 14cfc3613..82ff86247 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -85,7 +85,7 @@ impl UniversalRegionRelations<'_> {
/// outlives `fr` and (b) is not local.
///
/// (*) If there are multiple competing choices, we return all of them.
- pub(crate) fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec<RegionVid> {
+ pub(crate) fn non_local_upper_bounds(&self, fr: RegionVid) -> Vec<RegionVid> {
debug!("non_local_upper_bound(fr={:?})", fr);
let res = self.non_local_bounds(&self.inverse_outlives, fr);
assert!(!res.is_empty(), "can't find an upper bound!?");
@@ -98,7 +98,7 @@ impl UniversalRegionRelations<'_> {
let upper_bounds = self.non_local_upper_bounds(fr);
// In case we find more than one, reduce to one for
- // convenience. This is to prevent us from generating more
+ // convenience. This is to prevent us from generating more
// complex constraints, but it will cause spurious errors.
let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds);
@@ -128,7 +128,7 @@ impl UniversalRegionRelations<'_> {
let lower_bounds = self.non_local_bounds(&self.outlives, fr);
// In case we find more than one, reduce to one for
- // convenience. This is to prevent us from generating more
+ // convenience. This is to prevent us from generating more
// complex constraints, but it will cause spurious errors.
let post_dom = self.outlives.mutual_immediate_postdominator(lower_bounds);
@@ -148,9 +148,9 @@ impl UniversalRegionRelations<'_> {
/// Helper for `non_local_upper_bounds` and `non_local_lower_bounds`.
/// Repeatedly invokes `postdom_parent` until we find something that is not
/// local. Returns `None` if we never do so.
- fn non_local_bounds<'a>(
+ fn non_local_bounds(
&self,
- relation: &'a TransitiveRelation<RegionVid>,
+ relation: &TransitiveRelation<RegionVid>,
fr0: RegionVid,
) -> Vec<RegionVid> {
// This method assumes that `fr0` is one of the universally
@@ -359,14 +359,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
}
- OutlivesBound::RegionSubProjection(r_a, projection_b) => {
+ OutlivesBound::RegionSubAlias(r_a, alias_b) => {
self.region_bound_pairs
- .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
- }
-
- OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
- self.region_bound_pairs
- .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+ .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
}
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 62c6f9581..fa9ea769a 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -10,7 +10,7 @@
use rustc_index::vec::Idx;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
use crate::universal_regions::UniversalRegions;
@@ -18,6 +18,52 @@ use crate::universal_regions::UniversalRegions;
use super::{Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
+ /// Check explicit closure signature annotation,
+ /// e.g., `|x: FxHashMap<_, &'static u32>| ...`.
+ #[instrument(skip(self, body), level = "debug")]
+ pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
+ let mir_def_id = body.source.def_id().expect_local();
+ if !self.tcx().is_closure(mir_def_id.to_def_id()) {
+ return;
+ }
+ let Some(user_provided_poly_sig) =
+ self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id)
+ else {
+ return;
+ };
+
+ // Instantiate the canonicalized variables from user-provided signature
+ // (e.g., the `_` in the code above) with fresh variables.
+ // Then replace the bound items in the fn sig with fresh variables,
+ // so that they represent the view from "inside" the closure.
+ let user_provided_sig = self
+ .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
+ let user_provided_sig = self.infcx.replace_bound_vars_with_fresh_vars(
+ body.span,
+ LateBoundRegionConversionTime::FnCall,
+ user_provided_sig,
+ );
+
+ for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip(
+ // In MIR, closure args begin with an implicit `self`. Skip it!
+ body.args_iter().skip(1).map(|local| &body.local_decls[local]),
+ ) {
+ self.ascribe_user_type_skip_wf(
+ arg_decl.ty,
+ ty::UserType::Ty(user_ty),
+ arg_decl.source_info.span,
+ );
+ }
+
+ // If the user explicitly annotated the output type, enforce it.
+ let output_decl = &body.local_decls[RETURN_PLACE];
+ self.ascribe_user_type_skip_wf(
+ output_decl.ty,
+ ty::UserType::Ty(user_provided_sig.output()),
+ output_decl.source_info.span,
+ );
+ }
+
#[instrument(skip(self, body, universal_regions), level = "debug")]
pub(super) fn equate_inputs_and_outputs(
&mut self,
@@ -31,40 +77,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
debug!(?normalized_output_ty);
debug!(?normalized_input_tys);
- let mir_def_id = body.source.def_id().expect_local();
-
- // If the user explicitly annotated the input types, extract
- // those.
- //
- // e.g., `|x: FxHashMap<_, &'static u32>| ...`
- let user_provided_sig;
- if !self.tcx().is_closure(mir_def_id.to_def_id()) {
- user_provided_sig = None;
- } else {
- let typeck_results = self.tcx().typeck(mir_def_id);
- user_provided_sig =
- typeck_results.user_provided_sigs.get(&mir_def_id).map(|user_provided_poly_sig| {
- // Instantiate the canonicalized variables from
- // user-provided signature (e.g., the `_` in the code
- // above) with fresh variables.
- let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
- body.span,
- &user_provided_poly_sig,
- );
-
- // Replace the bound items in the fn sig with fresh
- // variables, so that they represent the view from
- // "inside" the closure.
- self.infcx.replace_bound_vars_with_fresh_vars(
- body.span,
- LateBoundRegionConversionTime::FnCall,
- poly_sig,
- )
- });
- }
-
- debug!(?normalized_input_tys, ?body.local_decls);
-
// Equate expected input tys with those in the MIR.
for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
if argument_index + 1 >= body.local_decls.len() {
@@ -87,28 +99,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
- if let Some(user_provided_sig) = user_provided_sig {
- for (argument_index, &user_provided_input_ty) in
- user_provided_sig.inputs().iter().enumerate()
- {
- // In MIR, closures begin an implicit `self`, so
- // argument N is stored in local N+2.
- let local = Local::new(argument_index + 2);
- let mir_input_ty = body.local_decls[local].ty;
- let mir_input_span = body.local_decls[local].source_info.span;
-
- // If the user explicitly annotated the input types, enforce those.
- let user_provided_input_ty =
- self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
-
- self.equate_normalized_input_or_output(
- user_provided_input_ty,
- mir_input_ty,
- mir_input_span,
- );
- }
- }
-
debug!(
"equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
body.yield_ty(),
@@ -154,29 +144,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
terr
);
};
-
- // If the user explicitly annotated the output types, enforce those.
- // Note that this only happens for closures.
- if let Some(user_provided_sig) = user_provided_sig {
- let user_provided_output_ty = user_provided_sig.output();
- let user_provided_output_ty =
- self.normalize(user_provided_output_ty, Locations::All(output_span));
- if let Err(err) = self.eq_types(
- user_provided_output_ty,
- mir_output_ty,
- Locations::All(output_span),
- ConstraintCategory::BoringNoLocation,
- ) {
- span_mirbug!(
- self,
- Location::START,
- "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
- mir_output_ty,
- user_provided_output_ty,
- err
- );
- }
- }
}
#[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index fda2cee43..8023ef60d 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -46,7 +46,7 @@ struct Appearance {
}
rustc_index::newtype_index! {
- pub struct AppearanceIndex { .. }
+ pub struct AppearanceIndex {}
}
impl vll::LinkElem for Appearance {
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 42b577175..3ff5d188a 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -328,7 +328,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
debug_assert!(self.drop_live_at.contains(term_point));
// Otherwise, scan backwards through the statements in the
- // block. One of them may be either a definition or use
+ // block. One of them may be either a definition or use
// live point.
let term_location = self.cx.elements.to_location(term_point);
debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 6d4ec6b72..81bd4c2a7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -38,7 +38,6 @@ use rustc_middle::ty::{
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -197,6 +196,8 @@ pub(crate) fn type_check<'mir, 'tcx>(
}
checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
+ checker.check_signature_annotation(&body);
+
liveness::generate(
&mut checker,
body,
@@ -208,7 +209,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
);
translate_outlives_facts(&mut checker);
- let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ let opaque_type_values = infcx.take_opaque_types();
let opaque_type_values = opaque_type_values
.into_iter()
@@ -391,23 +392,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
check_err(self, promoted_body, ty, promoted_ty);
}
} else {
- if let Err(terr) = self.cx.fully_perform_op(
- locations,
- ConstraintCategory::Boring,
- self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
- constant.literal.ty(),
+ self.cx.ascribe_user_type(
+ constant.literal.ty(),
+ UserType::TypeOf(
uv.def.did,
UserSubsts { substs: uv.substs, user_self_ty: None },
- )),
- ) {
- span_mirbug!(
- self,
- constant,
- "bad constant type {:?} ({:?})",
- constant,
- terr
- );
- }
+ ),
+ locations.span(&self.cx.body),
+ );
}
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
let unnormalized_ty = tcx.type_of(static_def_id);
@@ -612,7 +604,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
let locations = location.to_locations();
for constraint in constraints.outlives().iter() {
- let mut constraint = constraint.clone();
+ let mut constraint = *constraint;
constraint.locations = locations;
if let ConstraintCategory::Return(_)
| ConstraintCategory::UseAsConst
@@ -1041,58 +1033,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
debug!(?self.user_type_annotations);
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
- let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
- debug!(?annotation);
- match annotation {
- UserType::Ty(mut ty) => {
- ty = self.normalize(ty, Locations::All(span));
-
- if let Err(terr) = self.eq_types(
- ty,
- inferred_ty,
- Locations::All(span),
- ConstraintCategory::BoringNoLocation,
- ) {
- span_mirbug!(
- self,
- user_annotation,
- "bad user type ({:?} = {:?}): {:?}",
- ty,
- inferred_ty,
- terr
- );
- }
-
- self.prove_predicate(
- ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into())),
- Locations::All(span),
- ConstraintCategory::TypeAnnotation,
- );
- }
- UserType::TypeOf(def_id, user_substs) => {
- if let Err(terr) = self.fully_perform_op(
- Locations::All(span),
- ConstraintCategory::BoringNoLocation,
- self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
- inferred_ty,
- def_id,
- user_substs,
- )),
- ) {
- span_mirbug!(
- self,
- user_annotation,
- "bad user type AscribeUserType({:?}, {:?} {:?}, type_of={:?}): {:?}",
- inferred_ty,
- def_id,
- user_substs,
- self.tcx().type_of(def_id),
- terr,
- );
- }
- }
- }
+ self.ascribe_user_type(inferred_ty, annotation, span);
}
}
@@ -1153,16 +1095,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
category: ConstraintCategory<'tcx>,
) -> Fallible<()> {
let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
+ trace!(?annotated_type);
let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
let tcx = self.infcx.tcx;
for proj in &user_ty.projs {
+ if let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind() {
+ // There is nothing that we can compare here if we go through an opaque type.
+ // We're always in its defining scope as we can otherwise not project through
+ // it, so we're constraining it anyways.
+ return Ok(());
+ }
let projected_ty = curr_projected_ty.projection_ty_core(
tcx,
self.param_env,
proj,
- |this, field, _| {
+ |this, field, ()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
},
@@ -1170,10 +1119,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
curr_projected_ty = projected_ty;
}
- debug!(
- "user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
- user_ty.base, annotated_type, user_ty.projs, curr_projected_ty
- );
+ trace!(?curr_projected_ty);
let ty = curr_projected_ty.ty;
self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?;
@@ -1360,25 +1306,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
}
- TerminatorKind::SwitchInt { discr, switch_ty, .. } => {
+ TerminatorKind::SwitchInt { discr, .. } => {
self.check_operand(discr, term_location);
- let discr_ty = discr.ty(body, tcx);
- if let Err(terr) = self.sub_types(
- discr_ty,
- *switch_ty,
- term_location.to_locations(),
- ConstraintCategory::Assignment,
- ) {
- span_mirbug!(
- self,
- term,
- "bad SwitchInt ({:?} on {:?}): {:?}",
- switch_ty,
- discr_ty,
- terr
- );
- }
+ let switch_ty = discr.ty(body, tcx);
if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() {
span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty);
}
@@ -1734,7 +1665,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) {
let tcx = self.tcx();
- // Erase the regions from `ty` to get a global type. The
+ // Erase the regions from `ty` to get a global type. The
// `Sized` bound in no way depends on precise regions, so this
// shouldn't affect `is_sized`.
let erased_ty = tcx.erase_regions(ty);
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index a4a0c5b90..5b4d99682 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -637,7 +637,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap();
// The "inputs" of the closure in the
- // signature appear as a tuple. The MIR side
+ // signature appear as a tuple. The MIR side
// flattens this tuple.
let (&output, tuplized_inputs) =
inputs_and_output.skip_binder().split_last().unwrap();