summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck')
-rw-r--r--compiler/rustc_borrowck/Cargo.toml1
-rw-r--r--compiler/rustc_borrowck/src/constraint_generation.rs14
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs11
-rw-r--r--compiler/rustc_borrowck/src/consumers.rs9
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs150
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs182
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs218
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs30
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs163
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs168
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs127
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs26
-rw-r--r--compiler/rustc_borrowck/src/lib.rs76
-rw-r--r--compiler/rustc_borrowck/src/location.rs5
-rw-r--r--compiler/rustc_borrowck/src/nll.rs19
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs28
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs233
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs393
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs4
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs14
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs130
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs52
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs73
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs81
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs39
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs377
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs19
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs32
32 files changed, 1391 insertions, 1295 deletions
diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml
index fbf628e86..87c113f3e 100644
--- a/compiler/rustc_borrowck/Cargo.toml
+++ b/compiler/rustc_borrowck/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
either = "1.5.0"
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
index 5e9cec5c3..f185e402f 100644
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -14,8 +14,8 @@ use crate::{
places_conflict, region_infer::values::LivenessValues,
};
-pub(super) fn generate_constraints<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
+pub(super) fn generate_constraints<'tcx>(
+ infcx: &InferCtxt<'tcx>,
liveness_constraints: &mut LivenessValues<RegionVid>,
all_facts: &mut Option<AllFacts>,
location_table: &LocationTable,
@@ -31,14 +31,14 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
body,
};
- for (bb, data) in body.basic_blocks().iter_enumerated() {
+ for (bb, data) in body.basic_blocks.iter_enumerated() {
cg.visit_basic_block_data(bb, data);
}
}
/// 'cg = the duration of the constraint generation process itself.
-struct ConstraintGeneration<'cg, 'cx, 'tcx> {
- infcx: &'cg InferCtxt<'cx, 'tcx>,
+struct ConstraintGeneration<'cg, 'tcx> {
+ infcx: &'cg InferCtxt<'tcx>,
all_facts: &'cg mut Option<AllFacts>,
location_table: &'cg LocationTable,
liveness_constraints: &'cg mut LivenessValues<RegionVid>,
@@ -46,7 +46,7 @@ struct ConstraintGeneration<'cg, 'cx, 'tcx> {
body: &'cg Body<'tcx>,
}
-impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
+impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
self.super_basic_block_data(bb, data);
}
@@ -156,7 +156,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
}
}
-impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
+impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> {
/// Some variable with type `live_ty` is "regular live" at
/// `location` -- i.e., it may be used later. This means that all
/// regions appearing in the type `live_ty` must be live at
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index a504d0c91..df0412813 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -21,10 +21,7 @@ pub(crate) struct OutlivesConstraintSet<'tcx> {
impl<'tcx> OutlivesConstraintSet<'tcx> {
pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
- debug!(
- "OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
- constraint.sup, constraint.sub, constraint.locations
- );
+ debug!("OutlivesConstraintSet::push({:?})", constraint);
if constraint.sup == constraint.sub {
// 'a: 'a is pretty uninteresting
return;
@@ -73,7 +70,7 @@ impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
}
}
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq)]
pub struct OutlivesConstraint<'tcx> {
// NB. The ordering here is not significant for correctness, but
// it is for convenience. Before we dump the constraints in the
@@ -105,8 +102,8 @@ impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
- "({:?}: {:?}) due to {:?} ({:?})",
- self.sup, self.sub, self.locations, self.variance_info
+ "({:?}: {:?}) due to {:?} ({:?}) ({:?})",
+ self.sup, self.sub, self.locations, self.variance_info, self.category,
)
}
}
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index efc17a173..b162095f8 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -31,9 +31,8 @@ pub fn get_body_with_borrowck_facts<'tcx>(
def: ty::WithOptConstParam<LocalDefId>,
) -> BodyWithBorrowckFacts<'tcx> {
let (input_body, promoted) = tcx.mir_promoted(def);
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| {
- let input_body: &Body<'_> = &input_body.borrow();
- let promoted: &IndexVec<_, _> = &promoted.borrow();
- *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
- })
+ let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).build();
+ let input_body: &Body<'_> = &input_body.borrow();
+ let promoted: &IndexVec<_, _> = &promoted.borrow();
+ *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
}
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 97d5a8d15..9f7a4d499 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -143,7 +143,7 @@ struct OutOfScopePrecomputer<'a, 'tcx> {
impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
OutOfScopePrecomputer {
- visited: BitSet::new_empty(body.basic_blocks().len()),
+ visited: BitSet::new_empty(body.basic_blocks.len()),
visit_stack: vec![],
body,
regioncx,
@@ -391,7 +391,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
| mir::StatementKind::Retag { .. }
| mir::StatementKind::AscribeUserType(..)
| mir::StatementKind::Coverage(..)
- | mir::StatementKind::CopyNonOverlapping(..)
+ | mir::StatementKind::Intrinsic(..)
| 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 1ef2b0ae9..02071ed6b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -56,7 +56,7 @@ impl<'tcx> UniverseInfo<'tcx> {
) {
match self.0 {
UniverseInfoInner::RelateTys { expected, found } => {
- let err = mbcx.infcx.report_mismatched_types(
+ let err = mbcx.infcx.err_ctxt().report_mismatched_types(
&cause,
expected,
found,
@@ -238,20 +238,11 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
- cause.span,
- &self.canonical_query,
- |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
- try_extract_error_from_fulfill_cx(
- fulfill_cx,
- infcx,
- placeholder_region,
- error_region,
- )
- },
- )
+ let (ref infcx, key, _) =
+ mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
}
}
@@ -288,37 +279,24 @@ where
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
- cause.span,
- &self.canonical_query,
- |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
- let mut selcx = SelectionContext::new(infcx);
-
- // FIXME(lqd): Unify and de-duplicate the following with the actual
- // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
- // `ObligationCause`. The normalization results are currently different between
- // `AtExt::normalize` used in the query and `normalize` called below: the former fails
- // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
- // after #85499 lands to see if its fixes have erased this difference.
- let (param_env, value) = key.into_parts();
- let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
- &mut selcx,
- param_env,
- cause,
- value.value,
- );
- fulfill_cx.register_predicate_obligations(infcx, obligations);
-
- try_extract_error_from_fulfill_cx(
- fulfill_cx,
- infcx,
- placeholder_region,
- error_region,
- )
- },
- )
+ let (ref infcx, key, _) =
+ mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+
+ let mut selcx = SelectionContext::new(infcx);
+
+ // FIXME(lqd): Unify and de-duplicate the following with the actual
+ // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
+ // `ObligationCause`. The normalization results are currently different between
+ // `AtExt::normalize` used in the query and `normalize` called below: the former fails
+ // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
+ // after #85499 lands to see if its fixes have erased this difference.
+ let (param_env, value) = key.into_parts();
+ let Normalized { value: _, obligations } =
+ rustc_trait_selection::traits::normalize(&mut selcx, param_env, cause, value.value);
+ fulfill_cx.register_predicate_obligations(infcx, obligations);
+
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
}
}
@@ -349,21 +327,11 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
- cause.span,
- &self.canonical_query,
- |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
- .ok()?;
- try_extract_error_from_fulfill_cx(
- fulfill_cx,
- infcx,
- placeholder_region,
- error_region,
- )
- },
- )
+ let (ref infcx, key, _) =
+ mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)).ok()?;
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
}
}
@@ -407,7 +375,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
#[instrument(skip(fulfill_cx, infcx), level = "debug")]
fn try_extract_error_from_fulfill_cx<'tcx>(
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
@@ -427,7 +395,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
}
fn try_extract_error_from_region_constraints<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
region_constraints: &RegionConstraintData<'tcx>,
@@ -449,43 +417,37 @@ fn try_extract_error_from_region_constraints<'tcx>(
})?;
debug!(?sub_region, "cause = {:#?}", cause);
- let nice_error = match (error_region, *sub_region) {
- (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
- infcx,
- RegionResolutionError::SubSupConflict(
- vid,
- region_var_origin(vid),
- cause.clone(),
- error_region,
- cause.clone(),
- placeholder_region,
- vec![],
- ),
- ),
- (Some(error_region), _) => NiceRegionError::new(
- infcx,
- RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
+ let error = match (error_region, *sub_region) {
+ (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict(
+ vid,
+ region_var_origin(vid),
+ cause.clone(),
+ error_region,
+ cause.clone(),
+ placeholder_region,
+ vec![],
),
+ (Some(error_region), _) => {
+ RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region)
+ }
// Note universe here is wrong...
- (None, ty::ReVar(vid)) => NiceRegionError::new(
- infcx,
- RegionResolutionError::UpperBoundUniverseConflict(
- vid,
- region_var_origin(vid),
- universe_of_region(vid),
- cause.clone(),
- placeholder_region,
- ),
- ),
- (None, _) => NiceRegionError::new(
- infcx,
- RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
+ (None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict(
+ vid,
+ region_var_origin(vid),
+ universe_of_region(vid),
+ cause.clone(),
+ placeholder_region,
),
+ (None, _) => {
+ RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
+ }
};
- nice_error.try_report_from_nll().or_else(|| {
+ NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| {
if let SubregionOrigin::Subtype(trace) = cause {
Some(
- infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
+ infcx
+ .err_ctxt()
+ .report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch),
)
} else {
None
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 8bc8964bb..583bc2e28 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -16,7 +16,7 @@ use rustc_middle::mir::{
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
};
-use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
+use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
@@ -198,7 +198,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_span,
move_spans,
*moved_place,
- Some(used_place),
partially_str,
loop_message,
move_msg,
@@ -258,7 +257,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let ty = place.ty(self.body, self.infcx.tcx).ty;
// If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
- if is_loop_move & !in_pattern {
+ // Same for if we're in a loop, see #101119.
+ if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
err.span_suggestion_verbose(
@@ -368,6 +368,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
visitor.visit_body(&body);
+ let mut show_assign_sugg = false;
let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
| InitializationRequiringAction::Assignment = desired_action
{
@@ -395,6 +396,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.count()
== 0
{
+ show_assign_sugg = true;
"isn't initialized"
} else {
"is possibly-uninitialized"
@@ -445,13 +447,87 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
}
+
err.span_label(decl_span, "binding declared here but left uninitialized");
+ if show_assign_sugg {
+ struct LetVisitor {
+ decl_span: Span,
+ sugg_span: Option<Span>,
+ }
+
+ impl<'v> Visitor<'v> for LetVisitor {
+ fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+ if self.sugg_span.is_some() {
+ return;
+ }
+ if let hir::StmtKind::Local(hir::Local {
+ span, ty, init: None, ..
+ }) = &ex.kind && span.contains(self.decl_span) {
+ self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
+ }
+ hir::intravisit::walk_stmt(self, ex);
+ }
+ }
+
+ let mut visitor = LetVisitor { decl_span, sugg_span: None };
+ visitor.visit_body(&body);
+ if let Some(span) = visitor.sugg_span {
+ self.suggest_assign_value(&mut err, moved_place, span);
+ }
+ }
err
}
+ fn suggest_assign_value(
+ &self,
+ err: &mut Diagnostic,
+ moved_place: PlaceRef<'tcx>,
+ sugg_span: Span,
+ ) {
+ let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
+ debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
+
+ let tcx = self.infcx.tcx;
+ let implements_default = |ty, param_env| {
+ let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
+ return false;
+ };
+ // Regions are already solved, so we must use a fresh InferCtxt,
+ // but the type has region variables, so erase those.
+ tcx.infer_ctxt()
+ .build()
+ .type_implements_trait(
+ default_trait,
+ tcx.erase_regions(ty),
+ ty::List::empty(),
+ param_env,
+ )
+ .must_apply_modulo_regions()
+ };
+
+ let assign_value = match ty.kind() {
+ ty::Bool => "false",
+ ty::Float(_) => "0.0",
+ ty::Int(_) | ty::Uint(_) => "0",
+ ty::Never | ty::Error(_) => "",
+ ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
+ ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
+ _ => "todo!()",
+ };
+
+ if !assign_value.is_empty() {
+ err.span_suggestion_verbose(
+ sugg_span.shrink_to_hi(),
+ format!("consider assigning a value"),
+ format!(" = {}", assign_value),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
fn suggest_borrow_fn_like(
&self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ err: &mut Diagnostic,
ty: Ty<'tcx>,
move_sites: &[MoveSite],
value_name: &str,
@@ -526,12 +602,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
true
}
- fn suggest_adding_copy_bounds(
- &self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
- ty: Ty<'tcx>,
- span: Span,
- ) {
+ fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
let tcx = self.infcx.tcx;
let generics = tcx.generics_of(self.mir_def_id());
@@ -541,41 +612,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.and_then(|def_id| tcx.hir().get_generics(def_id))
else { return; };
// Try to find predicates on *generic params* that would allow copying `ty`
- let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
- let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
+ let infcx = tcx.infer_ctxt().build();
+ let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
- let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
- let cause = ObligationCause::new(
- span,
- self.mir_hir_id(),
- rustc_infer::traits::ObligationCauseCode::MiscObligation,
- );
- fulfill_cx.register_bound(
- &infcx,
- self.param_env,
- // Erase any region vids from the type, which may not be resolved
- infcx.tcx.erase_regions(ty),
- copy_did,
- cause,
- );
- // Select all, including ambiguous predicates
- let errors = fulfill_cx.select_all_or_error(&infcx);
-
- // Only emit suggestion if all required predicates are on generic
- errors
- .into_iter()
- .map(|err| match err.obligation.predicate.kind().skip_binder() {
- PredicateKind::Trait(predicate) => match predicate.self_ty().kind() {
- ty::Param(param_ty) => Ok((
- generics.type_param(param_ty, tcx),
- predicate.trait_ref.print_only_trait_path().to_string(),
- )),
- _ => Err(()),
- },
+ let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
+ let cause = ObligationCause::new(
+ span,
+ self.mir_hir_id(),
+ rustc_infer::traits::ObligationCauseCode::MiscObligation,
+ );
+ fulfill_cx.register_bound(
+ &infcx,
+ self.param_env,
+ // Erase any region vids from the type, which may not be resolved
+ infcx.tcx.erase_regions(ty),
+ copy_did,
+ cause,
+ );
+ // Select all, including ambiguous predicates
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+
+ // Only emit suggestion if all required predicates are on generic
+ let predicates: Result<Vec<_>, _> = errors
+ .into_iter()
+ .map(|err| match err.obligation.predicate.kind().skip_binder() {
+ PredicateKind::Trait(predicate) => match predicate.self_ty().kind() {
+ ty::Param(param_ty) => Ok((
+ generics.type_param(param_ty, tcx),
+ predicate.trait_ref.print_only_trait_path().to_string(),
+ )),
_ => Err(()),
- })
- .collect()
- });
+ },
+ _ => Err(()),
+ })
+ .collect();
if let Ok(predicates) = predicates {
suggest_constraining_type_params(
@@ -1124,6 +1194,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// short a lifetime. (But sometimes it is more useful to report
/// it as a more direct conflict between the execution of a
/// `Drop::drop` with an aliasing borrow.)
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn report_borrowed_value_does_not_live_long_enough(
&mut self,
location: Location,
@@ -1131,13 +1202,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
place_span: (Place<'tcx>, Span),
kind: Option<WriteKind>,
) {
- debug!(
- "report_borrowed_value_does_not_live_long_enough(\
- {:?}, {:?}, {:?}, {:?}\
- )",
- location, borrow, place_span, kind
- );
-
let drop_span = place_span.1;
let root_place =
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
@@ -1194,10 +1258,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
- debug!(
- "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
- place_desc, explanation
- );
+ debug!(?place_desc, ?explanation);
+
let err = match (place_desc, explanation) {
// If the outlives constraint comes from inside the closure,
// for example:
@@ -1469,6 +1531,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err
}
+ #[instrument(level = "debug", skip(self))]
fn report_temporary_value_does_not_live_long_enough(
&mut self,
location: Location,
@@ -1478,13 +1541,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
proper_span: Span,
explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
- debug!(
- "report_temporary_value_does_not_live_long_enough(\
- {:?}, {:?}, {:?}, {:?}\
- )",
- location, borrow, drop_span, proper_span
- );
-
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
explanation
{
@@ -2164,7 +2220,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
StorageDeadOrDrop::Destructor(_) => kind,
},
- ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
+ ProjectionElem::OpaqueCast { .. }
+ | ProjectionElem::Field(..)
+ | ProjectionElem::Downcast(..) => {
match place_ty.ty.kind() {
ty::Adt(def, _) if def.has_dtor(tcx) => {
// Report the outermost adt with a destructor
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 72aee0267..582d683dd 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -1,8 +1,5 @@
//! Print diagnostics to explain why values are borrowed.
-use std::collections::VecDeque;
-
-use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic};
use rustc_index::vec::IndexVec;
use rustc_infer::infer::NllRegionVariableOrigin;
@@ -15,7 +12,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt};
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{sym, DesugaringKind, Span};
-use crate::region_infer::BlameConstraint;
+use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
WriteKind,
@@ -38,6 +35,7 @@ pub(crate) enum BorrowExplanation<'tcx> {
span: Span,
region_name: RegionName,
opt_place_desc: Option<String>,
+ extra_info: Vec<ExtraConstraintInfo>,
},
Unexplained,
}
@@ -243,6 +241,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
ref region_name,
ref opt_place_desc,
from_closure: _,
+ ref extra_info,
} => {
region_name.highlight_region_name(err);
@@ -268,18 +267,30 @@ impl<'tcx> BorrowExplanation<'tcx> {
);
};
+ for extra in extra_info {
+ match extra {
+ ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
+ err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+ }
+ }
+ }
+
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
}
_ => {}
}
}
- pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic(
+
+ fn add_lifetime_bound_suggestion_to_diagnostic(
&self,
err: &mut Diagnostic,
category: &ConstraintCategory<'tcx>,
span: Span,
region_name: &RegionName,
) {
+ if !span.is_desugaring(DesugaringKind::OpaqueTy) {
+ return;
+ }
if let ConstraintCategory::OpaqueType = category {
let suggestable_name =
if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime };
@@ -305,18 +316,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&self,
borrow_region: RegionVid,
outlived_region: RegionVid,
- ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>) {
- let BlameConstraint { category, from_closure, cause, variance_info: _ } =
- self.regioncx.best_blame_constraint(
- &self.body,
- borrow_region,
- NllRegionVariableOrigin::FreeRegion,
- |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
- );
+ ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
+ let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
+ borrow_region,
+ NllRegionVariableOrigin::FreeRegion,
+ |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
+ );
+ let BlameConstraint { category, from_closure, cause, .. } = blame_constraint;
let outlived_fr_name = self.give_region_a_name(outlived_region);
- (category, from_closure, cause.span, outlived_fr_name)
+ (category, from_closure, cause.span, outlived_fr_name, extra_info)
}
/// Returns structured explanation for *why* the borrow contains the
@@ -332,37 +342,51 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// - second half is the place being accessed
///
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn explain_why_borrow_contains_point(
&self,
location: Location,
borrow: &BorrowData<'tcx>,
kind_place: Option<(WriteKind, Place<'tcx>)>,
) -> BorrowExplanation<'tcx> {
- debug!(
- "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
- location, borrow, kind_place
- );
-
let regioncx = &self.regioncx;
let body: &Body<'_> = &self.body;
let tcx = self.infcx.tcx;
let borrow_region_vid = borrow.region;
- debug!("explain_why_borrow_contains_point: borrow_region_vid={:?}", borrow_region_vid);
-
- let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
- debug!("explain_why_borrow_contains_point: region_sub={:?}", region_sub);
+ debug!(?borrow_region_vid);
+
+ let mut region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
+ debug!(?region_sub);
+
+ let mut use_location = location;
+ let mut use_in_later_iteration_of_loop = false;
+
+ if region_sub == borrow_region_vid {
+ // When `region_sub` is the same as `borrow_region_vid` (the location where the borrow is
+ // issued is the same location that invalidates the reference), this is likely a loop iteration
+ // - in this case, try using the loop terminator location in `find_sub_region_live_at`.
+ if let Some(loop_terminator_location) =
+ regioncx.find_loop_terminator_location(borrow.region, body)
+ {
+ region_sub = self
+ .regioncx
+ .find_sub_region_live_at(borrow_region_vid, loop_terminator_location);
+ debug!("explain_why_borrow_contains_point: region_sub in loop={:?}", region_sub);
+ use_location = loop_terminator_location;
+ use_in_later_iteration_of_loop = true;
+ }
+ }
- match find_use::find(body, regioncx, tcx, region_sub, location) {
+ match find_use::find(body, regioncx, tcx, region_sub, use_location) {
Some(Cause::LiveVar(local, location)) => {
let span = body.source_info(location).span;
let spans = self
.move_spans(Place::from(local).as_ref(), location)
.or_else(|| self.borrow_spans(span, location));
- let borrow_location = location;
- if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
- let later_use = self.later_use_kind(borrow, spans, location);
+ if use_in_later_iteration_of_loop {
+ let later_use = self.later_use_kind(borrow, spans, use_location);
BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
} else {
// Check if the location represents a `FakeRead`, and adapt the error
@@ -392,7 +416,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None => {
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
- let (category, from_closure, span, region_name) =
+ let (category, from_closure, span, region_name, extra_info) =
self.free_region_constraint_info(borrow_region_vid, region);
if let Some(region_name) = region_name {
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
@@ -402,150 +426,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span,
region_name,
opt_place_desc,
+ extra_info,
}
} else {
- debug!(
- "explain_why_borrow_contains_point: \
- Could not generate a region name"
- );
+ debug!("Could not generate a region name");
BorrowExplanation::Unexplained
}
} else {
- debug!(
- "explain_why_borrow_contains_point: \
- Could not generate an error region vid"
- );
+ debug!("Could not generate an error region vid");
BorrowExplanation::Unexplained
}
}
}
}
- /// true if `borrow_location` can reach `use_location` by going through a loop and
- /// `use_location` is also inside of that loop
- fn is_use_in_later_iteration_of_loop(
- &self,
- borrow_location: Location,
- use_location: Location,
- ) -> bool {
- let back_edge = self.reach_through_backedge(borrow_location, use_location);
- back_edge.map_or(false, |back_edge| self.can_reach_head_of_loop(use_location, back_edge))
- }
-
- /// Returns the outmost back edge if `from` location can reach `to` location passing through
- /// that back edge
- fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Location> {
- let mut visited_locations = FxHashSet::default();
- let mut pending_locations = VecDeque::new();
- visited_locations.insert(from);
- pending_locations.push_back(from);
- debug!("reach_through_backedge: from={:?} to={:?}", from, to,);
-
- let mut outmost_back_edge = None;
- while let Some(location) = pending_locations.pop_front() {
- debug!(
- "reach_through_backedge: location={:?} outmost_back_edge={:?}
- pending_locations={:?} visited_locations={:?}",
- location, outmost_back_edge, pending_locations, visited_locations
- );
-
- if location == to && outmost_back_edge.is_some() {
- // We've managed to reach the use location
- debug!("reach_through_backedge: found!");
- return outmost_back_edge;
- }
-
- let block = &self.body.basic_blocks()[location.block];
-
- if location.statement_index < block.statements.len() {
- let successor = location.successor_within_block();
- if visited_locations.insert(successor) {
- pending_locations.push_back(successor);
- }
- } else {
- pending_locations.extend(
- block
- .terminator()
- .successors()
- .map(|bb| Location { statement_index: 0, block: bb })
- .filter(|s| visited_locations.insert(*s))
- .map(|s| {
- if self.is_back_edge(location, s) {
- match outmost_back_edge {
- None => {
- outmost_back_edge = Some(location);
- }
-
- Some(back_edge)
- if location.dominates(back_edge, &self.dominators) =>
- {
- outmost_back_edge = Some(location);
- }
-
- Some(_) => {}
- }
- }
-
- s
- }),
- );
- }
- }
-
- None
- }
-
- /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the
- /// intermediate nodes
- fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool {
- self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default())
- }
-
- fn find_loop_head_dfs(
- &self,
- from: Location,
- loop_head: Location,
- visited_locations: &mut FxHashSet<Location>,
- ) -> bool {
- visited_locations.insert(from);
-
- if from == loop_head {
- return true;
- }
-
- if loop_head.dominates(from, &self.dominators) {
- let block = &self.body.basic_blocks()[from.block];
-
- if from.statement_index < block.statements.len() {
- let successor = from.successor_within_block();
-
- if !visited_locations.contains(&successor)
- && self.find_loop_head_dfs(successor, loop_head, visited_locations)
- {
- return true;
- }
- } else {
- for bb in block.terminator().successors() {
- let successor = Location { statement_index: 0, block: bb };
-
- if !visited_locations.contains(&successor)
- && self.find_loop_head_dfs(successor, loop_head, visited_locations)
- {
- return true;
- }
- }
- }
- }
-
- false
- }
-
- /// True if an edge `source -> target` is a backedge -- in other words, if the target
- /// dominates the source.
- fn is_back_edge(&self, source: Location, target: Location) -> bool {
- target.dominates(source, &self.dominators)
- }
-
/// Determine how the borrow was later used.
/// First span returned points to the location of the conflicting use
/// Second span if `Some` is returned in the case of closures and points
@@ -564,7 +458,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
UseSpans::PatUse(span)
| UseSpans::OtherUse(span)
| UseSpans::FnSelfUse { var_span: span, .. } => {
- let block = &self.body.basic_blocks()[location.block];
+ let block = &self.body.basic_blocks[location.block];
let kind = if let Some(&Statement {
kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 098e8de94..534d9ecae 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -237,6 +237,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
ProjectionElem::Downcast(..) if opt.including_downcast => return None,
ProjectionElem::Downcast(..) => (),
+ ProjectionElem::OpaqueCast(..) => (),
ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -317,6 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
}
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
+ ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
};
@@ -970,7 +972,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_span: Span,
move_spans: UseSpans<'tcx>,
moved_place: Place<'tcx>,
- used_place: Option<PlaceRef<'tcx>>,
partially_str: &str,
loop_message: &str,
move_msg: &str,
@@ -1024,7 +1025,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
- Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
+ Some(def_id) => {
+ let infcx = self.infcx.tcx.infer_ctxt().build();
type_known_to_meet_bound_modulo_regions(
&infcx,
self.param_env,
@@ -1035,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id,
DUMMY_SP,
)
- }),
+ }
_ => false,
};
if suggest {
@@ -1058,9 +1060,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
place_name, partially_str, loop_message
),
);
- // If we have a `&mut` ref, we need to reborrow.
- if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place
- .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind())
+ // If the moved place was a `&mut` ref, then we can
+ // suggest to reborrow it where it was moved, so it
+ // will still be valid by the time we get to the usage.
+ if let ty::Ref(_, _, hir::Mutability::Mut) =
+ moved_place.ty(self.body, self.infcx.tcx).ty.kind()
{
// If we are in a loop this will be suggested later.
if !is_loop_move {
@@ -1086,14 +1090,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
),
);
}
- if is_option_or_result && maybe_reinitialized_locations_is_empty {
- err.span_suggestion_verbose(
- fn_call_span.shrink_to_lo(),
- "consider calling `.as_ref()` to borrow the type's contents",
- "as_ref().",
- Applicability::MachineApplicable,
- );
- }
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
@@ -1102,6 +1098,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
);
}
+ if is_option_or_result && maybe_reinitialized_locations_is_empty {
+ err.span_label(
+ var_span,
+ "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents",
+ );
+ }
}
// Other desugarings takes &self, which cannot cause a move
_ => {}
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index cb3cd479a..5a47f4567 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -88,7 +88,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(StatementKind::Assign(box (
place,
Rvalue::Use(Operand::Move(move_from)),
- ))) = self.body.basic_blocks()[location.block]
+ ))) = self.body.basic_blocks[location.block]
.statements
.get(location.statement_index)
.map(|stmt| &stmt.kind)
@@ -360,7 +360,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
diag.span_label(upvar_span, "captured outer variable");
diag.span_label(
- self.body.span,
+ self.infcx.tcx.def_span(def_id),
format!("captured by this `{closure_kind}` closure"),
);
@@ -401,7 +401,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
if let Some(use_spans) = use_spans {
self.explain_captures(
- &mut err, span, span, use_spans, move_place, None, "", "", "", false, true,
+ &mut err, span, span, use_spans, move_place, "", "", "", false, true,
);
}
err
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 0ad4abbce..8ad40c0aa 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1,23 +1,23 @@
+use rustc_errors::{
+ Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed,
+};
use rustc_hir as hir;
+use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
use rustc_middle::hir::map::Map;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{
hir::place::PlaceBase,
- mir::{
- self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo,
- LocalKind, Location,
- },
+ mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{sym, BytePos, Span};
use crate::diagnostics::BorrowedContentSource;
use crate::MirBorrowckCtxt;
use rustc_const_eval::util::collect_writes::FindAssignments;
-use rustc_errors::{Applicability, Diagnostic};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum AccessKind {
@@ -169,6 +169,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
..,
ProjectionElem::Index(_)
| ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
],
@@ -309,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&& !matches!(
decl.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
- ImplicitSelfKind::MutRef
+ hir::ImplicitSelfKind::MutRef
))))
)
{
@@ -364,7 +365,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
&& let hir::PatKind::Binding(
- hir::BindingAnnotation::Unannotated,
+ hir::BindingAnnotation::NONE,
_,
upvar_ident,
_,
@@ -614,6 +615,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
"trait `IndexMut` is required to modify indexed content, \
but it is not implemented for `{ty}`",
));
+ self.suggest_map_index_mut_alternatives(ty, &mut err, span);
}
_ => (),
}
@@ -627,6 +629,127 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.buffer_error(err);
}
+ fn suggest_map_index_mut_alternatives(
+ &self,
+ ty: Ty<'_>,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ span: Span,
+ ) {
+ let Some(adt) = ty.ty_adt_def() else { return };
+ let did = adt.did();
+ if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
+ || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
+ {
+ struct V<'a, 'b, 'tcx, G: EmissionGuarantee> {
+ assign_span: Span,
+ err: &'a mut DiagnosticBuilder<'b, G>,
+ ty: Ty<'tcx>,
+ suggested: bool,
+ }
+ impl<'a, 'b: 'a, 'hir, 'tcx, G: EmissionGuarantee> Visitor<'hir> for V<'a, 'b, 'tcx, G> {
+ fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) {
+ hir::intravisit::walk_stmt(self, stmt);
+ let expr = match stmt.kind {
+ hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
+ hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr,
+ _ => {
+ return;
+ }
+ };
+ if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
+ && let hir::ExprKind::Index(val, index) = place.kind
+ && (expr.span == self.assign_span || place.span == self.assign_span)
+ {
+ // val[index] = rv;
+ // ---------- place
+ self.err.multipart_suggestions(
+ &format!(
+ "to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
+ self.ty,
+ ),
+ vec![
+ vec![ // val.insert(index, rv);
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".insert(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(rv.span.lo()),
+ ", ".to_string(),
+ ),
+ (rv.span.shrink_to_hi(), ")".to_string()),
+ ],
+ vec![ // val.get_mut(index).map(|v| { *v = rv; });
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".get_mut(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(place.span.hi()),
+ ").map(|val| { *val".to_string(),
+ ),
+ (
+ rv.span.shrink_to_hi(),
+ "; })".to_string(),
+ ),
+ ],
+ vec![ // let x = val.entry(index).or_insert(rv);
+ (val.span.shrink_to_lo(), "let val = ".to_string()),
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".entry(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(rv.span.lo()),
+ ").or_insert(".to_string(),
+ ),
+ (rv.span.shrink_to_hi(), ")".to_string()),
+ ],
+ ].into_iter(),
+ Applicability::MachineApplicable,
+ );
+ self.suggested = true;
+ } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
+ && let hir::ExprKind::Index(val, index) = receiver.kind
+ && expr.span == self.assign_span
+ {
+ // val[index].path(args..);
+ self.err.multipart_suggestion(
+ &format!("to modify a `{}` use `.get_mut()`", self.ty),
+ vec![
+ (
+ val.span.shrink_to_hi().with_hi(index.span.lo()),
+ ".get_mut(".to_string(),
+ ),
+ (
+ index.span.shrink_to_hi().with_hi(receiver.span.hi()),
+ ").map(|val| val".to_string(),
+ ),
+ (sp.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ self.suggested = true;
+ }
+ }
+ }
+ let hir_map = self.infcx.tcx.hir();
+ let def_id = self.body.source.def_id();
+ let hir_id = hir_map.local_def_id_to_hir_id(def_id.as_local().unwrap());
+ let node = hir_map.find(hir_id);
+ let Some(hir::Node::Item(item)) = node else { return; };
+ let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
+ let body = self.infcx.tcx.hir().body(body_id);
+ let mut v = V { assign_span: span, err, ty, suggested: false };
+ v.visit_body(body);
+ if !v.suggested {
+ err.help(&format!(
+ "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
+ ));
+ }
+ }
+ }
+
/// User cannot make signature of a trait mutable without changing the
/// trait. So we find if this error belongs to a trait and if so we move
/// suggestion to the trait or disable it if it is out of scope of this crate
@@ -786,11 +909,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
[
Expr {
kind:
- MethodCall(
- path_segment,
- _args,
- span,
- ),
+ MethodCall(path_segment, _, _, span),
hir_id,
..
},
@@ -810,10 +929,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
_,
) = hir_map.body(fn_body_id).value.kind
{
- let opt_suggestions = path_segment
- .hir_id
- .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
- .and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
+ let opt_suggestions = self
+ .infcx
+ .tcx
+ .typeck(path_segment.hir_id.owner.def_id)
+ .type_dependent_def_id(*hir_id)
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
.map(|def_id| self.infcx.tcx.associated_items(def_id))
.map(|assoc_items| {
@@ -851,6 +971,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let hir = self.infcx.tcx.hir();
let closure_id = self.mir_hir_id();
+ let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
let fn_call_id = hir.get_parent_node(closure_id);
let node = hir.get(fn_call_id);
let def_id = hir.enclosing_body_owner(fn_call_id);
@@ -902,7 +1023,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(span) = arg {
err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
err.span_label(func.span, "expects `Fn` instead of `FnMut`");
- err.span_label(self.body.span, "in this closure");
+ err.span_label(closure_span, "in this closure");
look_at_return = false;
}
}
@@ -911,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if look_at_return && hir.get_return_block(closure_id).is_some() {
// ...otherwise we are probably in the tail expression of the function, point at the
// return type.
- match hir.get_by_def_id(hir.get_parent_item(fn_call_id)) {
+ match hir.get_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. })
| hir::Node::TraitItem(hir::TraitItem {
ident,
@@ -928,7 +1049,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
sig.decl.output.span(),
"change this to return `FnMut` instead of `Fn`",
);
- err.span_label(self.body.span, "in this closure");
+ err.span_label(closure_span, "in this closure");
}
_ => {}
}
@@ -952,7 +1073,7 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
//
// Deliberately fall into this case for all implicit self types,
// so that we don't fall in to the next case with them.
- *kind == mir::ImplicitSelfKind::MutRef
+ *kind == hir::ImplicitSelfKind::MutRef
}
_ if Some(kw::SelfLower) == local_name => {
// Otherwise, check if the name is the `self` keyword - in which case
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index d359d7efb..35c3df768 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -6,7 +6,6 @@ use rustc_errors::Diagnostic;
use rustc_middle::ty::RegionVid;
use smallvec::SmallVec;
use std::collections::BTreeMap;
-use tracing::debug;
use crate::MirBorrowckCtxt;
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 176090c3b..15230718d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1,3 +1,5 @@
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
//! Error reporting machinery for lifetime errors.
use rustc_data_structures::fx::FxHashSet;
@@ -23,10 +25,13 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use crate::borrowck_errors;
-use crate::session_diagnostics::GenericDoesNotLiveLongEnough;
+use crate::session_diagnostics::{
+ FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
+ LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
+};
use super::{OutlivesSuggestionBuilder, RegionName};
-use crate::region_infer::BlameConstraint;
+use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
use crate::{
nll::ConstraintDescription,
region_infer::{values::RegionElement, TypeTest},
@@ -181,7 +186,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(lower_bound_region) = lower_bound_region {
let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
let origin = RelateParamBound(type_test_span, generic_ty, None);
- self.buffer_error(self.infcx.construct_generic_bound_failure(
+ self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure(
self.body.source.def_id().expect_local(),
type_test_span,
Some(origin),
@@ -229,7 +234,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
let (_, cause) = self.regioncx.find_outlives_blame_span(
- &self.body,
longer_fr,
NllRegionVariableOrigin::Placeholder(placeholder),
error_vid,
@@ -277,7 +281,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let tcx = self.infcx.tcx;
match tcx.hir().get_if_local(def_id) {
Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+ match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ {
Some(Node::Item(Item {
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
..
@@ -287,7 +292,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
Some(Node::TraitItem(trait_item)) => {
let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did) {
+ match tcx.hir().find_by_def_id(trait_did.def_id) {
Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
// The method being called is defined in the `trait`, but the `'static`
// obligation comes from the `impl`. Find that `impl` so that we can point
@@ -336,7 +341,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// Report an error because the universal region `fr` was required to outlive
/// `outlived_fr` but it is not known to do so. For example:
///
- /// ```compile_fail,E0312
+ /// ```compile_fail
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
/// ```
///
@@ -350,16 +355,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
) {
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
- let BlameConstraint { category, cause, variance_info, from_closure: _ } =
- self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
+ let (blame_constraint, extra_info) =
+ self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
});
+ let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;
debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
// Check if we can use one of the "nice region errors".
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
- let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
+ let infer_err = self.infcx.err_ctxt();
+ let nice = NiceRegionError::new_from_span(&infer_err, cause.span, o, f);
if let Some(diag) = nice.try_report_from_nll() {
self.buffer_error(diag);
return;
@@ -462,6 +469,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
+ for extra in extra_info {
+ match extra {
+ ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
+ diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+ }
+ }
+ }
+
self.buffer_error(diag);
}
@@ -488,12 +503,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
- let mut diag = self
- .infcx
- .tcx
- .sess
- .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body");
-
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
if let ty::Opaque(def_id, _) = *output_ty.kind() {
output_ty = self.infcx.tcx.type_of(def_id)
@@ -501,19 +510,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
debug!("report_fnmut_error: output_ty={:?}", output_ty);
- let message = match output_ty.kind() {
- ty::Closure(_, _) => {
- "returns a closure that contains a reference to a captured variable, which then \
- escapes the closure body"
- }
- ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => {
- "returns an `async` block that contains a reference to a captured variable, which then \
- escapes the closure body"
- }
- _ => "returns a reference to a captured variable which escapes the closure body",
+ let err = FnMutError {
+ span: *span,
+ ty_err: match output_ty.kind() {
+ ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span },
+ ty::Adt(def, _)
+ if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) =>
+ {
+ FnMutReturnTypeErr::ReturnAsyncBlock { span: *span }
+ }
+ _ => FnMutReturnTypeErr::ReturnRef { span: *span },
+ },
};
- diag.span_label(*span, message);
+ let mut diag = self.infcx.tcx.sess.create_err(err);
if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty {
@@ -532,20 +542,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
let upvar_span = upvars_map.get(&def_hir).unwrap().span;
- diag.span_label(upvar_def_span, "variable defined here");
- diag.span_label(upvar_span, "variable captured here");
+ diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span });
+ diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span });
}
}
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
- diag.span_label(fr_span, "inferred to be a `FnMut` closure");
+ diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
}
- diag.note(
- "`FnMut` closures only have access to their captured variables while they are \
- executing...",
- );
- diag.note("...therefore, they cannot allow references to captured variables to escape");
+ self.suggest_move_on_borrowing_closure(&mut diag);
diag
}
@@ -562,6 +568,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// LL | ref_obj(x)
/// | ^^^^^^^^^^ `x` escapes the function body here
/// ```
+ #[instrument(level = "debug", skip(self))]
fn report_escaping_data_error(
&self,
errci: &ErrorConstraintInfo<'tcx>,
@@ -680,42 +687,37 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
..
} = errci;
- let mut diag =
- self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough");
-
let (_, mir_def_name) =
self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id());
+ let err = LifetimeOutliveErr { span: *span };
+ let mut diag = self.infcx.tcx.sess.create_err(err);
+
let fr_name = self.give_region_a_name(*fr).unwrap();
fr_name.highlight_region_name(&mut diag);
let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap();
outlived_fr_name.highlight_region_name(&mut diag);
- match (category, outlived_fr_is_local, fr_is_local) {
- (ConstraintCategory::Return(_), true, _) => {
- diag.span_label(
- *span,
- format!(
- "{mir_def_name} was supposed to return data with lifetime `{outlived_fr_name}` but it is returning \
- data with lifetime `{fr_name}`",
- ),
- );
- }
- _ => {
- diag.span_label(
- *span,
- format!(
- "{}requires that `{}` must outlive `{}`",
- category.description(),
- fr_name,
- outlived_fr_name,
- ),
- );
- }
- }
+ let err_category = match (category, outlived_fr_is_local, fr_is_local) {
+ (ConstraintCategory::Return(_), true, _) => LifetimeReturnCategoryErr::WrongReturn {
+ span: *span,
+ mir_def_name,
+ outlived_fr_name,
+ fr_name: &fr_name,
+ },
+ _ => LifetimeReturnCategoryErr::ShortReturn {
+ span: *span,
+ category_desc: category.description(),
+ free_region_name: &fr_name,
+ outlived_fr_name,
+ },
+ };
+
+ diag.subdiagnostic(err_category);
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
+ self.suggest_move_on_borrowing_closure(&mut diag);
diag
}
@@ -783,7 +785,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn maybe_suggest_constrain_dyn_trait_impl(
&self,
- diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ diag: &mut Diagnostic,
f: Region<'tcx>,
o: Region<'tcx>,
category: &ConstraintCategory<'tcx>,
@@ -860,7 +862,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
ident.span,
"calling this method introduces the `impl`'s 'static` requirement",
);
- err.span_note(multi_span, "the used `impl` has a `'static` requirement");
+ err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
err.span_suggestion_verbose(
span.shrink_to_hi(),
"consider relaxing the implicit `'static` requirement",
@@ -901,4 +903,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
}
+
+ fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) {
+ let map = self.infcx.tcx.hir();
+ let body_id = map.body_owned_by(self.mir_def_id());
+ let expr = &map.body(body_id).value;
+ let mut closure_span = None::<rustc_span::Span>;
+ match expr.kind {
+ hir::ExprKind::MethodCall(.., args, _) => {
+ for arg in args {
+ if let hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ ..
+ }) = arg.kind
+ {
+ closure_span = Some(arg.span.shrink_to_lo());
+ break;
+ }
+ }
+ }
+ hir::ExprKind::Block(blk, _) => {
+ if let Some(ref expr) = blk.expr {
+ // only when the block is a closure
+ if let hir::ExprKind::Closure(hir::Closure {
+ capture_clause: hir::CaptureBy::Ref,
+ ..
+ }) = expr.kind
+ {
+ closure_span = Some(expr.span.shrink_to_lo());
+ }
+ }
+ }
+ _ => {}
+ }
+ if let Some(closure_span) = closure_span {
+ diag.span_suggestion_verbose(
+ closure_span,
+ "consider adding 'move' keyword before the nested closure",
+ "move ",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index a87e8bd5b..c044dbaba 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -251,7 +251,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
.or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
.or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
.or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr))
- .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr));
+ .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr))
+ .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr));
if let Some(ref value) = value {
self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
@@ -265,7 +266,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// *user* has a name for. In that case, we'll be able to map
/// `fr` to a `Region<'tcx>`, and that region will be one of
/// named variants.
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?;
@@ -357,11 +358,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::BoundRegionKind::BrAnon(_) => None,
},
- ty::ReLateBound(..)
- | ty::ReVar(..)
- | ty::RePlaceholder(..)
- | ty::ReEmpty(_)
- | ty::ReErased => None,
+ ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
}
}
@@ -373,7 +370,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | fn foo(x: &u32) { .. }
/// ------- fully elaborated type of `x` is `&'1 u32`
/// ```
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_arguments(
&self,
fr: RegionVid,
@@ -662,7 +659,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// | let x = Some(&22);
/// - fully elaborated type of `x` is `Option<&'1 u32>`
/// ```
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
@@ -682,7 +679,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// must be a closure since, in a free fn, such an argument would
/// have to either also appear in an argument (if using elision)
/// or be early bound (named, not in argument).
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
let tcx = self.infcx.tcx;
let hir = tcx.hir();
@@ -711,7 +708,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
hir::AsyncGeneratorKind::Block => " of async block",
hir::AsyncGeneratorKind::Closure => " of async closure",
hir::AsyncGeneratorKind::Fn => {
- let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id));
+ let parent_item =
+ hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
let output = &parent_item
.fn_decl()
.expect("generator lowered from async fn should be in fn")
@@ -772,7 +770,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
let hir = self.infcx.tcx.hir();
- let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
+ let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else {
span_bug!(
hir_ty.span,
"lowered return type of async fn is not OpaqueDef: {:?}",
@@ -814,7 +812,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
}
}
- #[tracing::instrument(level = "trace", skip(self))]
+ #[instrument(level = "trace", skip(self))]
fn give_name_if_anonymous_region_appears_in_yield_ty(
&self,
fr: RegionVid,
@@ -867,20 +865,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
};
let tcx = self.infcx.tcx;
- let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?;
- if tcx.parent(region.def_id) != body_parent_did
- || tcx.def_kind(body_parent_did) != DefKind::Impl
- {
+ let region_parent = tcx.parent(region.def_id);
+ if tcx.def_kind(region_parent) != DefKind::Impl {
return None;
}
- let mut found = false;
- tcx.fold_regions(tcx.type_of(body_parent_did), |r: ty::Region<'tcx>, _| {
- if *r == ty::ReEarlyBound(region) {
- found = true;
- }
- r
- });
+ let found = tcx
+ .any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region));
Some(RegionName {
name: self.synthesize_region_name(),
@@ -893,4 +884,92 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
),
})
}
+
+ fn give_name_if_anonymous_region_appears_in_arg_position_impl_trait(
+ &self,
+ fr: RegionVid,
+ ) -> Option<RegionName> {
+ let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else {
+ return None;
+ };
+ if region.has_name() {
+ return None;
+ };
+
+ let predicates = self
+ .infcx
+ .tcx
+ .predicates_of(self.body.source.def_id())
+ .instantiate_identity(self.infcx.tcx)
+ .predicates;
+
+ if let Some(upvar_index) = self
+ .regioncx
+ .universal_regions()
+ .defining_ty
+ .upvar_tys()
+ .position(|ty| self.any_param_predicate_mentions(&predicates, ty, region))
+ {
+ let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
+ self.infcx.tcx,
+ &self.upvars,
+ upvar_index,
+ );
+ let region_name = self.synthesize_region_name();
+
+ Some(RegionName {
+ name: region_name,
+ source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name),
+ })
+ } else if let Some(arg_index) = self
+ .regioncx
+ .universal_regions()
+ .unnormalized_input_tys
+ .iter()
+ .position(|ty| self.any_param_predicate_mentions(&predicates, *ty, region))
+ {
+ let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region(
+ self.body,
+ &self.local_names,
+ arg_index,
+ );
+ let region_name = self.synthesize_region_name();
+
+ Some(RegionName {
+ name: region_name,
+ source: RegionNameSource::AnonRegionFromArgument(
+ RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()),
+ ),
+ })
+ } else {
+ None
+ }
+ }
+
+ fn any_param_predicate_mentions(
+ &self,
+ predicates: &[ty::Predicate<'tcx>],
+ ty: Ty<'tcx>,
+ region: ty::EarlyBoundRegion,
+ ) -> bool {
+ let tcx = self.infcx.tcx;
+ ty.walk().any(|arg| {
+ if let ty::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Param(_) = ty.kind()
+ {
+ predicates.iter().any(|pred| {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(data) if data.self_ty() == ty => {}
+ ty::PredicateKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
+ _ => return false,
+ }
+ tcx.any_free_region_meets(pred, |r| {
+ *r == ty::ReEarlyBound(region)
+ })
+ })
+ } else {
+ false
+ }
+ })
+ }
}
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index ec521b1cf..3157f861d 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -1,6 +1,6 @@
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
+use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
use rustc_middle::mir::{BorrowKind, Mutability, Operand};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{Statement, StatementKind};
@@ -63,23 +63,24 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
StatementKind::FakeRead(box (_, _)) => {
// Only relevant for initialized/liveness/safety checks.
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+ self.consume_operand(location, op);
+ }
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
ref src,
ref dst,
ref count,
- }) => {
+ })) => {
self.consume_operand(location, src);
self.consume_operand(location, dst);
self.consume_operand(location, count);
}
- StatementKind::Nop
+ // Only relevant for mir typeck
+ StatementKind::AscribeUserType(..)
+ // Doesn't have any language semantics
| StatementKind::Coverage(..)
- | StatementKind::AscribeUserType(..)
- | StatementKind::Retag { .. }
- | StatementKind::StorageLive(..) => {
- // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
- // to borrow check.
- }
+ // Does not actually affect borrowck
+ | StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
location,
@@ -88,7 +89,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
LocalMutationIsAllowed::Yes,
);
}
- StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ StatementKind::Nop
+ | StatementKind::Retag { .. }
+ | StatementKind::Deinit(..)
+ | StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
}
}
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 3d8b07382..abfe253d4 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -3,7 +3,6 @@
#![allow(rustc::potential_query_instability)]
#![feature(box_patterns)]
#![feature(let_chains)]
-#![feature(let_else)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
@@ -19,15 +18,15 @@ extern crate tracing;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::dominators::Dominators;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
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_middle::mir::{
- traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
- PlaceRef, VarDebugInfoContents,
+ traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
+ Place, PlaceElem, PlaceRef, VarDebugInfoContents,
};
use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
@@ -51,6 +50,8 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveE
use rustc_mir_dataflow::Analysis;
use rustc_mir_dataflow::MoveDataParamEnv;
+use crate::session_diagnostics::VarNeedNotMut;
+
use self::diagnostics::{AccessKind, RegionName};
use self::location::LocationTable;
use self::prefixes::PrefixSet;
@@ -130,14 +131,11 @@ fn mir_borrowck<'tcx>(
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
- let opt_closure_req = tcx
- .infer_ctxt()
- .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner))
- .enter(|infcx| {
- let input_body: &Body<'_> = &input_body.borrow();
- let promoted: &IndexVec<_, _> = &promoted.borrow();
- do_mir_borrowck(&infcx, input_body, promoted, false).0
- });
+ let infcx =
+ tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build();
+ let input_body: &Body<'_> = &input_body.borrow();
+ let promoted: &IndexVec<_, _> = &promoted.borrow();
+ let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, false).0;
debug!("mir_borrowck done");
tcx.arena.alloc(opt_closure_req)
@@ -149,8 +147,8 @@ fn mir_borrowck<'tcx>(
/// region ids on which the borrow checking was performed together with Polonius
/// facts.
#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")]
-fn do_mir_borrowck<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+fn do_mir_borrowck<'tcx>(
+ infcx: &InferCtxt<'tcx>,
input_body: &Body<'tcx>,
input_promoted: &IndexVec<Promoted, Body<'tcx>>,
return_body_with_facts: bool,
@@ -425,17 +423,9 @@ fn do_mir_borrowck<'a, 'tcx>(
continue;
}
- tcx.struct_span_lint_hir(UNUSED_MUT, lint_root, span, |lint| {
- let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
- lint.build("variable does not need to be mutable")
- .span_suggestion_short(
- mut_span,
- "remove this `mut`",
- "",
- Applicability::MachineApplicable,
- )
- .emit();
- })
+ let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
+
+ tcx.emit_spanned_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
}
let tainted_by_errors = mbcx.emit_errors();
@@ -481,7 +471,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
}
struct MirBorrowckCtxt<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
body: &'cx Body<'tcx>,
move_data: &'cx MoveData<'tcx>,
@@ -597,22 +587,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
flow_state,
);
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
- ..
- }) => {
- span_bug!(
+ StatementKind::Intrinsic(box ref kind) => match kind {
+ NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
+ NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
span,
"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
)
}
- StatementKind::Nop
+ // Only relevant for mir typeck
+ StatementKind::AscribeUserType(..)
+ // Doesn't have any language semantics
| StatementKind::Coverage(..)
- | StatementKind::AscribeUserType(..)
- | StatementKind::Retag { .. }
- | StatementKind::StorageLive(..) => {
- // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
- // to borrow check.
- }
+ // Does not actually affect borrowck
+ | StatementKind::StorageLive(..) => {}
StatementKind::StorageDead(local) => {
self.access_place(
location,
@@ -622,7 +609,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
flow_state,
);
}
- StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+ StatementKind::Nop
+ | StatementKind::Retag { .. }
+ | StatementKind::Deinit(..)
+ | StatementKind::SetDiscriminant { .. } => {
bug!("Statement not allowed in this MIR phase")
}
}
@@ -982,6 +972,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
+ #[instrument(level = "debug", skip(self, flow_state))]
fn check_access_for_conflict(
&mut self,
location: Location,
@@ -990,11 +981,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
rw: ReadOrWrite,
flow_state: &Flows<'cx, 'tcx>,
) -> bool {
- debug!(
- "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})",
- location, place_span, sd, rw,
- );
-
let mut error_reported = false;
let tcx = self.infcx.tcx;
let body = self.body;
@@ -1458,13 +1444,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Checks whether a borrow of this place is invalidated when the function
/// exits
+ #[instrument(level = "debug", skip(self))]
fn check_for_invalidation_at_exit(
&mut self,
location: Location,
borrow: &BorrowData<'tcx>,
span: Span,
) {
- debug!("check_for_invalidation_at_exit({:?})", borrow);
let place = borrow.borrowed_place;
let mut root_place = PlaceRef { local: place.local, projection: &[] };
@@ -1791,6 +1777,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
for (place_base, elem) in place.iter_projections().rev() {
match elem {
ProjectionElem::Index(_/*operand*/) |
+ ProjectionElem::OpaqueCast(_) |
ProjectionElem::ConstantIndex { .. } |
// assigning to P[i] requires P to be valid.
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
@@ -2182,6 +2169,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
+ | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Downcast(..) => {
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs
index 70a311694..877944d3d 100644
--- a/compiler/rustc_borrowck/src/location.rs
+++ b/compiler/rustc_borrowck/src/location.rs
@@ -33,7 +33,7 @@ impl LocationTable {
pub(crate) fn new(body: &Body<'_>) -> Self {
let mut num_points = 0;
let statements_before_block = body
- .basic_blocks()
+ .basic_blocks
.iter()
.map(|block_data| {
let v = num_points;
@@ -86,8 +86,7 @@ impl LocationTable {
let (block, &first_index) = self
.statements_before_block
.iter_enumerated()
- .filter(|(_, first_index)| **first_index <= point_index)
- .last()
+ .rfind(|&(_, &first_index)| first_index <= point_index)
.unwrap();
let statement_index = (point_index - first_index) / 2;
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 0961203d7..08fdd28eb 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -55,8 +55,8 @@ pub(crate) struct NllOutput<'tcx> {
/// regions (e.g., region parameters) declared on the function. That set will need to be given to
/// `compute_regions`.
#[instrument(skip(infcx, param_env, body, promoted), level = "debug")]
-pub(crate) fn replace_regions_in_mir<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
+pub(crate) fn replace_regions_in_mir<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &mut Body<'tcx>,
promoted: &mut IndexVec<Promoted, Body<'tcx>>,
@@ -155,7 +155,7 @@ fn populate_polonius_move_facts(
///
/// This may result in errors being reported.
pub(crate) fn compute_regions<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
universal_regions: UniversalRegions<'tcx>,
body: &Body<'tcx>,
promoted: &IndexVec<Promoted, Body<'tcx>>,
@@ -318,8 +318,8 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
}
}
-pub(super) fn dump_mir_results<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub(super) fn dump_mir_results<'tcx>(
+ infcx: &InferCtxt<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
@@ -368,8 +368,8 @@ pub(super) fn dump_mir_results<'a, 'tcx>(
};
}
-pub(super) fn dump_annotation<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub(super) fn dump_annotation<'tcx>(
+ infcx: &InferCtxt<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
@@ -389,8 +389,9 @@ pub(super) fn dump_annotation<'a, 'tcx>(
// viewing the intraprocedural state, the -Zdump-mir output is
// better.
+ let def_span = tcx.def_span(body.source.def_id());
let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
- let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "external requirements");
+ let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "external requirements");
regioncx.annotate(tcx, &mut err);
@@ -409,7 +410,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
err
} else {
- let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements");
+ let mut err = tcx.sess.diagnostic().span_note_diag(def_span, "no external requirements");
regioncx.annotate(tcx, &mut err);
err
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 97335fd0d..0e71efd6f 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -44,6 +44,7 @@ pub(crate) fn places_conflict<'tcx>(
/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
/// array indices, for example) should be interpreted - this depends on what the caller wants in
/// order to make the conservative choice and preserve soundness.
+#[instrument(level = "debug", skip(tcx, body))]
pub(super) fn borrow_conflicts_with_place<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
@@ -53,11 +54,6 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
access: AccessDepth,
bias: PlaceConflictBias,
) -> bool {
- debug!(
- "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})",
- borrow_place, access_place, access, bias,
- );
-
// This Local/Local case is handled by the more general code below, but
// it's so common that it's a speed win to check for it first.
if let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() {
@@ -140,10 +136,9 @@ fn place_components_conflict<'tcx>(
for (i, (borrow_c, &access_c)) in
iter::zip(borrow_place.projection, access_place.projection).enumerate()
{
- debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
- let borrow_proj_base = &borrow_place.projection[..i];
+ debug!(?borrow_c, ?access_c);
- debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
+ let borrow_proj_base = &borrow_place.projection[..i];
// Borrow and access path both have more components.
//
@@ -180,7 +175,7 @@ fn place_components_conflict<'tcx>(
// idea, at least for now, so just give up and
// report a conflict. This is unsafe code anyway so
// the user could always use raw pointers.
- debug!("borrow_conflicts_with_place: arbitrary -> conflict");
+ debug!("arbitrary -> conflict");
return true;
}
Overlap::EqualOrDisjoint => {
@@ -189,7 +184,7 @@ fn place_components_conflict<'tcx>(
Overlap::Disjoint => {
// We have proven the borrow disjoint - further
// projections will remain disjoint.
- debug!("borrow_conflicts_with_place: disjoint");
+ debug!("disjoint");
return false;
}
}
@@ -255,6 +250,7 @@ fn place_components_conflict<'tcx>(
| (ProjectionElem::Index { .. }, _, _)
| (ProjectionElem::ConstantIndex { .. }, _, _)
| (ProjectionElem::Subslice { .. }, _, _)
+ | (ProjectionElem::OpaqueCast { .. }, _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
@@ -322,6 +318,17 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
Overlap::EqualOrDisjoint
}
+ (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => {
+ if v1 == v2 {
+ // same type - recur.
+ debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");
+ Overlap::EqualOrDisjoint
+ } else {
+ // Different types. Disjoint!
+ debug!("place_element_conflict: DISJOINT-OPAQUE");
+ Overlap::Disjoint
+ }
+ }
(ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {
if f1 == f2 {
// same field (e.g., `a.y` vs. `a.y`) - recur.
@@ -525,6 +532,7 @@ fn place_projection_conflict<'tcx>(
| ProjectionElem::Field(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
_,
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index bdf2becb7..2b50cbac9 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -81,6 +81,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
}
ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
+ | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Index(_) => {
cursor = cursor_base;
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 2894c6d29..8b63294fb 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -15,7 +15,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound,
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
- ConstraintCategory, Local, Location, ReturnConstraint,
+ ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
};
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::ObligationCauseCode;
@@ -135,7 +135,6 @@ pub struct RegionInferenceContext<'tcx> {
/// adds a new lower bound to the SCC it is analyzing: so you wind up
/// with `'R: 'O` where `'R` is the pick-region and `'O` is the
/// minimal viable option.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct AppliedMemberConstraint {
/// The SCC that was affected. (The "member region".)
///
@@ -246,6 +245,11 @@ enum Trace<'tcx> {
NotVisited,
}
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum ExtraConstraintInfo {
+ PlaceholderFromPredicate(Span),
+}
+
impl<'tcx> RegionInferenceContext<'tcx> {
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
@@ -561,7 +565,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(skip(self, infcx, body, polonius_output), level = "debug")]
pub(super) fn solve(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
polonius_output: Option<Rc<PoloniusOutput>>,
@@ -591,13 +595,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// constraints were too strong, and if so, emit or propagate those errors.
if infcx.tcx.sess.opts.unstable_opts.polonius {
self.check_polonius_subset_errors(
- body,
outlives_requirements.as_mut(),
&mut errors_buffer,
polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"),
);
} else {
- self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer);
+ self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer);
}
if errors_buffer.is_empty() {
@@ -832,7 +835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// 'a`. See `TypeTest` for more details.
fn check_type_tests(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
@@ -920,7 +923,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))]
fn try_promote_type_test(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
type_test: &TypeTest<'tcx>,
@@ -1033,7 +1036,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(level = "debug", skip(self, infcx))]
fn try_promote_type_test_subject(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
ty: Ty<'tcx>,
) -> Option<ClosureOutlivesSubject<'tcx>> {
let tcx = infcx.tcx;
@@ -1139,7 +1142,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// include the CFG anyhow.
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
/// a result `'y`.
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
debug!(r = %self.region_value_str(r));
@@ -1151,8 +1154,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
}
- debug!(?lub);
-
lub
}
@@ -1167,8 +1168,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Therefore, this method should only be used in diagnostic code,
/// where displaying *some* named universal region is better than
/// falling back to 'static.
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
- debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
+ debug!("{}", self.region_value_str(r));
// Find the smallest universal region that contains all other
// universal regions within `region`.
@@ -1177,7 +1179,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let static_r = self.universal_regions.fr_static;
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
- debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub);
+ debug!(?ur, ?lub, ?new_lub);
// The upper bound of two non-static regions is static: this
// means we know nothing about the relationship between these
// two regions. Pick a 'better' one to use when constructing
@@ -1201,7 +1203,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
- debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub);
+ debug!(?r, ?lub);
lub
}
@@ -1210,7 +1212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// `point`.
fn eval_verify_bound(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
generic_ty: Ty<'tcx>,
@@ -1260,7 +1262,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn eval_if_eq(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
@@ -1332,15 +1334,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
// Evaluate whether `sup_region: sub_region`.
- #[instrument(skip(self), level = "debug")]
+ #[instrument(skip(self), level = "debug", ret)]
fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
debug!(
- "eval_outlives: sup_region's value = {:?} universal={:?}",
+ "sup_region's value = {:?} universal={:?}",
self.region_value_str(sup_region),
self.universal_regions.is_universal_region(sup_region),
);
debug!(
- "eval_outlives: sub_region's value = {:?} universal={:?}",
+ "sub_region's value = {:?} universal={:?}",
self.region_value_str(sub_region),
self.universal_regions.is_universal_region(sub_region),
);
@@ -1353,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// true if `'sup` outlives static.
if !self.universe_compatible(sub_region_scc, sup_region_scc) {
debug!(
- "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
+ "sub universe `{sub_region_scc:?}` is not nameable \
by super `{sup_region_scc:?}`, promoting to static",
);
@@ -1374,9 +1376,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
});
if !universal_outlives {
- debug!(
- "eval_outlives: returning false because sub region contains a universal region not present in super"
- );
+ debug!("sub region contains a universal region not present in super");
return false;
}
@@ -1385,22 +1385,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if self.universal_regions.is_universal_region(sup_region) {
// Micro-opt: universal regions contain all points.
- debug!(
- "eval_outlives: returning true because super is universal and hence contains all points"
- );
+ debug!("super is universal and hence contains all points");
return true;
}
- let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
- debug!("returning {} because of comparison between points in sup/sub", result);
- result
+ debug!("comparison between points in sup/sub");
+
+ self.scc_values.contains_points(sup_region_scc, sub_region_scc)
}
/// Once regions have been propagated, this method is used to see
/// whether any of the constraints were too strong. In particular,
/// we want to check for a case where a universally quantified
/// region exceeded its bounds. Consider:
- /// ```compile_fail,E0312
+ /// ```compile_fail
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
/// ```
/// In this case, returning `x` requires `&'a u32 <: &'b u32`
@@ -1415,7 +1413,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// report them as errors.
fn check_universal_regions(
&self,
- body: &Body<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut RegionErrors<'tcx>,
) {
@@ -1426,7 +1423,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// they did not grow too large, accumulating any requirements
// for our caller into the `outlives_requirements` vector.
self.check_universal_region(
- body,
fr,
&mut propagated_outlives_requirements,
errors_buffer,
@@ -1455,7 +1451,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// <https://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/>
///
/// In the canonical example
- /// ```compile_fail,E0312
+ /// ```compile_fail
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
/// ```
/// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a
@@ -1467,7 +1463,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// report them as errors.
fn check_polonius_subset_errors(
&self,
- body: &Body<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut RegionErrors<'tcx>,
polonius_output: Rc<PoloniusOutput>,
@@ -1514,7 +1509,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let propagated = self.try_propagate_universal_region_error(
*longer_fr,
*shorter_fr,
- body,
&mut propagated_outlives_requirements,
);
if propagated == RegionRelationCheckResult::Error {
@@ -1554,13 +1548,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
///
/// Things that are to be propagated are accumulated into the
/// `outlives_requirements` vector.
- #[instrument(
- skip(self, body, propagated_outlives_requirements, errors_buffer),
- level = "debug"
- )]
+ #[instrument(skip(self, propagated_outlives_requirements, errors_buffer), level = "debug")]
fn check_universal_region(
&self,
- body: &Body<'tcx>,
longer_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
errors_buffer: &mut RegionErrors<'tcx>,
@@ -1583,7 +1573,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let RegionRelationCheckResult::Error = self.check_universal_region_relation(
longer_fr,
representative,
- body,
propagated_outlives_requirements,
) {
errors_buffer.push(RegionErrorKind::RegionError {
@@ -1603,7 +1592,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let RegionRelationCheckResult::Error = self.check_universal_region_relation(
longer_fr,
shorter_fr,
- body,
propagated_outlives_requirements,
) {
// We only report the first region error. Subsequent errors are hidden so as
@@ -1628,7 +1616,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
- body: &Body<'tcx>,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
) -> RegionRelationCheckResult {
// If it is known that `fr: o`, carry on.
@@ -1644,7 +1631,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.try_propagate_universal_region_error(
longer_fr,
shorter_fr,
- body,
propagated_outlives_requirements,
)
}
@@ -1656,7 +1642,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
- body: &Body<'tcx>,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
) -> RegionRelationCheckResult {
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
@@ -1668,7 +1653,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
let blame_span_category = self.find_outlives_blame_span(
- body,
longer_fr,
NllRegionVariableOrigin::FreeRegion,
shorter_fr,
@@ -1734,7 +1718,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn check_member_constraints(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
errors_buffer: &mut RegionErrors<'tcx>,
) {
let member_constraints = self.member_constraints.clone();
@@ -1822,50 +1806,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn retrieve_closure_constraint_info(
&self,
- _body: &Body<'tcx>,
- constraint: &OutlivesConstraint<'tcx>,
- ) -> BlameConstraint<'tcx> {
- let loc = match constraint.locations {
- Locations::All(span) => {
- return BlameConstraint {
- category: constraint.category,
- from_closure: false,
- cause: ObligationCause::dummy_with_span(span),
- variance_info: constraint.variance_info,
- };
+ constraint: OutlivesConstraint<'tcx>,
+ ) -> Option<(ConstraintCategory<'tcx>, Span)> {
+ match constraint.locations {
+ Locations::All(_) => None,
+ Locations::Single(loc) => {
+ self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)).copied()
}
- Locations::Single(loc) => loc,
- };
-
- let opt_span_category =
- self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
- opt_span_category
- .map(|&(category, span)| BlameConstraint {
- category,
- from_closure: true,
- cause: ObligationCause::dummy_with_span(span),
- variance_info: constraint.variance_info,
- })
- .unwrap_or(BlameConstraint {
- category: constraint.category,
- from_closure: false,
- cause: ObligationCause::dummy_with_span(constraint.span),
- variance_info: constraint.variance_info,
- })
+ }
}
/// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
pub(crate) fn find_outlives_blame_span(
&self,
- body: &Body<'tcx>,
fr1: RegionVid,
fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid,
) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
- let BlameConstraint { category, cause, .. } =
- self.best_blame_constraint(body, fr1, fr1_origin, |r| {
- self.provides_universal_region(r, fr1, fr2)
- });
+ let BlameConstraint { category, cause, .. } = self
+ .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2))
+ .0;
(category, cause)
}
@@ -1970,7 +1930,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
/// Finds some region R such that `fr1: R` and `R` is live at `elem`.
- #[instrument(skip(self), level = "trace")]
+ #[instrument(skip(self), level = "trace", ret)]
pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
trace!(scc = ?self.constraint_sccs.scc(fr1));
trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
@@ -2048,23 +2008,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// creating a constraint path that forces `R` to outlive
/// `from_region`, and then finding the best choices within that
/// path to blame.
+ #[instrument(level = "debug", skip(self, target_test))]
pub(crate) fn best_blame_constraint(
&self,
- body: &Body<'tcx>,
from_region: RegionVid,
from_region_origin: NllRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool,
- ) -> BlameConstraint<'tcx> {
- debug!(
- "best_blame_constraint(from_region={:?}, from_region_origin={:?})",
- from_region, from_region_origin
- );
-
+ ) -> (BlameConstraint<'tcx>, Vec<ExtraConstraintInfo>) {
// Find all paths
let (path, target_region) =
self.find_constraint_paths_between_regions(from_region, target_test).unwrap();
debug!(
- "best_blame_constraint: path={:#?}",
+ "path={:#?}",
path.iter()
.map(|c| format!(
"{:?} ({:?}: {:?})",
@@ -2075,6 +2030,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.collect::<Vec<_>>()
);
+ let mut extra_info = vec![];
+ for constraint in path.iter() {
+ let outlived = constraint.sub;
+ let Some(origin) = self.var_infos.get(outlived) else { continue; };
+ let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin else { continue; };
+ debug!(?constraint, ?p);
+ let ConstraintCategory::Predicate(span) = constraint.category else { continue; };
+ extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span));
+ // We only want to point to one
+ break;
+ }
+
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
// Instead, we use it to produce an improved `ObligationCauseCode`.
// FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
@@ -2100,23 +2067,33 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
.iter()
.map(|constraint| {
- if constraint.category == ConstraintCategory::ClosureBounds {
- self.retrieve_closure_constraint_info(body, &constraint)
- } else {
- BlameConstraint {
- category: constraint.category,
- from_closure: false,
- cause: ObligationCause::new(
- constraint.span,
- CRATE_HIR_ID,
- cause_code.clone(),
- ),
- variance_info: constraint.variance_info,
- }
+ let (category, span, from_closure, cause_code) =
+ if constraint.category == ConstraintCategory::ClosureBounds {
+ if let Some((category, span)) =
+ self.retrieve_closure_constraint_info(*constraint)
+ {
+ (category, span, true, ObligationCauseCode::MiscObligation)
+ } else {
+ (
+ constraint.category,
+ constraint.span,
+ false,
+ ObligationCauseCode::MiscObligation,
+ )
+ }
+ } else {
+ (constraint.category, constraint.span, false, cause_code.clone())
+ };
+ BlameConstraint {
+ category,
+ from_closure,
+ cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code),
+ variance_info: constraint.variance_info,
+ outlives_constraint: *constraint,
}
})
.collect();
- debug!("best_blame_constraint: categorized_path={:#?}", categorized_path);
+ debug!("categorized_path={:#?}", categorized_path);
// To find the best span to cite, we first try to look for the
// final constraint that is interesting and where the `sup` is
@@ -2214,10 +2191,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let best_choice =
if blame_source { range.rev().find(find_region) } else { range.find(find_region) };
- debug!(
- "best_blame_constraint: best_choice={:?} blame_source={}",
- best_choice, blame_source
- );
+ debug!(?best_choice, ?blame_source, ?extra_info);
if let Some(i) = best_choice {
if let Some(next) = categorized_path.get(i + 1) {
@@ -2226,7 +2200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
{
// The return expression is being influenced by the return type being
// impl Trait, point at the return type and not the return expr.
- return next.clone();
+ return (next.clone(), extra_info);
}
}
@@ -2246,7 +2220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
- return categorized_path[i].clone();
+ return (categorized_path[i].clone(), extra_info);
}
// If that search fails, that is.. unusual. Maybe everything
@@ -2254,14 +2228,35 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// appears to be the most interesting point to report to the
// user via an even more ad-hoc guess.
categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
- debug!("best_blame_constraint: sorted_path={:#?}", categorized_path);
+ debug!("sorted_path={:#?}", categorized_path);
- categorized_path.remove(0)
+ (categorized_path.remove(0), extra_info)
}
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
self.universe_causes[&universe].clone()
}
+
+ /// Tries to find the terminator of the loop in which the region 'r' resides.
+ /// Returns the location of the terminator if found.
+ pub(crate) fn find_loop_terminator_location(
+ &self,
+ r: RegionVid,
+ body: &Body<'_>,
+ ) -> Option<Location> {
+ let scc = self.constraint_sccs.scc(r.to_region_vid());
+ let locations = self.scc_values.locations_outlived_by(scc);
+ for location in locations {
+ let bb = &body[location.block];
+ if let Some(terminator) = &bb.terminator {
+ // terminator of a loop should be TerminatorKind::FalseUnwind
+ if let TerminatorKind::FalseUnwind { .. } = terminator.kind {
+ return Some(location);
+ }
+ }
+ }
+ None
+ }
}
impl<'tcx> RegionDefinition<'tcx> {
@@ -2338,7 +2333,13 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
outlives_requirement={:?}",
region, outlived_region, outlives_requirement,
);
- ty::Binder::dummy(ty::OutlivesPredicate(region.into(), outlived_region))
+ (
+ ty::Binder::dummy(ty::OutlivesPredicate(
+ region.into(),
+ outlived_region,
+ )),
+ ConstraintCategory::BoringNoLocation,
+ )
}
ClosureOutlivesSubject::Ty(ty) => {
@@ -2348,7 +2349,10 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
outlives_requirement={:?}",
ty, outlived_region, outlives_requirement,
);
- ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region))
+ (
+ ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)),
+ ConstraintCategory::BoringNoLocation,
+ )
}
}
})
@@ -2362,4 +2366,5 @@ pub struct BlameConstraint<'tcx> {
pub from_closure: bool,
pub cause: ObligationCause<'tcx>,
pub variance_info: ty::VarianceDiagInfo<'tcx>,
+ pub outlives_constraint: OutlivesConstraint<'tcx>,
}
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index d6712b6a4..465f353aa 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -2,18 +2,16 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::OpaqueTyOrigin;
-use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
use rustc_infer::infer::TyCtxtInferExt as _;
use rustc_infer::infer::{DefiningAnchor, InferCtxt};
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
-use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::TraitEngineExt as _;
use super::RegionInferenceContext;
@@ -58,10 +56,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
/// which has no `external_name` in which case we use `'empty` as the
/// region to pass to `infer_opaque_definition_from_instantiation`.
- #[instrument(level = "debug", skip(self, infcx))]
+ #[instrument(level = "debug", skip(self, infcx), ret)]
pub(crate) fn infer_opaque_types(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
@@ -107,7 +105,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.iter()
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
- .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
+ .unwrap_or(infcx.tcx.lifetimes.re_erased),
_ => region,
});
@@ -192,7 +190,7 @@ pub trait InferCtxtExt<'tcx> {
) -> Ty<'tcx>;
}
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an opaque type
@@ -227,31 +225,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return self.tcx.ty_error();
}
- let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
- // Use substs to build up a reverse map from regions to their
- // identity mappings. This is necessary because of `impl
- // Trait` lifetimes are computed by replacing existing
- // lifetimes with 'static and remapping only those used in the
- // `impl Trait` return type, resulting in the parameters
- // shifting.
- let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
- debug!(?id_substs);
- let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
- substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
- debug!("map = {:#?}", map);
-
- // Convert the type from the function into a type valid outside
- // the function, by replacing invalid regions with 'static,
- // after producing an error for each of them.
- let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
- self.tcx,
- opaque_type_key,
- map,
- instantiated_ty.ty,
- instantiated_ty.span,
- ));
- debug!(?definition_ty);
+ let definition_ty = instantiated_ty
+ .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin)
+ .ty;
if !check_opaque_type_parameter_valid(
self.tcx,
@@ -264,72 +240,70 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
- if let OpaqueTyOrigin::TyAlias = origin {
- // 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
- self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(
- move |infcx| {
- // Require the hidden type to be well-formed with only the generics of the opaque type.
- // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
- // hidden type is well formed even without those bounds.
- let predicate =
- ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
- .to_predicate(infcx.tcx);
- let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ let OpaqueTyOrigin::TyAlias = origin else {
+ return definition_ty;
+ };
+ let def_id = opaque_type_key.def_id;
+ // 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
+ let infcx =
+ self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build();
+ // Require the hidden type to be well-formed with only the generics of the opaque type.
+ // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+ // hidden type is well formed even without those bounds.
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
+ .to_predicate(infcx.tcx);
+ let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+
+ let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
- // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
- // the bounds that the function supplies.
- match infcx.register_hidden_type(
- OpaqueTypeKey { def_id, substs: id_substs },
- ObligationCause::misc(instantiated_ty.span, body_id),
- param_env,
+ // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
+ // the bounds that the function supplies.
+ let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
+ match infcx
+ .at(&ObligationCause::misc(instantiated_ty.span, body_id), param_env)
+ .eq(opaque_ty, definition_ty)
+ {
+ Ok(infer_ok) => {
+ for obligation in infer_ok.obligations {
+ fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+ }
+ }
+ Err(err) => {
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(
+ &ObligationCause::misc(instantiated_ty.span, body_id),
+ opaque_ty,
definition_ty,
- origin,
- ) {
- Ok(infer_ok) => {
- for obligation in infer_ok.obligations {
- fulfillment_cx.register_predicate_obligation(&infcx, obligation);
- }
- }
- Err(err) => {
- infcx
- .report_mismatched_types(
- &ObligationCause::misc(instantiated_ty.span, body_id),
- self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
- definition_ty,
- err,
- )
- .emit();
- }
- }
+ err,
+ )
+ .emit();
+ }
+ }
- fulfillment_cx.register_predicate_obligation(
- &infcx,
- Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
- );
+ fulfillment_cx.register_predicate_obligation(
+ &infcx,
+ Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
+ );
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = fulfillment_cx.select_all_or_error(&infcx);
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
- // This is still required for many(half of the tests in ui/type-alias-impl-trait)
- // tests to pass
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ // This is still required for many(half of the tests in ui/type-alias-impl-trait)
+ // tests to pass
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- if errors.is_empty() {
- definition_ty
- } else {
- infcx.report_fulfillment_errors(&errors, None, false);
- self.tcx.ty_error()
- }
- },
- )
- } else {
+ if errors.is_empty() {
definition_ty
+ } else {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ self.tcx.ty_error()
}
}
}
@@ -425,238 +399,3 @@ fn check_opaque_type_parameter_valid(
}
true
}
-
-struct ReverseMapper<'tcx> {
- tcx: TyCtxt<'tcx>,
-
- key: ty::OpaqueTypeKey<'tcx>,
- map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
- map_missing_regions_to_empty: bool,
-
- /// initially `Some`, set to `None` once error has been reported
- hidden_ty: Option<Ty<'tcx>>,
-
- /// Span of function being checked.
- span: Span,
-}
-
-impl<'tcx> ReverseMapper<'tcx> {
- fn new(
- tcx: TyCtxt<'tcx>,
- key: ty::OpaqueTypeKey<'tcx>,
- map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
- hidden_ty: Ty<'tcx>,
- span: Span,
- ) -> Self {
- Self {
- tcx,
- key,
- map,
- map_missing_regions_to_empty: false,
- hidden_ty: Some(hidden_ty),
- span,
- }
- }
-
- fn fold_kind_mapping_missing_regions_to_empty(
- &mut self,
- kind: GenericArg<'tcx>,
- ) -> GenericArg<'tcx> {
- assert!(!self.map_missing_regions_to_empty);
- self.map_missing_regions_to_empty = true;
- let kind = kind.fold_with(self);
- self.map_missing_regions_to_empty = false;
- kind
- }
-
- fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
- assert!(!self.map_missing_regions_to_empty);
- kind.fold_with(self)
- }
-}
-
-impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
- }
-
- #[instrument(skip(self), level = "debug")]
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- match *r {
- // Ignore bound regions and `'static` regions that appear in the
- // type, we only need to remap regions that reference lifetimes
- // from the function declaration.
- // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
- ty::ReLateBound(..) | ty::ReStatic => return r,
-
- // If regions have been erased (by writeback), don't try to unerase
- // them.
- ty::ReErased => return r,
-
- // The regions that we expect from borrow checking.
- ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
-
- ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
- // All of the regions in the type should either have been
- // erased by writeback, or mapped back to named regions by
- // borrow checking.
- bug!("unexpected region kind in opaque type: {:?}", r);
- }
- }
-
- let generics = self.tcx().generics_of(self.key.def_id);
- match self.map.get(&r.into()).map(|k| k.unpack()) {
- Some(GenericArgKind::Lifetime(r1)) => r1,
- Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
- None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
- None if generics.parent.is_some() => {
- if let Some(hidden_ty) = self.hidden_ty.take() {
- unexpected_hidden_region_diagnostic(
- self.tcx,
- self.tcx.def_span(self.key.def_id),
- hidden_ty,
- r,
- self.key,
- )
- .emit();
- }
- self.tcx.lifetimes.re_root_empty
- }
- None => {
- self.tcx
- .sess
- .struct_span_err(self.span, "non-defining opaque type use in defining scope")
- .span_label(
- self.span,
- format!(
- "lifetime `{}` is part of concrete type but not used in \
- parameter list of the `impl Trait` type alias",
- r
- ),
- )
- .emit();
-
- self.tcx().lifetimes.re_static
- }
- }
- }
-
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- match *ty.kind() {
- ty::Closure(def_id, substs) => {
- // I am a horrible monster and I pray for death. When
- // we encounter a closure here, it is always a closure
- // from within the function that we are currently
- // type-checking -- one that is now being encapsulated
- // in an opaque type. Ideally, we would
- // go through the types/lifetimes that it references
- // and treat them just like we would any other type,
- // which means we would error out if we find any
- // reference to a type/region that is not in the
- // "reverse map".
- //
- // **However,** in the case of closures, there is a
- // somewhat subtle (read: hacky) consideration. The
- // problem is that our closure types currently include
- // all the lifetime parameters declared on the
- // enclosing function, even if they are unused by the
- // closure itself. We can't readily filter them out,
- // so here we replace those values with `'empty`. This
- // can't really make a difference to the rest of the
- // compiler; those regions are ignored for the
- // outlives relation, and hence don't affect trait
- // selection or auto traits, and they are erased
- // during codegen.
-
- let generics = self.tcx.generics_of(def_id);
- let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
- if index < generics.parent_count {
- // Accommodate missing regions in the parent kinds...
- self.fold_kind_mapping_missing_regions_to_empty(kind)
- } else {
- // ...but not elsewhere.
- self.fold_kind_normally(kind)
- }
- }));
-
- self.tcx.mk_closure(def_id, substs)
- }
-
- ty::Generator(def_id, substs, movability) => {
- let generics = self.tcx.generics_of(def_id);
- let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
- if index < generics.parent_count {
- // Accommodate missing regions in the parent kinds...
- self.fold_kind_mapping_missing_regions_to_empty(kind)
- } else {
- // ...but not elsewhere.
- self.fold_kind_normally(kind)
- }
- }));
-
- self.tcx.mk_generator(def_id, substs, movability)
- }
-
- ty::Param(param) => {
- // Look it up in the substitution list.
- match self.map.get(&ty.into()).map(|k| k.unpack()) {
- // Found it in the substitution list; replace with the parameter from the
- // opaque type.
- Some(GenericArgKind::Type(t1)) => t1,
- Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
- None => {
- debug!(?param, ?self.map);
- self.tcx
- .sess
- .struct_span_err(
- self.span,
- &format!(
- "type parameter `{}` is part of concrete type but not \
- used in parameter list for the `impl Trait` type alias",
- ty
- ),
- )
- .emit();
-
- self.tcx().ty_error()
- }
- }
- }
-
- _ => ty.super_fold_with(self),
- }
- }
-
- fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
- trace!("checking const {:?}", ct);
- // Find a const parameter
- match ct.kind() {
- ty::ConstKind::Param(..) => {
- // Look it up in the substitution list.
- match self.map.get(&ct.into()).map(|k| k.unpack()) {
- // Found it in the substitution list, replace with the parameter from the
- // opaque type.
- Some(GenericArgKind::Const(c1)) => c1,
- Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
- None => {
- self.tcx
- .sess
- .struct_span_err(
- self.span,
- &format!(
- "const parameter `{}` is part of concrete type but not \
- used in parameter list for the `impl Trait` type alias",
- ct
- ),
- )
- .emit();
-
- self.tcx().const_error(ct.ty())
- }
- }
- }
-
- _ => ct,
- }
- }
-}
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index c81ef10f7..de20a4bb4 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -25,7 +25,7 @@ impl RegionValueElements {
pub(crate) fn new(body: &Body<'_>) -> Self {
let mut num_points = 0;
let statements_before_block: IndexVec<BasicBlock, usize> = body
- .basic_blocks()
+ .basic_blocks
.iter()
.map(|block_data| {
let v = num_points;
@@ -37,7 +37,7 @@ impl RegionValueElements {
debug!("RegionValueElements: num_points={:#?}", num_points);
let mut basic_blocks = IndexVec::with_capacity(num_points);
- for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
+ for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
}
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 7a8ce621c..f30237690 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,6 +1,7 @@
use rustc_index::vec::IndexVec;
use rustc_infer::infer::{InferCtxt, 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};
@@ -9,7 +10,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
/// inference variables, returning the number of variables created.
#[instrument(skip(infcx, body, promoted), level = "debug")]
pub fn renumber_mir<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
body: &mut Body<'tcx>,
promoted: &mut IndexVec<Promoted, Body<'tcx>>,
) {
@@ -27,7 +28,7 @@ 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
+pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
@@ -38,7 +39,7 @@ where
}
struct NllVisitor<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
@@ -77,7 +78,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
debug!(?region);
}
- fn visit_const(&mut self, constant: &mut ty::Const<'tcx>, _location: Location) {
- *constant = self.renumber_regions(*constant);
+ #[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);
+ debug!("constant: {:#?}", constant);
}
}
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 895723d44..cff3089c3 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -1,9 +1,12 @@
-use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_errors::{IntoDiagnosticArg, MultiSpan};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::Span;
-#[derive(SessionDiagnostic)]
-#[error(borrowck::move_unsized, code = "E0161")]
+use crate::diagnostics::RegionName;
+
+#[derive(Diagnostic)]
+#[diag(borrowck_move_unsized, code = "E0161")]
pub(crate) struct MoveUnsized<'tcx> {
pub ty: Ty<'tcx>,
#[primary_span]
@@ -11,8 +14,8 @@ pub(crate) struct MoveUnsized<'tcx> {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[error(borrowck::higher_ranked_lifetime_error)]
+#[derive(Diagnostic)]
+#[diag(borrowck_higher_ranked_lifetime_error)]
pub(crate) struct HigherRankedLifetimeError {
#[subdiagnostic]
pub cause: Option<HigherRankedErrorCause>,
@@ -20,25 +23,128 @@ pub(crate) struct HigherRankedLifetimeError {
pub span: Span,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub(crate) enum HigherRankedErrorCause {
- #[note(borrowck::could_not_prove)]
+ #[note(borrowck_could_not_prove)]
CouldNotProve { predicate: String },
- #[note(borrowck::could_not_normalize)]
+ #[note(borrowck_could_not_normalize)]
CouldNotNormalize { value: String },
}
-#[derive(SessionDiagnostic)]
-#[error(borrowck::higher_ranked_subtype_error)]
+#[derive(Diagnostic)]
+#[diag(borrowck_higher_ranked_subtype_error)]
pub(crate) struct HigherRankedSubtypeError {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[error(borrowck::generic_does_not_live_long_enough)]
+#[derive(Diagnostic)]
+#[diag(borrowck_generic_does_not_live_long_enough)]
pub(crate) struct GenericDoesNotLiveLongEnough {
pub kind: String,
#[primary_span]
pub span: Span,
}
+
+#[derive(LintDiagnostic)]
+#[diag(borrowck_var_does_not_need_mut)]
+pub(crate) struct VarNeedNotMut {
+ #[suggestion_short(applicability = "machine-applicable", code = "")]
+ pub span: Span,
+}
+#[derive(Diagnostic)]
+#[diag(borrowck_var_cannot_escape_closure)]
+#[note]
+#[note(cannot_escape)]
+pub(crate) struct FnMutError {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub ty_err: FnMutReturnTypeErr,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum VarHereDenote {
+ #[label(borrowck_var_here_captured)]
+ Captured {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(borrowck_var_here_defined)]
+ Defined {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(borrowck_closure_inferred_mut)]
+ FnMutInferred {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum FnMutReturnTypeErr {
+ #[label(borrowck_returned_closure_escaped)]
+ ReturnClosure {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(borrowck_returned_async_block_escaped)]
+ ReturnAsyncBlock {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(borrowck_returned_ref_escaped)]
+ ReturnRef {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(borrowck_lifetime_constraints_error)]
+pub(crate) struct LifetimeOutliveErr {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum LifetimeReturnCategoryErr<'a> {
+ #[label(borrowck_returned_lifetime_wrong)]
+ WrongReturn {
+ #[primary_span]
+ span: Span,
+ mir_def_name: &'a str,
+ outlived_fr_name: RegionName,
+ fr_name: &'a RegionName,
+ },
+ #[label(borrowck_returned_lifetime_short)]
+ ShortReturn {
+ #[primary_span]
+ span: Span,
+ category_desc: &'static str,
+ free_region_name: &'a RegionName,
+ outlived_fr_name: RegionName,
+ },
+}
+
+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)]
+ UsedImpl {
+ #[primary_span]
+ multi_span: MultiSpan,
+ },
+}
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 6cfe5efb6..a581726a1 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -24,8 +24,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
/// **Any `rustc_infer::infer` operations that might generate region
/// constraints should occur within this method so that those
/// constraints can be properly localized!**
- #[instrument(skip(self, category, op), level = "trace")]
- pub(super) fn fully_perform_op<R, Op>(
+ #[instrument(skip(self, op), level = "trace")]
+ pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
&mut self,
locations: Locations,
category: ConstraintCategory<'tcx>,
@@ -39,6 +39,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
+ debug!(?output, ?constraints);
+
if let Some(data) = constraints {
self.push_region_constraints(locations, category, data);
}
@@ -50,11 +52,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Some(error_info) => error_info.to_universe_info(old_universe),
None => UniverseInfo::other(),
};
- for u in old_universe..universe {
- self.borrowck_context
- .constraints
- .universe_causes
- .insert(u + 1, universe_info.clone());
+ for u in (old_universe + 1)..=universe {
+ self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
}
}
@@ -69,15 +68,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
where
T: TypeFoldable<'tcx>,
{
+ let old_universe = self.infcx.universe();
+
let (instantiated, _) =
self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
- for u in 0..canonical.max_universe.as_u32() {
- let info = UniverseInfo::other();
- self.borrowck_context
- .constraints
- .universe_causes
- .insert(ty::UniverseIndex::from_u32(u), info);
+ for u in (old_universe + 1)..=self.infcx.universe() {
+ self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other());
}
instantiated
@@ -90,17 +87,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
locations: Locations,
category: ConstraintCategory<'tcx>,
) {
- self.prove_predicates(
- Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
+ self.prove_predicate(
+ ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
polarity: ty::ImplPolarity::Positive,
- }))),
+ }))
+ .to_predicate(self.tcx()),
locations,
category,
);
}
+ #[instrument(level = "debug", skip(self))]
pub(super) fn normalize_and_prove_instantiated_predicates(
&mut self,
// Keep this parameter for now, in case we start using
@@ -115,8 +114,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.zip(instantiated_predicates.spans.into_iter())
{
debug!(?predicate);
- let predicate = self.normalize(predicate, locations);
- self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
+ let category = ConstraintCategory::Predicate(span);
+ let predicate = self.normalize_with_category(predicate, locations, category);
+ self.prove_predicate(predicate, locations, category);
}
}
@@ -152,15 +152,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
})
}
- #[instrument(skip(self), level = "debug")]
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
where
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
{
+ self.normalize_with_category(value, location, ConstraintCategory::Boring)
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ pub(super) fn normalize_with_category<T>(
+ &mut self,
+ value: T,
+ location: impl NormalizeLocation,
+ category: ConstraintCategory<'tcx>,
+ ) -> T
+ where
+ T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
+ {
let param_env = self.param_env;
self.fully_perform_op(
location.to_locations(),
- ConstraintCategory::Boring,
+ category,
param_env.and(type_op::normalize::Normalize::new(value)),
)
.unwrap_or_else(|NoSolution| {
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 167960918..d5bfc2f52 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{Span, DUMMY_SP};
@@ -19,7 +19,7 @@ use crate::{
};
pub(crate) struct ConstraintConversion<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
/// Each RBP `GK: 'a` is assumed to be true. These encode
@@ -43,7 +43,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
pub(crate) fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
@@ -86,7 +86,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
}
- pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
+ fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
debug!("generate: constraints at: {:#?}", self.locations);
// Extract out various useful fields we'll need below.
@@ -98,34 +98,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// 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 ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound vars", query_constraint,);
- });
+ let ty::OutlivesPredicate(k1, r2) =
+ query_constraint.0.no_bound_vars().unwrap_or_else(|| {
+ bug!("query_constraint {:?} contained bound vars", query_constraint,);
+ });
+
+ let constraint_category = query_constraint.1;
match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
let r1_vid = self.to_region_vid(r1);
let r2_vid = self.to_region_vid(r2);
- self.add_outlives(r1_vid, r2_vid);
+ self.add_outlives(r1_vid, r2_vid, constraint_category);
}
- GenericArgKind::Type(mut t1) => {
+ GenericArgKind::Type(t1) => {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
- // Placeholder regions need to be converted now because it may
- // create new region variables, which can't be done later when
- // verifying these bounds.
- if t1.has_placeholders() {
- t1 = tcx.fold_regions(t1, |r, _| match *r {
- ty::RePlaceholder(placeholder) => {
- self.constraints.placeholder_region(self.infcx, placeholder)
- }
- _ => r,
- });
- }
-
TypeOutlives::new(
&mut *self,
tcx,
@@ -133,7 +124,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
Some(implicit_region_bound),
param_env,
)
- .type_must_outlive(origin, t1, r2);
+ .type_must_outlive(origin, t1, r2, constraint_category);
}
GenericArgKind::Const(_) => {
@@ -143,6 +134,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
}
+ /// Placeholder regions need to be converted eagerly because it may
+ /// create new region variables, which we must not do when verifying
+ /// our region bounds.
+ ///
+ /// 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 {
+ if value.has_placeholders() {
+ self.tcx.fold_regions(value, |r, _| match *r {
+ ty::RePlaceholder(placeholder) => {
+ self.constraints.placeholder_region(self.infcx, placeholder)
+ }
+ _ => r,
+ })
+ } else {
+ value
+ }
+ }
+
fn verify_to_type_test(
&mut self,
generic_kind: GenericKind<'tcx>,
@@ -150,7 +160,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
verify_bound: VerifyBound<'tcx>,
) -> TypeTest<'tcx> {
let lower_bound = self.to_region_vid(region);
-
TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
}
@@ -162,10 +171,19 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
}
- fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
+ fn add_outlives(
+ &mut self,
+ sup: ty::RegionVid,
+ sub: ty::RegionVid,
+ category: ConstraintCategory<'tcx>,
+ ) {
+ let category = match self.category {
+ ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
+ _ => self.category,
+ };
self.constraints.outlives_constraints.push(OutlivesConstraint {
locations: self.locations,
- category: self.category,
+ category,
span: self.span,
sub,
sup,
@@ -185,10 +203,11 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
_origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
+ constraint_category: ConstraintCategory<'tcx>,
) {
let b = self.to_region_vid(b);
let a = self.to_region_vid(a);
- self.add_outlives(b, a);
+ self.add_outlives(b, a, constraint_category);
}
fn push_verify(
@@ -198,6 +217,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
a: ty::Region<'tcx>,
bound: VerifyBound<'tcx>,
) {
+ let kind = self.replace_placeholders_with_nll(kind);
+ let bound = self.replace_placeholders_with_nll(bound);
let type_test = self.verify_to_type_test(kind, a, bound);
self.add_type_test(type_test);
}
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 cc0318ede..029095926 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -1,5 +1,5 @@
use rustc_data_structures::frozen::Frozen;
-use rustc_data_structures::transitive_relation::TransitiveRelation;
+use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -8,7 +8,6 @@ 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::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
use type_op::TypeOpOutput;
@@ -48,7 +47,7 @@ pub(crate) struct CreateResult<'tcx> {
}
pub(crate) fn create<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
universal_regions: &Rc<UniversalRegions<'tcx>>,
@@ -61,25 +60,13 @@ pub(crate) fn create<'tcx>(
constraints,
universal_regions: universal_regions.clone(),
region_bound_pairs: Default::default(),
- relations: UniversalRegionRelations {
- universal_regions: universal_regions.clone(),
- outlives: Default::default(),
- inverse_outlives: Default::default(),
- },
+ outlives: Default::default(),
+ inverse_outlives: Default::default(),
}
.create()
}
impl UniversalRegionRelations<'_> {
- /// Records in the `outlives_relation` (and
- /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
- /// builder below.
- fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
- debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
- self.outlives.add(fr_a, fr_b);
- self.inverse_outlives.add(fr_b, fr_a);
- }
-
/// Given two universal regions, returns the postdominating
/// upper-bound (effectively the least upper bound).
///
@@ -209,19 +196,29 @@ impl UniversalRegionRelations<'_> {
}
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
- infcx: &'this InferCtxt<'this, 'tcx>,
+ infcx: &'this InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
universal_regions: Rc<UniversalRegions<'tcx>>,
implicit_region_bound: ty::Region<'tcx>,
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
// outputs:
- relations: UniversalRegionRelations<'tcx>,
+ outlives: TransitiveRelationBuilder<RegionVid>,
+ inverse_outlives: TransitiveRelationBuilder<RegionVid>,
region_bound_pairs: RegionBoundPairs<'tcx>,
}
impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
+ /// Records in the `outlives_relation` (and
+ /// `inverse_outlives_relation`) that `fr_a: fr_b`.
+ fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
+ debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b);
+ self.outlives.add(fr_a, fr_b);
+ self.inverse_outlives.add(fr_b, fr_a);
+ }
+
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
+ let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
let unnormalized_input_output_tys = self
.universal_regions
.unnormalized_input_tys
@@ -242,10 +239,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let constraint_sets: Vec<_> = unnormalized_input_output_tys
.flat_map(|ty| {
debug!("build: input_or_output={:?}", ty);
- // We only add implied bounds for the normalized type as the unnormalized
- // type may not actually get checked by the caller.
- //
- // Can otherwise be unsound, see #91068.
+ // 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))
@@ -254,7 +250,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.infcx
.tcx
.sess
- .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
+ .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
TypeOpOutput {
output: self.infcx.tcx.ty_error(),
constraints: None,
@@ -269,13 +265,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// }
// impl Foo for () {
// type Bar = ();
- // fn foo(&self) ->&() {}
+ // fn foo(&self) -> &() {}
// }
// ```
// Both &Self::Bar and &() are WF
- let constraints_implied = self.add_implied_bounds(norm_ty);
+ 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_implied)
+ constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
})
.collect();
@@ -292,9 +289,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
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.relations.relate_universal_regions(fr, fr);
- self.relations.relate_universal_regions(fr_static, fr);
- self.relations.relate_universal_regions(fr, fr_fn_body);
+ self.relate_universal_regions(fr, fr);
+ self.relate_universal_regions(fr_static, fr);
+ self.relate_universal_regions(fr, fr_fn_body);
}
for data in &constraint_sets {
@@ -304,8 +301,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
&self.region_bound_pairs,
self.implicit_region_bound,
self.param_env,
- Locations::All(DUMMY_SP),
- DUMMY_SP,
+ Locations::All(span),
+ span,
ConstraintCategory::Internal,
&mut self.constraints,
)
@@ -313,7 +310,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
CreateResult {
- universal_region_relations: Frozen::freeze(self.relations),
+ universal_region_relations: Frozen::freeze(UniversalRegionRelations {
+ universal_regions: self.universal_regions,
+ outlives: self.outlives.freeze(),
+ inverse_outlives: self.inverse_outlives.freeze(),
+ }),
region_bound_pairs: self.region_bound_pairs,
normalized_inputs_and_output,
}
@@ -346,17 +347,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
match outlives_bound {
OutlivesBound::RegionSubRegion(r1, r2) => {
- // `where Type:` is lowered to `where Type: 'empty` so that
- // we check `Type` is well formed, but there's no use for
- // this bound here.
- if r1.is_empty() {
- return;
- }
-
// The bound says that `r1 <= r2`; we store `r2: r1`.
let r1 = self.universal_regions.to_region_vid(r1);
let r2 = self.universal_regions.to_region_vid(r2);
- self.relations.relate_universal_regions(r2, r1);
+ self.relate_universal_regions(r2, r1);
}
OutlivesBound::RegionSubParam(r_a, param_b) => {
@@ -368,6 +362,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
}
+
+ OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+ self.region_bound_pairs
+ .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+ }
}
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 4431a2e8e..a66ddd27d 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,16 +7,11 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
-use crate::type_check::constraint_conversion::ConstraintConversion;
use rustc_index::vec::Idx;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
use rustc_middle::ty::Ty;
use rustc_span::Span;
-use rustc_span::DUMMY_SP;
-use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
-use rustc_trait_selection::traits::query::Fallible;
-use type_op::TypeOpOutput;
use crate::universal_regions::UniversalRegions;
@@ -185,7 +180,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
- #[instrument(skip(self, span), level = "debug")]
+ #[instrument(skip(self), level = "debug")]
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
if let Err(_) =
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
@@ -194,13 +189,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
// like to normalize *before* inserting into `local_decls`, but
// doing so ends up causing some other trouble.
- let b = match self.normalize_and_add_constraints(b) {
- Ok(n) => n,
- Err(_) => {
- debug!("equate_inputs_and_outputs: NoSolution");
- b
- }
- };
+ let b = self.normalize(b, Locations::All(span));
// Note: if we have to introduce new placeholders during normalization above, then we won't have
// added those universes to the universe info, which we would want in `relate_tys`.
@@ -218,28 +207,4 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
-
- pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
- let TypeOpOutput { output: norm_ty, constraints, .. } =
- self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
-
- debug!("{:?} normalized to {:?}", t, norm_ty);
-
- for data in constraints {
- ConstraintConversion::new(
- self.infcx,
- &self.borrowck_context.universal_regions,
- &self.region_bound_pairs,
- self.implicit_region_bound,
- self.param_env,
- Locations::All(DUMMY_SP),
- DUMMY_SP,
- ConstraintCategory::Internal,
- &mut self.borrowck_context.constraints,
- )
- .convert_all(&*data);
- }
-
- Ok(norm_ty)
- }
}
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d32b1edcd..3c1c3ab45 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
- self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
- OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
+ self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
+ OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType,
+ UserTypeAnnotationIndex,
};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP};
@@ -122,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: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
promoted: &IndexVec<Promoted, Body<'tcx>>,
@@ -137,8 +138,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
use_polonius: bool,
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
- let mut universe_causes = FxHashMap::default();
- universe_causes.insert(ty::UniverseIndex::from_u32(0), UniverseInfo::other());
let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::default(),
@@ -147,7 +146,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
member_constraints: MemberConstraintSet::default(),
closure_bounds_mapping: Default::default(),
type_tests: Vec::default(),
- universe_causes,
+ universe_causes: FxHashMap::default(),
};
let CreateResult {
@@ -164,9 +163,8 @@ pub(crate) fn type_check<'mir, 'tcx>(
debug!(?normalized_inputs_and_output);
- for u in ty::UniverseIndex::ROOT..infcx.universe() {
- let info = UniverseInfo::other();
- constraints.universe_causes.insert(u, info);
+ for u in ty::UniverseIndex::ROOT..=infcx.universe() {
+ constraints.universe_causes.insert(u, UniverseInfo::other());
}
let mut borrowck_context = BorrowCheckContext {
@@ -178,97 +176,15 @@ pub(crate) fn type_check<'mir, 'tcx>(
upvars,
};
- let opaque_type_values = type_check_internal(
+ let mut checker = TypeChecker::new(
infcx,
- param_env,
body,
- promoted,
+ param_env,
&region_bound_pairs,
implicit_region_bound,
&mut borrowck_context,
- |mut cx| {
- debug!("inside extra closure of type_check_internal");
- cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
- liveness::generate(
- &mut cx,
- body,
- elements,
- flow_inits,
- move_data,
- location_table,
- use_polonius,
- );
-
- translate_outlives_facts(&mut cx);
- let opaque_type_values =
- infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-
- opaque_type_values
- .into_iter()
- .map(|(opaque_type_key, decl)| {
- cx.fully_perform_op(
- Locations::All(body.span),
- ConstraintCategory::OpaqueType,
- CustomTypeOp::new(
- |infcx| {
- infcx.register_member_constraints(
- param_env,
- opaque_type_key,
- decl.hidden_type.ty,
- decl.hidden_type.span,
- );
- Ok(InferOk { value: (), obligations: vec![] })
- },
- || "opaque_type_map".to_string(),
- ),
- )
- .unwrap();
- let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
- trace!(
- "finalized opaque type {:?} to {:#?}",
- opaque_type_key,
- hidden_type.ty.kind()
- );
- if hidden_type.has_infer_types_or_consts() {
- infcx.tcx.sess.delay_span_bug(
- decl.hidden_type.span,
- &format!("could not resolve {:#?}", hidden_type.ty.kind()),
- );
- hidden_type.ty = infcx.tcx.ty_error();
- }
-
- (opaque_type_key, (hidden_type, decl.origin))
- })
- .collect()
- },
);
- MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
-}
-
-#[instrument(
- skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra),
- level = "debug"
-)]
-fn type_check_internal<'a, 'tcx, R>(
- infcx: &'a InferCtxt<'a, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- body: &'a Body<'tcx>,
- promoted: &'a IndexVec<Promoted, Body<'tcx>>,
- region_bound_pairs: &'a RegionBoundPairs<'tcx>,
- implicit_region_bound: ty::Region<'tcx>,
- borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
- extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
-) -> R {
- debug!("body: {:#?}", body);
- let mut checker = TypeChecker::new(
- infcx,
- body,
- param_env,
- region_bound_pairs,
- implicit_region_bound,
- borrowck_context,
- );
let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);
@@ -280,7 +196,56 @@ fn type_check_internal<'a, 'tcx, R>(
checker.typeck_mir(body);
}
- extra(checker)
+ checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
+ liveness::generate(
+ &mut checker,
+ body,
+ elements,
+ flow_inits,
+ move_data,
+ location_table,
+ use_polonius,
+ );
+
+ translate_outlives_facts(&mut checker);
+ let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+
+ let opaque_type_values = opaque_type_values
+ .into_iter()
+ .map(|(opaque_type_key, decl)| {
+ checker
+ .fully_perform_op(
+ Locations::All(body.span),
+ ConstraintCategory::OpaqueType,
+ CustomTypeOp::new(
+ |infcx| {
+ infcx.register_member_constraints(
+ param_env,
+ opaque_type_key,
+ decl.hidden_type.ty,
+ decl.hidden_type.span,
+ );
+ Ok(InferOk { value: (), obligations: vec![] })
+ },
+ || "opaque_type_map".to_string(),
+ ),
+ )
+ .unwrap();
+ let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
+ trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
+ if hidden_type.has_non_region_infer() {
+ infcx.tcx.sess.delay_span_bug(
+ decl.hidden_type.span,
+ &format!("could not resolve {:#?}", hidden_type.ty.kind()),
+ );
+ hidden_type.ty = infcx.tcx.ty_error();
+ }
+
+ (opaque_type_key, (hidden_type, decl.origin))
+ })
+ .collect();
+
+ MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
}
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
@@ -344,6 +309,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
+ debug!(?constant, ?location, "visit_constant");
+
self.super_constant(constant, location);
let ty = self.sanitize_type(constant, constant.literal.ty());
@@ -387,11 +354,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
let tcx = self.tcx();
let maybe_uneval = match constant.literal {
ConstantKind::Ty(ct) => match ct.kind() {
- ty::ConstKind::Unevaluated(uv) => Some(uv),
+ ty::ConstKind::Unevaluated(_) => {
+ bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct)
+ }
_ => None,
},
+ ConstantKind::Unevaluated(uv, _) => Some(uv),
_ => None,
};
+
if let Some(uv) = maybe_uneval {
if let Some(promoted) = uv.promoted {
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
@@ -454,12 +425,18 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}
if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() {
+ // const_trait_impl: use a non-const param env when checking that a FnDef type is well formed.
+ // this is because the well-formedness of the function does not need to be proved to have `const`
+ // impls for trait bounds.
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
+ let prev = self.cx.param_env;
+ self.cx.param_env = prev.without_const();
self.cx.normalize_and_prove_instantiated_predicates(
def_id,
instantiated_predicates,
locations,
);
+ self.cx.param_env = prev;
}
}
}
@@ -607,6 +584,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// modify their locations.
let all_facts = &mut None;
let mut constraints = Default::default();
+ let mut type_tests = Default::default();
let mut closure_bounds = Default::default();
let mut liveness_constraints =
LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
@@ -618,6 +596,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
&mut this.cx.borrowck_context.constraints.outlives_constraints,
&mut constraints,
);
+ mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests);
mem::swap(
&mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
&mut closure_bounds,
@@ -642,6 +621,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
swap_constraints(self);
let locations = location.to_locations();
+
+ // Use location of promoted const in collected constraints
+ for type_test in type_tests.iter() {
+ let mut type_test = type_test.clone();
+ type_test.locations = locations;
+ self.cx.borrowck_context.constraints.type_tests.push(type_test)
+ }
for constraint in constraints.outlives().iter() {
let mut constraint = constraint.clone();
constraint.locations = locations;
@@ -790,6 +776,19 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
PlaceTy::from_ty(fty)
}
+ ProjectionElem::OpaqueCast(ty) => {
+ let ty = self.sanitize_type(place, ty);
+ let ty = self.cx.normalize(ty, location);
+ self.cx
+ .eq_types(
+ base.ty,
+ ty,
+ location.to_locations(),
+ ConstraintCategory::TypeAnnotation,
+ )
+ .unwrap();
+ PlaceTy::from_ty(ty)
+ }
}
}
@@ -883,7 +882,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<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
last_span: Span,
body: &'a Body<'tcx>,
@@ -953,7 +952,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
impl<'tcx> MirTypeckRegionConstraints<'tcx> {
fn placeholder_region(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
placeholder: ty::PlaceholderRegion,
) -> ty::Region<'tcx> {
let placeholder_index = self.placeholder_indices.insert(placeholder);
@@ -1037,7 +1036,7 @@ impl Locations {
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
body: &'a Body<'tcx>,
param_env: ty::ParamEnv<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
@@ -1076,6 +1075,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
+ debug!(?annotation);
match annotation {
UserType::Ty(mut ty) => {
ty = self.normalize(ty, Locations::All(span));
@@ -1195,10 +1195,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
tcx,
self.param_env,
proj,
- |this, field, ()| {
+ |this, field, _| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
},
+ |_, _| unreachable!(),
);
curr_projected_ty = projected_ty;
}
@@ -1334,12 +1335,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
- ..
- }) => span_bug!(
- stmt.source_info.span,
- "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
- ),
+ StatementKind::Intrinsic(box ref kind) => match kind {
+ NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location),
+ NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
+ stmt.source_info.span,
+ "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics",
+ ),
+ },
StatementKind::FakeRead(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
@@ -1448,9 +1450,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
))
});
debug!(?sig);
- let sig = self.normalize(sig, term_location);
- self.check_call_dest(body, term, &sig, *destination, target, term_location);
-
+ // IMPORTANT: We have to prove well formed for the function signature before
+ // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
+ // get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
+ //
+ // Normalization results in a well formed type if the input is well formed, so we
+ // don't have to check it twice.
+ //
+ // See #91068 for an example.
self.prove_predicates(
sig.inputs_and_output
.iter()
@@ -1458,6 +1465,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
term_location.to_locations(),
ConstraintCategory::Boring,
);
+ let sig = self.normalize(sig, term_location);
+ self.check_call_dest(body, term, &sig, *destination, target, term_location);
// The ordinary liveness rules will ensure that all
// regions in the type of the callee are live here. We
@@ -1621,7 +1630,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if from_hir_call {
- ConstraintCategory::CallArgument(func_ty)
+ ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
} else {
ConstraintCategory::Boring
};
@@ -1774,7 +1783,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// `Sized` bound in no way depends on precise regions, so this
// shouldn't affect `is_sized`.
let erased_ty = tcx.erase_regions(ty);
- if !erased_ty.is_sized(tcx.at(span), self.param_env) {
+ if !erased_ty.is_sized(tcx, self.param_env) {
// in current MIR construction, all non-control-flow rvalue
// expressions evaluate through `as_temp` or `into` a return
// slot or local, so to find all unsized rvalues it is enough
@@ -1834,14 +1843,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+ debug!(?op, ?location, "check_operand");
+
if let Operand::Constant(constant) = op {
let maybe_uneval = match constant.literal {
- ConstantKind::Ty(ct) => match ct.kind() {
- ty::ConstKind::Unevaluated(uv) => Some(uv),
- _ => None,
- },
- _ => None,
+ ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
+ ConstantKind::Unevaluated(uv, _) => Some(uv),
};
+
if let Some(uv) = maybe_uneval {
if uv.promoted.is_none() {
let tcx = self.tcx();
@@ -1904,7 +1913,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
- &Rvalue::NullaryOp(_, ty) => {
+ &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => {
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]),
@@ -2033,6 +2042,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
+ CastKind::DynStar => {
+ // get the constraints from the target type (`dyn* Clone`)
+ //
+ // apply them to prove that the source type `Foo` implements `Clone` etc
+ let (existential_predicates, region) = match ty.kind() {
+ Dynamic(predicates, region, ty::DynStar) => (predicates, region),
+ _ => panic!("Invalid dyn* cast_ty"),
+ };
+
+ let self_ty = op.ty(body, tcx);
+
+ self.prove_predicates(
+ existential_predicates
+ .iter()
+ .map(|predicate| predicate.with_self_ty(tcx, self_ty)),
+ location.to_locations(),
+ ConstraintCategory::Cast,
+ );
+
+ let outlives_predicate =
+ tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
+ ty::OutlivesPredicate(self_ty, *region),
+ )));
+ self.prove_predicate(
+ outlives_predicate,
+ location.to_locations(),
+ ConstraintCategory::Cast,
+ );
+ }
+
CastKind::Pointer(PointerCast::MutToConstPointer) => {
let ty::RawPtr(ty::TypeAndMut {
ty: ty_from,
@@ -2176,25 +2215,104 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
-
- CastKind::Misc => {
+ CastKind::IntToInt => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
let cast_ty_to = CastTy::from_ty(*ty);
- // Misc casts are either between floats and ints, or one ptr type to another.
match (cast_ty_from, cast_ty_to) {
- (
- Some(CastTy::Int(_) | CastTy::Float),
- Some(CastTy::Int(_) | CastTy::Float),
- )
- | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
+ (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => (),
_ => {
span_mirbug!(
self,
rvalue,
- "Invalid Misc cast {:?} -> {:?}",
+ "Invalid IntToInt cast {:?} -> {:?}",
ty_from,
- ty,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::IntToFloat => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Int(_)), Some(CastTy::Float)) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid IntToFloat cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::FloatToInt => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Float), Some(CastTy::Int(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid FloatToInt cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::FloatToFloat => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Float), Some(CastTy::Float)) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid FloatToFloat cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::FnPtrToPtr => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid FnPtrToPtr cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::PtrToPtr => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid PtrToPtr cast {:?} -> {:?}",
+ ty_from,
+ ty
)
}
}
@@ -2490,6 +2608,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
ProjectionElem::Field(..)
| ProjectionElem::Downcast(..)
+ | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
@@ -2584,7 +2703,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.enumerate()
.filter_map(|(idx, constraint)| {
let ty::OutlivesPredicate(k1, r2) =
- constraint.no_bound_vars().unwrap_or_else(|| {
+ constraint.0.no_bound_vars().unwrap_or_else(|| {
bug!("query_constraint {:?} contained bound vars", constraint,);
});
@@ -2659,7 +2778,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.check_local(&body, local, local_decl);
}
- for (block, block_data) in body.basic_blocks().iter_enumerated() {
+ for (block, block_data) in body.basic_blocks.iter_enumerated() {
let mut location = Location { block, statement_index: 0 };
for stmt in &block_data.statements {
if !stmt.source_info.span.is_dummy() {
@@ -2710,7 +2829,7 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
/// constraints in our `InferCtxt`
type ErrorInfo = InstantiateOpaqueType<'tcx>;
- fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+ fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let (mut output, region_constraints) = scrape_region_constraints(infcx, || {
Ok(InferOk { value: (), obligations: self.obligations.clone() })
})?;
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index c97a6a1a6..4f2dc263b 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,6 +1,6 @@
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
use rustc_infer::infer::NllRegionVariableOrigin;
-use rustc_infer::traits::ObligationCause;
+use rustc_infer::traits::PredicateObligations;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::TypeRelation;
@@ -155,27 +155,16 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
true
}
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: PredicateObligations<'tcx>,
) -> Result<(), TypeError<'tcx>> {
- let param_env = self.param_env();
- let span = self.span();
- let def_id = self.type_checker.body.source.def_id().expect_local();
- let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
- let cause = ObligationCause::misc(span, body_id);
self.type_checker
.fully_perform_op(
self.locations,
self.category,
InstantiateOpaqueType {
- obligations: self
- .type_checker
- .infcx
- .handle_opaque_type(a, b, a_is_expected, &cause, param_env)?
- .obligations,
+ obligations,
// These fields are filled in during execution of the operation
base_universe: None,
region_constraints: None,
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 2a7713bc4..2beb5e0ab 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -22,8 +22,8 @@ use rustc_hir::{BodyOwnerKind, HirId};
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use std::iter;
use crate::nll::ToRegionVid;
@@ -54,13 +54,6 @@ pub struct UniversalRegions<'tcx> {
/// The total number of universal region variables instantiated.
num_universals: usize,
- /// A special region variable created for the `'empty(U0)` region.
- /// Note that this is **not** a "universal" region, as it doesn't
- /// represent a universally bound placeholder or any such thing.
- /// But we do create it here in this type because it's a useful region
- /// to have around in a few limited cases.
- pub root_empty: RegionVid,
-
/// The "defining" type for this function, with all universal
/// regions instantiated. For a closure or generator, this is the
/// closure type, but for a top-level function it's the `FnDef`.
@@ -226,7 +219,7 @@ impl<'tcx> UniversalRegions<'tcx> {
/// signature. This will also compute the relationships that are
/// known between those regions.
pub fn new(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
mir_def: ty::WithOptConstParam<LocalDefId>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
@@ -323,11 +316,7 @@ impl<'tcx> UniversalRegions<'tcx> {
/// See `UniversalRegionIndices::to_region_vid`.
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
- if let ty::ReEmpty(ty::UniverseIndex::ROOT) = *r {
- self.root_empty
- } else {
- self.indices.to_region_vid(r)
- }
+ self.indices.to_region_vid(r)
}
/// As part of the NLL unit tests, you can annotate a function with
@@ -393,7 +382,7 @@ impl<'tcx> UniversalRegions<'tcx> {
}
struct UniversalRegionsBuilder<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
mir_def: ty::WithOptConstParam<LocalDefId>,
mir_hir_id: HirId,
param_env: ty::ParamEnv<'tcx>,
@@ -425,7 +414,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
- // If this is is a 'root' body (not a closure/generator/inline const), then
+ // If this is a 'root' body (not a closure/generator/inline const), then
// there are no extern regions, so the local regions start at the same
// position as the (empty) sub-list of extern regions
let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id {
@@ -501,16 +490,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
_ => None,
};
- let root_empty = self
- .infcx
- .next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true })
- .to_region_vid();
-
UniversalRegions {
indices,
fr_static,
fr_fn_body,
- root_empty,
first_extern_index,
first_local_index,
num_universals,
@@ -716,7 +699,7 @@ trait InferCtxtExt<'tcx> {
);
}
-impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn replace_free_regions_with_nll_infer_vars<T>(
&self,
origin: NllRegionVariableOrigin,
@@ -768,10 +751,9 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
) {
- debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
- debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
+ debug!(?r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
debug!(?region_vid);