1 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
2 use rustc_infer::infer::canonical::Canonical;
3 use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
4 use rustc_infer::infer::region_constraints::Constraint;
5 use rustc_infer::infer::region_constraints::RegionConstraintData;
6 use rustc_infer::infer::RegionVariableOrigin;
7 use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
8 use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
9 use rustc_middle::ty::error::TypeError;
10 use rustc_middle::ty::RegionVid;
11 use rustc_middle::ty::UniverseIndex;
12 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
14 use rustc_trait_selection::traits::query::type_op;
15 use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
16 use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
21 use crate::region_infer::values::RegionElement;
22 use crate::session_diagnostics::HigherRankedErrorCause;
23 use crate::session_diagnostics::HigherRankedLifetimeError;
24 use crate::session_diagnostics::HigherRankedSubtypeError;
25 use crate::MirBorrowckCtxt;
28 pub(crate) struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
30 /// What operation a universe was created for.
32 enum UniverseInfoInner<'tcx> {
33 /// Relating two types which have binders.
34 RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
35 /// Created from performing a `TypeOp`.
36 TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
41 impl<'tcx> UniverseInfo<'tcx> {
42 pub(crate) fn other() -> UniverseInfo<'tcx> {
43 UniverseInfo(UniverseInfoInner::Other)
46 pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
47 UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
50 pub(crate) fn report_error(
52 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
53 placeholder: ty::PlaceholderRegion,
54 error_element: RegionElement,
55 cause: ObligationCause<'tcx>,
58 UniverseInfoInner::RelateTys { expected, found } => {
59 let err = mbcx.infcx.report_mismatched_types(
63 TypeError::RegionsPlaceholderMismatch,
65 mbcx.buffer_error(err);
67 UniverseInfoInner::TypeOp(ref type_op_info) => {
68 type_op_info.report_error(mbcx, placeholder, error_element, cause);
70 UniverseInfoInner::Other => {
71 // FIXME: This error message isn't great, but it doesn't show
72 // up in the existing UI tests. Consider investigating this
75 mbcx.infcx.tcx.sess.create_err(HigherRankedSubtypeError { span: cause.span }),
82 pub(crate) trait ToUniverseInfo<'tcx> {
83 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
86 impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
87 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
88 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
89 base_universe: Some(base_universe),
95 impl<'tcx> ToUniverseInfo<'tcx>
96 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
98 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
99 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
100 canonical_query: self,
106 impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
107 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
109 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
110 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
111 canonical_query: self,
117 impl<'tcx> ToUniverseInfo<'tcx>
118 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
120 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
121 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
122 canonical_query: self,
128 impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
129 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
130 // We can't rerun custom type ops.
131 UniverseInfo::other()
135 impl<'tcx> ToUniverseInfo<'tcx> for ! {
136 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
141 #[allow(unused_lifetimes)]
142 trait TypeOpInfo<'tcx> {
143 /// Returns an error to be reported if rerunning the type op fails to
144 /// recover the error's cause.
149 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
151 fn base_universe(&self) -> ty::UniverseIndex;
155 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
156 cause: ObligationCause<'tcx>,
157 placeholder_region: ty::Region<'tcx>,
158 error_region: Option<ty::Region<'tcx>>,
159 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
163 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
164 placeholder: ty::PlaceholderRegion,
165 error_element: RegionElement,
166 cause: ObligationCause<'tcx>,
168 let tcx = mbcx.infcx.tcx;
169 let base_universe = self.base_universe();
171 let Some(adjusted_universe) =
172 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
174 mbcx.buffer_error(self.fallback_error(tcx, cause.span));
178 let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
179 name: placeholder.name,
180 universe: adjusted_universe.into(),
184 if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
185 let adjusted_universe =
186 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
187 adjusted_universe.map(|adjusted| {
188 tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
189 name: error_placeholder.name,
190 universe: adjusted.into(),
197 debug!(?placeholder_region);
199 let span = cause.span;
200 let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
202 if let Some(nice_error) = nice_error {
203 mbcx.buffer_error(nice_error);
205 mbcx.buffer_error(self.fallback_error(tcx, span));
210 struct PredicateQuery<'tcx> {
212 Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
213 base_universe: ty::UniverseIndex,
216 impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
221 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
222 tcx.sess.create_err(HigherRankedLifetimeError {
223 cause: Some(HigherRankedErrorCause::CouldNotProve {
224 predicate: self.canonical_query.value.value.predicate.to_string(),
230 fn base_universe(&self) -> ty::UniverseIndex {
236 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
237 cause: ObligationCause<'tcx>,
238 placeholder_region: ty::Region<'tcx>,
239 error_region: Option<ty::Region<'tcx>>,
240 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
241 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
243 &self.canonical_query,
244 |ref infcx, key, _| {
245 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
246 type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
247 try_extract_error_from_fulfill_cx(
258 struct NormalizeQuery<'tcx, T> {
259 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
260 base_universe: ty::UniverseIndex,
263 impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
265 T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
271 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
272 tcx.sess.create_err(HigherRankedLifetimeError {
273 cause: Some(HigherRankedErrorCause::CouldNotNormalize {
274 value: self.canonical_query.value.value.value.to_string(),
280 fn base_universe(&self) -> ty::UniverseIndex {
286 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
287 cause: ObligationCause<'tcx>,
288 placeholder_region: ty::Region<'tcx>,
289 error_region: Option<ty::Region<'tcx>>,
290 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
291 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
293 &self.canonical_query,
294 |ref infcx, key, _| {
295 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
297 let mut selcx = SelectionContext::new(infcx);
299 // FIXME(lqd): Unify and de-duplicate the following with the actual
300 // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
301 // `ObligationCause`. The normalization results are currently different between
302 // `AtExt::normalize` used in the query and `normalize` called below: the former fails
303 // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
304 // after #85499 lands to see if its fixes have erased this difference.
305 let (param_env, value) = key.into_parts();
306 let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
312 fulfill_cx.register_predicate_obligations(infcx, obligations);
314 try_extract_error_from_fulfill_cx(
325 struct AscribeUserTypeQuery<'tcx> {
326 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
327 base_universe: ty::UniverseIndex,
330 impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
335 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
336 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
337 // and is only the fallback when the nice error fails. Consider improving this some more.
338 tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
341 fn base_universe(&self) -> ty::UniverseIndex {
347 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
348 cause: ObligationCause<'tcx>,
349 placeholder_region: ty::Region<'tcx>,
350 error_region: Option<ty::Region<'tcx>>,
351 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
352 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
354 &self.canonical_query,
355 |ref infcx, key, _| {
356 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
357 type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
359 try_extract_error_from_fulfill_cx(
370 impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
375 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
376 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
377 // and is only the fallback when the nice error fails. Consider improving this some more.
378 tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
381 fn base_universe(&self) -> ty::UniverseIndex {
382 self.base_universe.unwrap()
387 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
388 _cause: ObligationCause<'tcx>,
389 placeholder_region: ty::Region<'tcx>,
390 error_region: Option<ty::Region<'tcx>>,
391 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
392 try_extract_error_from_region_constraints(
396 self.region_constraints.as_ref().unwrap(),
397 // We're using the original `InferCtxt` that we
398 // started MIR borrowchecking with, so the region
399 // constraints have already been taken. Use the data from
400 // our `mbcx` instead.
401 |vid| mbcx.regioncx.var_infos[vid].origin,
402 |vid| mbcx.regioncx.var_infos[vid].universe,
407 #[instrument(skip(fulfill_cx, infcx), level = "debug")]
408 fn try_extract_error_from_fulfill_cx<'tcx>(
409 mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
410 infcx: &InferCtxt<'_, 'tcx>,
411 placeholder_region: ty::Region<'tcx>,
412 error_region: Option<ty::Region<'tcx>>,
413 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
414 // We generally shouldn't have errors here because the query was
415 // already run, but there's no point using `delay_span_bug`
416 // when we're going to emit an error here anyway.
417 let _errors = fulfill_cx.select_all_or_error(infcx);
418 let region_constraints = infcx.with_region_constraints(|r| r.clone());
419 try_extract_error_from_region_constraints(
424 |vid| infcx.region_var_origin(vid),
425 |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
429 fn try_extract_error_from_region_constraints<'tcx>(
430 infcx: &InferCtxt<'_, 'tcx>,
431 placeholder_region: ty::Region<'tcx>,
432 error_region: Option<ty::Region<'tcx>>,
433 region_constraints: &RegionConstraintData<'tcx>,
434 mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
435 mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
436 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
437 let (sub_region, cause) =
438 region_constraints.constraints.iter().find_map(|(constraint, cause)| {
440 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
441 Some((sub, cause.clone()))
443 // FIXME: Should this check the universe of the var?
444 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
445 Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
451 debug!(?sub_region, "cause = {:#?}", cause);
452 let nice_error = match (error_region, *sub_region) {
453 (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
455 RegionResolutionError::SubSupConflict(
457 region_var_origin(vid),
465 (Some(error_region), _) => NiceRegionError::new(
467 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
469 // Note universe here is wrong...
470 (None, ty::ReVar(vid)) => NiceRegionError::new(
472 RegionResolutionError::UpperBoundUniverseConflict(
474 region_var_origin(vid),
475 universe_of_region(vid),
480 (None, _) => NiceRegionError::new(
482 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
485 nice_error.try_report_from_nll().or_else(|| {
486 if let SubregionOrigin::Subtype(trace) = cause {
487 Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch))