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