1use std::fmt;
2use std::rc::Rc;
3
4use rustc_errors::Diag;
5use rustc_hir::def_id::LocalDefId;
6use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
7use rustc_infer::infer::{
8 InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _,
9};
10use rustc_infer::traits::ObligationCause;
11use rustc_infer::traits::query::{
12 CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpDeeplyNormalizeGoal,
13 CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal,
14};
15use rustc_middle::ty::error::TypeError;
16use rustc_middle::ty::{
17 self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex,
18};
19use rustc_span::Span;
20use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
21use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError;
22use rustc_trait_selection::traits::ObligationCtxt;
23use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
24use tracing::{debug, instrument};
25
26use crate::MirBorrowckCtxt;
27use crate::region_infer::values::RegionElement;
28use crate::session_diagnostics::{
29 HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
30};
31
32#[derive(Clone)]
34pub(crate) enum UniverseInfo<'tcx> {
35 RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
37 TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
39 Other,
41}
42
43impl<'tcx> UniverseInfo<'tcx> {
44 pub(crate) fn other() -> UniverseInfo<'tcx> {
45 UniverseInfo::Other
46 }
47
48 pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
49 UniverseInfo::RelateTys { expected, found }
50 }
51
52 pub(crate) fn report_error(
53 &self,
54 mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
55 placeholder: ty::PlaceholderRegion,
56 error_element: RegionElement,
57 cause: ObligationCause<'tcx>,
58 ) {
59 match *self {
60 UniverseInfo::RelateTys { expected, found } => {
61 let err = mbcx.infcx.err_ctxt().report_mismatched_types(
62 &cause,
63 mbcx.infcx.param_env,
64 expected,
65 found,
66 TypeError::RegionsPlaceholderMismatch,
67 );
68 mbcx.buffer_error(err);
69 }
70 UniverseInfo::TypeOp(ref type_op_info) => {
71 type_op_info.report_error(mbcx, placeholder, error_element, cause);
72 }
73 UniverseInfo::Other => {
74 mbcx.buffer_error(
78 mbcx.dcx().create_err(HigherRankedSubtypeError { span: cause.span }),
79 );
80 }
81 }
82 }
83}
84
85pub(crate) trait ToUniverseInfo<'tcx> {
86 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
87}
88
89impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
90 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
91 UniverseInfo::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
92 base_universe: Some(base_universe),
93 ..self
94 }))
95 }
96}
97
98impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpProvePredicateGoal<'tcx> {
99 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
100 UniverseInfo::TypeOp(Rc::new(PredicateQuery { canonical_query: self, base_universe }))
101 }
102}
103
104impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUniverseInfo<'tcx>
105 for CanonicalTypeOpNormalizeGoal<'tcx, T>
106{
107 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
108 UniverseInfo::TypeOp(Rc::new(NormalizeQuery { canonical_query: self, base_universe }))
109 }
110}
111
112impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUniverseInfo<'tcx>
113 for CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T>
114{
115 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
116 UniverseInfo::TypeOp(Rc::new(DeeplyNormalizeQuery { canonical_query: self, base_universe }))
117 }
118}
119
120impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpAscribeUserTypeGoal<'tcx> {
121 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
122 UniverseInfo::TypeOp(Rc::new(AscribeUserTypeQuery { canonical_query: self, base_universe }))
123 }
124}
125
126impl<'tcx> ToUniverseInfo<'tcx> for ! {
127 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
128 self
129 }
130}
131
132#[allow(unused_lifetimes)]
133pub(crate) trait TypeOpInfo<'tcx> {
134 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx>;
137
138 fn base_universe(&self) -> ty::UniverseIndex;
139
140 fn nice_error<'infcx>(
141 &self,
142 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
143 cause: ObligationCause<'tcx>,
144 placeholder_region: ty::Region<'tcx>,
145 error_region: Option<ty::Region<'tcx>>,
146 ) -> Option<Diag<'infcx>>;
147
148 #[instrument(level = "debug", skip(self, mbcx))]
149 fn report_error(
150 &self,
151 mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
152 placeholder: ty::PlaceholderRegion,
153 error_element: RegionElement,
154 cause: ObligationCause<'tcx>,
155 ) {
156 let tcx = mbcx.infcx.tcx;
157 let base_universe = self.base_universe();
158 debug!(?base_universe);
159
160 let Some(adjusted_universe) =
161 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
162 else {
163 mbcx.buffer_error(self.fallback_error(tcx, cause.span));
164 return;
165 };
166
167 let placeholder_region = ty::Region::new_placeholder(
168 tcx,
169 ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound },
170 );
171
172 let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) =
173 error_element
174 {
175 let adjusted_universe =
176 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
177 adjusted_universe.map(|adjusted| {
178 ty::Region::new_placeholder(
179 tcx,
180 ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound },
181 )
182 })
183 } else {
184 None
185 };
186
187 debug!(?placeholder_region);
188
189 let span = cause.span;
190 let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
191
192 debug!(?nice_error);
193
194 if let Some(nice_error) = nice_error {
195 mbcx.buffer_error(nice_error);
196 } else {
197 mbcx.buffer_error(self.fallback_error(tcx, span));
198 }
199 }
200}
201
202struct PredicateQuery<'tcx> {
203 canonical_query: CanonicalTypeOpProvePredicateGoal<'tcx>,
204 base_universe: ty::UniverseIndex,
205}
206
207impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
208 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
209 tcx.dcx().create_err(HigherRankedLifetimeError {
210 cause: Some(HigherRankedErrorCause::CouldNotProve {
211 predicate: self.canonical_query.canonical.value.value.predicate.to_string(),
212 }),
213 span,
214 })
215 }
216
217 fn base_universe(&self) -> ty::UniverseIndex {
218 self.base_universe
219 }
220
221 fn nice_error<'infcx>(
222 &self,
223 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
224 cause: ObligationCause<'tcx>,
225 placeholder_region: ty::Region<'tcx>,
226 error_region: Option<ty::Region<'tcx>>,
227 ) -> Option<Diag<'infcx>> {
228 let (infcx, key, _) =
229 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
230 let ocx = ObligationCtxt::new(&infcx);
231 type_op_prove_predicate_with_cause(&ocx, key, cause);
232 let diag = try_extract_error_from_fulfill_cx(
233 &ocx,
234 mbcx.mir_def_id(),
235 placeholder_region,
236 error_region,
237 )?
238 .with_dcx(mbcx.dcx());
239 Some(diag)
240 }
241}
242
243struct NormalizeQuery<'tcx, T> {
244 canonical_query: CanonicalTypeOpNormalizeGoal<'tcx, T>,
245 base_universe: ty::UniverseIndex,
246}
247
248impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
249where
250 T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
251{
252 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
253 tcx.dcx().create_err(HigherRankedLifetimeError {
254 cause: Some(HigherRankedErrorCause::CouldNotNormalize {
255 value: self.canonical_query.canonical.value.value.value.to_string(),
256 }),
257 span,
258 })
259 }
260
261 fn base_universe(&self) -> ty::UniverseIndex {
262 self.base_universe
263 }
264
265 fn nice_error<'infcx>(
266 &self,
267 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
268 cause: ObligationCause<'tcx>,
269 placeholder_region: ty::Region<'tcx>,
270 error_region: Option<ty::Region<'tcx>>,
271 ) -> Option<Diag<'infcx>> {
272 let (infcx, key, _) =
273 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
274 let ocx = ObligationCtxt::new(&infcx);
275
276 let (param_env, value) = key.into_parts();
283 let _ = ocx.normalize(&cause, param_env, value.value);
284
285 let diag = try_extract_error_from_fulfill_cx(
286 &ocx,
287 mbcx.mir_def_id(),
288 placeholder_region,
289 error_region,
290 )?
291 .with_dcx(mbcx.dcx());
292 Some(diag)
293 }
294}
295
296struct DeeplyNormalizeQuery<'tcx, T> {
297 canonical_query: CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T>,
298 base_universe: ty::UniverseIndex,
299}
300
301impl<'tcx, T> TypeOpInfo<'tcx> for DeeplyNormalizeQuery<'tcx, T>
302where
303 T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
304{
305 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
306 tcx.dcx().create_err(HigherRankedLifetimeError {
307 cause: Some(HigherRankedErrorCause::CouldNotNormalize {
308 value: self.canonical_query.canonical.value.value.value.to_string(),
309 }),
310 span,
311 })
312 }
313
314 fn base_universe(&self) -> ty::UniverseIndex {
315 self.base_universe
316 }
317
318 fn nice_error<'infcx>(
319 &self,
320 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
321 cause: ObligationCause<'tcx>,
322 placeholder_region: ty::Region<'tcx>,
323 error_region: Option<ty::Region<'tcx>>,
324 ) -> Option<Diag<'infcx>> {
325 let (infcx, key, _) =
326 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
327 let ocx = ObligationCtxt::new(&infcx);
328
329 let (param_env, value) = key.into_parts();
330 let _ = ocx.deeply_normalize(&cause, param_env, value.value);
331
332 let diag = try_extract_error_from_fulfill_cx(
333 &ocx,
334 mbcx.mir_def_id(),
335 placeholder_region,
336 error_region,
337 )?
338 .with_dcx(mbcx.dcx());
339 Some(diag)
340 }
341}
342
343struct AscribeUserTypeQuery<'tcx> {
344 canonical_query: CanonicalTypeOpAscribeUserTypeGoal<'tcx>,
345 base_universe: ty::UniverseIndex,
346}
347
348impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
349 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
350 tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
353 }
354
355 fn base_universe(&self) -> ty::UniverseIndex {
356 self.base_universe
357 }
358
359 fn nice_error<'infcx>(
360 &self,
361 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
362 cause: ObligationCause<'tcx>,
363 placeholder_region: ty::Region<'tcx>,
364 error_region: Option<ty::Region<'tcx>>,
365 ) -> Option<Diag<'infcx>> {
366 let (infcx, key, _) =
367 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
368 let ocx = ObligationCtxt::new(&infcx);
369 type_op_ascribe_user_type_with_span(&ocx, key, cause.span).ok()?;
370 let diag = try_extract_error_from_fulfill_cx(
371 &ocx,
372 mbcx.mir_def_id(),
373 placeholder_region,
374 error_region,
375 )?
376 .with_dcx(mbcx.dcx());
377 Some(diag)
378 }
379}
380
381impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
382 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
383 tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
386 }
387
388 fn base_universe(&self) -> ty::UniverseIndex {
389 self.base_universe.unwrap()
390 }
391
392 fn nice_error<'infcx>(
393 &self,
394 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
395 _cause: ObligationCause<'tcx>,
396 placeholder_region: ty::Region<'tcx>,
397 error_region: Option<ty::Region<'tcx>>,
398 ) -> Option<Diag<'infcx>> {
399 try_extract_error_from_region_constraints(
400 mbcx.infcx,
401 mbcx.mir_def_id(),
402 placeholder_region,
403 error_region,
404 self.region_constraints.as_ref().unwrap(),
405 |vid| mbcx.regioncx.var_infos[vid].origin,
410 |vid| mbcx.regioncx.var_infos[vid].universe,
411 )
412 }
413}
414
415#[instrument(skip(ocx), level = "debug")]
416fn try_extract_error_from_fulfill_cx<'a, 'tcx>(
417 ocx: &ObligationCtxt<'a, 'tcx>,
418 generic_param_scope: LocalDefId,
419 placeholder_region: ty::Region<'tcx>,
420 error_region: Option<ty::Region<'tcx>>,
421) -> Option<Diag<'a>> {
422 let _errors = ocx.select_all_or_error();
426 let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone());
427 try_extract_error_from_region_constraints(
428 ocx.infcx,
429 generic_param_scope,
430 placeholder_region,
431 error_region,
432 ®ion_constraints,
433 |vid| ocx.infcx.region_var_origin(vid),
434 |vid| ocx.infcx.universe_of_region(ty::Region::new_var(ocx.infcx.tcx, vid)),
435 )
436}
437
438#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
439fn try_extract_error_from_region_constraints<'a, 'tcx>(
440 infcx: &'a InferCtxt<'tcx>,
441 generic_param_scope: LocalDefId,
442 placeholder_region: ty::Region<'tcx>,
443 error_region: Option<ty::Region<'tcx>>,
444 region_constraints: &RegionConstraintData<'tcx>,
445 mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
446 mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
447) -> Option<Diag<'a>> {
448 let placeholder_universe = match placeholder_region.kind() {
449 ty::RePlaceholder(p) => p.universe,
450 ty::ReVar(vid) => universe_of_region(vid),
451 _ => ty::UniverseIndex::ROOT,
452 };
453 let matches =
454 |a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) {
455 (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
456 _ => a_region == b_region,
457 };
458 let mut check =
459 |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint {
460 Constraint::RegSubReg(sub, sup)
461 if ((exact && sup == placeholder_region)
462 || (!exact && matches(sup, placeholder_region)))
463 && sup != sub =>
464 {
465 Some((sub, cause.clone()))
466 }
467 Constraint::VarSubReg(vid, sup)
468 if (exact
469 && sup == placeholder_region
470 && !universe_of_region(vid).can_name(placeholder_universe))
471 || (!exact && matches(sup, placeholder_region)) =>
472 {
473 Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
474 }
475 _ => None,
476 };
477 let mut info = region_constraints
478 .constraints
479 .iter()
480 .find_map(|(constraint, cause)| check(constraint, cause, true));
481 if info.is_none() {
482 info = region_constraints
483 .constraints
484 .iter()
485 .find_map(|(constraint, cause)| check(constraint, cause, false));
486 }
487 let (sub_region, cause) = info?;
488
489 debug!(?sub_region, "cause = {:#?}", cause);
490 let error = match (error_region, *sub_region) {
491 (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict(
492 vid,
493 region_var_origin(vid),
494 cause.clone(),
495 error_region,
496 cause.clone(),
497 placeholder_region,
498 vec![],
499 ),
500 (Some(error_region), _) => {
501 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region)
502 }
503 (None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict(
505 vid,
506 region_var_origin(vid),
507 universe_of_region(vid),
508 cause.clone(),
509 placeholder_region,
510 ),
511 (None, _) => {
512 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
513 }
514 };
515 NiceRegionError::new(&infcx.err_ctxt(), generic_param_scope, error)
516 .try_report_from_nll()
517 .or_else(|| {
518 if let SubregionOrigin::Subtype(trace) = cause {
519 Some(infcx.err_ctxt().report_and_explain_type_error(
520 *trace,
521 infcx.tcx.param_env(generic_param_scope),
522 TypeError::RegionsPlaceholderMismatch,
523 ))
524 } else {
525 None
526 }
527 })
528}