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_erroneous_element(
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_erroneous_element(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))]
152 fn report_erroneous_element(
153 &self,
154 mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
155 placeholder: ty::PlaceholderRegion,
156 error_element: RegionElement,
157 cause: ObligationCause<'tcx>,
158 ) {
159 let tcx = mbcx.infcx.tcx;
160 let base_universe = self.base_universe();
161 debug!(?base_universe);
162
163 let Some(adjusted_universe) =
164 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
165 else {
166 mbcx.buffer_error(self.fallback_error(tcx, cause.span));
167 return;
168 };
169
170 let placeholder_region = ty::Region::new_placeholder(
171 tcx,
172 ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound },
173 );
174
175 let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) =
176 error_element
177 {
178 let adjusted_universe =
179 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
180 adjusted_universe.map(|adjusted| {
181 ty::Region::new_placeholder(
182 tcx,
183 ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound },
184 )
185 })
186 } else {
187 None
188 };
189
190 debug!(?placeholder_region);
191
192 let span = cause.span;
193 let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
194
195 debug!(?nice_error);
196 mbcx.buffer_error(nice_error.unwrap_or_else(|| self.fallback_error(tcx, span)));
197 }
198}
199
200struct PredicateQuery<'tcx> {
201 canonical_query: CanonicalTypeOpProvePredicateGoal<'tcx>,
202 base_universe: ty::UniverseIndex,
203}
204
205impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
206 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
207 tcx.dcx().create_err(HigherRankedLifetimeError {
208 cause: Some(HigherRankedErrorCause::CouldNotProve {
209 predicate: self.canonical_query.canonical.value.value.predicate.to_string(),
210 }),
211 span,
212 })
213 }
214
215 fn base_universe(&self) -> ty::UniverseIndex {
216 self.base_universe
217 }
218
219 fn nice_error<'infcx>(
220 &self,
221 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
222 cause: ObligationCause<'tcx>,
223 placeholder_region: ty::Region<'tcx>,
224 error_region: Option<ty::Region<'tcx>>,
225 ) -> Option<Diag<'infcx>> {
226 let (infcx, key, _) =
227 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
228 let ocx = ObligationCtxt::new(&infcx);
229 type_op_prove_predicate_with_cause(&ocx, key, cause);
230 let diag = try_extract_error_from_fulfill_cx(
231 &ocx,
232 mbcx.mir_def_id(),
233 placeholder_region,
234 error_region,
235 )?
236 .with_dcx(mbcx.dcx());
237 Some(diag)
238 }
239}
240
241struct NormalizeQuery<'tcx, T> {
242 canonical_query: CanonicalTypeOpNormalizeGoal<'tcx, T>,
243 base_universe: ty::UniverseIndex,
244}
245
246impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
247where
248 T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
249{
250 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
251 tcx.dcx().create_err(HigherRankedLifetimeError {
252 cause: Some(HigherRankedErrorCause::CouldNotNormalize {
253 value: self.canonical_query.canonical.value.value.value.to_string(),
254 }),
255 span,
256 })
257 }
258
259 fn base_universe(&self) -> ty::UniverseIndex {
260 self.base_universe
261 }
262
263 fn nice_error<'infcx>(
264 &self,
265 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
266 cause: ObligationCause<'tcx>,
267 placeholder_region: ty::Region<'tcx>,
268 error_region: Option<ty::Region<'tcx>>,
269 ) -> Option<Diag<'infcx>> {
270 let (infcx, key, _) =
271 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
272 let ocx = ObligationCtxt::new(&infcx);
273
274 let (param_env, value) = key.into_parts();
281 let _ = ocx.normalize(&cause, param_env, value.value);
282
283 let diag = try_extract_error_from_fulfill_cx(
284 &ocx,
285 mbcx.mir_def_id(),
286 placeholder_region,
287 error_region,
288 )?
289 .with_dcx(mbcx.dcx());
290 Some(diag)
291 }
292}
293
294struct DeeplyNormalizeQuery<'tcx, T> {
295 canonical_query: CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T>,
296 base_universe: ty::UniverseIndex,
297}
298
299impl<'tcx, T> TypeOpInfo<'tcx> for DeeplyNormalizeQuery<'tcx, T>
300where
301 T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
302{
303 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
304 tcx.dcx().create_err(HigherRankedLifetimeError {
305 cause: Some(HigherRankedErrorCause::CouldNotNormalize {
306 value: self.canonical_query.canonical.value.value.value.to_string(),
307 }),
308 span,
309 })
310 }
311
312 fn base_universe(&self) -> ty::UniverseIndex {
313 self.base_universe
314 }
315
316 fn nice_error<'infcx>(
317 &self,
318 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
319 cause: ObligationCause<'tcx>,
320 placeholder_region: ty::Region<'tcx>,
321 error_region: Option<ty::Region<'tcx>>,
322 ) -> Option<Diag<'infcx>> {
323 let (infcx, key, _) =
324 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
325 let ocx = ObligationCtxt::new(&infcx);
326
327 let (param_env, value) = key.into_parts();
328 let _ = ocx.deeply_normalize(&cause, param_env, value.value);
329
330 let diag = try_extract_error_from_fulfill_cx(
331 &ocx,
332 mbcx.mir_def_id(),
333 placeholder_region,
334 error_region,
335 )?
336 .with_dcx(mbcx.dcx());
337 Some(diag)
338 }
339}
340
341struct AscribeUserTypeQuery<'tcx> {
342 canonical_query: CanonicalTypeOpAscribeUserTypeGoal<'tcx>,
343 base_universe: ty::UniverseIndex,
344}
345
346impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
347 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
348 tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
351 }
352
353 fn base_universe(&self) -> ty::UniverseIndex {
354 self.base_universe
355 }
356
357 fn nice_error<'infcx>(
358 &self,
359 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
360 cause: ObligationCause<'tcx>,
361 placeholder_region: ty::Region<'tcx>,
362 error_region: Option<ty::Region<'tcx>>,
363 ) -> Option<Diag<'infcx>> {
364 let (infcx, key, _) =
365 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
366 let ocx = ObligationCtxt::new(&infcx);
367 type_op_ascribe_user_type_with_span(&ocx, key, cause.span).ok()?;
368 let diag = try_extract_error_from_fulfill_cx(
369 &ocx,
370 mbcx.mir_def_id(),
371 placeholder_region,
372 error_region,
373 )?
374 .with_dcx(mbcx.dcx());
375 Some(diag)
376 }
377}
378
379impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
380 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
381 tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
384 }
385
386 fn base_universe(&self) -> ty::UniverseIndex {
387 self.base_universe.unwrap()
388 }
389
390 fn nice_error<'infcx>(
391 &self,
392 mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
393 _cause: ObligationCause<'tcx>,
394 placeholder_region: ty::Region<'tcx>,
395 error_region: Option<ty::Region<'tcx>>,
396 ) -> Option<Diag<'infcx>> {
397 try_extract_error_from_region_constraints(
398 mbcx.infcx,
399 mbcx.mir_def_id(),
400 placeholder_region,
401 error_region,
402 self.region_constraints.as_ref().unwrap(),
403 |vid| RegionVariableOrigin::Nll(mbcx.regioncx.definitions[vid].origin),
408 |vid| mbcx.regioncx.definitions[vid].universe,
409 )
410 }
411}
412
413#[instrument(skip(ocx), level = "debug")]
414fn try_extract_error_from_fulfill_cx<'a, 'tcx>(
415 ocx: &ObligationCtxt<'a, 'tcx>,
416 generic_param_scope: LocalDefId,
417 placeholder_region: ty::Region<'tcx>,
418 error_region: Option<ty::Region<'tcx>>,
419) -> Option<Diag<'a>> {
420 let _errors = ocx.select_all_or_error();
424 let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone());
425 try_extract_error_from_region_constraints(
426 ocx.infcx,
427 generic_param_scope,
428 placeholder_region,
429 error_region,
430 ®ion_constraints,
431 |vid| ocx.infcx.region_var_origin(vid),
432 |vid| ocx.infcx.universe_of_region(ty::Region::new_var(ocx.infcx.tcx, vid)),
433 )
434}
435
436#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
437fn try_extract_error_from_region_constraints<'a, 'tcx>(
438 infcx: &'a InferCtxt<'tcx>,
439 generic_param_scope: LocalDefId,
440 placeholder_region: ty::Region<'tcx>,
441 error_region: Option<ty::Region<'tcx>>,
442 region_constraints: &RegionConstraintData<'tcx>,
443 mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
444 mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
445) -> Option<Diag<'a>> {
446 let placeholder_universe = match placeholder_region.kind() {
447 ty::RePlaceholder(p) => p.universe,
448 ty::ReVar(vid) => universe_of_region(vid),
449 _ => ty::UniverseIndex::ROOT,
450 };
451 let regions_the_same =
453 |a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) {
454 (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
455 _ => a_region == b_region,
456 };
457 let mut check =
458 |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint {
459 Constraint::RegSubReg(sub, sup)
460 if ((exact && sup == placeholder_region)
461 || (!exact && regions_the_same(sup, placeholder_region)))
462 && sup != sub =>
463 {
464 Some((sub, cause.clone()))
465 }
466 Constraint::VarSubReg(vid, sup)
467 if (exact
468 && sup == placeholder_region
469 && !universe_of_region(vid).can_name(placeholder_universe))
470 || (!exact && regions_the_same(sup, placeholder_region)) =>
471 {
472 Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
473 }
474 _ => None,
475 };
476
477 let mut find_culprit = |exact_match: bool| {
478 region_constraints
479 .constraints
480 .iter()
481 .find_map(|(constraint, cause)| check(constraint, cause, exact_match))
482 };
483
484 let (sub_region, cause) = find_culprit(true).or_else(|| find_culprit(false))?;
485
486 debug!(?sub_region, "cause = {:#?}", cause);
487 let error = match (error_region, sub_region.kind()) {
488 (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict(
489 vid,
490 region_var_origin(vid),
491 cause.clone(),
492 error_region,
493 cause.clone(),
494 placeholder_region,
495 vec![],
496 ),
497 (Some(error_region), _) => {
498 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region)
499 }
500 (None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict(
502 vid,
503 region_var_origin(vid),
504 universe_of_region(vid),
505 cause.clone(),
506 placeholder_region,
507 ),
508 (None, _) => {
509 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
510 }
511 };
512 NiceRegionError::new(&infcx.err_ctxt(), generic_param_scope, error)
513 .try_report_from_nll()
514 .or_else(|| {
515 if let SubregionOrigin::Subtype(trace) = cause {
516 Some(infcx.err_ctxt().report_and_explain_type_error(
517 *trace,
518 infcx.tcx.param_env(generic_param_scope),
519 TypeError::RegionsPlaceholderMismatch,
520 ))
521 } else {
522 None
523 }
524 })
525}