diff options
Diffstat (limited to 'compiler/rustc_infer')
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/outlives/mod.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/outlives/obligations.rs | 41 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/outlives/verify.rs | 29 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/lib.rs | 1 |
6 files changed, 70 insertions, 35 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index db01b5bd707..006638b740e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -518,6 +518,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } + + RegionResolutionError::CannotNormalize(ty, origin) => { + self.tcx + .dcx() + .struct_span_err(origin.span(), format!("cannot normalize `{ty}`")) + .emit(); + } } } } @@ -559,7 +566,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { RegionResolutionError::GenericBoundFailure(..) => true, RegionResolutionError::ConcreteFailure(..) | RegionResolutionError::SubSupConflict(..) - | RegionResolutionError::UpperBoundUniverseConflict(..) => false, + | RegionResolutionError::UpperBoundUniverseConflict(..) + | RegionResolutionError::CannotNormalize(..) => false, }; let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { @@ -574,6 +582,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(), RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), + RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(), }); errors } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 0562c6ccfcf..4a1169e68e0 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -98,6 +98,8 @@ pub enum RegionResolutionError<'tcx> { SubregionOrigin<'tcx>, // cause of the constraint Region<'tcx>, // the placeholder `'b` ), + + CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>), } impl<'tcx> RegionResolutionError<'tcx> { @@ -106,7 +108,8 @@ impl<'tcx> RegionResolutionError<'tcx> { RegionResolutionError::ConcreteFailure(origin, _, _) | RegionResolutionError::GenericBoundFailure(origin, _, _) | RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _) - | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin, + | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) + | RegionResolutionError::CannotNormalize(_, origin) => origin, } } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 6379f84aa25..926e198b219 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,11 +1,11 @@ //! Various code related to computing outlives relations. use self::env::OutlivesEnvironment; use super::region_constraints::RegionConstraintData; -use super::{InferCtxt, RegionResolutionError}; +use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; use rustc_middle::traits::query::OutlivesBound; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; pub mod components; pub mod env; @@ -41,12 +41,22 @@ impl<'tcx> InferCtxt<'tcx> { /// 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`. + /// + /// If you are in a crate that has access to `rustc_trait_selection`, + /// then it's probably better to use `resolve_regions`, + /// which knows how to normalize registered region obligations. #[must_use] - pub fn resolve_regions( + pub fn resolve_regions_with_normalize( &self, outlives_env: &OutlivesEnvironment<'tcx>, + deeply_normalize_ty: impl Fn(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, Ty<'tcx>>, ) -> Vec<RegionResolutionError<'tcx>> { - self.process_registered_region_obligations(outlives_env); + match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) { + Ok(()) => {} + Err((ty, origin)) => { + return vec![RegionResolutionError::CannotNormalize(ty, origin)]; + } + }; let (var_infos, data) = { let mut inner = self.inner.borrow_mut(); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index d7a3bfcbc41..b10bf98e8b5 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -70,6 +70,7 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::DUMMY_SP; use smallvec::smallvec; use super::env::OutlivesEnvironment; @@ -123,26 +124,54 @@ impl<'tcx> InferCtxt<'tcx> { /// flow of the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- /// right before lexical region resolution. - #[instrument(level = "debug", skip(self, outlives_env))] - pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) { + #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))] + pub fn process_registered_region_obligations<E>( + &self, + outlives_env: &OutlivesEnvironment<'tcx>, + mut deeply_normalize_ty: impl FnMut(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, E>, + ) -> Result<(), (E, SubregionOrigin<'tcx>)> { assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot"); + let normalized_caller_bounds: Vec<_> = outlives_env + .param_env + .caller_bounds() + .iter() + .filter_map(|clause| { + let bound_clause = clause.kind(); + let ty::ClauseKind::TypeOutlives(outlives) = bound_clause.skip_binder() else { + return None; + }; + Some( + deeply_normalize_ty( + outlives.0, + SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP), + ) + .map(|ty| bound_clause.rebind(ty::OutlivesPredicate(ty, outlives.1))), + ) + }) + // FIXME(-Znext-solver): How do we accurately report an error here :( + .try_collect() + .map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?; + let my_region_obligations = self.take_registered_region_obligations(); for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { + let sup_type = + deeply_normalize_ty(sup_type, origin.clone()).map_err(|e| (e, origin.clone()))?; debug!(?sup_type, ?sub_region, ?origin); - let sup_type = self.resolve_vars_if_possible(sup_type); let outlives = &mut TypeOutlives::new( self, self.tcx, outlives_env.region_bound_pairs(), None, - outlives_env.param_env, + &normalized_caller_bounds, ); let category = origin.to_constraint_category(); outlives.type_must_outlive(origin, sup_type, sub_region, category); } + + Ok(()) } } @@ -190,7 +219,7 @@ where tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], ) -> Self { Self { delegate, @@ -199,7 +228,7 @@ where tcx, region_bound_pairs, implicit_region_bound, - param_env, + caller_bounds, ), } } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 7a85268492b..5d2f51c689b 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -23,7 +23,7 @@ pub struct VerifyBoundCx<'cx, 'tcx> { /// Outside of borrowck the only way to prove `T: '?0` is by /// setting `'?0` to `'empty`. implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], } impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { @@ -31,9 +31,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { tcx: TyCtxt<'tcx>, region_bound_pairs: &'cx RegionBoundPairs<'tcx>, implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, + caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>], ) -> Self { - Self { tcx, region_bound_pairs, implicit_region_bound, param_env } + Self { tcx, region_bound_pairs, implicit_region_bound, caller_bounds } } #[instrument(level = "debug", skip(self))] @@ -219,8 +219,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // To start, collect bounds from user environment. Note that // parameter environments are already elaborated, so we don't // have to worry about that. - let c_b = self.param_env.caller_bounds(); - let param_bounds = self.collect_outlives_from_clause_list(erased_ty, c_b.into_iter()); + let param_bounds = self.caller_bounds.iter().copied().filter(move |outlives_predicate| { + super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty) + }); // Next, collect regions we scraped from the well-formedness // constraints in the fn signature. To do that, we walk the list @@ -307,22 +308,4 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { .filter_map(|p| p.no_bound_vars()) .map(|OutlivesPredicate(_, r)| r) } - - /// Searches through a predicate list for a predicate `T: 'a`. - /// - /// Careful: does not elaborate predicates, and just uses `==` - /// when comparing `ty` for equality, so `ty` must be something - /// that does not involve inference variables and where you - /// otherwise want a precise match. - fn collect_outlives_from_clause_list( - &self, - erased_ty: Ty<'tcx>, - clauses: impl Iterator<Item = ty::Clause<'tcx>>, - ) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> - { - let tcx = self.tcx; - clauses.filter_map(|p| p.as_type_outlives_clause()).filter(move |outlives_predicate| { - super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty) - }) - } } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 9e3de1825ed..e2dd4b49e1a 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -21,6 +21,7 @@ #![feature(extend_one)] #![feature(let_chains)] #![feature(if_let_guard)] +#![feature(iterator_try_collect)] #![feature(min_specialization)] #![feature(try_blocks)] #![recursion_limit = "512"] // For rustdoc |
