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 Some(adjusted_universe) =
146 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
148 mbcx.buffer_error(self.fallback_error(tcx, cause.span));
152 let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
153 name: placeholder.name,
154 universe: adjusted_universe.into(),
158 if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
159 let adjusted_universe =
160 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
161 adjusted_universe.map(|adjusted| {
162 tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
163 name: error_placeholder.name,
164 universe: adjusted.into(),
171 debug!(?placeholder_region);
173 let span = cause.span;
174 let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
176 if let Some(nice_error) = nice_error {
177 mbcx.buffer_error(nice_error);
179 mbcx.buffer_error(self.fallback_error(tcx, span));
184 struct PredicateQuery<'tcx> {
186 Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
187 base_universe: ty::UniverseIndex,
190 impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
191 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
192 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
193 err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
197 fn base_universe(&self) -> ty::UniverseIndex {
204 cause: ObligationCause<'tcx>,
205 placeholder_region: ty::Region<'tcx>,
206 error_region: Option<ty::Region<'tcx>>,
207 ) -> Option<DiagnosticBuilder<'tcx>> {
208 tcx.infer_ctxt().enter_with_canonical(
210 &self.canonical_query,
211 |ref infcx, key, _| {
212 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
213 type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
214 try_extract_error_from_fulfill_cx(
225 struct NormalizeQuery<'tcx, T> {
226 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
227 base_universe: ty::UniverseIndex,
230 impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
232 T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
234 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
235 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
236 err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
240 fn base_universe(&self) -> ty::UniverseIndex {
247 cause: ObligationCause<'tcx>,
248 placeholder_region: ty::Region<'tcx>,
249 error_region: Option<ty::Region<'tcx>>,
250 ) -> Option<DiagnosticBuilder<'tcx>> {
251 tcx.infer_ctxt().enter_with_canonical(
253 &self.canonical_query,
254 |ref infcx, key, _| {
255 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
257 let mut selcx = SelectionContext::new(infcx);
259 // FIXME(lqd): Unify and de-duplicate the following with the actual
260 // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
261 // `ObligationCause`. The normalization results are currently different between
262 // `AtExt::normalize` used in the query and `normalize` called below: the former fails
263 // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
264 // after #85499 lands to see if its fixes have erased this difference.
265 let (param_env, value) = key.into_parts();
266 let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
272 fulfill_cx.register_predicate_obligations(infcx, obligations);
274 try_extract_error_from_fulfill_cx(
285 struct AscribeUserTypeQuery<'tcx> {
286 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
287 base_universe: ty::UniverseIndex,
290 impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
291 fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
292 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
293 // and is only the fallback when the nice error fails. Consider improving this some more.
294 tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
297 fn base_universe(&self) -> ty::UniverseIndex {
304 cause: ObligationCause<'tcx>,
305 placeholder_region: ty::Region<'tcx>,
306 error_region: Option<ty::Region<'tcx>>,
307 ) -> Option<DiagnosticBuilder<'tcx>> {
308 tcx.infer_ctxt().enter_with_canonical(
310 &self.canonical_query,
311 |ref infcx, key, _| {
312 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
313 type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
315 try_extract_error_from_fulfill_cx(
326 #[instrument(skip(fulfill_cx, infcx), level = "debug")]
327 fn try_extract_error_from_fulfill_cx<'tcx>(
328 mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
329 infcx: &InferCtxt<'_, 'tcx>,
330 placeholder_region: ty::Region<'tcx>,
331 error_region: Option<ty::Region<'tcx>>,
332 ) -> Option<DiagnosticBuilder<'tcx>> {
335 // We generally shouldn't have errors here because the query was
336 // already run, but there's no point using `delay_span_bug`
337 // when we're going to emit an error here anyway.
338 let _errors = fulfill_cx.select_all_or_error(infcx);
340 let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
341 debug!("{:#?}", region_constraints);
342 region_constraints.constraints.iter().find_map(|(constraint, cause)| {
344 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
345 Some((sub, cause.clone()))
347 // FIXME: Should this check the universe of the var?
348 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
349 Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
356 debug!(?sub_region, "cause = {:#?}", cause);
357 let nice_error = match (error_region, *sub_region) {
358 (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
360 RegionResolutionError::SubSupConflict(
362 infcx.region_var_origin(vid),
370 (Some(error_region), _) => NiceRegionError::new(
372 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
374 // Note universe here is wrong...
375 (None, ty::ReVar(vid)) => NiceRegionError::new(
377 RegionResolutionError::UpperBoundUniverseConflict(
379 infcx.region_var_origin(vid),
380 infcx.universe_of_region(sub_region),
385 (None, _) => NiceRegionError::new(
387 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
390 nice_error.try_report_from_nll().or_else(|| {
391 if let SubregionOrigin::Subtype(trace) = cause {
393 infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),