1 use rustc_errors::DiagnosticBuilder;
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 err.buffer(&mut mbcx.errors_buffer);
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
74 .struct_span_err(cause.span, "higher-ranked subtype error")
75 .buffer(&mut mbcx.errors_buffer);
81 crate trait ToUniverseInfo<'tcx> {
82 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
85 impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
86 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
87 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
88 base_universe: Some(base_universe),
94 impl<'tcx> ToUniverseInfo<'tcx>
95 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
97 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
98 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
99 canonical_query: self,
105 impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
106 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
108 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
109 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
110 canonical_query: self,
116 impl<'tcx> ToUniverseInfo<'tcx>
117 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
119 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
120 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
121 canonical_query: self,
127 impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
128 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
129 // We can't rerun custom type ops.
130 UniverseInfo::other()
134 impl<'tcx> ToUniverseInfo<'tcx> for ! {
135 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
140 #[allow(unused_lifetimes)]
141 trait TypeOpInfo<'tcx> {
142 /// Returns an error to be reported if rerunning the type op fails to
143 /// recover the error's cause.
144 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
146 fn base_universe(&self) -> ty::UniverseIndex;
150 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
151 cause: ObligationCause<'tcx>,
152 placeholder_region: ty::Region<'tcx>,
153 error_region: Option<ty::Region<'tcx>>,
154 ) -> Option<DiagnosticBuilder<'tcx>>;
158 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
159 placeholder: ty::PlaceholderRegion,
160 error_element: RegionElement,
161 cause: ObligationCause<'tcx>,
163 let tcx = mbcx.infcx.tcx;
164 let base_universe = self.base_universe();
166 let adjusted_universe = if let Some(adjusted) =
167 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
171 self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer);
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 nice_error.buffer(&mut mbcx.errors_buffer);
202 self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
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> {
214 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
215 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
216 err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
220 fn base_universe(&self) -> ty::UniverseIndex {
226 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
227 cause: ObligationCause<'tcx>,
228 placeholder_region: ty::Region<'tcx>,
229 error_region: Option<ty::Region<'tcx>>,
230 ) -> Option<DiagnosticBuilder<'tcx>> {
231 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
233 &self.canonical_query,
234 |ref infcx, key, _| {
235 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
236 type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
237 try_extract_error_from_fulfill_cx(
248 struct NormalizeQuery<'tcx, T> {
249 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
250 base_universe: ty::UniverseIndex,
253 impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
255 T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
257 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
258 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
259 err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
263 fn base_universe(&self) -> ty::UniverseIndex {
269 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
270 cause: ObligationCause<'tcx>,
271 placeholder_region: ty::Region<'tcx>,
272 error_region: Option<ty::Region<'tcx>>,
273 ) -> Option<DiagnosticBuilder<'tcx>> {
274 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
276 &self.canonical_query,
277 |ref infcx, key, _| {
278 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
280 let mut selcx = SelectionContext::new(infcx);
282 // FIXME(lqd): Unify and de-duplicate the following with the actual
283 // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
284 // `ObligationCause`. The normalization results are currently different between
285 // `AtExt::normalize` used in the query and `normalize` called below: the former fails
286 // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
287 // after #85499 lands to see if its fixes have erased this difference.
288 let (param_env, value) = key.into_parts();
289 let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
295 fulfill_cx.register_predicate_obligations(infcx, obligations);
297 try_extract_error_from_fulfill_cx(
308 struct AscribeUserTypeQuery<'tcx> {
309 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
310 base_universe: ty::UniverseIndex,
313 impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
314 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
315 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
316 // and is only the fallback when the nice error fails. Consider improving this some more.
317 tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
320 fn base_universe(&self) -> ty::UniverseIndex {
326 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
327 cause: ObligationCause<'tcx>,
328 placeholder_region: ty::Region<'tcx>,
329 error_region: Option<ty::Region<'tcx>>,
330 ) -> Option<DiagnosticBuilder<'tcx>> {
331 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
333 &self.canonical_query,
334 |ref infcx, key, _| {
335 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
336 type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
338 try_extract_error_from_fulfill_cx(
349 impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
350 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
351 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
352 // and is only the fallback when the nice error fails. Consider improving this some more.
353 tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!")
356 fn base_universe(&self) -> ty::UniverseIndex {
357 self.base_universe.unwrap()
362 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
363 _cause: ObligationCause<'tcx>,
364 placeholder_region: ty::Region<'tcx>,
365 error_region: Option<ty::Region<'tcx>>,
366 ) -> Option<DiagnosticBuilder<'tcx>> {
367 try_extract_error_from_region_constraints(
371 self.region_constraints.as_ref().unwrap(),
372 // We're using the original `InferCtxt` that we
373 // started MIR borrowchecking with, so the region
374 // constraints have already been taken. Use the data from
375 // our `mbcx` instead.
376 |vid| mbcx.regioncx.var_infos[vid].origin,
377 |vid| mbcx.regioncx.var_infos[vid].universe,
382 #[instrument(skip(fulfill_cx, infcx), level = "debug")]
383 fn try_extract_error_from_fulfill_cx<'tcx>(
384 mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
385 infcx: &InferCtxt<'_, 'tcx>,
386 placeholder_region: ty::Region<'tcx>,
387 error_region: Option<ty::Region<'tcx>>,
388 ) -> Option<DiagnosticBuilder<'tcx>> {
389 // We generally shouldn't have errors here because the query was
390 // already run, but there's no point using `delay_span_bug`
391 // when we're going to emit an error here anyway.
392 let _errors = fulfill_cx.select_all_or_error(infcx);
393 let region_constraints = infcx.with_region_constraints(|r| r.clone());
394 try_extract_error_from_region_constraints(
399 |vid| infcx.region_var_origin(vid),
400 |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
404 fn try_extract_error_from_region_constraints<'tcx>(
405 infcx: &InferCtxt<'_, 'tcx>,
406 placeholder_region: ty::Region<'tcx>,
407 error_region: Option<ty::Region<'tcx>>,
408 region_constraints: &RegionConstraintData<'tcx>,
409 mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
410 mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
411 ) -> Option<DiagnosticBuilder<'tcx>> {
412 let (sub_region, cause) =
413 region_constraints.constraints.iter().find_map(|(constraint, cause)| {
415 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
416 Some((sub, cause.clone()))
418 // FIXME: Should this check the universe of the var?
419 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
420 Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
426 debug!(?sub_region, "cause = {:#?}", cause);
427 let nice_error = match (error_region, sub_region) {
428 (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
430 RegionResolutionError::SubSupConflict(
432 region_var_origin(vid),
440 (Some(error_region), _) => NiceRegionError::new(
442 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
444 // Note universe here is wrong...
445 (None, &ty::ReVar(vid)) => NiceRegionError::new(
447 RegionResolutionError::UpperBoundUniverseConflict(
449 region_var_origin(vid),
450 universe_of_region(vid),
455 (None, _) => NiceRegionError::new(
457 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
460 nice_error.try_report_from_nll().or_else(|| {
461 if let SubregionOrigin::Subtype(trace) = cause {
463 infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),