1 #![deny(rustc::untranslatable_diagnostic)]
2 #![deny(rustc::diagnostic_outside_of_impl)]
4 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
5 use rustc_infer::infer::canonical::Canonical;
6 use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
7 use rustc_infer::infer::region_constraints::Constraint;
8 use rustc_infer::infer::region_constraints::RegionConstraintData;
9 use rustc_infer::infer::RegionVariableOrigin;
10 use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
11 use rustc_infer::traits::ObligationCause;
12 use rustc_middle::ty::error::TypeError;
13 use rustc_middle::ty::RegionVid;
14 use rustc_middle::ty::UniverseIndex;
15 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
17 use rustc_trait_selection::traits::query::type_op;
18 use rustc_trait_selection::traits::ObligationCtxt;
19 use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
24 use crate::region_infer::values::RegionElement;
25 use crate::session_diagnostics::HigherRankedErrorCause;
26 use crate::session_diagnostics::HigherRankedLifetimeError;
27 use crate::session_diagnostics::HigherRankedSubtypeError;
28 use crate::MirBorrowckCtxt;
31 pub(crate) struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
33 /// What operation a universe was created for.
35 enum UniverseInfoInner<'tcx> {
36 /// Relating two types which have binders.
37 RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
38 /// Created from performing a `TypeOp`.
39 TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
44 impl<'tcx> UniverseInfo<'tcx> {
45 pub(crate) fn other() -> UniverseInfo<'tcx> {
46 UniverseInfo(UniverseInfoInner::Other)
49 pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
50 UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
53 pub(crate) fn report_error(
55 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
56 placeholder: ty::PlaceholderRegion,
57 error_element: RegionElement,
58 cause: ObligationCause<'tcx>,
61 UniverseInfoInner::RelateTys { expected, found } => {
62 let err = mbcx.infcx.err_ctxt().report_mismatched_types(
66 TypeError::RegionsPlaceholderMismatch,
68 mbcx.buffer_error(err);
70 UniverseInfoInner::TypeOp(ref type_op_info) => {
71 type_op_info.report_error(mbcx, placeholder, error_element, cause);
73 UniverseInfoInner::Other => {
74 // FIXME: This error message isn't great, but it doesn't show
75 // up in the existing UI tests. Consider investigating this
78 mbcx.infcx.tcx.sess.create_err(HigherRankedSubtypeError { span: cause.span }),
85 pub(crate) trait ToUniverseInfo<'tcx> {
86 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
89 impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
90 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
91 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
92 base_universe: Some(base_universe),
98 impl<'tcx> ToUniverseInfo<'tcx>
99 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
101 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
102 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
103 canonical_query: self,
109 impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
110 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
112 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
113 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
114 canonical_query: self,
120 impl<'tcx> ToUniverseInfo<'tcx>
121 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
123 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
124 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
125 canonical_query: self,
131 impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
132 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
133 // We can't rerun custom type ops.
134 UniverseInfo::other()
138 impl<'tcx> ToUniverseInfo<'tcx> for ! {
139 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
144 #[allow(unused_lifetimes)]
145 trait TypeOpInfo<'tcx> {
146 /// Returns an error to be reported if rerunning the type op fails to
147 /// recover the error's cause.
152 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
154 fn base_universe(&self) -> ty::UniverseIndex;
158 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
159 cause: ObligationCause<'tcx>,
160 placeholder_region: ty::Region<'tcx>,
161 error_region: Option<ty::Region<'tcx>>,
162 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
164 #[instrument(level = "debug", skip(self, mbcx))]
167 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
168 placeholder: ty::PlaceholderRegion,
169 error_element: RegionElement,
170 cause: ObligationCause<'tcx>,
172 let tcx = mbcx.infcx.tcx;
173 let base_universe = self.base_universe();
174 debug!(?base_universe);
176 let Some(adjusted_universe) =
177 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
179 mbcx.buffer_error(self.fallback_error(tcx, cause.span));
183 let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
184 name: placeholder.name,
185 universe: adjusted_universe.into(),
189 if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
190 let adjusted_universe =
191 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
192 adjusted_universe.map(|adjusted| {
193 tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
194 name: error_placeholder.name,
195 universe: adjusted.into(),
202 debug!(?placeholder_region);
204 let span = cause.span;
205 let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
207 if let Some(nice_error) = nice_error {
208 mbcx.buffer_error(nice_error);
210 mbcx.buffer_error(self.fallback_error(tcx, span));
215 struct PredicateQuery<'tcx> {
217 Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
218 base_universe: ty::UniverseIndex,
221 impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
226 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
227 tcx.sess.create_err(HigherRankedLifetimeError {
228 cause: Some(HigherRankedErrorCause::CouldNotProve {
229 predicate: self.canonical_query.value.value.predicate.to_string(),
235 fn base_universe(&self) -> ty::UniverseIndex {
241 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
242 cause: ObligationCause<'tcx>,
243 placeholder_region: ty::Region<'tcx>,
244 error_region: Option<ty::Region<'tcx>>,
245 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
246 let (infcx, key, _) =
247 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
248 let ocx = ObligationCtxt::new(&infcx);
249 type_op_prove_predicate_with_cause(&ocx, key, cause);
250 try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
254 struct NormalizeQuery<'tcx, T> {
255 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
256 base_universe: ty::UniverseIndex,
259 impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
261 T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
267 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
268 tcx.sess.create_err(HigherRankedLifetimeError {
269 cause: Some(HigherRankedErrorCause::CouldNotNormalize {
270 value: self.canonical_query.value.value.value.to_string(),
276 fn base_universe(&self) -> ty::UniverseIndex {
282 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
283 cause: ObligationCause<'tcx>,
284 placeholder_region: ty::Region<'tcx>,
285 error_region: Option<ty::Region<'tcx>>,
286 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
287 let (infcx, key, _) =
288 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
289 let ocx = ObligationCtxt::new(&infcx);
291 // FIXME(lqd): Unify and de-duplicate the following with the actual
292 // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
293 // `ObligationCause`. The normalization results are currently different between
294 // `QueryNormalizeExt::query_normalize` used in the query and `normalize` called below:
295 // the former fails to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test.
296 // Check after #85499 lands to see if its fixes have erased this difference.
297 let (param_env, value) = key.into_parts();
298 let _ = ocx.normalize(&cause, param_env, value.value);
300 try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
304 struct AscribeUserTypeQuery<'tcx> {
305 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
306 base_universe: ty::UniverseIndex,
309 impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
314 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
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.create_err(HigherRankedLifetimeError { cause: None, span })
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, ErrorGuaranteed>> {
331 let (infcx, key, _) =
332 mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
333 let ocx = ObligationCtxt::new(&infcx);
334 type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
335 try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
339 impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
344 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
345 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
346 // and is only the fallback when the nice error fails. Consider improving this some more.
347 tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
350 fn base_universe(&self) -> ty::UniverseIndex {
351 self.base_universe.unwrap()
356 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
357 _cause: ObligationCause<'tcx>,
358 placeholder_region: ty::Region<'tcx>,
359 error_region: Option<ty::Region<'tcx>>,
360 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
361 try_extract_error_from_region_constraints(
365 self.region_constraints.as_ref().unwrap(),
366 // We're using the original `InferCtxt` that we
367 // started MIR borrowchecking with, so the region
368 // constraints have already been taken. Use the data from
369 // our `mbcx` instead.
370 |vid| mbcx.regioncx.var_infos[vid].origin,
371 |vid| mbcx.regioncx.var_infos[vid].universe,
376 #[instrument(skip(ocx), level = "debug")]
377 fn try_extract_error_from_fulfill_cx<'tcx>(
378 ocx: &ObligationCtxt<'_, 'tcx>,
379 placeholder_region: ty::Region<'tcx>,
380 error_region: Option<ty::Region<'tcx>>,
381 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
382 // We generally shouldn't have errors here because the query was
383 // already run, but there's no point using `delay_span_bug`
384 // when we're going to emit an error here anyway.
385 let _errors = ocx.select_all_or_error();
386 let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone());
387 try_extract_error_from_region_constraints(
392 |vid| ocx.infcx.region_var_origin(vid),
393 |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_region(ty::ReVar(vid))),
397 #[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
398 fn try_extract_error_from_region_constraints<'tcx>(
399 infcx: &InferCtxt<'tcx>,
400 placeholder_region: ty::Region<'tcx>,
401 error_region: Option<ty::Region<'tcx>>,
402 region_constraints: &RegionConstraintData<'tcx>,
403 mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
404 mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
405 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
406 let (sub_region, cause) =
407 region_constraints.constraints.iter().find_map(|(constraint, cause)| {
409 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
410 Some((sub, cause.clone()))
412 // FIXME: Should this check the universe of the var?
413 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
414 Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
420 debug!(?sub_region, "cause = {:#?}", cause);
421 let error = match (error_region, *sub_region) {
422 (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict(
424 region_var_origin(vid),
431 (Some(error_region), _) => {
432 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region)
434 // Note universe here is wrong...
435 (None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict(
437 region_var_origin(vid),
438 universe_of_region(vid),
443 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
446 NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| {
447 if let SubregionOrigin::Subtype(trace) = cause {
451 .report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch),