3 use rustc_infer::infer::{canonical::Canonical, InferOk};
4 use rustc_middle::mir::ConstraintCategory;
5 use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
6 use rustc_span::def_id::DefId;
8 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
9 use rustc_trait_selection::traits::query::{Fallible, NoSolution};
10 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
12 use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
14 use super::{Locations, NormalizeLocation, TypeChecker};
16 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
17 /// Given some operation `op` that manipulates types, proves
18 /// predicates, or otherwise uses the inference context, executes
19 /// `op` and then executes all the further obligations that `op`
20 /// returns. This will yield a set of outlives constraints amongst
21 /// regions which are extracted and stored as having occurred at
24 /// **Any `rustc_infer::infer` operations that might generate region
25 /// constraints should occur within this method so that those
26 /// constraints can be properly localized!**
27 #[instrument(skip(self, op), level = "trace")]
28 pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
31 category: ConstraintCategory<'tcx>,
35 Op: type_op::TypeOp<'tcx, Output = R>,
36 Op::ErrorInfo: ToUniverseInfo<'tcx>,
38 let old_universe = self.infcx.universe();
40 let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
42 debug!(?output, ?constraints);
44 if let Some(data) = constraints {
45 self.push_region_constraints(locations, category, data);
48 let universe = self.infcx.universe();
50 if old_universe != universe {
51 let universe_info = match error_info {
52 Some(error_info) => error_info.to_universe_info(old_universe),
53 None => UniverseInfo::other(),
55 for u in (old_universe + 1)..=universe {
56 self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
63 pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>(
66 canonical: &Canonical<'tcx, T>,
69 T: TypeFoldable<'tcx>,
71 let old_universe = self.infcx.universe();
73 let (instantiated, _) =
74 self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
76 for u in (old_universe + 1)..=self.infcx.universe() {
77 self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other());
83 #[instrument(skip(self), level = "debug")]
84 pub(super) fn prove_trait_ref(
86 trait_ref: ty::TraitRef<'tcx>,
88 category: ConstraintCategory<'tcx>,
91 ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
93 constness: ty::BoundConstness::NotConst,
94 polarity: ty::ImplPolarity::Positive,
101 #[instrument(level = "debug", skip(self))]
102 pub(super) fn normalize_and_prove_instantiated_predicates(
104 // Keep this parameter for now, in case we start using
105 // it in `ConstraintCategory` at some point.
107 instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
108 locations: Locations,
110 for (predicate, span) in instantiated_predicates {
112 let category = ConstraintCategory::Predicate(span);
113 let predicate = self.normalize_with_category(predicate, locations, category);
114 self.prove_predicate(predicate, locations, category);
118 pub(super) fn prove_predicates(
120 predicates: impl IntoIterator<Item = impl ToPredicate<'tcx> + std::fmt::Debug>,
121 locations: Locations,
122 category: ConstraintCategory<'tcx>,
124 for predicate in predicates {
125 self.prove_predicate(predicate, locations, category);
129 #[instrument(skip(self), level = "debug")]
130 pub(super) fn prove_predicate(
132 predicate: impl ToPredicate<'tcx> + std::fmt::Debug,
133 locations: Locations,
134 category: ConstraintCategory<'tcx>,
136 let param_env = self.param_env;
137 let predicate = predicate.to_predicate(self.tcx());
138 self.fully_perform_op(
141 param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
143 .unwrap_or_else(|NoSolution| {
144 span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
148 pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
150 T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
152 self.normalize_with_category(value, location, ConstraintCategory::Boring)
155 #[instrument(skip(self), level = "debug")]
156 pub(super) fn normalize_with_category<T>(
159 location: impl NormalizeLocation,
160 category: ConstraintCategory<'tcx>,
163 T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
165 let param_env = self.param_env;
166 self.fully_perform_op(
167 location.to_locations(),
169 param_env.and(type_op::normalize::Normalize::new(value)),
171 .unwrap_or_else(|NoSolution| {
172 span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
177 #[instrument(skip(self), level = "debug")]
178 pub(super) fn ascribe_user_type(
181 user_ty: ty::UserType<'tcx>,
184 // FIXME: Ideally MIR types are normalized, but this is not always true.
185 let mir_ty = self.normalize(mir_ty, Locations::All(span));
187 self.fully_perform_op(
188 Locations::All(span),
189 ConstraintCategory::Boring,
190 self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
192 .unwrap_or_else(|err| {
196 "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
201 /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
203 /// FIXME(#104478, #104477): This is a hack for backward-compatibility.
204 #[instrument(skip(self), level = "debug")]
205 pub(super) fn ascribe_user_type_skip_wf(
208 user_ty: ty::UserType<'tcx>,
211 let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
213 // A fast path for a common case with closure input/output types.
214 if let ty::Infer(_) = user_ty.kind() {
215 self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring)
220 let mir_ty = self.normalize(mir_ty, Locations::All(span));
221 let cause = ObligationCause::dummy_with_span(span);
222 let param_env = self.param_env;
223 let op = |infcx: &'_ _| {
224 let ocx = ObligationCtxt::new_in_snapshot(infcx);
225 let user_ty = ocx.normalize(&cause, param_env, user_ty);
226 ocx.eq(&cause, param_env, user_ty, mir_ty)?;
227 if !ocx.select_all_or_error().is_empty() {
228 return Err(NoSolution);
230 Ok(InferOk { value: (), obligations: vec![] })
233 self.fully_perform_op(
234 Locations::All(span),
235 ConstraintCategory::Boring,
236 type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()),
238 .unwrap_or_else(|err| {
242 "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",