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::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
6 use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
7 use rustc_middle::ty::error::TypeError;
8 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
10 use rustc_trait_selection::traits::query::type_op;
11 use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
12 use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
17 use crate::region_infer::values::RegionElement;
18 use crate::MirBorrowckCtxt;
21 crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
23 /// What operation a universe was created for.
25 enum UniverseInfoInner<'tcx> {
26 /// Relating two types which have binders.
27 RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
28 /// Created from performing a `TypeOp`.
29 TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
34 impl<'tcx> UniverseInfo<'tcx> {
35 crate fn other() -> UniverseInfo<'tcx> {
36 UniverseInfo(UniverseInfoInner::Other)
39 crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
40 UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
43 crate fn report_error(
45 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
46 placeholder: ty::PlaceholderRegion,
47 error_element: RegionElement,
48 cause: ObligationCause<'tcx>,
51 UniverseInfoInner::RelateTys { expected, found } => {
52 let err = mbcx.infcx.report_mismatched_types(
56 TypeError::RegionsPlaceholderMismatch,
58 mbcx.buffer_error(err);
60 UniverseInfoInner::TypeOp(ref type_op_info) => {
61 type_op_info.report_error(mbcx, placeholder, error_element, cause);
63 UniverseInfoInner::Other => {
64 // FIXME: This error message isn't great, but it doesn't show
65 // up in the existing UI tests. Consider investigating this
68 mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"),
75 crate trait ToUniverseInfo<'tcx> {
76 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
79 impl<'tcx> ToUniverseInfo<'tcx>
80 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
82 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
83 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
84 canonical_query: self,
90 impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
91 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
93 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
94 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
95 canonical_query: self,
101 impl<'tcx> ToUniverseInfo<'tcx>
102 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
104 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
105 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
106 canonical_query: self,
112 impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
113 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
114 // We can't rerun custom type ops.
115 UniverseInfo::other()
119 #[allow(unused_lifetimes)]
120 trait TypeOpInfo<'tcx> {
121 /// Returns an error to be reported if rerunning the type op fails to
122 /// recover the error's cause.
123 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
125 fn base_universe(&self) -> ty::UniverseIndex;
130 cause: ObligationCause<'tcx>,
131 placeholder_region: ty::Region<'tcx>,
132 error_region: Option<ty::Region<'tcx>>,
133 ) -> Option<DiagnosticBuilder<'tcx>>;
137 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
138 placeholder: ty::PlaceholderRegion,
139 error_element: RegionElement,
140 cause: ObligationCause<'tcx>,
142 let tcx = mbcx.infcx.tcx;
143 let base_universe = self.base_universe();
145 let adjusted_universe = if let Some(adjusted) =
146 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
150 mbcx.buffer_error(self.fallback_error(tcx, cause.span));
154 let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
155 name: placeholder.name,
156 universe: adjusted_universe.into(),
160 if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
161 let adjusted_universe =
162 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
163 adjusted_universe.map(|adjusted| {
164 tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
165 name: error_placeholder.name,
166 universe: adjusted.into(),
173 debug!(?placeholder_region);
175 let span = cause.span;
176 let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
178 if let Some(nice_error) = nice_error {
179 mbcx.buffer_error(nice_error);
181 mbcx.buffer_error(self.fallback_error(tcx, span));
186 struct PredicateQuery<'tcx> {
188 Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
189 base_universe: ty::UniverseIndex,
192 impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
193 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
194 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
195 err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
199 fn base_universe(&self) -> ty::UniverseIndex {
206 cause: ObligationCause<'tcx>,
207 placeholder_region: ty::Region<'tcx>,
208 error_region: Option<ty::Region<'tcx>>,
209 ) -> Option<DiagnosticBuilder<'tcx>> {
210 tcx.infer_ctxt().enter_with_canonical(
212 &self.canonical_query,
213 |ref infcx, key, _| {
214 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
215 type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
216 try_extract_error_from_fulfill_cx(
227 struct NormalizeQuery<'tcx, T> {
228 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
229 base_universe: ty::UniverseIndex,
232 impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
234 T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
236 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
237 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
238 err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
242 fn base_universe(&self) -> ty::UniverseIndex {
249 cause: ObligationCause<'tcx>,
250 placeholder_region: ty::Region<'tcx>,
251 error_region: Option<ty::Region<'tcx>>,
252 ) -> Option<DiagnosticBuilder<'tcx>> {
253 tcx.infer_ctxt().enter_with_canonical(
255 &self.canonical_query,
256 |ref infcx, key, _| {
257 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
259 let mut selcx = SelectionContext::new(infcx);
261 // FIXME(lqd): Unify and de-duplicate the following with the actual
262 // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
263 // `ObligationCause`. The normalization results are currently different between
264 // `AtExt::normalize` used in the query and `normalize` called below: the former fails
265 // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
266 // after #85499 lands to see if its fixes have erased this difference.
267 let (param_env, value) = key.into_parts();
268 let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
274 fulfill_cx.register_predicate_obligations(infcx, obligations);
276 try_extract_error_from_fulfill_cx(
287 struct AscribeUserTypeQuery<'tcx> {
288 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
289 base_universe: ty::UniverseIndex,
292 impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
293 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
294 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
295 // and is only the fallback when the nice error fails. Consider improving this some more.
296 tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
299 fn base_universe(&self) -> ty::UniverseIndex {
306 cause: ObligationCause<'tcx>,
307 placeholder_region: ty::Region<'tcx>,
308 error_region: Option<ty::Region<'tcx>>,
309 ) -> Option<DiagnosticBuilder<'tcx>> {
310 tcx.infer_ctxt().enter_with_canonical(
312 &self.canonical_query,
313 |ref infcx, key, _| {
314 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
315 type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
317 try_extract_error_from_fulfill_cx(
328 #[instrument(skip(fulfill_cx, infcx), level = "debug")]
329 fn try_extract_error_from_fulfill_cx<'tcx>(
330 mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
331 infcx: &InferCtxt<'_, 'tcx>,
332 placeholder_region: ty::Region<'tcx>,
333 error_region: Option<ty::Region<'tcx>>,
334 ) -> Option<DiagnosticBuilder<'tcx>> {
337 // We generally shouldn't have errors here because the query was
338 // already run, but there's no point using `delay_span_bug`
339 // when we're going to emit an error here anyway.
340 let _errors = fulfill_cx.select_all_or_error(infcx);
342 let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
343 debug!("{:#?}", region_constraints);
344 region_constraints.constraints.iter().find_map(|(constraint, cause)| {
346 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
347 Some((sub, cause.clone()))
349 // FIXME: Should this check the universe of the var?
350 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
351 Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
358 debug!(?sub_region, "cause = {:#?}", cause);
359 let nice_error = match (error_region, sub_region) {
360 (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
362 RegionResolutionError::SubSupConflict(
364 infcx.region_var_origin(vid),
372 (Some(error_region), _) => NiceRegionError::new(
374 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
376 // Note universe here is wrong...
377 (None, &ty::ReVar(vid)) => NiceRegionError::new(
379 RegionResolutionError::UpperBoundUniverseConflict(
381 infcx.region_var_origin(vid),
382 infcx.universe_of_region(sub_region),
387 (None, _) => NiceRegionError::new(
389 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
392 nice_error.try_report_from_nll().or_else(|| {
393 if let SubregionOrigin::Subtype(trace) = cause {
395 infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),