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