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 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 err.buffer(&mut mbcx.errors_buffer);
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
70 .struct_span_err(cause.span, "higher-ranked subtype error")
71 .buffer(&mut mbcx.errors_buffer);
77 crate trait ToUniverseInfo<'tcx> {
78 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
81 impl<'tcx> ToUniverseInfo<'tcx>
82 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
84 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
85 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
86 canonical_query: self,
92 impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
93 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
95 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
96 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
97 canonical_query: self,
103 impl<'tcx> ToUniverseInfo<'tcx>
104 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
106 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
107 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
108 canonical_query: self,
114 impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
115 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
116 // We can't rerun custom type ops.
117 UniverseInfo::other()
121 #[allow(unused_lifetimes)]
122 trait TypeOpInfo<'tcx> {
123 /// Returns an error to be reported if rerunning the type op fails to
124 /// recover the error's cause.
125 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
127 fn base_universe(&self) -> ty::UniverseIndex;
132 cause: ObligationCause<'tcx>,
133 placeholder_region: ty::Region<'tcx>,
134 error_region: Option<ty::Region<'tcx>>,
135 ) -> Option<DiagnosticBuilder<'tcx>>;
139 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
140 placeholder: ty::PlaceholderRegion,
141 error_element: RegionElement,
142 cause: ObligationCause<'tcx>,
144 let tcx = mbcx.infcx.tcx;
145 let base_universe = self.base_universe();
147 let adjusted_universe = if let Some(adjusted) =
148 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
152 self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer);
156 let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
157 name: placeholder.name,
158 universe: adjusted_universe.into(),
162 if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
163 let adjusted_universe =
164 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
165 adjusted_universe.map(|adjusted| {
166 tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
167 name: error_placeholder.name,
168 universe: adjusted.into(),
175 debug!(?placeholder_region);
177 let span = cause.span;
178 let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
180 if let Some(nice_error) = nice_error {
181 nice_error.buffer(&mut mbcx.errors_buffer);
183 self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
188 struct PredicateQuery<'tcx> {
190 Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
191 base_universe: ty::UniverseIndex,
194 impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
195 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
196 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
197 err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
201 fn base_universe(&self) -> ty::UniverseIndex {
208 cause: ObligationCause<'tcx>,
209 placeholder_region: ty::Region<'tcx>,
210 error_region: Option<ty::Region<'tcx>>,
211 ) -> Option<DiagnosticBuilder<'tcx>> {
212 tcx.infer_ctxt().enter_with_canonical(
214 &self.canonical_query,
215 |ref infcx, key, _| {
216 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
217 type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
218 try_extract_error_from_fulfill_cx(
229 struct NormalizeQuery<'tcx, T> {
230 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
231 base_universe: ty::UniverseIndex,
234 impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
236 T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
238 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
239 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
240 err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
244 fn base_universe(&self) -> ty::UniverseIndex {
251 cause: ObligationCause<'tcx>,
252 placeholder_region: ty::Region<'tcx>,
253 error_region: Option<ty::Region<'tcx>>,
254 ) -> Option<DiagnosticBuilder<'tcx>> {
255 tcx.infer_ctxt().enter_with_canonical(
257 &self.canonical_query,
258 |ref infcx, key, _| {
259 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
261 let mut selcx = SelectionContext::new(infcx);
263 // FIXME(lqd): Unify and de-duplicate the following with the actual
264 // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
265 // `ObligationCause`. The normalization results are currently different between
266 // `AtExt::normalize` used in the query and `normalize` called below: the former fails
267 // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
268 // after #85499 lands to see if its fixes have erased this difference.
269 let (param_env, value) = key.into_parts();
270 let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
276 fulfill_cx.register_predicate_obligations(infcx, obligations);
278 try_extract_error_from_fulfill_cx(
289 struct AscribeUserTypeQuery<'tcx> {
290 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
291 base_universe: ty::UniverseIndex,
294 impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
295 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
296 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
297 // and is only the fallback when the nice error fails. Consider improving this some more.
298 tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
301 fn base_universe(&self) -> ty::UniverseIndex {
308 cause: ObligationCause<'tcx>,
309 placeholder_region: ty::Region<'tcx>,
310 error_region: Option<ty::Region<'tcx>>,
311 ) -> Option<DiagnosticBuilder<'tcx>> {
312 tcx.infer_ctxt().enter_with_canonical(
314 &self.canonical_query,
315 |ref infcx, key, _| {
316 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
317 type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
319 try_extract_error_from_fulfill_cx(
330 #[instrument(skip(fulfill_cx, infcx), level = "debug")]
331 fn try_extract_error_from_fulfill_cx<'tcx>(
332 mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
333 infcx: &InferCtxt<'_, 'tcx>,
334 placeholder_region: ty::Region<'tcx>,
335 error_region: Option<ty::Region<'tcx>>,
336 ) -> Option<DiagnosticBuilder<'tcx>> {
339 // We generally shouldn't have errors here because the query was
340 // already run, but there's no point using `delay_span_bug`
341 // when we're going to emit an error here anyway.
342 let _errors = fulfill_cx.select_all_or_error(infcx);
344 let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
345 debug!("{:#?}", region_constraints);
346 region_constraints.constraints.iter().find_map(|(constraint, cause)| {
348 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
349 Some((sub, cause.clone()))
351 // FIXME: Should this check the universe of the var?
352 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
353 Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
360 debug!(?sub_region, "cause = {:#?}", cause);
361 let nice_error = match (error_region, sub_region) {
362 (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
364 RegionResolutionError::SubSupConflict(
366 infcx.region_var_origin(vid),
373 (Some(error_region), _) => NiceRegionError::new(
375 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
377 // Note universe here is wrong...
378 (None, &ty::ReVar(vid)) => NiceRegionError::new(
380 RegionResolutionError::UpperBoundUniverseConflict(
382 infcx.region_var_origin(vid),
383 infcx.universe_of_region(sub_region),
388 (None, _) => NiceRegionError::new(
390 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
393 nice_error.try_report_from_nll().or_else(|| {
394 if let SubregionOrigin::Subtype(trace) = cause {
396 infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),