]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
Auto merge of #105657 - oli-obk:mk_projection_ty, r=lcnr
[rust.git] / compiler / rustc_borrowck / src / diagnostics / bound_region_errors.rs
1 #![deny(rustc::untranslatable_diagnostic)]
2 #![deny(rustc::diagnostic_outside_of_impl)]
3
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};
16 use rustc_span::Span;
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};
20
21 use std::fmt;
22 use std::rc::Rc;
23
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;
29
30 #[derive(Clone)]
31 pub(crate) struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
32
33 /// What operation a universe was created for.
34 #[derive(Clone)]
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>),
40     /// Any other reason.
41     Other,
42 }
43
44 impl<'tcx> UniverseInfo<'tcx> {
45     pub(crate) fn other() -> UniverseInfo<'tcx> {
46         UniverseInfo(UniverseInfoInner::Other)
47     }
48
49     pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
50         UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
51     }
52
53     pub(crate) fn report_error(
54         &self,
55         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
56         placeholder: ty::PlaceholderRegion,
57         error_element: RegionElement,
58         cause: ObligationCause<'tcx>,
59     ) {
60         match self.0 {
61             UniverseInfoInner::RelateTys { expected, found } => {
62                 let err = mbcx.infcx.err_ctxt().report_mismatched_types(
63                     &cause,
64                     expected,
65                     found,
66                     TypeError::RegionsPlaceholderMismatch,
67                 );
68                 mbcx.buffer_error(err);
69             }
70             UniverseInfoInner::TypeOp(ref type_op_info) => {
71                 type_op_info.report_error(mbcx, placeholder, error_element, cause);
72             }
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
76                 // some more.
77                 mbcx.buffer_error(
78                     mbcx.infcx.tcx.sess.create_err(HigherRankedSubtypeError { span: cause.span }),
79                 );
80             }
81         }
82     }
83 }
84
85 pub(crate) trait ToUniverseInfo<'tcx> {
86     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
87 }
88
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),
93             ..self
94         })))
95     }
96 }
97
98 impl<'tcx> ToUniverseInfo<'tcx>
99     for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
100 {
101     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
102         UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
103             canonical_query: self,
104             base_universe,
105         })))
106     }
107 }
108
109 impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
110     for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
111 {
112     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
113         UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
114             canonical_query: self,
115             base_universe,
116         })))
117     }
118 }
119
120 impl<'tcx> ToUniverseInfo<'tcx>
121     for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
122 {
123     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
124         UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
125             canonical_query: self,
126             base_universe,
127         })))
128     }
129 }
130
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()
135     }
136 }
137
138 impl<'tcx> ToUniverseInfo<'tcx> for ! {
139     fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
140         self
141     }
142 }
143
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.
148     fn fallback_error(
149         &self,
150         tcx: TyCtxt<'tcx>,
151         span: Span,
152     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
153
154     fn base_universe(&self) -> ty::UniverseIndex;
155
156     fn nice_error(
157         &self,
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>>;
163
164     #[instrument(level = "debug", skip(self, mbcx))]
165     fn report_error(
166         &self,
167         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
168         placeholder: ty::PlaceholderRegion,
169         error_element: RegionElement,
170         cause: ObligationCause<'tcx>,
171     ) {
172         let tcx = mbcx.infcx.tcx;
173         let base_universe = self.base_universe();
174         debug!(?base_universe);
175
176         let Some(adjusted_universe) =
177             placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
178         else {
179             mbcx.buffer_error(self.fallback_error(tcx, cause.span));
180             return;
181         };
182
183         let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
184             name: placeholder.name,
185             universe: adjusted_universe.into(),
186         }));
187
188         let error_region =
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(),
196                     }))
197                 })
198             } else {
199                 None
200             };
201
202         debug!(?placeholder_region);
203
204         let span = cause.span;
205         let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
206
207         if let Some(nice_error) = nice_error {
208             mbcx.buffer_error(nice_error);
209         } else {
210             mbcx.buffer_error(self.fallback_error(tcx, span));
211         }
212     }
213 }
214
215 struct PredicateQuery<'tcx> {
216     canonical_query:
217         Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
218     base_universe: ty::UniverseIndex,
219 }
220
221 impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
222     fn fallback_error(
223         &self,
224         tcx: TyCtxt<'tcx>,
225         span: Span,
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(),
230             }),
231             span,
232         })
233     }
234
235     fn base_universe(&self) -> ty::UniverseIndex {
236         self.base_universe
237     }
238
239     fn nice_error(
240         &self,
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)
251     }
252 }
253
254 struct NormalizeQuery<'tcx, T> {
255     canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
256     base_universe: ty::UniverseIndex,
257 }
258
259 impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
260 where
261     T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
262 {
263     fn fallback_error(
264         &self,
265         tcx: TyCtxt<'tcx>,
266         span: Span,
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(),
271             }),
272             span,
273         })
274     }
275
276     fn base_universe(&self) -> ty::UniverseIndex {
277         self.base_universe
278     }
279
280     fn nice_error(
281         &self,
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);
290
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);
299
300         try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
301     }
302 }
303
304 struct AscribeUserTypeQuery<'tcx> {
305     canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
306     base_universe: ty::UniverseIndex,
307 }
308
309 impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
310     fn fallback_error(
311         &self,
312         tcx: TyCtxt<'tcx>,
313         span: Span,
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 })
318     }
319
320     fn base_universe(&self) -> ty::UniverseIndex {
321         self.base_universe
322     }
323
324     fn nice_error(
325         &self,
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)
336     }
337 }
338
339 impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
340     fn fallback_error(
341         &self,
342         tcx: TyCtxt<'tcx>,
343         span: Span,
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 })
348     }
349
350     fn base_universe(&self) -> ty::UniverseIndex {
351         self.base_universe.unwrap()
352     }
353
354     fn nice_error(
355         &self,
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(
362             mbcx.infcx,
363             placeholder_region,
364             error_region,
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,
372         )
373     }
374 }
375
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(
388         ocx.infcx,
389         placeholder_region,
390         error_region,
391         &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))),
394     )
395 }
396
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)| {
408             match *constraint {
409                 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
410                     Some((sub, cause.clone()))
411                 }
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()))
415                 }
416                 _ => None,
417             }
418         })?;
419
420     debug!(?sub_region, "cause = {:#?}", cause);
421     let error = match (error_region, *sub_region) {
422         (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict(
423             vid,
424             region_var_origin(vid),
425             cause.clone(),
426             error_region,
427             cause.clone(),
428             placeholder_region,
429             vec![],
430         ),
431         (Some(error_region), _) => {
432             RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region)
433         }
434         // Note universe here is wrong...
435         (None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict(
436             vid,
437             region_var_origin(vid),
438             universe_of_region(vid),
439             cause.clone(),
440             placeholder_region,
441         ),
442         (None, _) => {
443             RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
444         }
445     };
446     NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| {
447         if let SubregionOrigin::Subtype(trace) = cause {
448             Some(
449                 infcx
450                     .err_ctxt()
451                     .report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch),
452             )
453         } else {
454             None
455         }
456     })
457 }