diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
commit | 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch) | |
tree | 3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /compiler/rustc_infer/src/infer/mod.rs | |
parent | Releasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_infer/src/infer/mod.rs')
-rw-r--r-- | compiler/rustc_infer/src/infer/mod.rs | 333 |
1 files changed, 142 insertions, 191 deletions
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index bd1f96635..66f51328b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,3 +1,4 @@ +pub use self::at::DefineOpaqueTypes; pub use self::freshen::TypeFreshener; pub use self::lexical_region_resolve::RegionResolutionError; pub use self::LateBoundRegionConversionTime::*; @@ -38,13 +39,13 @@ use rustc_span::Span; use std::cell::{Cell, RefCell}; use std::fmt; +use std::ops::Drop; 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, }; @@ -94,10 +95,10 @@ pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< /// call to `start_snapshot` and `rollback_to`. #[derive(Clone)] pub struct InferCtxtInner<'tcx> { - /// Cache for projections. This cache is snapshotted along with the infcx. + /// Cache for projections. /// - /// Public so that `traits::project` can use it. - pub projection_cache: traits::ProjectionCacheStorage<'tcx>, + /// This cache is snapshotted along with the infcx. + projection_cache: traits::ProjectionCacheStorage<'tcx>, /// We instantiate `UnificationTable` with `bounds<Ty>` because the types /// that might instantiate a general type variable have an order, @@ -114,24 +115,26 @@ pub struct InferCtxtInner<'tcx> { float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>, /// Tracks the set of region variables and the constraints between them. + /// /// This is initially `Some(_)` but when /// `resolve_regions_and_report_errors` is invoked, this gets set to `None` /// -- further attempts to perform unification, etc., may fail if new /// region constraints would've been added. region_constraint_storage: Option<RegionConstraintStorage<'tcx>>, - /// A set of constraints that regionck must validate. Each - /// constraint has the form `T:'a`, meaning "some type `T` must + /// A set of constraints that regionck must validate. + /// + /// Each constraint has the form `T:'a`, meaning "some type `T` must /// outlive the lifetime 'a". These constraints derive from /// instantiated type parameters. So if you had a struct defined - /// like + /// like the following: /// ```ignore (illustrative) - /// struct Foo<T:'static> { ... } + /// struct Foo<T: 'static> { ... } /// ``` - /// then in some expression `let x = Foo { ... }` it will + /// In some expression `let x = Foo { ... }`, it will /// instantiate the type parameter `T` with a fresh type `$0`. At /// the same time, it will record a region obligation of - /// `$0:'static`. This will get checked later by regionck. (We + /// `$0: 'static`. This will get checked later by regionck. (We /// can't generally check these things right away because we have /// to wait until types are resolved.) /// @@ -185,6 +188,16 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] + fn try_type_variables_probe_ref( + &self, + vid: ty::TyVid, + ) -> Option<&type_variable::TypeVariableValue<'tcx>> { + // Uses a read-only view of the unification table, this way we don't + // need an undo log. + self.type_variable_storage.eq_relations_ref().try_probe_value(vid) + } + + #[inline] fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> { self.type_variable_storage.with_log(&mut self.undo_log) } @@ -268,7 +281,7 @@ pub struct InferCtxt<'tcx> { /// Caches the results of trait evaluation. pub evaluation_cache: select::EvaluationCache<'tcx>, - /// the set of predicates on which errors have been reported, to + /// The set of predicates on which errors have been reported, to /// avoid reporting the same error twice. pub reported_trait_errors: RefCell<FxIndexMap<Span, Vec<ty::Predicate<'tcx>>>>, @@ -291,7 +304,7 @@ pub struct InferCtxt<'tcx> { tainted_by_errors: Cell<Option<ErrorGuaranteed>>, /// Track how many errors were reported when this infcx is created. - /// If the number of errors increases, that's also a sign (line + /// If the number of errors increases, that's also a sign (like /// `tainted_by_errors`) to avoid reporting certain kinds of errors. // FIXME(matthewjasper) Merge into `tainted_by_errors` err_count_on_creation: usize, @@ -313,7 +326,7 @@ pub struct InferCtxt<'tcx> { /// During coherence we have to assume that other crates may add /// additional impls which we currently don't know about. /// - /// To deal with this evaluation should be conservative + /// To deal with this evaluation, we should be conservative /// and consider the possibility of impls from outside this crate. /// This comes up primarily when resolving ambiguity. Imagine /// there is some trait reference `$0: Bar` where `$0` is an @@ -323,12 +336,17 @@ pub struct InferCtxt<'tcx> { /// bound to some type that in a downstream crate that implements /// `Bar`. /// - /// Outside of coherence we set this to false because we are only + /// Outside of coherence, we set this to false because we are only /// interested in types that the user could actually have written. /// In other words, we consider `$0: Bar` to be unimplemented if /// there is no type that the user could *actually name* that /// would satisfy it. This avoids crippling inference, basically. pub intercrate: bool, + + /// Flag that is set when we enter canonicalization. Used for debugging to ensure + /// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin` + /// inside non-canonicalization contexts. + inside_canonicalization_ctxt: Cell<bool>, } /// See the `error_reporting` module for more details. @@ -336,6 +354,7 @@ pub struct InferCtxt<'tcx> { pub enum ValuePairs<'tcx> { Regions(ExpectedFound<ty::Region<'tcx>>), Terms(ExpectedFound<ty::Term<'tcx>>), + Aliases(ExpectedFound<ty::AliasTy<'tcx>>), TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>), PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>), Sigs(ExpectedFound<ty::FnSig<'tcx>>), @@ -373,7 +392,7 @@ pub enum SubregionOrigin<'tcx> { Subtype(Box<TypeTrace<'tcx>>), /// When casting `&'a T` to an `&'b Trait` object, - /// relating `'a` to `'b` + /// relating `'a` to `'b`. RelateObjectBound(Span), /// Some type parameter was instantiated with the given type, @@ -384,7 +403,7 @@ pub enum SubregionOrigin<'tcx> { /// that must outlive some other region. RelateRegionParamBound(Span), - /// Creating a pointer `b` to contents of another reference + /// Creating a pointer `b` to contents of another reference. Reborrow(Span), /// (&'a &'b T) where a >= b @@ -398,7 +417,7 @@ pub enum SubregionOrigin<'tcx> { trait_item_def_id: DefId, }, - /// Checking that the bounds of a trait's associated type hold for a given impl + /// Checking that the bounds of a trait's associated type hold for a given impl. CheckAssociatedTypeBounds { parent: Box<SubregionOrigin<'tcx>>, impl_item_def_id: LocalDefId, @@ -435,32 +454,33 @@ pub enum LateBoundRegionConversionTime { AssocTypeProjection(DefId), } -/// Reasons to create a region inference variable +/// Reasons to create a region inference variable. /// -/// See `error_reporting` module for more details +/// See `error_reporting` module for more details. #[derive(Copy, Clone, Debug)] pub enum RegionVariableOrigin { - /// Region variables created for ill-categorized reasons, - /// mostly indicates places in need of refactoring + /// Region variables created for ill-categorized reasons. + /// + /// They mostly indicate places in need of refactoring. MiscVariable(Span), - /// Regions created by a `&P` or `[...]` pattern + /// Regions created by a `&P` or `[...]` pattern. PatternRegion(Span), - /// Regions created by `&` operator + /// Regions created by `&` operator. + /// AddrOfRegion(Span), - - /// Regions created as part of an autoref of a method receiver + /// Regions created as part of an autoref of a method receiver. Autoref(Span), - /// Regions created as part of an automatic coercion + /// Regions created as part of an automatic coercion. Coercion(Span), - /// Region variables created as the values for early-bound regions + /// Region variables created as the values for early-bound regions. EarlyBoundRegion(Span, Symbol), /// Region variables created for bound regions - /// in a function or method that is called + /// in a function or method that is called. LateBoundRegion(Span, ty::BoundRegionKind, LateBoundRegionConversionTime), UpvarRegion(ty::UpvarId, Span), @@ -534,7 +554,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> { } } -/// Used to configure inference contexts before their creation +/// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, defining_use_anchor: DefiningAnchor, @@ -570,8 +590,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn intercrate(mut self) -> Self { - self.intercrate = true; + pub fn intercrate(mut self, intercrate: bool) -> Self { + self.intercrate = intercrate; self } @@ -618,6 +638,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, + inside_canonicalization_ctxt: Cell::new(false), } } } @@ -691,12 +712,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { - freshen::TypeFreshener::new(self, false) - } - - /// Like `freshener`, but does not replace `'static` regions. - pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { - freshen::TypeFreshener::new(self, true) + freshen::TypeFreshener::new(self) } pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> { @@ -726,7 +742,7 @@ impl<'tcx> InferCtxt<'tcx> { &'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>, - define_opaque_types: bool, + define_opaque_types: DefineOpaqueTypes, ) -> CombineFields<'a, 'tcx> { CombineFields { infcx: self, @@ -835,9 +851,9 @@ impl<'tcx> InferCtxt<'tcx> { /// Scan the constraints produced since `snapshot` began and returns: /// - /// - `None` -- if none of them involve "region outlives" constraints - /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder - /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders + /// - `None` -- if none of them involves "region outlives" constraints. + /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder. + /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders. pub fn region_constraints_added_in_snapshot( &self, snapshot: &CombinedSnapshot<'tcx>, @@ -852,16 +868,12 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot) } - pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { - self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup); - } - pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool where T: at::ToTrace<'tcx>, { let origin = &ObligationCause::dummy(); - self.probe(|_| self.at(origin, param_env).sub(a, b).is_ok()) + self.probe(|_| self.at(origin, param_env).sub(DefineOpaqueTypes::No, a, b).is_ok()) } pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool @@ -869,7 +881,7 @@ impl<'tcx> InferCtxt<'tcx> { T: at::ToTrace<'tcx>, { let origin = &ObligationCause::dummy(); - self.probe(|_| self.at(origin, param_env).eq(a, b).is_ok()) + self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok()) } #[instrument(skip(self), level = "debug")] @@ -964,7 +976,8 @@ impl<'tcx> InferCtxt<'tcx> { let ty::SubtypePredicate { a_is_expected, a, b } = self.instantiate_binder_with_placeholders(predicate); - let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; + let ok = + self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?; Ok(ok.unit()) })) @@ -1199,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; @@ -1356,6 +1280,32 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().root_var(var) } + pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> { + self.inner.borrow_mut().const_unification_table().find(var) + } + + /// Resolves an int var to a rigid int type, if it was constrained to one, + /// or else the root int var in the unification table. + pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { + let mut inner = self.inner.borrow_mut(); + if let Some(value) = inner.int_unification_table().probe_value(vid) { + value.to_type(self.tcx) + } else { + self.tcx.mk_int_var(inner.int_unification_table().find(vid)) + } + } + + /// Resolves a float var to a rigid int type, if it was constrained to one, + /// or else the root float var in the unification table. + pub fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { + let mut inner = self.inner.borrow_mut(); + if let Some(value) = inner.float_unification_table().probe_value(vid) { + value.to_type(self.tcx) + } else { + self.tcx.mk_float_var(inner.float_unification_table().find(vid)) + } + } + /// Where possible, replaces type/const variables in /// `value` with their final value. Note that region variables /// are unaffected. If a type/const variable has not been unified, it @@ -1614,6 +1564,28 @@ impl<'tcx> InferCtxt<'tcx> { tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span) } + /// The returned function is used in a fast path. If it returns `true` the variable is + /// unchanged, `false` indicates that the status is unknown. + #[inline] + pub fn is_ty_infer_var_definitely_unchanged<'a>( + &'a self, + ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) { + // This hoists the borrow/release out of the loop body. + let inner = self.inner.try_borrow(); + + return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) { + (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => { + use self::type_variable::TypeVariableValue; + + match inner.try_type_variables_probe_ref(ty_var) { + Some(TypeVariableValue::Unknown { .. }) => true, + _ => false, + } + } + _ => false, + }; + } + /// `ty_or_const_infer_var_changed` is equivalent to one of these two: /// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`) /// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`) @@ -1664,59 +1636,34 @@ impl<'tcx> InferCtxt<'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, - ); + pub fn inside_canonicalization_ctxt(&self) -> bool { + self.inside_canonicalization_ctxt.get() + } - self.resolve_regions_and_report_errors(generic_param_scope, outlives_env) + pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> { + let prev_ctxt = self.inside_canonicalization_ctxt(); + self.inside_canonicalization_ctxt.set(true); + CanonicalizationCtxtGuard { prev_ctxt, infcx: self } } - /// 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); - } + fn set_canonicalization_ctxt_to(&self, ctxt: bool) { + self.inside_canonicalization_ctxt.set(ctxt); + } +} - if errors.is_empty() { - Ok(()) - } else { - Err(self - .tcx - .sess - .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")) - } +pub struct CanonicalizationCtxtGuard<'cx, 'tcx> { + prev_ctxt: bool, + infcx: &'cx InferCtxt<'tcx>, +} + +impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> { + fn drop(&mut self) { + self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt) } +} +impl<'tcx> TypeErrCtxt<'_, 'tcx> { // [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), @@ -1770,7 +1717,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } -/// Helper for `ty_or_const_infer_var_changed` (see comment on that), currently +/// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently /// used only for `traits::fulfill`'s list of `stalled_on` inference variables. #[derive(Copy, Clone, Debug)] pub enum TyOrConstInferVar<'tcx> { @@ -2043,13 +1990,17 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>( fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Infer(_) = t.kind() { + let idx = { + let idx = self.idx; + self.idx += 1; + idx + }; self.tcx.mk_placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, - name: ty::BoundTyKind::Anon({ - let idx = self.idx; - self.idx += 1; - idx - }), + bound: ty::BoundTy { + var: ty::BoundVar::from_u32(idx), + kind: ty::BoundTyKind::Anon, + }, }) } else { t.super_fold_with(self) @@ -2066,7 +2017,7 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>( self.tcx.mk_const( ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, - name: ty::BoundVar::from_u32({ + bound: ty::BoundVar::from_u32({ let idx = self.idx; self.idx += 1; idx |