1use std::fmt;
2
3use rustc_errors::ErrorGuaranteed;
4use rustc_infer::infer::canonical::Canonical;
5use rustc_infer::infer::outlives::env::RegionBoundPairs;
6use rustc_middle::bug;
7use rustc_middle::mir::{Body, ConstraintCategory};
8use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
9use rustc_span::Span;
10use rustc_span::def_id::DefId;
11use rustc_trait_selection::solve::NoSolution;
12use rustc_trait_selection::traits::ObligationCause;
13use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
14use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
15use tracing::{debug, instrument};
16
17use super::{Locations, NormalizeLocation, TypeChecker};
18use crate::BorrowckInferCtxt;
19use crate::diagnostics::ToUniverseInfo;
20use crate::type_check::{MirTypeckRegionConstraints, constraint_conversion};
21use crate::universal_regions::UniversalRegions;
22
23#[instrument(skip(infcx, constraints, op), level = "trace")]
24pub(crate) fn fully_perform_op_raw<'tcx, R: fmt::Debug, Op>(
25 infcx: &BorrowckInferCtxt<'tcx>,
26 body: &Body<'tcx>,
27 universal_regions: &UniversalRegions<'tcx>,
28 region_bound_pairs: &RegionBoundPairs<'tcx>,
29 known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
30 constraints: &mut MirTypeckRegionConstraints<'tcx>,
31 locations: Locations,
32 category: ConstraintCategory<'tcx>,
33 op: Op,
34) -> Result<R, ErrorGuaranteed>
35where
36 Op: type_op::TypeOp<'tcx, Output = R>,
37 Op::ErrorInfo: ToUniverseInfo<'tcx>,
38{
39 let old_universe = infcx.universe();
40
41 let TypeOpOutput { output, constraints: query_constraints, error_info } =
42 op.fully_perform(infcx, infcx.root_def_id, locations.span(body))?;
43 if cfg!(debug_assertions) {
44 let data = infcx.take_and_reset_region_constraints();
45 if !data.is_empty() {
46 panic!("leftover region constraints: {data:#?}");
47 }
48 }
49
50 debug!(?output, ?query_constraints);
51
52 if let Some(data) = query_constraints {
53 constraint_conversion::ConstraintConversion::new(
54 infcx,
55 universal_regions,
56 region_bound_pairs,
57 known_type_outlives_obligations,
58 locations,
59 locations.span(body),
60 category,
61 constraints,
62 )
63 .convert_all(data);
64 }
65
66 let universe = infcx.universe();
69 if old_universe != universe
70 && let Some(error_info) = error_info
71 {
72 let universe_info = error_info.to_universe_info(old_universe);
73 for u in (old_universe + 1)..=universe {
74 constraints.universe_causes.insert(u, universe_info.clone());
75 }
76 }
77
78 Ok(output)
79}
80
81impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
82 #[instrument(skip(self, op), level = "trace")]
93 pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
94 &mut self,
95 locations: Locations,
96 category: ConstraintCategory<'tcx>,
97 op: Op,
98 ) -> Result<R, ErrorGuaranteed>
99 where
100 Op: type_op::TypeOp<'tcx, Output = R>,
101 Op::ErrorInfo: ToUniverseInfo<'tcx>,
102 {
103 fully_perform_op_raw(
104 self.infcx,
105 self.body,
106 self.universal_regions,
107 self.region_bound_pairs,
108 self.known_type_outlives_obligations,
109 self.constraints,
110 locations,
111 category,
112 op,
113 )
114 }
115
116 pub(super) fn instantiate_canonical<T>(
117 &mut self,
118 span: Span,
119 canonical: &Canonical<'tcx, T>,
120 ) -> T
121 where
122 T: TypeFoldable<TyCtxt<'tcx>>,
123 {
124 let (instantiated, _) = self.infcx.instantiate_canonical(span, canonical);
125 instantiated
126 }
127
128 #[instrument(skip(self), level = "debug")]
129 pub(super) fn prove_trait_ref(
130 &mut self,
131 trait_ref: ty::TraitRef<'tcx>,
132 locations: Locations,
133 category: ConstraintCategory<'tcx>,
134 ) {
135 self.prove_predicate(
136 ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait(
137 ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive },
138 ))),
139 locations,
140 category,
141 );
142 }
143
144 #[instrument(level = "debug", skip(self))]
145 pub(super) fn normalize_and_prove_instantiated_predicates(
146 &mut self,
147 _def_id: DefId,
150 instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
151 locations: Locations,
152 ) {
153 for (predicate, span) in instantiated_predicates {
154 debug!(?span, ?predicate);
155 let category = ConstraintCategory::Predicate(span);
156 let predicate = self.normalize_with_category(predicate, locations, category);
157 self.prove_predicate(predicate, locations, category);
158 }
159 }
160
161 pub(super) fn prove_predicates(
162 &mut self,
163 predicates: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + std::fmt::Debug>,
164 locations: Locations,
165 category: ConstraintCategory<'tcx>,
166 ) {
167 for predicate in predicates {
168 self.prove_predicate(predicate, locations, category);
169 }
170 }
171
172 #[instrument(skip(self), level = "debug")]
173 pub(super) fn prove_predicate(
174 &mut self,
175 predicate: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + std::fmt::Debug,
176 locations: Locations,
177 category: ConstraintCategory<'tcx>,
178 ) {
179 let param_env = self.infcx.param_env;
180 let predicate = predicate.upcast(self.tcx());
181 let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
182 locations,
183 category,
184 param_env.and(type_op::prove_predicate::ProvePredicate { predicate }),
185 );
186 }
187
188 pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
189 where
190 T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
191 {
192 self.normalize_with_category(value, location, ConstraintCategory::Boring)
193 }
194
195 pub(super) fn deeply_normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
196 where
197 T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
198 {
199 let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
200 location.to_locations(),
201 ConstraintCategory::Boring,
202 self.infcx.param_env.and(type_op::normalize::DeeplyNormalize { value }),
203 );
204 result.unwrap_or(value)
205 }
206
207 #[instrument(skip(self), level = "debug")]
208 pub(super) fn normalize_with_category<T>(
209 &mut self,
210 value: T,
211 location: impl NormalizeLocation,
212 category: ConstraintCategory<'tcx>,
213 ) -> T
214 where
215 T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
216 {
217 let param_env = self.infcx.param_env;
218 let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
219 location.to_locations(),
220 category,
221 param_env.and(type_op::normalize::Normalize { value }),
222 );
223 result.unwrap_or(value)
224 }
225
226 #[instrument(skip(self), level = "debug")]
227 pub(super) fn struct_tail(
228 &mut self,
229 ty: Ty<'tcx>,
230 location: impl NormalizeLocation,
231 ) -> Ty<'tcx> {
232 let tcx = self.tcx();
233 let body = self.body;
234
235 let cause = ObligationCause::misc(
236 location.to_locations().span(body),
237 body.source.def_id().expect_local(),
238 );
239
240 if self.infcx.next_trait_solver() {
241 let param_env = self.infcx.param_env;
242 self.fully_perform_op(
244 location.to_locations(),
245 ConstraintCategory::Boring,
246 CustomTypeOp::new(
247 |ocx| {
248 let structurally_normalize = |ty| {
249 ocx.structurally_normalize_ty(
250 &cause,
251 param_env,
252 ty,
253 )
254 .unwrap_or_else(|_| bug!("struct tail should have been computable, since we computed it in HIR"))
255 };
256
257 let tail = tcx.struct_tail_raw(
258 ty,
259 &cause,
260 structurally_normalize,
261 || {},
262 );
263
264 Ok(tail)
265 },
266 "normalizing struct tail",
267 ),
268 )
269 .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
270 } else {
271 let mut normalize = |ty| self.normalize(ty, location);
272 let tail = tcx.struct_tail_raw(ty, &cause, &mut normalize, || {});
273 normalize(tail)
274 }
275 }
276
277 #[instrument(skip(self), level = "debug")]
278 pub(super) fn structurally_resolve(
279 &mut self,
280 ty: Ty<'tcx>,
281 location: impl NormalizeLocation,
282 ) -> Ty<'tcx> {
283 if self.infcx.next_trait_solver() {
284 let body = self.body;
285 let param_env = self.infcx.param_env;
286 self.fully_perform_op(
288 location.to_locations(),
289 ConstraintCategory::Boring,
290 CustomTypeOp::new(
291 |ocx| {
292 ocx.structurally_normalize_ty(
293 &ObligationCause::misc(
294 location.to_locations().span(body),
295 body.source.def_id().expect_local(),
296 ),
297 param_env,
298 ty,
299 )
300 .map_err(|_| NoSolution)
301 },
302 "normalizing struct tail",
303 ),
304 )
305 .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar))
306 } else {
307 self.normalize(ty, location)
308 }
309 }
310
311 #[instrument(skip(self), level = "debug")]
312 pub(super) fn ascribe_user_type(
313 &mut self,
314 mir_ty: Ty<'tcx>,
315 user_ty: ty::UserType<'tcx>,
316 span: Span,
317 ) {
318 let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
319 Locations::All(span),
320 ConstraintCategory::Boring,
321 self.infcx
322 .param_env
323 .and(type_op::ascribe_user_type::AscribeUserType { mir_ty, user_ty }),
324 );
325 }
326
327 #[instrument(skip(self), level = "debug")]
331 pub(super) fn ascribe_user_type_skip_wf(
332 &mut self,
333 mir_ty: Ty<'tcx>,
334 user_ty: ty::UserType<'tcx>,
335 span: Span,
336 ) {
337 let ty::UserTypeKind::Ty(user_ty) = user_ty.kind else { bug!() };
338
339 if let ty::Infer(_) = user_ty.kind() {
341 self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring)
342 .unwrap();
343 return;
344 }
345
346 let mir_ty = self.normalize(mir_ty, Locations::All(span));
348
349 let cause = ObligationCause::dummy_with_span(span);
350 let param_env = self.infcx.param_env;
351 let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
352 Locations::All(span),
353 ConstraintCategory::Boring,
354 type_op::custom::CustomTypeOp::new(
355 |ocx| {
356 let user_ty = ocx.normalize(&cause, param_env, user_ty);
357 ocx.eq(&cause, param_env, user_ty, mir_ty)?;
358 Ok(())
359 },
360 "ascribe_user_type_skip_wf",
361 ),
362 );
363 }
364}