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::MirBorrowckCtxt;
25 crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
27 /// What operation a universe was created for.
29 enum UniverseInfoInner<'tcx> {
30 /// Relating two types which have binders.
31 RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
32 /// Created from performing a `TypeOp`.
33 TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
38 impl<'tcx> UniverseInfo<'tcx> {
39 crate fn other() -> UniverseInfo<'tcx> {
40 UniverseInfo(UniverseInfoInner::Other)
43 crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
44 UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
47 crate fn report_error(
49 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
50 placeholder: ty::PlaceholderRegion,
51 error_element: RegionElement,
52 cause: ObligationCause<'tcx>,
55 UniverseInfoInner::RelateTys { expected, found } => {
56 let err = mbcx.infcx.report_mismatched_types(
60 TypeError::RegionsPlaceholderMismatch,
62 mbcx.buffer_error(err);
64 UniverseInfoInner::TypeOp(ref type_op_info) => {
65 type_op_info.report_error(mbcx, placeholder, error_element, cause);
67 UniverseInfoInner::Other => {
68 // FIXME: This error message isn't great, but it doesn't show
69 // up in the existing UI tests. Consider investigating this
72 mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"),
79 crate trait ToUniverseInfo<'tcx> {
80 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
83 impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
84 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
85 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
86 base_universe: Some(base_universe),
92 impl<'tcx> ToUniverseInfo<'tcx>
93 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
95 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
96 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
97 canonical_query: self,
103 impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
104 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
106 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
107 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
108 canonical_query: self,
114 impl<'tcx> ToUniverseInfo<'tcx>
115 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
117 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
118 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
119 canonical_query: self,
125 impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
126 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
127 // We can't rerun custom type ops.
128 UniverseInfo::other()
132 impl<'tcx> ToUniverseInfo<'tcx> for ! {
133 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
138 #[allow(unused_lifetimes)]
139 trait TypeOpInfo<'tcx> {
140 /// Returns an error to be reported if rerunning the type op fails to
141 /// recover the error's cause.
146 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
148 fn base_universe(&self) -> ty::UniverseIndex;
152 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
153 cause: ObligationCause<'tcx>,
154 placeholder_region: ty::Region<'tcx>,
155 error_region: Option<ty::Region<'tcx>>,
156 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
160 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
161 placeholder: ty::PlaceholderRegion,
162 error_element: RegionElement,
163 cause: ObligationCause<'tcx>,
165 let tcx = mbcx.infcx.tcx;
166 let base_universe = self.base_universe();
168 let Some(adjusted_universe) =
169 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
171 mbcx.buffer_error(self.fallback_error(tcx, cause.span));
175 let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
176 name: placeholder.name,
177 universe: adjusted_universe.into(),
181 if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
182 let adjusted_universe =
183 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
184 adjusted_universe.map(|adjusted| {
185 tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
186 name: error_placeholder.name,
187 universe: adjusted.into(),
194 debug!(?placeholder_region);
196 let span = cause.span;
197 let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
199 if let Some(nice_error) = nice_error {
200 mbcx.buffer_error(nice_error);
202 mbcx.buffer_error(self.fallback_error(tcx, span));
207 struct PredicateQuery<'tcx> {
209 Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
210 base_universe: ty::UniverseIndex,
213 impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
218 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
219 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
220 err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
224 fn base_universe(&self) -> ty::UniverseIndex {
230 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
231 cause: ObligationCause<'tcx>,
232 placeholder_region: ty::Region<'tcx>,
233 error_region: Option<ty::Region<'tcx>>,
234 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
235 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
237 &self.canonical_query,
238 |ref infcx, key, _| {
239 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
240 type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
241 try_extract_error_from_fulfill_cx(
252 struct NormalizeQuery<'tcx, T> {
253 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
254 base_universe: ty::UniverseIndex,
257 impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
259 T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
265 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
266 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
267 err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
271 fn base_universe(&self) -> ty::UniverseIndex {
277 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
278 cause: ObligationCause<'tcx>,
279 placeholder_region: ty::Region<'tcx>,
280 error_region: Option<ty::Region<'tcx>>,
281 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
282 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
284 &self.canonical_query,
285 |ref infcx, key, _| {
286 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
288 let mut selcx = SelectionContext::new(infcx);
290 // FIXME(lqd): Unify and de-duplicate the following with the actual
291 // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
292 // `ObligationCause`. The normalization results are currently different between
293 // `AtExt::normalize` used in the query and `normalize` called below: the former fails
294 // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
295 // after #85499 lands to see if its fixes have erased this difference.
296 let (param_env, value) = key.into_parts();
297 let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
303 fulfill_cx.register_predicate_obligations(infcx, obligations);
305 try_extract_error_from_fulfill_cx(
316 struct AscribeUserTypeQuery<'tcx> {
317 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
318 base_universe: ty::UniverseIndex,
321 impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
326 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
327 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
328 // and is only the fallback when the nice error fails. Consider improving this some more.
329 tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
332 fn base_universe(&self) -> ty::UniverseIndex {
338 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
339 cause: ObligationCause<'tcx>,
340 placeholder_region: ty::Region<'tcx>,
341 error_region: Option<ty::Region<'tcx>>,
342 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
343 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
345 &self.canonical_query,
346 |ref infcx, key, _| {
347 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
348 type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
350 try_extract_error_from_fulfill_cx(
361 impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
366 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
367 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
368 // and is only the fallback when the nice error fails. Consider improving this some more.
369 tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!")
372 fn base_universe(&self) -> ty::UniverseIndex {
373 self.base_universe.unwrap()
378 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
379 _cause: ObligationCause<'tcx>,
380 placeholder_region: ty::Region<'tcx>,
381 error_region: Option<ty::Region<'tcx>>,
382 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
383 try_extract_error_from_region_constraints(
387 self.region_constraints.as_ref().unwrap(),
388 // We're using the original `InferCtxt` that we
389 // started MIR borrowchecking with, so the region
390 // constraints have already been taken. Use the data from
391 // our `mbcx` instead.
392 |vid| mbcx.regioncx.var_infos[vid].origin,
393 |vid| mbcx.regioncx.var_infos[vid].universe,
398 #[instrument(skip(fulfill_cx, infcx), level = "debug")]
399 fn try_extract_error_from_fulfill_cx<'tcx>(
400 mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
401 infcx: &InferCtxt<'_, 'tcx>,
402 placeholder_region: ty::Region<'tcx>,
403 error_region: Option<ty::Region<'tcx>>,
404 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
405 // We generally shouldn't have errors here because the query was
406 // already run, but there's no point using `delay_span_bug`
407 // when we're going to emit an error here anyway.
408 let _errors = fulfill_cx.select_all_or_error(infcx);
409 let region_constraints = infcx.with_region_constraints(|r| r.clone());
410 try_extract_error_from_region_constraints(
415 |vid| infcx.region_var_origin(vid),
416 |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
420 fn try_extract_error_from_region_constraints<'tcx>(
421 infcx: &InferCtxt<'_, 'tcx>,
422 placeholder_region: ty::Region<'tcx>,
423 error_region: Option<ty::Region<'tcx>>,
424 region_constraints: &RegionConstraintData<'tcx>,
425 mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
426 mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
427 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
428 let (sub_region, cause) =
429 region_constraints.constraints.iter().find_map(|(constraint, cause)| {
431 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
432 Some((sub, cause.clone()))
434 // FIXME: Should this check the universe of the var?
435 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
436 Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
442 debug!(?sub_region, "cause = {:#?}", cause);
443 let nice_error = match (error_region, *sub_region) {
444 (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
446 RegionResolutionError::SubSupConflict(
448 region_var_origin(vid),
456 (Some(error_region), _) => NiceRegionError::new(
458 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
460 // Note universe here is wrong...
461 (None, ty::ReVar(vid)) => NiceRegionError::new(
463 RegionResolutionError::UpperBoundUniverseConflict(
465 region_var_origin(vid),
466 universe_of_region(vid),
471 (None, _) => NiceRegionError::new(
473 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
476 nice_error.try_report_from_nll().or_else(|| {
477 if let SubregionOrigin::Subtype(trace) = cause {
479 infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),