Rollup merge of #110220 - lcnr:regionzz, r=compiler-errors
cleanup our region error API - require `TypeErrCtxt` to always result in an error, closing #108810 - move `resolve_regions_and_report_errors` to the `ObligationCtxt` - call `process_registered_region_obligations` in `resolve_regions` - move `resolve_regions` into the `outlives` submodule - add `#[must_use]` to functions returning lists of errors r? types
This commit is contained in:
commit
6f1500aec2
15 changed files with 192 additions and 237 deletions
|
@ -452,11 +452,8 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(
|
||||
defining_use_anchor,
|
||||
&outlives_environment,
|
||||
);
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env);
|
||||
}
|
||||
}
|
||||
// Clean up after ourselves
|
||||
|
|
|
@ -332,10 +332,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()),
|
||||
);
|
||||
infcx.process_registered_region_obligations(
|
||||
outlives_env.region_bound_pairs(),
|
||||
outlives_env.param_env,
|
||||
);
|
||||
let errors = infcx.resolve_regions(&outlives_env);
|
||||
if !errors.is_empty() {
|
||||
// FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
|
||||
|
@ -722,18 +718,18 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
return Err(reported);
|
||||
}
|
||||
|
||||
let collected_types = collector.types;
|
||||
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
|
||||
);
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.check_region_obligations_and_report_errors(impl_m_def_id, &outlives_environment)?;
|
||||
ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?;
|
||||
|
||||
let mut collected_tys = FxHashMap::default();
|
||||
for (def_id, (ty, substs)) in collector.types {
|
||||
for (def_id, (ty, substs)) in collected_types {
|
||||
match infcx.fully_resolve(ty) {
|
||||
Ok(ty) => {
|
||||
// `ty` contains free regions that we created earlier while liberating the
|
||||
|
@ -1742,11 +1738,8 @@ pub(super) fn compare_impl_const_raw(
|
|||
return Err(infcx.err_ctxt().report_fulfillment_errors(&errors));
|
||||
}
|
||||
|
||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
infcx
|
||||
.err_ctxt()
|
||||
.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment)?;
|
||||
Ok(())
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env)
|
||||
}
|
||||
|
||||
pub(super) fn compare_impl_ty<'tcx>(
|
||||
|
@ -1845,13 +1838,8 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
infcx.err_ctxt().check_region_obligations_and_report_errors(
|
||||
impl_ty.def_id.expect_local(),
|
||||
&outlives_environment,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
|
||||
}
|
||||
|
||||
/// Validate that `ProjectionCandidate`s created for this associated type will
|
||||
|
@ -2063,14 +2051,8 @@ pub(super) fn check_type_bounds<'tcx>(
|
|||
// Finally, resolve all regions. This catches wily misuses of
|
||||
// lifetime parameters.
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
||||
infcx.err_ctxt().check_region_obligations_and_report_errors(
|
||||
impl_ty.def_id.expect_local(),
|
||||
&outlives_environment,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
|
||||
}
|
||||
|
||||
fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
|
||||
|
|
|
@ -114,11 +114,9 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
|
|||
return;
|
||||
}
|
||||
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
||||
let _ = infcx
|
||||
.err_ctxt()
|
||||
.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
|
||||
let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env);
|
||||
}
|
||||
|
||||
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
|
||||
|
@ -680,12 +678,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
|
|||
|
||||
add_constraints(&infcx, region_bound_pairs);
|
||||
|
||||
infcx.process_registered_region_obligations(
|
||||
outlives_environment.region_bound_pairs(),
|
||||
param_env,
|
||||
);
|
||||
let errors = infcx.resolve_regions(&outlives_environment);
|
||||
|
||||
debug!(?errors, "errors");
|
||||
|
||||
// If we were able to prove that the type outlives the region without
|
||||
|
|
|
@ -354,9 +354,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
|
|||
|
||||
// Finally, resolve all regions.
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let _ = infcx
|
||||
.err_ctxt()
|
||||
.check_region_obligations_and_report_errors(impl_did, &outlives_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -592,7 +590,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
|
|||
|
||||
// Finally, resolve all regions.
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(impl_did, &outlives_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
|
||||
|
||||
CoerceUnsizedInfo { custom_kind: kind }
|
||||
}
|
||||
|
|
|
@ -180,8 +180,7 @@ fn get_impl_substs(
|
|||
|
||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
|
||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
let _ =
|
||||
infcx.err_ctxt().check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
|
||||
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
|
||||
let span = tcx.def_span(impl1_def_id);
|
||||
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
|
||||
|
|
|
@ -74,6 +74,7 @@ use rustc_middle::ty::{
|
|||
self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
|
||||
use rustc_target::spec::abi;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
@ -113,7 +114,11 @@ fn escape_literal(s: &str) -> String {
|
|||
|
||||
/// A helper for building type related errors. The `typeck_results`
|
||||
/// field is only populated during an in-progress typeck.
|
||||
/// Get an instance by calling `InferCtxt::err` or `FnCtxt::infer_err`.
|
||||
/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`.
|
||||
///
|
||||
/// You must only create this if you intend to actually emit an error.
|
||||
/// This provides a lot of utility methods which should not be used
|
||||
/// during the happy path.
|
||||
pub struct TypeErrCtxt<'a, 'tcx> {
|
||||
pub infcx: &'a InferCtxt<'tcx>,
|
||||
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
|
||||
|
@ -125,6 +130,19 @@ pub struct TypeErrCtxt<'a, 'tcx> {
|
|||
Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
|
||||
}
|
||||
|
||||
impl Drop for TypeErrCtxt<'_, '_> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(_) = self.infcx.tcx.sess.has_errors_or_delayed_span_bugs() {
|
||||
// ok, emitted an error.
|
||||
} else {
|
||||
self.infcx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeErrCtxt<'_, '_> {
|
||||
/// This is just to avoid a potential footgun of accidentally
|
||||
/// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
|
||||
|
@ -409,7 +427,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
&self,
|
||||
generic_param_scope: LocalDefId,
|
||||
errors: &[RegionResolutionError<'tcx>],
|
||||
) {
|
||||
) -> ErrorGuaranteed {
|
||||
if let Some(guaranteed) = self.infcx.tainted_by_errors() {
|
||||
return guaranteed;
|
||||
}
|
||||
|
||||
debug!("report_region_errors(): {} errors to start", errors.len());
|
||||
|
||||
// try to pre-process the errors, which will group some of them
|
||||
|
@ -489,6 +511,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tcx
|
||||
.sess
|
||||
.delay_span_bug(self.tcx.def_span(generic_param_scope), "expected region errors")
|
||||
}
|
||||
|
||||
// This method goes through all the errors and try to group certain types
|
||||
|
|
|
@ -45,8 +45,7 @@ use self::combine::CombineFields;
|
|||
use self::error_reporting::TypeErrCtxt;
|
||||
use self::free_regions::RegionRelations;
|
||||
use self::lexical_region_resolve::LexicalRegionResolutions;
|
||||
use self::outlives::env::OutlivesEnvironment;
|
||||
use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
|
||||
use self::region_constraints::{GenericKind, VarInfos, VerifyBound};
|
||||
use self::region_constraints::{
|
||||
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
|
||||
};
|
||||
|
@ -1213,95 +1212,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
self.tainted_by_errors.set(Some(e));
|
||||
}
|
||||
|
||||
pub fn skip_region_resolution(&self) {
|
||||
let (var_infos, _) = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let inner = &mut *inner;
|
||||
// Note: `inner.region_obligations` may not be empty, because we
|
||||
// didn't necessarily call `process_registered_region_obligations`.
|
||||
// This is okay, because that doesn't introduce new vars.
|
||||
inner
|
||||
.region_constraint_storage
|
||||
.take()
|
||||
.expect("regions already resolved")
|
||||
.with_log(&mut inner.undo_log)
|
||||
.into_infos_and_data()
|
||||
};
|
||||
|
||||
let lexical_region_resolutions = LexicalRegionResolutions {
|
||||
values: rustc_index::vec::IndexVec::from_elem_n(
|
||||
crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
|
||||
var_infos.len(),
|
||||
),
|
||||
};
|
||||
|
||||
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
|
||||
assert!(old_value.is_none());
|
||||
}
|
||||
|
||||
/// Process the region constraints and return any errors that
|
||||
/// result. After this, no more unification operations should be
|
||||
/// done -- or the compiler will panic -- but it is legal to use
|
||||
/// `resolve_vars_if_possible` as well as `fully_resolve`.
|
||||
pub fn resolve_regions(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) -> Vec<RegionResolutionError<'tcx>> {
|
||||
let (var_infos, data) = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let inner = &mut *inner;
|
||||
assert!(
|
||||
self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
|
||||
"region_obligations not empty: {:#?}",
|
||||
inner.region_obligations
|
||||
);
|
||||
inner
|
||||
.region_constraint_storage
|
||||
.take()
|
||||
.expect("regions already resolved")
|
||||
.with_log(&mut inner.undo_log)
|
||||
.into_infos_and_data()
|
||||
};
|
||||
|
||||
let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
|
||||
|
||||
let (lexical_region_resolutions, errors) =
|
||||
lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
|
||||
|
||||
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
|
||||
assert!(old_value.is_none());
|
||||
|
||||
errors
|
||||
}
|
||||
/// Obtains (and clears) the current set of region
|
||||
/// constraints. The inference context is still usable: further
|
||||
/// unifications will simply add new constraints.
|
||||
///
|
||||
/// This method is not meant to be used with normal lexical region
|
||||
/// resolution. Rather, it is used in the NLL mode as a kind of
|
||||
/// interim hack: basically we run normal type-check and generate
|
||||
/// region constraints as normal, but then we take them and
|
||||
/// translate them into the form that the NLL solver
|
||||
/// understands. See the NLL module for mode details.
|
||||
pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
|
||||
assert!(
|
||||
self.inner.borrow().region_obligations.is_empty(),
|
||||
"region_obligations not empty: {:#?}",
|
||||
self.inner.borrow().region_obligations
|
||||
);
|
||||
|
||||
self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
|
||||
}
|
||||
|
||||
/// Gives temporary access to the region constraint data.
|
||||
pub fn with_region_constraints<R>(
|
||||
&self,
|
||||
op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
|
||||
) -> R {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
op(inner.unwrap_region_constraints().data())
|
||||
}
|
||||
|
||||
pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let inner = &mut *inner;
|
||||
|
@ -1754,56 +1664,6 @@ impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
/// Processes registered region obliations and resolves regions, reporting
|
||||
/// any errors if any were raised. Prefer using this function over manually
|
||||
/// calling `resolve_regions_and_report_errors`.
|
||||
pub fn check_region_obligations_and_report_errors(
|
||||
&self,
|
||||
generic_param_scope: LocalDefId,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
self.process_registered_region_obligations(
|
||||
outlives_env.region_bound_pairs(),
|
||||
outlives_env.param_env,
|
||||
);
|
||||
|
||||
self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
|
||||
}
|
||||
|
||||
/// Process the region constraints and report any errors that
|
||||
/// result. After this, no more unification operations should be
|
||||
/// done -- or the compiler will panic -- but it is legal to use
|
||||
/// `resolve_vars_if_possible` as well as `fully_resolve`.
|
||||
///
|
||||
/// Make sure to call [`InferCtxt::process_registered_region_obligations`]
|
||||
/// first, or preferably use [`TypeErrCtxt::check_region_obligations_and_report_errors`]
|
||||
/// to do both of these operations together.
|
||||
pub fn resolve_regions_and_report_errors(
|
||||
&self,
|
||||
generic_param_scope: LocalDefId,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let errors = self.resolve_regions(outlives_env);
|
||||
|
||||
if let None = self.tainted_by_errors() {
|
||||
// As a heuristic, just skip reporting region errors
|
||||
// altogether if other errors have been reported while
|
||||
// this infcx was in use. This is totally hokey but
|
||||
// otherwise we have a hard time separating legit region
|
||||
// errors from silly ones.
|
||||
self.report_region_errors(generic_param_scope, &errors);
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(self
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"))
|
||||
}
|
||||
}
|
||||
|
||||
// [Note-Type-error-reporting]
|
||||
// An invariant is that anytime the expected or actual type is Error (the special
|
||||
// error type, meaning that an error occurred when typechecking this expression),
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
//! Various code related to computing outlives relations.
|
||||
use self::env::OutlivesEnvironment;
|
||||
use super::region_constraints::RegionConstraintData;
|
||||
use super::{InferCtxt, RegionResolutionError};
|
||||
use crate::infer::free_regions::RegionRelations;
|
||||
use crate::infer::lexical_region_resolve::{self, LexicalRegionResolutions};
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::ty;
|
||||
|
||||
pub mod components;
|
||||
pub mod env;
|
||||
|
@ -6,9 +13,6 @@ pub mod obligations;
|
|||
pub mod test_type_match;
|
||||
pub mod verify;
|
||||
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::ty;
|
||||
|
||||
#[instrument(level = "debug", skip(param_env), ret)]
|
||||
pub fn explicit_outlives_bounds<'tcx>(
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
@ -39,3 +43,98 @@ pub fn explicit_outlives_bounds<'tcx>(
|
|||
))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)),
|
||||
})
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
pub fn skip_region_resolution(&self) {
|
||||
let (var_infos, _) = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let inner = &mut *inner;
|
||||
// Note: `inner.region_obligations` may not be empty, because we
|
||||
// didn't necessarily call `process_registered_region_obligations`.
|
||||
// This is okay, because that doesn't introduce new vars.
|
||||
inner
|
||||
.region_constraint_storage
|
||||
.take()
|
||||
.expect("regions already resolved")
|
||||
.with_log(&mut inner.undo_log)
|
||||
.into_infos_and_data()
|
||||
};
|
||||
|
||||
let lexical_region_resolutions = LexicalRegionResolutions {
|
||||
values: rustc_index::vec::IndexVec::from_elem_n(
|
||||
crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
|
||||
var_infos.len(),
|
||||
),
|
||||
};
|
||||
|
||||
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
|
||||
assert!(old_value.is_none());
|
||||
}
|
||||
|
||||
/// Process the region constraints and return any errors that
|
||||
/// result. After this, no more unification operations should be
|
||||
/// done -- or the compiler will panic -- but it is legal to use
|
||||
/// `resolve_vars_if_possible` as well as `fully_resolve`.
|
||||
#[must_use]
|
||||
pub fn resolve_regions(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) -> Vec<RegionResolutionError<'tcx>> {
|
||||
self.process_registered_region_obligations(outlives_env);
|
||||
|
||||
let (var_infos, data) = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let inner = &mut *inner;
|
||||
assert!(
|
||||
self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
|
||||
"region_obligations not empty: {:#?}",
|
||||
inner.region_obligations
|
||||
);
|
||||
inner
|
||||
.region_constraint_storage
|
||||
.take()
|
||||
.expect("regions already resolved")
|
||||
.with_log(&mut inner.undo_log)
|
||||
.into_infos_and_data()
|
||||
};
|
||||
|
||||
let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
|
||||
|
||||
let (lexical_region_resolutions, errors) =
|
||||
lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
|
||||
|
||||
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
|
||||
assert!(old_value.is_none());
|
||||
|
||||
errors
|
||||
}
|
||||
|
||||
/// Obtains (and clears) the current set of region
|
||||
/// constraints. The inference context is still usable: further
|
||||
/// unifications will simply add new constraints.
|
||||
///
|
||||
/// This method is not meant to be used with normal lexical region
|
||||
/// resolution. Rather, it is used in the NLL mode as a kind of
|
||||
/// interim hack: basically we run normal type-check and generate
|
||||
/// region constraints as normal, but then we take them and
|
||||
/// translate them into the form that the NLL solver
|
||||
/// understands. See the NLL module for mode details.
|
||||
pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
|
||||
assert!(
|
||||
self.inner.borrow().region_obligations.is_empty(),
|
||||
"region_obligations not empty: {:#?}",
|
||||
self.inner.borrow().region_obligations
|
||||
);
|
||||
|
||||
self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
|
||||
}
|
||||
|
||||
/// Gives temporary access to the region constraint data.
|
||||
pub fn with_region_constraints<R>(
|
||||
&self,
|
||||
op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
|
||||
) -> R {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
op(inner.unwrap_region_constraints().data())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ use rustc_middle::ty::subst::GenericArgKind;
|
|||
use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitableExt};
|
||||
use smallvec::smallvec;
|
||||
|
||||
use super::env::OutlivesEnvironment;
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Registers that the given region obligation must be resolved
|
||||
/// from within the scope of `body_id`. These regions are enqueued
|
||||
|
@ -112,39 +114,17 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
std::mem::take(&mut self.inner.borrow_mut().region_obligations)
|
||||
}
|
||||
|
||||
/// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors`
|
||||
/// instead of calling this directly.
|
||||
///
|
||||
/// Process the region obligations that must be proven (during
|
||||
/// `regionck`) for the given `body_id`, given information about
|
||||
/// the region bounds in scope and so forth. This function must be
|
||||
/// invoked for all relevant body-ids before region inference is
|
||||
/// done (or else an assert will fire).
|
||||
/// the region bounds in scope and so forth.
|
||||
///
|
||||
/// See the `region_obligations` field of `InferCtxt` for some
|
||||
/// comments about how this function fits into the overall expected
|
||||
/// flow of the inferencer. The key point is that it is
|
||||
/// invoked after all type-inference variables have been bound --
|
||||
/// towards the end of regionck. This also ensures that the
|
||||
/// region-bound-pairs are available (see comments above regarding
|
||||
/// closures).
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `region_bound_pairs_map`: the set of region bounds implied by
|
||||
/// the parameters and where-clauses. In particular, each pair
|
||||
/// `('a, K)` in this list tells us that the bounds in scope
|
||||
/// indicate that `K: 'a`, where `K` is either a generic
|
||||
/// parameter like `T` or a projection like `T::Item`.
|
||||
/// - `param_env` is the parameter environment for the enclosing function.
|
||||
/// - `body_id` is the body-id whose region obligations are being
|
||||
/// processed.
|
||||
#[instrument(level = "debug", skip(self, region_bound_pairs))]
|
||||
pub fn process_registered_region_obligations(
|
||||
&self,
|
||||
region_bound_pairs: &RegionBoundPairs<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) {
|
||||
/// right before lexical region resolution.
|
||||
#[instrument(level = "debug", skip(self, outlives_env))]
|
||||
pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) {
|
||||
assert!(
|
||||
!self.in_snapshot.get(),
|
||||
"cannot process registered region obligations in a snapshot"
|
||||
|
@ -153,15 +133,16 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
let my_region_obligations = self.take_registered_region_obligations();
|
||||
|
||||
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
|
||||
debug!(
|
||||
"process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}",
|
||||
sup_type, sub_region, origin
|
||||
);
|
||||
|
||||
debug!(?sup_type, ?sub_region, ?origin);
|
||||
let sup_type = self.resolve_vars_if_possible(sup_type);
|
||||
|
||||
let outlives =
|
||||
&mut TypeOutlives::new(self, self.tcx, ®ion_bound_pairs, None, param_env);
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
self,
|
||||
self.tcx,
|
||||
&outlives_env.region_bound_pairs(),
|
||||
None,
|
||||
outlives_env.param_env,
|
||||
);
|
||||
let category = origin.to_constraint_category();
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region, category);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
|||
obligation: PredicateObligation<'tcx>,
|
||||
);
|
||||
|
||||
#[must_use]
|
||||
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
|
||||
|
||||
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
|
||||
|
@ -58,6 +59,7 @@ pub trait TraitEngineExt<'tcx> {
|
|||
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
||||
);
|
||||
|
||||
#[must_use]
|
||||
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
|
||||
}
|
||||
|
||||
infcx.process_registered_region_obligations(&Default::default(), full_env);
|
||||
let outlives_env = OutlivesEnvironment::new(full_env);
|
||||
infcx.process_registered_region_obligations(&outlives_env);
|
||||
|
||||
let region_data =
|
||||
infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
|
||||
|
|
|
@ -405,9 +405,6 @@ fn resolve_negative_obligation<'tcx>(
|
|||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
|
||||
);
|
||||
|
||||
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
|
||||
|
||||
infcx.resolve_regions(&outlives_env).is_empty()
|
||||
}
|
||||
|
||||
|
|
|
@ -6,11 +6,13 @@ use super::{ChalkFulfillmentContext, FulfillmentContext};
|
|||
use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
|
||||
use crate::traits::NormalizeExt;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_infer::infer::at::ToTrace;
|
||||
use rustc_infer::infer::canonical::{
|
||||
Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
|
||||
};
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
||||
use rustc_infer::traits::query::Fallible;
|
||||
use rustc_infer::traits::{
|
||||
|
@ -173,14 +175,33 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
|||
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> {
|
||||
self.engine.borrow_mut().select_where_possible(self.infcx)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
|
||||
self.engine.borrow_mut().select_all_or_error(self.infcx)
|
||||
}
|
||||
|
||||
/// Resolves regions and reports errors.
|
||||
///
|
||||
/// Takes ownership of the context as doing trait solving afterwards
|
||||
/// will result in region constraints getting ignored.
|
||||
pub fn resolve_regions_and_report_errors(
|
||||
self,
|
||||
generic_param_scope: LocalDefId,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let errors = self.infcx.resolve_regions(&outlives_env);
|
||||
if errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(self.infcx.err_ctxt().report_region_errors(generic_param_scope, &errors))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assumed_wf_types(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
|
|
@ -1776,7 +1776,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
// constrain inference variables a bit more to nested obligations from normalize so
|
||||
// we can have more helpful errors.
|
||||
ocx.select_where_possible();
|
||||
//
|
||||
// we intentionally drop errors from normalization here,
|
||||
// since the normalization is just done to improve the error message.
|
||||
let _ = ocx.select_where_possible();
|
||||
|
||||
if let Err(new_err) = ocx.eq_exp(
|
||||
&obligation.cause,
|
||||
|
|
|
@ -117,10 +117,6 @@ pub fn type_allowed_to_implement_copy<'tcx>(
|
|||
FxIndexSet::from_iter([self_type]),
|
||||
),
|
||||
);
|
||||
infcx.process_registered_region_obligations(
|
||||
outlives_env.region_bound_pairs(),
|
||||
param_env,
|
||||
);
|
||||
let errors = infcx.resolve_regions(&outlives_env);
|
||||
if !errors.is_empty() {
|
||||
infringing.push((field, ty, InfringingFieldsReason::Regions(errors)));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue