diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
commit | 17d40c6057c88f4c432b0d7bac88e1b84cb7e67f (patch) | |
tree | 3f66c4a5918660bb8a758ab6cda5ff8ee4f6cdcd /compiler/rustc_infer/src/infer/mod.rs | |
parent | Adding upstream version 1.64.0+dfsg1. (diff) | |
download | rustc-upstream/1.65.0+dfsg1.tar.xz rustc-upstream/1.65.0+dfsg1.zip |
Adding upstream version 1.65.0+dfsg1.upstream/1.65.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 | 126 |
1 files changed, 82 insertions, 44 deletions
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d7d1b5fa2..3abed1221 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -32,7 +33,7 @@ pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::cell::{Cell, Ref, RefCell}; use std::fmt; @@ -316,12 +317,12 @@ pub struct InferCtxt<'a, 'tcx> { /// /// Don't read this flag directly, call `is_tainted_by_errors()` /// and `set_tainted_by_errors()`. - tainted_by_errors_flag: Cell<bool>, + 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 /// `tainted_by_errors`) to avoid reporting certain kinds of errors. - // FIXME(matthewjasper) Merge into `tainted_by_errors_flag` + // FIXME(matthewjasper) Merge into `tainted_by_errors` err_count_on_creation: usize, /// This flag is true while there is an active snapshot. @@ -337,6 +338,9 @@ pub struct InferCtxt<'a, 'tcx> { /// when we enter into a higher-ranked (`for<..>`) type or trait /// bound. universe: Cell<ty::UniverseIndex>, + + normalize_fn_sig_for_diagnostic: + Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, } /// See the `error_reporting` module for more details. @@ -350,12 +354,11 @@ pub enum ValuePairs<'tcx> { impl<'tcx> ValuePairs<'tcx> { pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - if let ValuePairs::Terms(ExpectedFound { - expected: ty::Term::Ty(expected), - found: ty::Term::Ty(found), - }) = self + if let ValuePairs::Terms(ExpectedFound { expected, found }) = self + && let Some(expected) = expected.ty() + && let Some(found) = found.ty() { - Some((*expected, *found)) + Some((expected, found)) } else { None } @@ -406,7 +409,11 @@ pub enum SubregionOrigin<'tcx> { /// Comparing the signature and requirements of an impl method against /// the containing trait. - CompareImplItemObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId }, + CompareImplItemObligation { + span: Span, + impl_item_def_id: LocalDefId, + trait_item_def_id: DefId, + }, /// Checking that the bounds of a trait's associated type hold for a given impl CheckAssociatedTypeBounds { @@ -414,12 +421,24 @@ pub enum SubregionOrigin<'tcx> { impl_item_def_id: LocalDefId, trait_item_def_id: DefId, }, + + AscribeUserTypeProvePredicate(Span), } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(SubregionOrigin<'_>, 32); +impl<'tcx> SubregionOrigin<'tcx> { + pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { + match self { + Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(), + Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span), + _ => ConstraintCategory::BoringNoLocation, + } + } +} + /// Times when we replace late-bound regions with variables: #[derive(Clone, Copy, Debug)] pub enum LateBoundRegionConversionTime { @@ -504,7 +523,7 @@ pub enum FixupError<'tcx> { } /// See the `region_obligations` field for more information. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct RegionObligation<'tcx> { pub sub_region: ty::Region<'tcx>, pub sup_type: Ty<'tcx>, @@ -540,6 +559,8 @@ pub struct InferCtxtBuilder<'tcx> { defining_use_anchor: DefiningAnchor, considering_regions: bool, fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>, + normalize_fn_sig_for_diagnostic: + Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, } pub trait TyCtxtInferExt<'tcx> { @@ -553,6 +574,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { defining_use_anchor: DefiningAnchor::Error, considering_regions: true, fresh_typeck_results: None, + normalize_fn_sig_for_diagnostic: None, } } } @@ -582,6 +604,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn with_normalize_fn_sig_for_diagnostic( + mut self, + fun: Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>, + ) -> Self { + self.normalize_fn_sig_for_diagnostic = Some(fun); + self + } + /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -611,6 +641,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { defining_use_anchor, considering_regions, ref fresh_typeck_results, + ref normalize_fn_sig_for_diagnostic, } = *self; let in_progress_typeck_results = fresh_typeck_results.as_ref(); f(InferCtxt { @@ -624,11 +655,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> { evaluation_cache: Default::default(), reported_trait_errors: Default::default(), reported_closure_mismatch: Default::default(), - tainted_by_errors_flag: Cell::new(false), + tainted_by_errors: Cell::new(None), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), + normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic + .as_ref() + .map(|f| f.clone()), }) } } @@ -988,7 +1022,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, predicate: ty::PolyCoercePredicate<'tcx>, - ) -> Option<InferResult<'tcx, ()>> { + ) -> Result<InferResult<'tcx, ()>, (TyVid, TyVid)> { let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate { a_is_expected: false, // when coercing from `a` to `b`, `b` is expected a: p.a, @@ -1002,7 +1036,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, predicate: ty::PolySubtypePredicate<'tcx>, - ) -> Option<InferResult<'tcx, ()>> { + ) -> Result<InferResult<'tcx, ()>, (TyVid, TyVid)> { // Check for two unresolved inference variables, in which case we can // make no progress. This is partly a micro-optimization, but it's // also an opportunity to "sub-unify" the variables. This isn't @@ -1021,12 +1055,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { match (r_a.kind(), r_b.kind()) { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { self.inner.borrow_mut().type_variables().sub(a_vid, b_vid); - return None; + return Err((a_vid, b_vid)); } _ => {} } - Some(self.commit_if_ok(|_snapshot| { + Ok(self.commit_if_ok(|_snapshot| { let ty::SubtypePredicate { a_is_expected, a, b } = self.replace_bound_vars_with_placeholders(predicate); @@ -1227,23 +1261,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn is_tainted_by_errors(&self) -> bool { debug!( "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ - tainted_by_errors_flag={})", + tainted_by_errors={})", self.tcx.sess.err_count(), self.err_count_on_creation, - self.tainted_by_errors_flag.get() + self.tainted_by_errors.get().is_some() ); if self.tcx.sess.err_count() > self.err_count_on_creation { return true; // errors reported since this infcx was made } - self.tainted_by_errors_flag.get() + self.tainted_by_errors.get().is_some() } /// Set the "tainted by errors" flag to true. We call this when we /// observe an error from a prior pass. pub fn set_tainted_by_errors(&self) { debug!("set_tainted_by_errors()"); - self.tainted_by_errors_flag.set(true) + self.tainted_by_errors.set(Some( + self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"), + )); } pub fn skip_region_resolution(&self) { @@ -1313,7 +1349,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// `resolve_vars_if_possible` as well as `fully_resolve`. /// /// Make sure to call [`InferCtxt::process_registered_region_obligations`] - /// first, or preferrably use [`InferCtxt::check_region_obligations_and_report_errors`] + /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`] /// to do both of these operations together. pub fn resolve_regions_and_report_errors( &self, @@ -1527,8 +1563,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { actual: Ty<'tcx>, err: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let trace = TypeTrace::types(cause, true, expected, actual); - self.report_and_explain_type_error(trace, &err) + self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) } pub fn report_mismatched_consts( @@ -1538,8 +1573,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { actual: ty::Const<'tcx>, err: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let trace = TypeTrace::consts(cause, true, expected, actual); - self.report_and_explain_type_error(trace, &err) + self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) } pub fn replace_bound_vars_with_fresh_vars<T>( @@ -1656,7 +1690,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn try_const_eval_resolve( &self, param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::Unevaluated<'tcx>, + unevaluated: ty::Unevaluated<'tcx, ()>, ty: Ty<'tcx>, span: Option<Span>, ) -> Result<ty::Const<'tcx>, ErrorHandled> { @@ -1691,7 +1725,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn const_eval_resolve( &self, mut param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::Unevaluated<'tcx>, + unevaluated: ty::Unevaluated<'tcx, ()>, span: Option<Span>, ) -> EvalToValTreeResult<'tcx> { let mut substs = self.resolve_vars_if_possible(unevaluated.substs); @@ -1700,7 +1734,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Postpone the evaluation of constants whose substs depend on inference // variables if substs.has_infer_types_or_consts() { - let ac = AbstractConst::new(self.tcx, unevaluated.shrink()); + let ac = AbstractConst::new(self.tcx, unevaluated); match ac { Ok(None) => { substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did); @@ -1722,11 +1756,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!(?param_env_erased); debug!(?substs_erased); - let unevaluated = ty::Unevaluated { - def: unevaluated.def, - substs: substs_erased, - promoted: unevaluated.promoted, - }; + let unevaluated = + ty::Unevaluated { def: unevaluated.def, substs: substs_erased, promoted: () }; // The return value is the evaluated value which doesn't contain any reference to inference // variables, thus we don't need to substitute back the original values. @@ -1814,7 +1845,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> { /// Tries to extract an inference variable from a type, returns `None` /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`). - pub fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> { + fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> { match *ty.kind() { ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)), ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)), @@ -1825,7 +1856,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> { /// Tries to extract an inference variable from a constant, returns `None` /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). - pub fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> { + fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> { match ct.kind() { ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), _ => None, @@ -1937,6 +1968,18 @@ impl<'tcx> TypeTrace<'tcx> { } } + pub fn poly_trait_refs( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: ty::PolyTraitRef<'tcx>, + b: ty::PolyTraitRef<'tcx>, + ) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())), + } + } + pub fn consts( cause: &ObligationCause<'tcx>, a_is_expected: bool, @@ -1962,6 +2005,7 @@ impl<'tcx> SubregionOrigin<'tcx> { DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, CompareImplItemObligation { span, .. } => span, + AscribeUserTypeProvePredicate(span) => span, CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), } } @@ -1994,6 +2038,10 @@ impl<'tcx> SubregionOrigin<'tcx> { parent: Box::new(default()), }, + traits::ObligationCauseCode::AscribeUserTypeProvePredicate(span) => { + SubregionOrigin::AscribeUserTypeProvePredicate(span) + } + _ => default(), } } @@ -2015,16 +2063,6 @@ impl RegionVariableOrigin { } } -impl<'tcx> fmt::Debug for RegionObligation<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "RegionObligation(sub_region={:?}, sup_type={:?})", - self.sub_region, self.sup_type - ) - } -} - /// Replaces substs that reference param or infer variables with suitable /// placeholders. This function is meant to remove these param and infer /// substs when they're not actually needed to evaluate a constant. |