summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:43 +0000
commit3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245 (patch)
treedaf049b282ab10e8c3d03e409b3cd84ff3f7690c /compiler/rustc_borrowck
parentAdding debian version 1.68.2+dfsg1-1. (diff)
downloadrustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.tar.xz
rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.zip
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_borrowck')
-rw-r--r--compiler/rustc_borrowck/locales/en-US.ftl129
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/constraint_generation.rs4
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs16
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs45
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs33
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs52
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs72
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs104
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs40
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs3
-rw-r--r--compiler/rustc_borrowck/src/lib.rs118
-rw-r--r--compiler/rustc_borrowck/src/nll.rs46
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs262
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs67
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs5
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs71
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs18
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs11
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs20
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs181
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs6
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs100
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs63
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs189
30 files changed, 1102 insertions, 582 deletions
diff --git a/compiler/rustc_borrowck/locales/en-US.ftl b/compiler/rustc_borrowck/locales/en-US.ftl
new file mode 100644
index 000000000..a3b6b5e81
--- /dev/null
+++ b/compiler/rustc_borrowck/locales/en-US.ftl
@@ -0,0 +1,129 @@
+borrowck_move_unsized =
+ cannot move a value of type `{$ty}`
+ .label = the size of `{$ty}` cannot be statically determined
+
+borrowck_higher_ranked_lifetime_error =
+ higher-ranked lifetime error
+
+borrowck_could_not_prove =
+ could not prove `{$predicate}`
+
+borrowck_could_not_normalize =
+ could not normalize `{$value}`
+
+borrowck_higher_ranked_subtype_error =
+ higher-ranked subtype error
+
+borrowck_generic_does_not_live_long_enough =
+ `{$kind}` does not live long enough
+
+borrowck_move_borrowed =
+ cannot move out of `{$desc}` because it is borrowed
+
+borrowck_var_does_not_need_mut =
+ variable does not need to be mutable
+ .suggestion = remove this `mut`
+
+borrowck_var_cannot_escape_closure =
+ captured variable cannot escape `FnMut` closure body
+ .note = `FnMut` closures only have access to their captured variables while they are executing...
+ .cannot_escape = ...therefore, they cannot allow references to captured variables to escape
+
+borrowck_var_here_defined = variable defined here
+
+borrowck_var_here_captured = variable captured here
+
+borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
+
+borrowck_returned_closure_escaped =
+ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+
+borrowck_returned_async_block_escaped =
+ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
+
+borrowck_returned_ref_escaped =
+ returns a reference to a captured variable which escapes the closure body
+
+borrowck_lifetime_constraints_error =
+ lifetime may not live long enough
+
+borrowck_returned_lifetime_wrong =
+ {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`
+
+borrowck_returned_lifetime_short =
+ {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`
+
+borrowck_used_impl_require_static =
+ the used `impl` has a `'static` requirement
+
+borrowck_capture_kind_label =
+ capture is {$kind_desc} because of use here
+
+borrowck_var_borrow_by_use_place_in_generator =
+ borrow occurs due to use of {$place} in closure in generator
+
+borrowck_var_borrow_by_use_place_in_closure =
+ borrow occurs due to use of {$place} in closure
+
+borrowck_var_borrow_by_use_place =
+ borrow occurs due to use of {$place}
+
+borrowck_borrow_due_to_use_generator =
+ borrow occurs due to use in generator
+
+borrowck_use_due_to_use_generator =
+ use occurs due to use in generator
+
+borrowck_assign_due_to_use_generator =
+ assign occurs due to use in generator
+
+borrowck_assign_part_due_to_use_generator =
+ assign to part occurs due to use in generator
+
+borrowck_borrow_due_to_use_closure =
+ borrow occurs due to use in closure
+
+borrowck_use_due_to_use_closure =
+ use occurs due to use in closure
+
+borrowck_assign_due_to_use_closure =
+ assignment occurs due to use in closure
+
+borrowck_assign_part_due_to_use_closure =
+ assignment to part occurs due to use in closure
+
+borrowck_capture_immute =
+ capture is immutable because of use here
+
+borrowck_capture_mut =
+ capture is mutable because of use here
+
+borrowck_capture_move =
+ capture is moved because of use here
+
+borrowck_var_move_by_use_place_in_generator =
+ move occurs due to use of {$place} in generator
+
+borrowck_var_move_by_use_place_in_closure =
+ move occurs due to use of {$place} in closure
+
+borrowck_cannot_move_when_borrowed =
+ cannot move out of {$place ->
+ [value] value
+ *[other] {$place}
+ } because it is borrowed
+ .label = borrow of {$borrow_place ->
+ [value] value
+ *[other] {$borrow_place}
+ } occurs here
+ .move_label = move out of {$value_place ->
+ [value] value
+ *[other] {$value_place}
+ } occurs here
+
+borrowck_opaque_type_non_generic_param =
+ expected generic {$kind} parameter, found `{$ty}`
+ .label = {STREQ($ty, "'static") ->
+ [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
+ *[other] this generic parameter must be used with a generic {$kind} parameter
+ }
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index a4943d112..2bbb9618d 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -37,7 +37,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
desc,
);
- err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_desc));
+ err.span_label(borrow_span, format!("{} is borrowed here", borrow_desc));
err.span_label(span, format!("use of borrowed {}", borrow_desc));
err
}
@@ -250,8 +250,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
desc,
);
- err.span_label(borrow_span, format!("borrow of {} occurs here", desc));
- err.span_label(span, format!("assignment to borrowed {} occurs here", desc));
+ err.span_label(borrow_span, format!("{} is borrowed here", desc));
+ err.span_label(span, format!("{} is assigned to here but it was already borrowed", desc));
err
}
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
index 11b31c3f1..1427f5cb3 100644
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::{
};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
use crate::{
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid,
@@ -165,7 +165,7 @@ impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> {
/// `location`.
fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location)
where
- T: TypeVisitable<'tcx>,
+ T: TypeVisitable<TyCtxt<'tcx>>,
{
debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location);
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 1f0b8adea..f370c0216 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -17,7 +17,7 @@ pub(crate) mod graph;
/// constraints of the form `R1: R2`. Each constraint is identified by
/// a unique `OutlivesConstraintIndex` and you can index into the set
/// (`constraint_set[i]`) to access the constraint details.
-#[derive(Clone, Default)]
+#[derive(Clone, Debug, Default)]
pub(crate) struct OutlivesConstraintSet<'tcx> {
outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>>,
}
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 8c4885770..2821677c5 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -393,6 +393,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
| mir::StatementKind::AscribeUserType(..)
| mir::StatementKind::Coverage(..)
| mir::StatementKind::Intrinsic(..)
+ | mir::StatementKind::ConstEvalCounter
| mir::StatementKind::Nop => {}
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 1550958ab..68205fa45 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -106,7 +106,7 @@ impl<'tcx> ToUniverseInfo<'tcx>
}
}
-impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
+impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUniverseInfo<'tcx>
for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
{
fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
@@ -180,20 +180,20 @@ trait TypeOpInfo<'tcx> {
return;
};
- let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
+ let placeholder_region = tcx.mk_re_placeholder(ty::Placeholder {
name: placeholder.name,
universe: adjusted_universe.into(),
- }));
+ });
let error_region =
if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
let adjusted_universe =
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
adjusted_universe.map(|adjusted| {
- tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
+ tcx.mk_re_placeholder(ty::Placeholder {
name: error_placeholder.name,
universe: adjusted.into(),
- }))
+ })
})
} else {
None
@@ -258,7 +258,7 @@ struct NormalizeQuery<'tcx, T> {
impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
where
- T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
+ T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
{
fn fallback_error(
&self,
@@ -390,7 +390,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
error_region,
&region_constraints,
|vid| ocx.infcx.region_var_origin(vid),
- |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_region(ty::ReVar(vid))),
+ |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_re_var(vid)),
)
}
@@ -411,7 +411,7 @@ fn try_extract_error_from_region_constraints<'tcx>(
}
// FIXME: Should this check the universe of the var?
Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
- Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
+ Some((infcx.tcx.mk_re_var(vid), cause.clone()))
}
_ => None,
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index e5a36259f..cb97699d7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -6,7 +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::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
use rustc_infer::infer::TyCtxtInferExt;
@@ -236,10 +236,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
let needs_note = match ty.kind() {
ty::Closure(id, _) => {
- let tables = self.infcx.tcx.typeck(id.expect_local());
- let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local());
-
- tables.closure_kind_origins().get(hir_id).is_none()
+ self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none()
}
_ => true,
};
@@ -766,7 +763,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
let cause = ObligationCause::new(
span,
- self.mir_hir_id(),
+ self.mir_def_id(),
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
let errors = rustc_trait_selection::traits::fully_solve_bound(
@@ -803,6 +800,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
predicates
.iter()
.map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
+ None,
);
}
}
@@ -1185,11 +1183,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return None;
};
debug!("checking call args for uses of inner_param: {:?}", args);
- if args.contains(&Operand::Move(inner_param)) {
- Some((loc, term))
- } else {
- None
- }
+ args.contains(&Operand::Move(inner_param)).then_some((loc, term))
}) else {
debug!("no uses of inner_param found as a by-move call arg");
return;
@@ -1497,7 +1491,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
assert!(root_place.projection.is_empty());
let proper_span = self.body.local_decls[root_place.local].source_info.span;
- let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
+ let root_place_projection = self.infcx.tcx.mk_place_elems(root_place.projection);
if self.access_place_error_reported.contains(&(
Place { local: root_place.local, projection: root_place_projection },
@@ -1673,7 +1667,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
format!("`{}` would have to be valid for `{}`...", name, region_name),
);
- let fn_hir_id = self.mir_hir_id();
err.span_label(
drop_span,
format!(
@@ -1681,19 +1674,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
name,
self.infcx
.tcx
- .hir()
- .opt_name(fn_hir_id)
+ .opt_item_name(self.mir_def_id().to_def_id())
.map(|name| format!("function `{}`", name))
.unwrap_or_else(|| {
- match &self
- .infcx
- .tcx
- .typeck(self.mir_def_id())
- .node_type(fn_hir_id)
- .kind()
- {
- ty::Closure(..) => "enclosing closure",
- ty::Generator(..) => "enclosing generator",
+ match &self.infcx.tcx.def_kind(self.mir_def_id()) {
+ DefKind::Closure => "enclosing closure",
+ DefKind::Generator => "enclosing generator",
kind => bug!("expected closure or generator, found {:?}", kind),
}
.to_string()
@@ -1736,7 +1722,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&self.local_names,
&mut err,
"",
- None,
+ Some(borrow_span),
None,
);
}
@@ -2138,7 +2124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
let tcx = self.infcx.tcx;
- let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id());
+ let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id());
let mut err =
borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
@@ -2595,11 +2581,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if is_closure {
None
} else {
- let ty = self.infcx.tcx.type_of(self.mir_def_id());
+ let ty = self.infcx.tcx.type_of(self.mir_def_id()).subst_identity();
match ty.kind() {
ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
self.mir_def_id(),
- self.infcx.tcx.fn_sig(self.mir_def_id()),
+ self.infcx.tcx.fn_sig(self.mir_def_id()).subst_identity(),
),
_ => None,
}
@@ -2645,6 +2631,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
operands,
) = rvalue
{
+ let def_id = def_id.expect_local();
for operand in operands {
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
continue;
@@ -2667,7 +2654,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// into a place then we should annotate the closure in
// case it ends up being assigned into the return place.
annotated_closure =
- self.annotate_fn_sig(*def_id, substs.as_closure().sig());
+ self.annotate_fn_sig(def_id, substs.as_closure().sig());
debug!(
"annotate_argument_and_return_for_borrow: \
annotated_closure={:?} assigned_from_local={:?} \
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 209574709..19855075c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -1,6 +1,8 @@
//! Print diagnostics to explain why values are borrowed.
use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir as hir;
+use rustc_hir::intravisit::Visitor;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::{
@@ -11,6 +13,7 @@ use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::{self, RegionVid, TyCtxt};
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{sym, DesugaringKind, Span};
+use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
@@ -63,6 +66,36 @@ impl<'tcx> BorrowExplanation<'tcx> {
borrow_span: Option<Span>,
multiple_borrow_span: Option<(Span, Span)>,
) {
+ if let Some(span) = borrow_span {
+ let def_id = body.source.def_id();
+ if let Some(node) = tcx.hir().get_if_local(def_id)
+ && let Some(body_id) = node.body_id()
+ {
+ let body = tcx.hir().body(body_id);
+ let mut expr_finder = FindExprBySpan::new(span);
+ expr_finder.visit_expr(body.value);
+ if let Some(mut expr) = expr_finder.result {
+ while let hir::ExprKind::AddrOf(_, _, inner)
+ | hir::ExprKind::Unary(hir::UnOp::Deref, inner)
+ | hir::ExprKind::Field(inner, _)
+ | hir::ExprKind::MethodCall(_, inner, _, _)
+ | hir::ExprKind::Index(inner, _) = &expr.kind
+ {
+ expr = inner;
+ }
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind
+ && let [hir::PathSegment { ident, args: None, .. }] = p.segments
+ && let hir::def::Res::Local(hir_id) = p.res
+ && let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id)
+ {
+ err.span_label(
+ pat.span,
+ &format!("binding `{ident}` declared here"),
+ );
+ }
+ }
+ }
+ }
match *self {
BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
let message = match later_use_kind {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 1b40b7143..a99fd594a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -115,11 +115,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
let did = did.expect_local();
- let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
-
- if let Some((span, hir_place)) =
- self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
- {
+ if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.span_note(
*span,
&format!(
@@ -139,11 +135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some(target) = target {
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
let did = did.expect_local();
- let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
-
- if let Some((span, hir_place)) =
- self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
- {
+ if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.span_note(
*span,
&format!(
@@ -373,14 +365,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
//
// We know the field exists so it's safe to call operator[] and `unwrap` here.
let def_id = def_id.expect_local();
- let var_id = self
- .infcx
- .tcx
- .typeck(def_id)
- .closure_min_captures_flattened(def_id)
- .nth(field.index())
- .unwrap()
- .get_root_variable();
+ let var_id =
+ self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
Some(self.infcx.tcx.hir().name(var_id).to_string())
}
@@ -817,6 +803,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&& let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind
{
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
+ let def_id = def_id.expect_local();
if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
self.closure_span(def_id, moved_place, places)
{
@@ -945,6 +932,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
box AggregateKind::Generator(def_id, _, _) => (def_id, true),
_ => continue,
};
+ let def_id = def_id.expect_local();
debug!(
"borrow_spans: def_id={:?} is_generator={:?} places={:?}",
@@ -985,7 +973,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
for (captured_place, place) in
- self.infcx.tcx.typeck(def_id).closure_min_captures_flattened(def_id).zip(places)
+ self.infcx.tcx.closure_captures(def_id).iter().zip(places)
{
match place {
Operand::Copy(place) | Operand::Move(place)
@@ -1064,7 +1052,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
}
- CallKind::Normal { self_arg, desugaring, method_did } => {
+ CallKind::Normal { self_arg, desugaring, method_did, method_substs } => {
let self_arg = self_arg.unwrap();
let tcx = self.infcx.tcx;
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
@@ -1128,17 +1116,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"{place_name} {partially_str}moved due to this method call{loop_message}",
),
);
+
let infcx = tcx.infer_ctxt().build();
+ // Erase and shadow everything that could be passed to the new infcx.
let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
+ let method_substs = tcx.erase_regions(method_substs);
+
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(
+ && let self_ty = infcx.instantiate_binder_with_fresh_vars(
fn_call_span,
LateBoundRegionConversionTime::FnCall,
- tcx.fn_sig(method_did).input(0),
+ tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
)
- && infcx.can_eq(self.param_env, ty, self_ty).is_ok()
+ && infcx.can_eq(self.param_env, ty, self_ty)
{
err.span_suggestion_verbose(
fn_call_span.shrink_to_lo(),
@@ -1176,13 +1168,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
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 parent_self_ty =
+ matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
+ .then_some(parent_did)
+ .and_then(|did| match tcx.type_of(did).subst_identity().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))
});
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 6db3c858a..5e4c7292e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -448,7 +448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
- use_spans.args_span_label(err, format!("move out of {place_desc} occurs here"));
+ use_spans.args_span_label(err, format!("{place_desc} is moved here"));
}
}
}
@@ -467,7 +467,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
span.shrink_to_lo(),
"consider borrowing here",
- "&".to_string(),
+ '&',
Applicability::MaybeIncorrect,
);
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 45b15c2c5..328ac880d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -344,7 +344,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} else {
err.span_help(source_info.span, "try removing `&mut` here");
}
- } else if decl.mutability == Mutability::Not {
+ } else if decl.mutability.is_not() {
if matches!(
decl.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
@@ -385,7 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
local_decl.source_info.span.shrink_to_lo(),
"consider changing this to be mutable",
- "mut ".to_string(),
+ "mut ",
Applicability::MachineApplicable,
);
let tcx = self.infcx.tcx;
@@ -606,12 +606,63 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
Some((false, err_label_span, message)) => {
- err.span_label(
- err_label_span,
- &format!(
- "consider changing this binding's type to be: `{message}`"
- ),
- );
+ struct BindingFinder {
+ span: Span,
+ hir_id: Option<hir::HirId>,
+ }
+
+ impl<'tcx> Visitor<'tcx> for BindingFinder {
+ fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
+ if let hir::StmtKind::Local(local) = s.kind {
+ if local.pat.span == self.span {
+ self.hir_id = Some(local.hir_id);
+ }
+ }
+ hir::intravisit::walk_stmt(self, s);
+ }
+ }
+ let hir_map = self.infcx.tcx.hir();
+ let def_id = self.body.source.def_id();
+ let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local());
+ let node = hir_map.find(hir_id);
+ let hir_id = if let Some(hir::Node::Item(item)) = node
+ && let hir::ItemKind::Fn(.., body_id) = item.kind
+ {
+ let body = hir_map.body(body_id);
+ let mut v = BindingFinder {
+ span: err_label_span,
+ hir_id: None,
+ };
+ v.visit_body(body);
+ v.hir_id
+ } else {
+ None
+ };
+ if let Some(hir_id) = hir_id
+ && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
+ {
+ let (changing, span, sugg) = match local.ty {
+ Some(ty) => ("changing", ty.span, message),
+ None => (
+ "specifying",
+ local.pat.span.shrink_to_hi(),
+ format!(": {message}"),
+ ),
+ };
+ err.span_suggestion_verbose(
+ span,
+ &format!("consider {changing} this binding's type"),
+ sugg,
+ Applicability::HasPlaceholders,
+ );
+ } else {
+ err.span_label(
+ err_label_span,
+ &format!(
+ "consider changing this binding's type to be: `{message}`"
+ ),
+ );
+ }
}
None => {}
}
@@ -850,10 +901,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err: &mut Diagnostic,
) {
let tables = tcx.typeck(closure_local_def_id);
- let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id);
- if let Some((span, closure_kind_origin)) =
- &tables.closure_kind_origins().get(closure_hir_id)
- {
+ if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) {
let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
let root_hir_id = upvar_id.var_path.hir_id;
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 187861ba1..ffe82b46c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -415,7 +415,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
/// ```
///
- /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
+ /// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
pub(crate) fn report_region_error(
&mut self,
fr: RegionVid,
@@ -575,7 +575,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() {
- output_ty = self.infcx.tcx.type_of(def_id)
+ output_ty = self.infcx.tcx.type_of(def_id).subst_identity()
};
debug!("report_fnmut_error: output_ty={:?}", output_ty);
@@ -583,10 +583,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let err = FnMutError {
span: *span,
ty_err: match output_ty.kind() {
- ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span },
ty::Generator(def, ..) if self.infcx.tcx.generator_is_async(*def) => {
FnMutReturnTypeErr::ReturnAsyncBlock { span: *span }
}
+ _ if output_ty.contains_closure() => {
+ FnMutReturnTypeErr::ReturnClosure { span: *span }
+ }
_ => FnMutReturnTypeErr::ReturnRef { span: *span },
},
};
@@ -658,10 +660,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
errci.outlived_fr,
);
- let (_, escapes_from) = self
- .infcx
- .tcx
- .article_and_description(self.regioncx.universal_regions().defining_ty.def_id());
+ let escapes_from =
+ self.infcx.tcx.def_descr(self.regioncx.universal_regions().defining_ty.def_id());
// Revert to the normal error in these cases.
// Assignments aren't "escapes" in function items.
@@ -755,8 +755,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
..
} = errci;
- let (_, mir_def_name) =
- self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id());
+ let mir_def_name = self.infcx.tcx.def_descr(self.mir_def_id().to_def_id());
let err = LifetimeOutliveErr { span: *span };
let mut diag = self.infcx.tcx.sess.create_err(err);
@@ -813,17 +812,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if *outlived_f != ty::ReStatic {
return;
}
+ let suitable_region = self.infcx.tcx.is_suitable_region(f);
+ let Some(suitable_region) = suitable_region else { return; };
- let fn_returns = self
- .infcx
- .tcx
- .is_suitable_region(f)
- .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
- .unwrap_or_default();
-
- if fn_returns.is_empty() {
- return;
- }
+ let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.def_id);
let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
param
@@ -839,15 +831,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
let captures = format!("captures data from {arg}");
- return nice_region_error::suggest_new_region_bound(
- self.infcx.tcx,
- diag,
- fn_returns,
- lifetime.to_string(),
- 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),
+ if !fn_returns.is_empty() {
+ nice_region_error::suggest_new_region_bound(
+ self.infcx.tcx,
+ diag,
+ fn_returns,
+ lifetime.to_string(),
+ Some(arg),
+ captures,
+ Some((param.param_ty_span, param.param_ty.to_string())),
+ Some(suitable_region.def_id),
+ );
+ return;
+ }
+
+ let Some((alias_tys, alias_span)) = self
+ .infcx
+ .tcx
+ .return_type_impl_or_dyn_traits_with_type_alias(suitable_region.def_id) else { return; };
+
+ // in case the return type of the method is a type alias
+ let mut spans_suggs: Vec<_> = Vec::new();
+ for alias_ty in alias_tys {
+ if alias_ty.span.desugaring_kind().is_some() {
+ // Skip `async` desugaring `impl Future`.
+ ()
+ }
+ if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
+ spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
+ }
+ }
+ spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string()));
+ diag.multipart_suggestion_verbose(
+ &format!(
+ "to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias"
+ ),
+ spans_suggs,
+ Applicability::MaybeIncorrect,
);
}
}
@@ -873,7 +893,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
debug!(?fn_did, ?substs);
// Only suggest this on function calls, not closures
- let ty = tcx.type_of(fn_did);
+ let ty = tcx.type_of(fn_did).subst_identity();
debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
if let ty::Closure(_, _) = ty.kind() {
return;
@@ -929,7 +949,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.push_span_label(*span, "this has an implicit `'static` lifetime requirement");
multi_span.push_span_label(
ident.span,
- "calling this method introduces the `impl`'s 'static` requirement",
+ "calling this method introduces the `impl`'s `'static` requirement",
);
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
err.span_suggestion_verbose(
@@ -976,7 +996,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
let map = self.infcx.tcx.hir();
let body_id = map.body_owned_by(self.mir_def_id());
- let expr = &map.body(body_id).value;
+ let expr = &map.body(body_id).value.peel_blocks();
let mut closure_span = None::<rustc_span::Span>;
match expr.kind {
hir::ExprKind::MethodCall(.., args, _) => {
@@ -991,20 +1011,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
}
- hir::ExprKind::Block(blk, _) => {
- if let Some(expr) = blk.expr {
- // only when the block is a closure
- if let hir::ExprKind::Closure(hir::Closure {
- capture_clause: hir::CaptureBy::Ref,
- body,
- ..
- }) = expr.kind
- {
- let body = map.body(*body);
- if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) {
- closure_span = Some(expr.span.shrink_to_lo());
- }
- }
+ hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ body,
+ ..
+ }) => {
+ let body = map.body(*body);
+ if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) {
+ closure_span = Some(expr.span.shrink_to_lo());
}
}
_ => {}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 9233287cf..f6881a2e5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -187,6 +187,12 @@ impl Display for RegionName {
}
}
+impl rustc_errors::IntoDiagnosticArg for RegionName {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+}
+
impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId {
self.body.source.def_id().expect_local()
@@ -274,17 +280,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
debug!("give_region_a_name: error_region = {:?}", error_region);
match *error_region {
- ty::ReEarlyBound(ebr) => {
- if ebr.has_name() {
- let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
- Some(RegionName {
- name: ebr.name,
- source: RegionNameSource::NamedEarlyBoundRegion(span),
- })
- } else {
- None
- }
- }
+ ty::ReEarlyBound(ebr) => ebr.has_name().then(|| {
+ let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
+ RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyBoundRegion(span) }
+ }),
ty::ReStatic => {
Some(RegionName { name: kw::StaticLifetime, source: RegionNameSource::Static })
@@ -337,11 +336,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let note = match closure_kind_ty.to_opt_closure_kind() {
Some(ty::ClosureKind::Fn) => {
"closure implements `Fn`, so references to captured variables \
- can't escape the closure"
+ can't escape the closure"
}
Some(ty::ClosureKind::FnMut) => {
"closure implements `FnMut`, so references to captured variables \
- can't escape the closure"
+ can't escape the closure"
}
Some(ty::ClosureKind::FnOnce) => {
bug!("BrEnv in a `FnOnce` closure");
@@ -358,7 +357,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::BoundRegionKind::BrAnon(..) => None,
},
- ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
+ ty::ReLateBound(..)
+ | ty::ReVar(..)
+ | ty::RePlaceholder(..)
+ | ty::ReErased
+ | ty::ReError(_) => None,
}
}
@@ -842,12 +845,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let tcx = self.infcx.tcx;
let region_parent = tcx.parent(region.def_id);
- if tcx.def_kind(region_parent) != DefKind::Impl {
+ let DefKind::Impl { .. } = tcx.def_kind(region_parent) else {
return None;
- }
+ };
- let found = tcx
- .any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region));
+ let found = tcx.any_free_region_meets(&tcx.type_of(region_parent).subst_identity(), |r| {
+ *r == ty::ReEarlyBound(region)
+ });
Some(RegionName {
name: self.synthesize_region_name(),
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 6fd929005..6217676d5 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -91,7 +91,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
LocalMutationIsAllowed::Yes,
);
}
- StatementKind::Nop
+ StatementKind::ConstEvalCounter
+ | StatementKind::Nop
| StatementKind::Retag { .. }
| StatementKind::Deinit(..)
| StatementKind::SetDiscriminant { .. } => {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 73ea7314b..0f591460e 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1,6 +1,7 @@
//! This query borrow-checks the MIR to (further) ensure it is not broken.
#![allow(rustc::potential_query_instability)]
+#![feature(associated_type_bounds)]
#![feature(box_patterns)]
#![feature(let_chains)]
#![feature(min_specialization)]
@@ -20,12 +21,15 @@ extern crate tracing;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::{Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::ChunkedBitSet;
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{
+ DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
+};
+use rustc_macros::fluent_messages;
use rustc_middle::mir::{
traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
Place, PlaceElem, PlaceRef, VarDebugInfoContents,
@@ -43,6 +47,7 @@ use smallvec::SmallVec;
use std::cell::OnceCell;
use std::cell::RefCell;
use std::collections::BTreeMap;
+use std::ops::Deref;
use std::rc::Rc;
use rustc_mir_dataflow::impls::{
@@ -94,6 +99,9 @@ use nll::{PoloniusOutput, ToRegionVid};
use place_ext::PlaceExt;
use places_conflict::{places_conflict, PlaceConflictBias};
use region_infer::RegionInferenceContext;
+use renumber::RegionCtxt;
+
+fluent_messages! { "../locales/en-US.ftl" }
// FIXME(eddyb) perhaps move this somewhere more centrally.
#[derive(Debug)]
@@ -167,10 +175,10 @@ fn do_mir_borrowck<'tcx>(
return_body_with_facts: bool,
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
let def = input_body.source.with_opt_param().as_local().unwrap();
-
debug!(?def);
let tcx = infcx.tcx;
+ let infcx = BorrowckInferCtxt::new(infcx);
let param_env = tcx.param_env(def.did);
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
@@ -194,14 +202,14 @@ fn do_mir_borrowck<'tcx>(
let mut errors = error::BorrowckErrors::new(infcx.tcx);
// Gather the upvars of a closure, if any.
- let tables = tcx.typeck_opt_const_arg(def);
- if let Some(e) = tables.tainted_by_errors {
+ if let Some(e) = input_body.tainted_by_errors {
infcx.set_tainted_by_errors(e);
errors.set_tainted_by_errors(e);
}
- let upvars: Vec<_> = tables
- .closure_min_captures_flattened(def.did)
- .map(|captured_place| {
+ let upvars: Vec<_> = tcx
+ .closure_captures(def.did)
+ .iter()
+ .map(|&captured_place| {
let capture = captured_place.info.capture_kind;
let by_ref = match capture {
ty::UpvarCapture::ByValue => false,
@@ -218,7 +226,7 @@ fn do_mir_borrowck<'tcx>(
let mut body_owned = input_body.clone();
let mut promoted = input_promoted.clone();
let free_regions =
- nll::replace_regions_in_mir(infcx, param_env, &mut body_owned, &mut promoted);
+ nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted);
let body = &body_owned; // no further changes
let location_table_owned = LocationTable::new(body);
@@ -256,7 +264,7 @@ fn do_mir_borrowck<'tcx>(
opt_closure_req,
nll_errors,
} = nll::compute_regions(
- infcx,
+ &infcx,
free_regions,
body,
&promoted,
@@ -271,12 +279,12 @@ fn do_mir_borrowck<'tcx>(
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests, as well as helping with debugging.
- nll::dump_mir_results(infcx, &body, &regioncx, &opt_closure_req);
+ nll::dump_mir_results(&infcx, &body, &regioncx, &opt_closure_req);
// We also have a `#[rustc_regions]` annotation that causes us to dump
// information.
nll::dump_annotation(
- infcx,
+ &infcx,
&body,
&regioncx,
&opt_closure_req,
@@ -320,7 +328,7 @@ fn do_mir_borrowck<'tcx>(
if let Err((move_data, move_errors)) = move_data_results {
let mut promoted_mbcx = MirBorrowckCtxt {
- infcx,
+ infcx: &infcx,
param_env,
body: promoted_body,
move_data: &move_data,
@@ -349,7 +357,7 @@ fn do_mir_borrowck<'tcx>(
}
let mut mbcx = MirBorrowckCtxt {
- infcx,
+ infcx: &infcx,
param_env,
body,
move_data: &mdpe.move_data,
@@ -481,8 +489,84 @@ pub struct BodyWithBorrowckFacts<'tcx> {
pub location_table: LocationTable,
}
+pub struct BorrowckInferCtxt<'cx, 'tcx> {
+ pub(crate) infcx: &'cx InferCtxt<'tcx>,
+ pub(crate) reg_var_to_origin: RefCell<FxHashMap<ty::RegionVid, RegionCtxt>>,
+}
+
+impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
+ pub(crate) fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
+ BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) }
+ }
+
+ pub(crate) fn next_region_var<F>(
+ &self,
+ origin: RegionVariableOrigin,
+ get_ctxt_fn: F,
+ ) -> ty::Region<'tcx>
+ where
+ F: Fn() -> RegionCtxt,
+ {
+ let next_region = self.infcx.next_region_var(origin);
+ let vid = next_region
+ .as_var()
+ .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
+
+ if cfg!(debug_assertions) {
+ debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
+ let ctxt = get_ctxt_fn();
+ let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
+ let prev = var_to_origin.insert(vid, ctxt);
+
+ // This only makes sense if not called in a canonicalization context. If this
+ // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
+ // or modify how we track nll region vars for that map.
+ assert!(matches!(prev, None));
+ }
+
+ next_region
+ }
+
+ #[instrument(skip(self, get_ctxt_fn), level = "debug")]
+ pub(crate) fn next_nll_region_var<F>(
+ &self,
+ origin: NllRegionVariableOrigin,
+ get_ctxt_fn: F,
+ ) -> ty::Region<'tcx>
+ where
+ F: Fn() -> RegionCtxt,
+ {
+ let next_region = self.infcx.next_nll_region_var(origin.clone());
+ let vid = next_region
+ .as_var()
+ .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
+
+ if cfg!(debug_assertions) {
+ debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
+ let ctxt = get_ctxt_fn();
+ let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
+ let prev = var_to_origin.insert(vid, ctxt);
+
+ // This only makes sense if not called in a canonicalization context. If this
+ // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
+ // or modify how we track nll region vars for that map.
+ assert!(matches!(prev, None));
+ }
+
+ next_region
+ }
+}
+
+impl<'cx, 'tcx> Deref for BorrowckInferCtxt<'cx, 'tcx> {
+ type Target = InferCtxt<'tcx>;
+
+ fn deref(&self) -> &'cx Self::Target {
+ self.infcx
+ }
+}
+
struct MirBorrowckCtxt<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'tcx>,
+ infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
param_env: ParamEnv<'tcx>,
body: &'cx Body<'tcx>,
move_data: &'cx MoveData<'tcx>,
@@ -609,7 +693,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
StatementKind::AscribeUserType(..)
// Doesn't have any language semantics
| StatementKind::Coverage(..)
- // Does not actually affect borrowck
+ // These do not actually affect borrowck
+ | StatementKind::ConstEvalCounter
| StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
@@ -1277,6 +1362,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// in order to populate our used_mut set.
match **aggregate_kind {
AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) => {
+ let def_id = def_id.expect_local();
let BorrowCheckResult { used_mut_upvars, .. } =
self.infcx.tcx.mir_borrowck(def_id);
debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index b2d92d0db..96228338a 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -5,16 +5,14 @@
use rustc_data_structures::vec_map::VecMap;
use rustc_hir::def_id::LocalDefId;
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
use rustc_middle::mir::{
BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
Promoted,
};
-use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid};
+use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid, TyCtxt};
use rustc_span::symbol::sym;
use std::env;
-use std::fmt::Debug;
use std::io;
use std::path::PathBuf;
use std::rc::Rc;
@@ -37,7 +35,7 @@ use crate::{
renumber,
type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
universal_regions::UniversalRegions,
- Upvar,
+ BorrowckInferCtxt, Upvar,
};
pub type PoloniusOutput = Output<RustcFacts>;
@@ -58,7 +56,7 @@ pub(crate) struct NllOutput<'tcx> {
/// `compute_regions`.
#[instrument(skip(infcx, param_env, body, promoted), level = "debug")]
pub(crate) fn replace_regions_in_mir<'tcx>(
- infcx: &InferCtxt<'tcx>,
+ infcx: &BorrowckInferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &mut Body<'tcx>,
promoted: &mut IndexVec<Promoted, Body<'tcx>>,
@@ -157,7 +155,7 @@ fn populate_polonius_move_facts(
///
/// This may result in errors being reported.
pub(crate) fn compute_regions<'cx, 'tcx>(
- infcx: &InferCtxt<'tcx>,
+ infcx: &BorrowckInferCtxt<'_, 'tcx>,
universal_regions: UniversalRegions<'tcx>,
body: &Body<'tcx>,
promoted: &IndexVec<Promoted, Body<'tcx>>,
@@ -259,6 +257,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
);
let mut regioncx = RegionInferenceContext::new(
+ infcx,
var_origins,
universal_regions,
placeholder_indices,
@@ -322,10 +321,10 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
}
pub(super) fn dump_mir_results<'tcx>(
- infcx: &InferCtxt<'tcx>,
+ infcx: &BorrowckInferCtxt<'_, 'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
- closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
+ closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
) {
if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) {
return;
@@ -340,9 +339,11 @@ pub(super) fn dump_mir_results<'tcx>(
if let Some(closure_region_requirements) = closure_region_requirements {
writeln!(out, "| Free Region Constraints")?;
- for_each_region_constraint(closure_region_requirements, &mut |msg| {
- writeln!(out, "| {}", msg)
- })?;
+ for_each_region_constraint(
+ infcx.tcx,
+ closure_region_requirements,
+ &mut |msg| writeln!(out, "| {}", msg),
+ )?;
writeln!(out, "|")?;
}
}
@@ -369,11 +370,13 @@ pub(super) fn dump_mir_results<'tcx>(
};
}
+#[allow(rustc::diagnostic_outside_of_impl)]
+#[allow(rustc::untranslatable_diagnostic)]
pub(super) fn dump_annotation<'tcx>(
- infcx: &InferCtxt<'tcx>,
+ infcx: &BorrowckInferCtxt<'_, 'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
- closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
+ closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
errors: &mut crate::error::BorrowckErrors<'tcx>,
) {
@@ -403,7 +406,7 @@ pub(super) fn dump_annotation<'tcx>(
// Dump the region constraints we are imposing *between* those
// newly created variables.
- for_each_region_constraint(closure_region_requirements, &mut |msg| {
+ for_each_region_constraint(tcx, closure_region_requirements, &mut |msg| {
err.note(msg);
Ok(())
})
@@ -424,16 +427,19 @@ pub(super) fn dump_annotation<'tcx>(
errors.buffer_non_error_diag(err);
}
-fn for_each_region_constraint(
- closure_region_requirements: &ClosureRegionRequirements<'_>,
+fn for_each_region_constraint<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ closure_region_requirements: &ClosureRegionRequirements<'tcx>,
with_msg: &mut dyn FnMut(&str) -> io::Result<()>,
) -> io::Result<()> {
for req in &closure_region_requirements.outlives_requirements {
- let subject: &dyn Debug = match &req.subject {
- ClosureOutlivesSubject::Region(subject) => subject,
- ClosureOutlivesSubject::Ty(ty) => ty,
+ let subject = match req.subject {
+ ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject),
+ ClosureOutlivesSubject::Ty(ty) => {
+ format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid)))
+ }
};
- with_msg(&format!("where {:?}: {:?}", subject, req.outlived_free_region,))?;
+ with_msg(&format!("where {}: {:?}", subject, req.outlived_free_region,))?;
}
Ok(())
}
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 238172ea3..e6195de40 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -7,18 +7,18 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_hir::CRATE_HIR_ID;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
- Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
- ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
+ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
+ ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
+ TerminatorKind,
};
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_span::Span;
use crate::{
@@ -35,6 +35,7 @@ use crate::{
},
type_check::{free_region_relations::UniversalRegionRelations, Locations},
universal_regions::UniversalRegions,
+ BorrowckInferCtxt,
};
mod dump_mir;
@@ -244,6 +245,70 @@ pub enum ExtraConstraintInfo {
PlaceholderFromPredicate(Span),
}
+#[instrument(skip(infcx, sccs), level = "debug")]
+fn sccs_info<'cx, 'tcx>(
+ infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
+ sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
+) {
+ use crate::renumber::RegionCtxt;
+
+ let var_to_origin = infcx.reg_var_to_origin.borrow();
+
+ let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
+ var_to_origin_sorted.sort_by(|a, b| a.0.cmp(&b.0));
+ let mut debug_str = "region variables to origins:\n".to_string();
+ for (reg_var, origin) in var_to_origin_sorted.into_iter() {
+ debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin));
+ }
+ debug!(debug_str);
+
+ let num_components = sccs.scc_data().ranges().len();
+ let mut components = vec![FxHashSet::default(); num_components];
+
+ for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() {
+ let reg_var = ty::RegionVid::from_usize(reg_var_idx);
+ let origin = var_to_origin.get(&reg_var).unwrap_or_else(|| &RegionCtxt::Unknown);
+ components[scc_idx.as_usize()].insert((reg_var, *origin));
+ }
+
+ let mut components_str = "strongly connected components:".to_string();
+ for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
+ let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
+ components_str.push_str(&format!(
+ "{:?}: {:?})",
+ ConstraintSccIndex::from_usize(scc_idx),
+ regions_info,
+ ))
+ }
+ debug!(components_str);
+
+ // calculate the best representative for each component
+ let components_representatives = components
+ .into_iter()
+ .enumerate()
+ .map(|(scc_idx, region_ctxts)| {
+ let repr = region_ctxts
+ .into_iter()
+ .map(|reg_var_origin| reg_var_origin.1)
+ .max_by(|x, y| x.preference_value().cmp(&y.preference_value()))
+ .unwrap();
+
+ (ConstraintSccIndex::from_usize(scc_idx), repr)
+ })
+ .collect::<FxHashMap<_, _>>();
+
+ let mut scc_node_to_edges = FxHashMap::default();
+ for (scc_idx, repr) in components_representatives.iter() {
+ let edges_range = sccs.scc_data().ranges()[*scc_idx].clone();
+ let edges = &sccs.scc_data().all_successors()[edges_range];
+ let edge_representatives =
+ edges.iter().map(|scc_idx| components_representatives[scc_idx]).collect::<Vec<_>>();
+ scc_node_to_edges.insert((scc_idx, repr), edge_representatives);
+ }
+
+ debug!("SCC edges {:#?}", scc_node_to_edges);
+}
+
impl<'tcx> RegionInferenceContext<'tcx> {
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
@@ -252,7 +317,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
///
/// The `outlives_constraints` and `type_tests` are an initial set
/// of constraints produced by the MIR type check.
- pub(crate) fn new(
+ pub(crate) fn new<'cx>(
+ _infcx: &BorrowckInferCtxt<'cx, 'tcx>,
var_infos: VarInfos,
universal_regions: Rc<UniversalRegions<'tcx>>,
placeholder_indices: Rc<PlaceholderIndices>,
@@ -264,6 +330,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
liveness_constraints: LivenessValues<RegionVid>,
elements: &Rc<RegionValueElements>,
) -> Self {
+ debug!("universal_regions: {:#?}", universal_regions);
+ debug!("outlives constraints: {:#?}", outlives_constraints);
+ debug!("placeholder_indices: {:#?}", placeholder_indices);
+ debug!("type tests: {:#?}", type_tests);
+
// Create a RegionDefinition for each inference variable.
let definitions: IndexVec<_, _> = var_infos
.iter()
@@ -275,6 +346,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let fr_static = universal_regions.fr_static;
let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static));
+ if cfg!(debug_assertions) {
+ sccs_info(_infcx, constraint_sccs.clone());
+ }
+
let mut scc_values =
RegionValues::new(elements, universal_regions.len(), &placeholder_indices);
@@ -747,20 +822,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
debug!(?choice_regions, "after ub");
- // If we ruled everything out, we're done.
- if choice_regions.is_empty() {
- return false;
- }
-
- // Otherwise, we need to find the minimum remaining choice, if
- // any, and take that.
- debug!("choice_regions remaining are {:#?}", choice_regions);
- let Some(&min_choice) = choice_regions.iter().find(|&r1| {
+ // At this point we can pick any member of `choice_regions`, but to avoid potential
+ // non-determinism we will pick the *unique minimum* choice.
+ //
+ // Because universal regions are only partially ordered (i.e, not every two regions are
+ // comparable), we will ignore any region that doesn't compare to all others when picking
+ // the minimum choice.
+ // For example, consider `choice_regions = ['static, 'a, 'b, 'c, 'd, 'e]`, where
+ // `'static: 'a, 'static: 'b, 'a: 'c, 'b: 'c, 'c: 'd, 'c: 'e`.
+ // `['d, 'e]` are ignored because they do not compare - the same goes for `['a, 'b]`.
+ let totally_ordered_subset = choice_regions.iter().copied().filter(|&r1| {
choice_regions.iter().all(|&r2| {
- self.universal_region_relations.outlives(r2, *r1)
+ self.universal_region_relations.outlives(r1, r2)
+ || self.universal_region_relations.outlives(r2, r1)
})
+ });
+ // Now we're left with `['static, 'c]`. Pick `'c` as the minimum!
+ let Some(min_choice) = totally_ordered_subset.reduce(|r1, r2| {
+ 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) => r1.min(r2),
+ (true, false) => r2,
+ (false, true) => r1,
+ (false, false) => bug!("incomparable regions in total order"),
+ }
}) else {
- debug!("no choice region outlived by all others");
+ debug!("no unique minimum choice");
return false;
};
@@ -802,7 +890,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// from a universe it can't name; at present, the only way for
/// this to be true is if `scc` outlives `'static`. This is
/// actually stricter than necessary: ideally, we'd support bounds
- /// like `for<'a: 'b`>` that might then allow us to approximate
+ /// like `for<'a: 'b>` that might then allow us to approximate
/// `'a` with `'b` and not `'static`. But it will have to do for
/// now.
fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
@@ -997,18 +1085,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
true
}
- /// When we promote a type test `T: 'r`, we have to convert the
- /// type `T` into something we can store in a query result (so
- /// something allocated for `'tcx`). This is problematic if `ty`
- /// contains regions. During the course of NLL region checking, we
- /// will have replaced all of those regions with fresh inference
- /// variables. To create a test subject, we want to replace those
- /// inference variables with some region from the closure
- /// signature -- this is not always possible, so this is a
- /// fallible process. Presuming we do find a suitable region, we
- /// will use it's *external name*, which will be a `RegionKind`
- /// variant that can be used in query responses such as
- /// `ReEarlyBound`.
+ /// When we promote a type test `T: 'r`, we have to replace all region
+ /// variables in the type `T` with an equal universal region from the
+ /// closure signature.
+ /// This is not always possible, so this is a fallible process.
#[instrument(level = "debug", skip(self, infcx))]
fn try_promote_type_test_subject(
&self,
@@ -1017,91 +1097,63 @@ impl<'tcx> RegionInferenceContext<'tcx> {
) -> Option<ClosureOutlivesSubject<'tcx>> {
let tcx = infcx.tcx;
+ // Opaque types' substs may include useless lifetimes.
+ // We will replace them with ReStatic.
+ struct OpaqueFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ }
+ impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for OpaqueFolder<'tcx> {
+ fn interner(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ use ty::TypeSuperFoldable as _;
+ let tcx = self.tcx;
+ let &ty::Alias(ty::Opaque, ty::AliasTy { substs, def_id, .. }) = t.kind() else {
+ return t.super_fold_with(self);
+ };
+ let substs =
+ std::iter::zip(substs, tcx.variances_of(def_id)).map(|(arg, v)| {
+ match (arg.unpack(), v) {
+ (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => {
+ tcx.lifetimes.re_static.into()
+ }
+ _ => arg.fold_with(self),
+ }
+ });
+ tcx.mk_opaque(def_id, tcx.mk_substs_from_iter(substs))
+ }
+ }
+
+ let ty = ty.fold_with(&mut OpaqueFolder { tcx });
+
let ty = tcx.fold_regions(ty, |r, _depth| {
- let region_vid = self.to_region_vid(r);
+ let r_vid = self.to_region_vid(r);
+ let r_scc = self.constraint_sccs.scc(r_vid);
// The challenge if this. We have some region variable `r`
// whose value is a set of CFG points and universal
// regions. We want to find if that set is *equivalent* to
// any of the named regions found in the closure.
- //
- // To do so, we compute the
- // `non_local_universal_upper_bound`. This will be a
- // non-local, universal region that is greater than `r`.
- // However, it might not be *contained* within `r`, so
- // then we further check whether this bound is contained
- // in `r`. If so, we can say that `r` is equivalent to the
- // bound.
- //
- // Let's work through a few examples. For these, imagine
- // that we have 3 non-local regions (I'll denote them as
- // `'static`, `'a`, and `'b`, though of course in the code
- // they would be represented with indices) where:
- //
- // - `'static: 'a`
- // - `'static: 'b`
- //
- // First, let's assume that `r` is some existential
- // variable with an inferred value `{'a, 'static}` (plus
- // some CFG nodes). In this case, the non-local upper
- // bound is `'static`, since that outlives `'a`. `'static`
- // is also a member of `r` and hence we consider `r`
- // equivalent to `'static` (and replace it with
- // `'static`).
- //
- // Now let's consider the inferred value `{'a, 'b}`. This
- // means `r` is effectively `'a | 'b`. I'm not sure if
- // this can come about, actually, but assuming it did, we
- // would get a non-local upper bound of `'static`. Since
- // `'static` is not contained in `r`, we would fail to
- // find an equivalent.
- let upper_bound = self.non_local_universal_upper_bound(region_vid);
- if self.region_contains(region_vid, upper_bound) {
- self.definitions[upper_bound].external_name.unwrap_or(r)
- } else {
- // In the case of a failure, use a `ReVar` result. This will
- // cause the `needs_infer` later on to return `None`.
- r
- }
+ // To do so, we simply check every candidate `u_r` for equality.
+ self.scc_values
+ .universal_regions_outlived_by(r_scc)
+ .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
+ .find(|&u_r| self.eval_equal(u_r, r_vid))
+ .map(|u_r| tcx.mk_re_var(u_r))
+ // In the case of a failure, use `ReErased`. We will eventually
+ // return `None` in this case.
+ .unwrap_or(tcx.lifetimes.re_erased)
});
debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
- // `needs_infer` will only be true if we failed to promote some region.
- if ty.needs_infer() {
+ // This will be true if we failed to promote some region.
+ if ty.has_erased_regions() {
return None;
}
- Some(ClosureOutlivesSubject::Ty(ty))
- }
-
- /// Given some universal or existential region `r`, finds a
- /// non-local, universal region `r+` that outlives `r` at entry to (and
- /// exit from) the closure. In the worst case, this will be
- /// `'static`.
- ///
- /// This is used for two purposes. First, if we are propagated
- /// some requirement `T: r`, we can use this method to enlarge `r`
- /// to something we can encode for our creator (which only knows
- /// about non-local, universal regions). It is also used when
- /// encoding `T` as part of `try_promote_type_test_subject` (see
- /// that fn for details).
- ///
- /// This is based on the result `'y` of `universal_upper_bound`,
- /// except that it converts further takes the non-local upper
- /// bound of `'y`, so that the final result is non-local.
- fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
- debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
-
- let lub = self.universal_upper_bound(r);
-
- // Grow further to get smallest universal region known to
- // creator.
- let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub);
-
- debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub);
-
- non_local_lub
+ Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::bind(tcx, ty)))
}
/// Returns a universally quantified region that outlives the
@@ -1279,13 +1331,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// we use this kind of hacky solution.
fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
{
tcx.fold_regions(value, |r, _db| {
let vid = self.to_region_vid(r);
let scc = self.constraint_sccs.scc(vid);
let repr = self.scc_representatives[scc];
- tcx.mk_region(ty::ReVar(repr))
+ tcx.mk_re_var(repr)
})
}
@@ -1707,7 +1759,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
// If not, report an error.
- let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid));
+ let member_region = infcx.tcx.mk_re_var(member_region_vid);
errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion {
span: m_c.definition_span,
hidden_ty: m_c.hidden_ty,
@@ -2022,7 +2074,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.map(|constraint| BlameConstraint {
category: constraint.category,
from_closure: constraint.from_closure,
- cause: ObligationCause::new(constraint.span, CRATE_HIR_ID, cause_code.clone()),
+ cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()),
variance_info: constraint.variance_info,
outlives_constraint: *constraint,
})
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index db5a67a8b..c550e37c6 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,12 +1,13 @@
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::vec_map::VecMap;
+use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::TyCtxtInferExt as _;
use rustc_infer::infer::{DefiningAnchor, InferCtxt};
use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
-use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -91,11 +92,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
None => {
subst_regions.push(vid);
- infcx.tcx.sess.delay_span_bug(
+ infcx.tcx.mk_re_error_with_message(
concrete_type.span,
"opaque type with non-universal region substs",
- );
- infcx.tcx.lifetimes.re_static
+ )
}
}
};
@@ -150,13 +150,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// once we convert the generic parameters to those of the opaque type.
if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
if prev.ty != ty {
- if !ty.references_error() {
+ let guar = ty.error_reported().err().unwrap_or_else(|| {
prev.report_mismatch(
&OpaqueHiddenType { ty, span: concrete_type.span },
infcx.tcx,
- );
- }
- prev.ty = infcx.tcx.ty_error();
+ )
+ });
+ prev.ty = infcx.tcx.ty_error(guar);
}
// Pick a better span if there is one.
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
@@ -179,7 +179,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// region names in error messages.
pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
{
tcx.fold_regions(ty, |region, _| match *region {
ty::ReVar(vid) => {
@@ -248,20 +248,20 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
origin: OpaqueTyOrigin,
) -> Ty<'tcx> {
if let Some(e) = self.tainted_by_errors() {
- return self.tcx.ty_error_with_guaranteed(e);
+ return self.tcx.ty_error(e);
}
let definition_ty = instantiated_ty
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
.ty;
- if !check_opaque_type_parameter_valid(
+ if let Err(guar) = check_opaque_type_parameter_valid(
self.tcx,
opaque_type_key,
origin,
instantiated_ty.span,
) {
- return self.tcx.ty_error();
+ return self.tcx.ty_error(guar);
}
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
@@ -273,9 +273,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
// This logic duplicates most of `check_opaque_meets_bounds`.
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
let param_env = self.tcx.param_env(def_id);
- let body_id = self.tcx.local_def_id_to_hir_id(def_id);
// HACK This bubble is required for this tests to pass:
- // type-alias-impl-trait/issue-67844-nested-opaque.rs
+ // nested-return-type2-tait2.rs
+ // nested-return-type2-tait3.rs
let infcx =
self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build();
let ocx = ObligationCtxt::new(&infcx);
@@ -290,7 +290,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
// the bounds that the function supplies.
let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
if let Err(err) = ocx.eq(
- &ObligationCause::misc(instantiated_ty.span, body_id),
+ &ObligationCause::misc(instantiated_ty.span, def_id),
param_env,
opaque_ty,
definition_ty,
@@ -298,7 +298,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
infcx
.err_ctxt()
.report_mismatched_types(
- &ObligationCause::misc(instantiated_ty.span, body_id),
+ &ObligationCause::misc(instantiated_ty.span, def_id),
opaque_ty,
definition_ty,
err,
@@ -309,7 +309,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
ocx.register_obligation(Obligation::misc(
infcx.tcx,
instantiated_ty.span,
- body_id,
+ def_id,
param_env,
predicate,
));
@@ -326,7 +326,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
definition_ty
} else {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
- self.tcx.ty_error_with_guaranteed(reported)
+ self.tcx.ty_error(reported)
}
}
}
@@ -336,7 +336,7 @@ fn check_opaque_type_parameter_valid(
opaque_type_key: OpaqueTypeKey<'_>,
origin: OpaqueTyOrigin,
span: Span,
-) -> bool {
+) -> Result<(), ErrorGuaranteed> {
match origin {
// No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct
@@ -359,7 +359,7 @@ fn check_opaque_type_parameter_valid(
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
//
// which would error here on all of the `'static` args.
- OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
+ OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
// Check these
OpaqueTyOrigin::TyAlias => {}
}
@@ -368,18 +368,6 @@ fn check_opaque_type_parameter_valid(
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
- GenericArgKind::Lifetime(lt) if lt.is_static() => {
- tcx.sess
- .struct_span_err(span, "non-defining opaque type use in defining scope")
- .span_label(
- tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
- "cannot use static lifetime; use a bound lifetime \
- instead or remove the lifetime parameter from the \
- opaque type",
- )
- .emit();
- return false;
- }
GenericArgKind::Lifetime(lt) => {
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
}
@@ -392,13 +380,13 @@ fn check_opaque_type_parameter_valid(
// Prevent `fn foo() -> Foo<u32>` from being defining.
let opaque_param = opaque_generics.param_at(i, tcx);
let kind = opaque_param.kind.descr();
- tcx.sess.emit_err(NonGenericOpaqueTypeParam {
+
+ return Err(tcx.sess.emit_err(NonGenericOpaqueTypeParam {
ty: arg,
kind,
span,
param_span: tcx.def_span(opaque_param.def_id),
- });
- return false;
+ }));
}
}
@@ -409,12 +397,13 @@ fn check_opaque_type_parameter_valid(
.into_iter()
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
.collect();
- tcx.sess
+ return Err(tcx
+ .sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
.span_note(spans, &format!("{} used multiple times", descr))
- .emit();
- return false;
+ .emit());
}
}
- true
+
+ Ok(())
}
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index c3dfeedc2..8132800f1 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -181,12 +181,13 @@ impl<N: Idx> LivenessValues<N> {
/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
/// rustc to the internal `PlaceholderIndex` values that are used in
/// NLL.
-#[derive(Default)]
+#[derive(Debug, Default)]
pub(crate) struct PlaceholderIndices {
indices: FxIndexSet<ty::PlaceholderRegion>,
}
impl PlaceholderIndices {
+ /// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion`
pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
let (index, _) = self.indices.insert_full(placeholder);
index.into()
@@ -234,7 +235,7 @@ pub(crate) struct RegionValues<N: Idx> {
free_regions: SparseBitMatrix<N, RegionVid>,
/// Placeholders represent bound regions -- so something like `'a`
- /// in for<'a> fn(&'a u32)`.
+ /// in `for<'a> fn(&'a u32)`.
placeholders: SparseBitMatrix<N, PlaceholderIndex>,
}
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 084754830..016f6f78d 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,18 +1,20 @@
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
+use crate::BorrowckInferCtxt;
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
+use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::visit::{MutVisitor, TyContext};
use rustc_middle::mir::Constant;
use rustc_middle::mir::{Body, Location, Promoted};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_span::{Span, Symbol};
/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
#[instrument(skip(infcx, body, promoted), level = "debug")]
pub fn renumber_mir<'tcx>(
- infcx: &InferCtxt<'tcx>,
+ infcx: &BorrowckInferCtxt<'_, 'tcx>,
body: &mut Body<'tcx>,
promoted: &mut IndexVec<Promoted, Body<'tcx>>,
) {
@@ -29,27 +31,68 @@ pub fn renumber_mir<'tcx>(
/// Replaces all regions appearing in `value` with fresh inference
/// variables.
-#[instrument(skip(infcx), level = "debug")]
-pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> T
+#[instrument(skip(infcx, get_ctxt_fn), level = "debug")]
+pub(crate) fn renumber_regions<'tcx, T, F>(
+ infcx: &BorrowckInferCtxt<'_, 'tcx>,
+ value: T,
+ get_ctxt_fn: F,
+) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
+ F: Fn() -> RegionCtxt,
{
infcx.tcx.fold_regions(value, |_region, _depth| {
let origin = NllRegionVariableOrigin::Existential { from_forall: false };
- infcx.next_nll_region_var(origin)
+ infcx.next_nll_region_var(origin, || get_ctxt_fn())
})
}
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub(crate) enum BoundRegionInfo {
+ Name(Symbol),
+ Span(Span),
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub(crate) enum RegionCtxt {
+ Location(Location),
+ TyContext(TyContext),
+ Free(Symbol),
+ Bound(BoundRegionInfo),
+ LateBound(BoundRegionInfo),
+ Existential(Option<Symbol>),
+ Placeholder(BoundRegionInfo),
+ Unknown,
+}
+
+impl RegionCtxt {
+ /// Used to determine the representative of a component in the strongly connected
+ /// constraint graph
+ pub(crate) fn preference_value(self) -> usize {
+ let _anon = Symbol::intern("anon");
+
+ match self {
+ RegionCtxt::Unknown => 1,
+ RegionCtxt::Existential(None) => 2,
+ RegionCtxt::Existential(Some(_anon)) | RegionCtxt::Free(_anon) => 2,
+ RegionCtxt::Location(_) => 3,
+ RegionCtxt::TyContext(_) => 4,
+ _ => 5,
+ }
+ }
+}
+
struct NllVisitor<'a, 'tcx> {
- infcx: &'a InferCtxt<'tcx>,
+ infcx: &'a BorrowckInferCtxt<'a, 'tcx>,
}
impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
- fn renumber_regions<T>(&mut self, value: T) -> T
+ fn renumber_regions<T, F>(&mut self, value: T, region_ctxt_fn: F) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
+ F: Fn() -> RegionCtxt,
{
- renumber_regions(self.infcx, value)
+ renumber_regions(self.infcx, value, region_ctxt_fn)
}
}
@@ -60,14 +103,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
- *ty = self.renumber_regions(*ty);
+ *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context));
debug!(?ty);
}
#[instrument(skip(self), level = "debug")]
fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
- *substs = self.renumber_regions(*substs);
+ *substs = self.renumber_regions(*substs, || RegionCtxt::Location(location));
debug!(?substs);
}
@@ -75,7 +118,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) {
let old_region = *region;
- *region = self.renumber_regions(old_region);
+ *region = self.renumber_regions(old_region, || RegionCtxt::Location(location));
debug!(?region);
}
@@ -83,7 +126,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _location: Location) {
let literal = constant.literal;
- constant.literal = self.renumber_regions(literal);
+ constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(_location));
debug!("constant: {:#?}", constant);
}
}
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 23acf1592..a36789290 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -1,4 +1,4 @@
-use rustc_errors::{IntoDiagnosticArg, MultiSpan};
+use rustc_errors::MultiSpan;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{GenericArg, Ty};
use rustc_span::Span;
@@ -55,7 +55,7 @@ pub(crate) struct VarNeedNotMut {
#[derive(Diagnostic)]
#[diag(borrowck_var_cannot_escape_closure)]
#[note]
-#[note(cannot_escape)]
+#[note(borrowck_cannot_escape)]
pub(crate) struct FnMutError {
#[primary_span]
pub span: Span,
@@ -128,18 +128,6 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
},
}
-impl IntoDiagnosticArg for &RegionName {
- fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
- format!("{}", self).into_diagnostic_arg()
- }
-}
-
-impl IntoDiagnosticArg for RegionName {
- fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
- format!("{}", self).into_diagnostic_arg()
- }
-}
-
#[derive(Subdiagnostic)]
pub(crate) enum RequireStaticErr {
#[note(borrowck_used_impl_require_static)]
@@ -235,7 +223,7 @@ pub(crate) struct MoveBorrow<'a> {
pub borrow_place: &'a str,
pub value_place: &'a str,
#[primary_span]
- #[label(move_label)]
+ #[label(borrowck_move_label)]
pub span: Span,
#[label]
pub borrow_span: Span,
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 11729e2c8..b27d5d205 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -2,7 +2,7 @@ use std::fmt;
use rustc_infer::infer::{canonical::Canonical, InferOk};
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::def_id::DefId;
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
@@ -66,7 +66,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
canonical: &Canonical<'tcx, T>,
) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
{
let old_universe = self.infcx.universe();
@@ -117,7 +117,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
pub(super) fn prove_predicates(
&mut self,
- predicates: impl IntoIterator<Item = impl ToPredicate<'tcx> + std::fmt::Debug>,
+ predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>,
locations: Locations,
category: ConstraintCategory<'tcx>,
) {
@@ -181,9 +181,6 @@ impl<'a, 'tcx> TypeChecker<'a, '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,
@@ -217,7 +214,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return;
}
+ // FIXME: Ideally MIR types are normalized, but this is not always true.
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: &'_ _| {
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index e15d1b99a..a93561350 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -6,8 +6,8 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
use rustc_span::{Span, DUMMY_SP};
use crate::{
@@ -83,16 +83,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
self.constraints.member_constraints = tmp;
- for (predicate, constraint_category) in outlives {
- // At the moment, we never generate any "higher-ranked"
- // region constraints like `for<'a> 'a: 'b`. At some point
- // when we move to universes, we will, and this assertion
- // will start to fail.
- let predicate = predicate.no_bound_vars().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound vars", predicate,);
- });
-
- self.convert(predicate, *constraint_category);
+ for &(predicate, constraint_category) in outlives {
+ self.convert(predicate, constraint_category);
}
}
@@ -124,7 +116,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
let subject = match outlives_requirement.subject {
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
- ClosureOutlivesSubject::Ty(ty) => ty.into(),
+ ClosureOutlivesSubject::Ty(subject_ty) => {
+ subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
+ }
};
self.category = outlives_requirement.category;
@@ -179,7 +173,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
///
/// FIXME: This should get removed once higher ranked region obligations
/// are dealt with during trait solving.
- fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+ fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
if value.has_placeholders() {
self.tcx.fold_regions(value, |r, _| match *r {
ty::RePlaceholder(placeholder) => {
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 82ff86247..4004966c4 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -8,6 +8,7 @@ use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
use type_op::TypeOpOutput;
@@ -92,31 +93,6 @@ impl UniversalRegionRelations<'_> {
res
}
- /// Returns the "postdominating" bound of the set of
- /// `non_local_upper_bounds` for the given region.
- pub(crate) fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
- 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
- // complex constraints, but it will cause spurious errors.
- let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds);
-
- debug!("non_local_bound: post_dom={:?}", post_dom);
-
- post_dom
- .and_then(|post_dom| {
- // If the mutual immediate postdom is not local, then
- // there is no non-local result we can return.
- if !self.universal_regions.is_local_free_region(post_dom) {
- Some(post_dom)
- } else {
- None
- }
- })
- .unwrap_or(self.universal_regions.fr_static)
- }
-
/// Finds a "lower bound" for `fr` that is not local. In other
/// words, returns the largest (*) known region `fr1` that (a) is
/// outlived by `fr` and (b) is not local.
@@ -217,8 +193,27 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.inverse_outlives.add(fr_b, fr_a);
}
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
+
+ // Insert the facts we know from the predicates. Why? Why not.
+ let param_env = self.param_env;
+ self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
+
+ // - outlives is reflexive, so `'r: 'r` for every region `'r`
+ // - `'static: 'r` for every region `'r`
+ // - `'r: 'fn_body` for every (other) universally quantified
+ // region `'r`, all of which are provided by our caller
+ let fr_static = self.universal_regions.fr_static;
+ let fr_fn_body = self.universal_regions.fr_fn_body;
+ for fr in self.universal_regions.universal_regions() {
+ debug!("build: relating free region {:?} to itself and to 'static", fr);
+ self.relate_universal_regions(fr, fr);
+ self.relate_universal_regions(fr_static, fr);
+ self.relate_universal_regions(fr, fr_fn_body);
+ }
+
let unnormalized_input_output_tys = self
.universal_regions
.unnormalized_input_tys
@@ -236,78 +231,59 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// the `relations` is built.
let mut normalized_inputs_and_output =
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
- let constraint_sets: Vec<_> = unnormalized_input_output_tys
- .flat_map(|ty| {
- debug!("build: input_or_output={:?}", ty);
- // We add implied bounds from both the unnormalized and normalized ty.
- // See issue #87748
- let constraints_implied1 = self.add_implied_bounds(ty);
- let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
- .param_env
- .and(type_op::normalize::Normalize::new(ty))
- .fully_perform(self.infcx)
- .unwrap_or_else(|_| {
- let reported = self
- .infcx
- .tcx
- .sess
- .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
- TypeOpOutput {
- output: self.infcx.tcx.ty_error_with_guaranteed(reported),
- constraints: None,
- error_info: None,
- }
- });
- // Note: we need this in examples like
- // ```
- // trait Foo {
- // type Bar;
- // fn foo(&self) -> &Self::Bar;
- // }
- // impl Foo for () {
- // type Bar = ();
- // fn foo(&self) -> &() {}
- // }
- // ```
- // Both &Self::Bar and &() are WF
- let constraints_implied2 =
- if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
- normalized_inputs_and_output.push(norm_ty);
- constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
- })
- .collect();
+ let mut constraints = vec![];
+ for ty in unnormalized_input_output_tys {
+ debug!("build: input_or_output={:?}", ty);
+ // We add implied bounds from both the unnormalized and normalized ty.
+ // See issue #87748
+ let constraints_unnorm = self.add_implied_bounds(ty);
+ if let Some(c) = constraints_unnorm {
+ constraints.push(c)
+ }
+ let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
+ .param_env
+ .and(type_op::normalize::Normalize::new(ty))
+ .fully_perform(self.infcx)
+ .unwrap_or_else(|_| {
+ let guar = self
+ .infcx
+ .tcx
+ .sess
+ .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
+ TypeOpOutput {
+ output: self.infcx.tcx.ty_error(guar),
+ constraints: None,
+ error_info: None,
+ }
+ });
+ if let Some(c) = constraints_normalize {
+ constraints.push(c)
+ }
- // Insert the facts we know from the predicates. Why? Why not.
- let param_env = self.param_env;
- self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
+ // Note: we need this in examples like
+ // ```
+ // trait Foo {
+ // type Bar;
+ // fn foo(&self) -> &Self::Bar;
+ // }
+ // impl Foo for () {
+ // type Bar = ();
+ // fn foo(&self) ->&() {}
+ // }
+ // ```
+ // Both &Self::Bar and &() are WF
+ if ty != norm_ty {
+ let constraints_norm = self.add_implied_bounds(norm_ty);
+ if let Some(c) = constraints_norm {
+ constraints.push(c)
+ }
+ }
- // Finally:
- // - outlives is reflexive, so `'r: 'r` for every region `'r`
- // - `'static: 'r` for every region `'r`
- // - `'r: 'fn_body` for every (other) universally quantified
- // region `'r`, all of which are provided by our caller
- let fr_static = self.universal_regions.fr_static;
- let fr_fn_body = self.universal_regions.fr_fn_body;
- for fr in self.universal_regions.universal_regions() {
- debug!("build: relating free region {:?} to itself and to 'static", fr);
- self.relate_universal_regions(fr, fr);
- self.relate_universal_regions(fr_static, fr);
- self.relate_universal_regions(fr, fr_fn_body);
+ normalized_inputs_and_output.push(norm_ty);
}
- for data in &constraint_sets {
- constraint_conversion::ConstraintConversion::new(
- self.infcx,
- &self.universal_regions,
- &self.region_bound_pairs,
- self.implicit_region_bound,
- self.param_env,
- Locations::All(span),
- span,
- ConstraintCategory::Internal,
- &mut self.constraints,
- )
- .convert_all(data);
+ for c in constraints {
+ self.push_region_constraints(c, span);
}
CreateResult {
@@ -321,6 +297,24 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
}
+ #[instrument(skip(self, data), level = "debug")]
+ fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
+ debug!("constraints generated: {:#?}", data);
+
+ constraint_conversion::ConstraintConversion::new(
+ self.infcx,
+ &self.universal_regions,
+ &self.region_bound_pairs,
+ self.implicit_region_bound,
+ self.param_env,
+ Locations::All(span),
+ span,
+ ConstraintCategory::Internal,
+ &mut self.constraints,
+ )
+ .convert_all(data);
+ }
+
/// Update the type of a single local, which should represent
/// either the return type of the MIR or one of its arguments. At
/// the same time, compute and add any implied bounds that come
@@ -332,6 +326,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
.fully_perform(self.infcx)
.unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
+ debug!(?bounds, ?constraints);
self.add_outlives_bounds(bounds);
constraints
}
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index fa9ea769a..717020ea5 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -26,11 +26,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
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;
- };
+ let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
// Instantiate the canonicalized variables from user-provided signature
// (e.g., the `_` in the code above) with fresh variables.
@@ -38,7 +34,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// 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(
+ let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
body.span,
LateBoundRegionConversionTime::FnCall,
user_provided_sig,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index d5c401ae1..a411aec51 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -50,13 +50,11 @@ pub(super) fn generate<'mir, 'tcx>(
compute_relevant_live_locals(typeck.tcx(), &free_regions, &body);
let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx());
- let polonius_drop_used = if facts_enabled {
+ let polonius_drop_used = facts_enabled.then(|| {
let mut drop_used = Vec::new();
polonius::populate_access_facts(typeck, body, location_table, move_data, &mut drop_used);
- Some(drop_used)
- } else {
- None
- };
+ drop_used
+ });
trace::trace(
typeck,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 3ff5d188a..473c05963 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -3,7 +3,7 @@ use rustc_index::bit_set::HybridBitSet;
use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
-use rustc_middle::ty::{Ty, TypeVisitable};
+use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -477,7 +477,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
/// points `live_at`.
fn add_use_live_facts_for(
&mut self,
- value: impl TypeVisitable<'tcx>,
+ value: impl TypeVisitable<TyCtxt<'tcx>>,
live_at: &IntervalSet<PointIndex>,
) {
debug!("add_use_live_facts_for(value={:?})", value);
@@ -542,7 +542,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
fn make_all_regions_live(
elements: &RegionValueElements,
typeck: &mut TypeChecker<'_, 'tcx>,
- value: impl TypeVisitable<'tcx>,
+ value: impl TypeVisitable<TyCtxt<'tcx>>,
live_at: &IntervalSet<PointIndex>,
) {
debug!("make_all_regions_live(value={:?})", value);
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 81bd4c2a7..a49da3da6 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -30,7 +30,7 @@ use rustc_middle::mir::*;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
-use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
@@ -64,7 +64,7 @@ use crate::{
region_infer::TypeTest,
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
universal_regions::{DefiningTy, UniversalRegions},
- Upvar,
+ BorrowckInferCtxt, Upvar,
};
macro_rules! span_mirbug {
@@ -123,7 +123,7 @@ mod relate_tys;
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
/// - `elements` -- MIR region map
pub(crate) fn type_check<'mir, 'tcx>(
- infcx: &InferCtxt<'tcx>,
+ infcx: &BorrowckInferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
promoted: &IndexVec<Promoted, Body<'tcx>>,
@@ -137,7 +137,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
upvars: &[Upvar<'tcx>],
use_polonius: bool,
) -> MirTypeckResults<'tcx> {
- let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
+ let implicit_region_bound = infcx.tcx.mk_re_var(universal_regions.fr_fn_body);
let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::default(),
@@ -239,7 +239,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
decl.hidden_type.span,
&format!("could not resolve {:#?}", hidden_type.ty.kind()),
);
- hidden_type.ty = infcx.tcx.ty_error_with_guaranteed(reported);
+ hidden_type.ty = infcx.tcx.ty_error(reported);
}
(opaque_type_key, (hidden_type, decl.origin))
@@ -402,7 +402,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
);
}
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
- let unnormalized_ty = tcx.type_of(static_def_id);
+ let unnormalized_ty = tcx.type_of(static_def_id).subst_identity();
let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
@@ -529,12 +529,12 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
for elem in place.projection.iter() {
if place_ty.variant_index.is_none() {
- if place_ty.ty.references_error() {
+ if let Err(guar) = place_ty.ty.error_reported() {
assert!(self.errors_reported);
- return PlaceTy::from_ty(self.tcx().ty_error());
+ return PlaceTy::from_ty(self.tcx().ty_error(guar));
}
}
- place_ty = self.sanitize_projection(place_ty, elem, place, location);
+ place_ty = self.sanitize_projection(place_ty, elem, place, location, context);
}
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
@@ -630,12 +630,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
}
+ #[instrument(skip(self), level = "debug")]
fn sanitize_projection(
&mut self,
base: PlaceTy<'tcx>,
pi: PlaceElem<'tcx>,
place: &Place<'tcx>,
location: Location,
+ context: PlaceContext,
) -> PlaceTy<'tcx> {
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
let tcx = self.tcx();
@@ -713,8 +715,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
match self.field_ty(place, base, field, location) {
Ok(ty) => {
let ty = self.cx.normalize(ty, location);
- if let Err(terr) = self.cx.eq_types(
+ debug!(?fty, ?ty);
+
+ if let Err(terr) = self.cx.relate_types(
ty,
+ self.get_ambient_variance(context),
fty,
location.to_locations(),
ConstraintCategory::Boring,
@@ -743,9 +748,10 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);
self.cx
- .eq_types(
- base.ty,
+ .relate_types(
ty,
+ self.get_ambient_variance(context),
+ base.ty,
location.to_locations(),
ConstraintCategory::TypeAnnotation,
)
@@ -757,7 +763,22 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
fn error(&mut self) -> Ty<'tcx> {
self.errors_reported = true;
- self.tcx().ty_error()
+ self.tcx().ty_error_misc()
+ }
+
+ fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance {
+ use rustc_middle::mir::visit::NonMutatingUseContext::*;
+ use rustc_middle::mir::visit::NonUseContext::*;
+
+ match context {
+ PlaceContext::MutatingUse(_) => ty::Invariant,
+ PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
+ PlaceContext::NonMutatingUse(
+ Inspect | Copy | Move | SharedBorrow | ShallowBorrow | UniqueBorrow | AddressOf
+ | Projection,
+ ) => ty::Covariant,
+ PlaceContext::NonUse(AscribeUserTy) => ty::Covariant,
+ }
}
fn field_ty(
@@ -845,7 +866,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
/// way, it accrues region constraints -- these can later be used by
/// NLL region checking.
struct TypeChecker<'a, 'tcx> {
- infcx: &'a InferCtxt<'tcx>,
+ infcx: &'a BorrowckInferCtxt<'a, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
last_span: Span,
body: &'a Body<'tcx>,
@@ -910,6 +931,8 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
}
impl<'tcx> MirTypeckRegionConstraints<'tcx> {
+ /// Creates a `Region` for a given `PlaceholderRegion`, or returns the
+ /// region that corresponds to a previously created one.
fn placeholder_region(
&mut self,
infcx: &InferCtxt<'tcx>,
@@ -996,7 +1019,7 @@ impl Locations {
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn new(
- infcx: &'a InferCtxt<'tcx>,
+ infcx: &'a BorrowckInferCtxt<'a, 'tcx>,
body: &'a Body<'tcx>,
param_env: ty::ParamEnv<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
@@ -1258,6 +1281,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| StatementKind::StorageDead(..)
| StatementKind::Retag { .. }
| StatementKind::Coverage(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => {}
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
@@ -1332,11 +1356,34 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
};
let (sig, map) = tcx.replace_late_bound_regions(sig, |br| {
- self.infcx.next_region_var(LateBoundRegion(
- term.source_info.span,
- br.kind,
- LateBoundRegionConversionTime::FnCall,
- ))
+ use crate::renumber::{BoundRegionInfo, RegionCtxt};
+ use rustc_span::Symbol;
+
+ let region_ctxt_fn = || {
+ let reg_info = match br.kind {
+ ty::BoundRegionKind::BrAnon(_, Some(span)) => {
+ BoundRegionInfo::Span(span)
+ }
+ ty::BoundRegionKind::BrAnon(..) => {
+ BoundRegionInfo::Name(Symbol::intern("anon"))
+ }
+ ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
+ ty::BoundRegionKind::BrEnv => {
+ BoundRegionInfo::Name(Symbol::intern("env"))
+ }
+ };
+
+ RegionCtxt::LateBound(reg_info)
+ };
+
+ self.infcx.next_region_var(
+ LateBoundRegion(
+ term.source_info.span,
+ br.kind,
+ LateBoundRegionConversionTime::FnCall,
+ ),
+ region_ctxt_fn,
+ )
});
debug!(?sig);
// IMPORTANT: We have to prove well formed for the function signature before
@@ -1483,7 +1530,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
None => {
- if !sig.output().is_privately_uninhabited(self.tcx(), self.param_env) {
+ // The signature in this call can reference region variables,
+ // so erase them before calling a query.
+ let output_ty = self.tcx().erase_regions(sig.output());
+ if !output_ty.is_privately_uninhabited(self.tcx(), self.param_env) {
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
}
}
@@ -1776,7 +1826,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// than 1.
// If the length is larger than 1, the repeat expression will need to copy the
// element, so we require the `Copy` trait.
- if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
+ if len.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
match operand {
Operand::Copy(..) | Operand::Constant(..) => {
// These are always okay: direct use of a const, or a value that can evidently be copied.
@@ -2027,7 +2077,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
};
- if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not {
+ if ty_to_mut.is_mut() && ty_mut.is_not() {
span_mirbug!(
self,
rvalue,
@@ -2532,7 +2582,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// clauses on the struct.
AggregateKind::Closure(def_id, substs)
| AggregateKind::Generator(def_id, substs, _) => {
- (def_id.to_def_id(), self.prove_closure_bounds(tcx, def_id, substs, location))
+ (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location))
}
AggregateKind::Array(_) | AggregateKind::Tuple => {
@@ -2583,7 +2633,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
DefKind::InlineConst => substs.as_inline_const().parent_substs(),
other => bug!("unexpected item {:?}", other),
};
- let parent_substs = tcx.mk_substs(parent_substs.iter());
+ let parent_substs = tcx.mk_substs(parent_substs);
assert_eq!(typeck_root_substs.len(), parent_substs.len());
if let Err(_) = self.eq_substs(
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index b2702eafd..d96372fb9 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,14 +1,15 @@
-use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
+use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_infer::traits::PredicateObligations;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{self, Ty};
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
use rustc_trait_selection::traits::query::Fallible;
use crate::constraints::OutlivesConstraint;
use crate::diagnostics::UniverseInfo;
+use crate::renumber::{BoundRegionInfo, RegionCtxt};
use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
@@ -100,23 +101,65 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
universe
}
- fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
+ #[instrument(skip(self), level = "debug")]
+ fn next_existential_region_var(
+ &mut self,
+ from_forall: bool,
+ _name: Option<Symbol>,
+ ) -> ty::Region<'tcx> {
let origin = NllRegionVariableOrigin::Existential { from_forall };
- self.type_checker.infcx.next_nll_region_var(origin)
+
+ let reg_var =
+ self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(_name));
+
+ reg_var
}
+ #[instrument(skip(self), level = "debug")]
fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
- self.type_checker
+ let reg = self
+ .type_checker
.borrowck_context
.constraints
- .placeholder_region(self.type_checker.infcx, placeholder)
+ .placeholder_region(self.type_checker.infcx, placeholder);
+
+ let reg_info = match placeholder.name {
+ ty::BoundRegionKind::BrAnon(_, Some(span)) => BoundRegionInfo::Span(span),
+ ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(Symbol::intern("anon")),
+ ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
+ ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(Symbol::intern("env")),
+ };
+
+ let reg_var =
+ reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg));
+ let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
+ let prev = var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info));
+ assert!(matches!(prev, None));
+
+ reg
}
+ #[instrument(skip(self), level = "debug")]
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
- self.type_checker.infcx.next_nll_region_var_in_universe(
+ let reg = self.type_checker.infcx.next_nll_region_var_in_universe(
NllRegionVariableOrigin::Existential { from_forall: false },
universe,
- )
+ );
+
+ let reg_var =
+ reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg));
+
+ if cfg!(debug_assertions) {
+ let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
+ let prev = var_to_origin.insert(reg_var, RegionCtxt::Existential(None));
+
+ // It only makes sense to track region vars in non-canonicalization contexts. If this
+ // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
+ // or modify how we track nll region vars for that map.
+ assert!(matches!(prev, None));
+ }
+
+ reg
}
fn push_outlives(
@@ -140,10 +183,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
);
}
- fn normalization() -> NormalizationStrategy {
- NormalizationStrategy::Eager
- }
-
fn forbid_inference_vars() -> bool {
true
}
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 5b4d99682..15d7613a8 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -18,17 +18,20 @@ use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{BodyOwnerKind, HirId};
+use rustc_hir::BodyOwnerKind;
use rustc_index::vec::{Idx, IndexVec};
-use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
+use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{
self, DefIdTree, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt,
};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
+use rustc_span::Symbol;
use std::iter;
use crate::nll::ToRegionVid;
+use crate::renumber::{BoundRegionInfo, RegionCtxt};
+use crate::BorrowckInferCtxt;
#[derive(Debug)]
pub struct UniversalRegions<'tcx> {
@@ -162,11 +165,14 @@ struct UniversalRegionIndices<'tcx> {
/// `ty::Region` to the internal `RegionVid` we are using. This is
/// used because trait matching and type-checking will feed us
/// region constraints that reference those regions and we need to
- /// be able to map them our internal `RegionVid`. This is
+ /// be able to map them to our internal `RegionVid`. This is
/// basically equivalent to an `InternalSubsts`, except that it also
/// contains an entry for `ReStatic` -- it might be nice to just
/// use a substs, and then handle `ReStatic` another way.
indices: FxHashMap<ty::Region<'tcx>, RegionVid>,
+
+ /// The vid assigned to `'static`. Used only for diagnostics.
+ pub fr_static: RegionVid,
}
#[derive(Debug, PartialEq)]
@@ -221,13 +227,11 @@ impl<'tcx> UniversalRegions<'tcx> {
/// signature. This will also compute the relationships that are
/// known between those regions.
pub fn new(
- infcx: &InferCtxt<'tcx>,
+ infcx: &BorrowckInferCtxt<'_, 'tcx>,
mir_def: ty::WithOptConstParam<LocalDefId>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
- let tcx = infcx.tcx;
- let mir_hir_id = tcx.hir().local_def_id_to_hir_id(mir_def.did);
- UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build()
+ UniversalRegionsBuilder { infcx, mir_def, param_env }.build()
}
/// Given a reference to a closure type, extracts all the values
@@ -382,9 +386,8 @@ impl<'tcx> UniversalRegions<'tcx> {
}
struct UniversalRegionsBuilder<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'tcx>,
+ infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
mir_def: ty::WithOptConstParam<LocalDefId>,
- mir_hir_id: HirId,
param_env: ty::ParamEnv<'tcx>,
}
@@ -400,7 +403,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars());
// Create the "global" region that is always free in all contexts: 'static.
- let fr_static = self.infcx.next_nll_region_var(FR).to_region_vid();
+ let fr_static = self
+ .infcx
+ .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("static")))
+ .to_region_vid();
// We've now added all the global regions. The next ones we
// add will be external.
@@ -432,7 +438,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
- let region_vid = self.infcx.next_nll_region_var(FR);
+ let region_vid = {
+ let name = match r.get_name() {
+ Some(name) => name,
+ _ => Symbol::intern("anon"),
+ };
+
+ self.infcx.next_nll_region_var(FR, || {
+ RegionCtxt::LateBound(BoundRegionInfo::Name(name))
+ })
+ };
+
debug!(?region_vid);
indices.insert_late_bound_region(r, region_vid.to_region_vid());
}
@@ -460,7 +476,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def.did, |r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
- let region_vid = self.infcx.next_nll_region_var(FR);
+ let region_vid = {
+ let name = match r.get_name() {
+ Some(name) => name,
+ _ => Symbol::intern("anon"),
+ };
+
+ self.infcx.next_nll_region_var(FR, || {
+ RegionCtxt::LateBound(BoundRegionInfo::Name(name))
+ })
+ };
+
debug!(?region_vid);
indices.insert_late_bound_region(r, region_vid.to_region_vid());
}
@@ -472,28 +498,32 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// C-variadic fns also have a `VaList` input that's not listed in the signature
// (as it's created inside the body itself, not passed in from outside).
if let DefiningTy::FnDef(def_id, _) = defining_ty {
- if self.infcx.tcx.fn_sig(def_id).c_variadic() {
+ if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
let va_list_did = self.infcx.tcx.require_lang_item(
LangItem::VaList,
Some(self.infcx.tcx.def_span(self.mir_def.did)),
);
- let region = self
- .infcx
- .tcx
- .mk_region(ty::ReVar(self.infcx.next_nll_region_var(FR).to_region_vid()));
- let va_list_ty = self
+
+ let reg_vid = self
.infcx
- .tcx
- .bound_type_of(va_list_did)
- .subst(self.infcx.tcx, &[region.into()]);
+ .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic")))
+ .to_region_vid();
+
+ let region = self.infcx.tcx.mk_re_var(reg_vid);
+ let va_list_ty =
+ self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]);
- unnormalized_input_tys = self.infcx.tcx.mk_type_list(
+ unnormalized_input_tys = self.infcx.tcx.mk_type_list_from_iter(
unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)),
);
}
}
- let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid();
+ let fr_fn_body = self
+ .infcx
+ .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("fn_body")))
+ .to_region_vid();
+
let num_universals = self.infcx.num_region_vars();
debug!("build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index);
@@ -527,12 +557,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
match tcx.hir().body_owner_kind(self.mir_def.did) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
- let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
- tcx.type_of(typeck_root_def_id)
- } else {
- let tables = tcx.typeck(self.mir_def.did);
- tables.node_type(self.mir_hir_id)
- };
+ let defining_ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity();
debug!("defining_ty (pre-replacement): {:?}", defining_ty);
@@ -561,7 +586,18 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
} else {
- let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+ // FIXME this line creates a dependency between borrowck and typeck.
+ //
+ // This is required for `AscribeUserType` canonical query, which will call
+ // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes
+ // into borrowck, which is ICE #78174.
+ //
+ // As a workaround, inline consts have an additional generic param (`ty`
+ // below), so that `type_of(inline_const_def_id).substs(substs)` uses the
+ // proper type with NLL infer vars.
+ let ty = tcx
+ .typeck(self.mir_def.did)
+ .node_type(tcx.local_def_id_to_hir_id(self.mir_def.did));
let substs = InlineConstSubsts::new(
tcx,
InlineConstSubstsParts { parent_substs: identity_substs, ty },
@@ -609,7 +645,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let subst_mapping =
iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid()));
- UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect() }
+ UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect(), fr_static }
}
fn compute_inputs_and_output(
@@ -623,7 +659,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
assert_eq!(self.mir_def.did.to_def_id(), def_id);
let closure_sig = substs.as_closure().sig();
let inputs_and_output = closure_sig.inputs_and_output();
- let bound_vars = tcx.mk_bound_variable_kinds(
+ let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
inputs_and_output
.bound_vars()
.iter()
@@ -633,7 +669,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
kind: ty::BrEnv,
};
- let env_region = ty::ReLateBound(ty::INNERMOST, br);
+ let env_region = tcx.mk_re_late_bound(ty::INNERMOST, br);
let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap();
// The "inputs" of the closure in the
@@ -647,7 +683,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
};
ty::Binder::bind_with_vars(
- tcx.mk_type_list(
+ tcx.mk_type_list_from_iter(
iter::once(closure_ty).chain(inputs).chain(iter::once(output)),
),
bound_vars,
@@ -660,12 +696,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let output = substs.as_generator().return_ty();
let generator_ty = tcx.mk_generator(def_id, substs, movability);
let inputs_and_output =
- self.infcx.tcx.intern_type_list(&[generator_ty, resume_ty, output]);
+ self.infcx.tcx.mk_type_list(&[generator_ty, resume_ty, output]);
ty::Binder::dummy(inputs_and_output)
}
DefiningTy::FnDef(def_id, _) => {
- let sig = tcx.fn_sig(def_id);
+ let sig = tcx.fn_sig(def_id).subst_identity();
let sig = indices.fold_to_region_vids(tcx, sig);
sig.inputs_and_output()
}
@@ -674,15 +710,15 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// For a constant body, there are no inputs, and one
// "output" (the type of the constant).
assert_eq!(self.mir_def.did.to_def_id(), def_id);
- let ty = tcx.type_of(self.mir_def.def_id_for_type_of());
+ let ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity();
let ty = indices.fold_to_region_vids(tcx, ty);
- ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+ ty::Binder::dummy(tcx.mk_type_list(&[ty]))
}
DefiningTy::InlineConst(def_id, substs) => {
assert_eq!(self.mir_def.did.to_def_id(), def_id);
let ty = substs.as_inline_const().ty();
- ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+ ty::Binder::dummy(tcx.mk_type_list(&[ty]))
}
}
}
@@ -695,7 +731,7 @@ trait InferCtxtExt<'tcx> {
value: T,
) -> T
where
- T: TypeFoldable<'tcx>;
+ T: TypeFoldable<TyCtxt<'tcx>>;
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
@@ -705,7 +741,7 @@ trait InferCtxtExt<'tcx> {
indices: &mut UniversalRegionIndices<'tcx>,
) -> T
where
- T: TypeFoldable<'tcx>;
+ T: TypeFoldable<TyCtxt<'tcx>>;
fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
&self,
@@ -720,16 +756,27 @@ trait InferCtxtExt<'tcx> {
);
}
-impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
+impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
+ #[instrument(skip(self), level = "debug")]
fn replace_free_regions_with_nll_infer_vars<T>(
&self,
origin: NllRegionVariableOrigin,
value: T,
) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
{
- self.tcx.fold_regions(value, |_region, _depth| self.next_nll_region_var(origin))
+ self.infcx.tcx.fold_regions(value, |region, _depth| {
+ let name = match region.get_name() {
+ Some(name) => name,
+ _ => Symbol::intern("anon"),
+ };
+ debug!(?region, ?name);
+
+ let reg_var = self.next_nll_region_var(origin, || RegionCtxt::Free(name));
+
+ reg_var
+ })
}
#[instrument(level = "debug", skip(self, indices))]
@@ -741,15 +788,20 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
indices: &mut UniversalRegionIndices<'tcx>,
) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
{
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
debug!(?br);
- let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
- scope: all_outlive_scope.to_def_id(),
- bound_region: br.kind,
- }));
- let region_vid = self.next_nll_region_var(origin);
+ let liberated_region = self.tcx.mk_re_free(all_outlive_scope.to_def_id(), br.kind);
+ let region_vid = {
+ let name = match br.kind.get_name() {
+ Some(name) => name,
+ _ => Symbol::intern("anon"),
+ };
+
+ self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name)))
+ };
+
indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
debug!(?liberated_region, ?region_vid);
region_vid
@@ -775,7 +827,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
for_each_late_bound_region_in_recursive_scope(self.tcx, mir_def_id, |r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
- let region_vid = self.next_nll_region_var(FR);
+ let region_vid = {
+ let name = match r.get_name() {
+ Some(name) => name,
+ _ => Symbol::intern("anon"),
+ };
+
+ self.next_nll_region_var(FR, || {
+ RegionCtxt::LateBound(BoundRegionInfo::Name(name))
+ })
+ };
+
debug!(?region_vid);
indices.insert_late_bound_region(r, region_vid.to_region_vid());
}
@@ -791,8 +853,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
for_each_late_bound_region_in_item(self.tcx, mir_def_id, |r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
- let region_vid = self.next_nll_region_var(FR);
- debug!(?region_vid);
+ let region_vid = {
+ let name = match r.get_name() {
+ Some(name) => name,
+ _ => Symbol::intern("anon"),
+ };
+
+ self.next_nll_region_var(FR, || {
+ RegionCtxt::LateBound(BoundRegionInfo::Name(name))
+ })
+ };
+
indices.insert_late_bound_region(r, region_vid.to_region_vid());
}
});
@@ -821,6 +892,11 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
if let ty::ReVar(..) = *r {
r.to_region_vid()
+ } else if r.is_error() {
+ // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the
+ // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if
+ // errors are being emitted and 2) it leaves the happy path unaffected.
+ self.fr_static
} else {
*self
.indices
@@ -833,9 +909,9 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
/// returned by `to_region_vid`.
pub fn fold_to_region_vids<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T
where
- T: TypeFoldable<'tcx>,
+ T: TypeFoldable<TyCtxt<'tcx>>,
{
- tcx.fold_regions(value, |region, _| tcx.mk_region(ty::ReVar(self.to_region_vid(region))))
+ tcx.fold_regions(value, |region, _| tcx.mk_re_var(self.to_region_vid(region)))
}
}
@@ -875,8 +951,7 @@ fn for_each_late_bound_region_in_item<'tcx>(
for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) {
let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; };
- let liberated_region = tcx
- .mk_region(ty::ReFree(ty::FreeRegion { scope: mir_def_id.to_def_id(), bound_region }));
+ let liberated_region = tcx.mk_re_free(mir_def_id.to_def_id(), bound_region);
f(liberated_region);
}
}