]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / diagnostics / bound_region_errors.rs
1 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
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::region_constraints::RegionConstraintData;
6 use rustc_infer::infer::RegionVariableOrigin;
7 use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
8 use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
9 use rustc_middle::ty::error::TypeError;
10 use rustc_middle::ty::RegionVid;
11 use rustc_middle::ty::UniverseIndex;
12 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
13 use rustc_span::Span;
14 use rustc_trait_selection::traits::query::type_op;
15 use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
16 use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
17
18 use std::fmt;
19 use std::rc::Rc;
20
21 use crate::region_infer::values::RegionElement;
22 use crate::MirBorrowckCtxt;
23
24 #[derive(Clone)]
25 crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
26
27 /// What operation a universe was created for.
28 #[derive(Clone)]
29 enum UniverseInfoInner<'tcx> {
30 /// Relating two types which have binders.
31 RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
32 /// Created from performing a `TypeOp`.
33 TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
34 /// Any other reason.
35 Other,
36 }
37
38 impl<'tcx> UniverseInfo<'tcx> {
39 crate fn other() -> UniverseInfo<'tcx> {
40 UniverseInfo(UniverseInfoInner::Other)
41 }
42
43 crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
44 UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
45 }
46
47 crate fn report_error(
48 &self,
49 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
50 placeholder: ty::PlaceholderRegion,
51 error_element: RegionElement,
52 cause: ObligationCause<'tcx>,
53 ) {
54 match self.0 {
55 UniverseInfoInner::RelateTys { expected, found } => {
56 let err = mbcx.infcx.report_mismatched_types(
57 &cause,
58 expected,
59 found,
60 TypeError::RegionsPlaceholderMismatch,
61 );
62 mbcx.buffer_error(err);
63 }
64 UniverseInfoInner::TypeOp(ref type_op_info) => {
65 type_op_info.report_error(mbcx, placeholder, error_element, cause);
66 }
67 UniverseInfoInner::Other => {
68 // FIXME: This error message isn't great, but it doesn't show
69 // up in the existing UI tests. Consider investigating this
70 // some more.
71 mbcx.buffer_error(
72 mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"),
73 );
74 }
75 }
76 }
77 }
78
79 crate trait ToUniverseInfo<'tcx> {
80 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
81 }
82
83 impl<'tcx> ToUniverseInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
84 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
85 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(crate::type_check::InstantiateOpaqueType {
86 base_universe: Some(base_universe),
87 ..self
88 })))
89 }
90 }
91
92 impl<'tcx> ToUniverseInfo<'tcx>
93 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
94 {
95 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
96 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
97 canonical_query: self,
98 base_universe,
99 })))
100 }
101 }
102
103 impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
104 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
105 {
106 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
107 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
108 canonical_query: self,
109 base_universe,
110 })))
111 }
112 }
113
114 impl<'tcx> ToUniverseInfo<'tcx>
115 for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
116 {
117 fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
118 UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
119 canonical_query: self,
120 base_universe,
121 })))
122 }
123 }
124
125 impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
126 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
127 // We can't rerun custom type ops.
128 UniverseInfo::other()
129 }
130 }
131
132 impl<'tcx> ToUniverseInfo<'tcx> for ! {
133 fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
134 self
135 }
136 }
137
138 #[allow(unused_lifetimes)]
139 trait TypeOpInfo<'tcx> {
140 /// Returns an error to be reported if rerunning the type op fails to
141 /// recover the error's cause.
142 fn fallback_error(
143 &self,
144 tcx: TyCtxt<'tcx>,
145 span: Span,
146 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
147
148 fn base_universe(&self) -> ty::UniverseIndex;
149
150 fn nice_error(
151 &self,
152 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
153 cause: ObligationCause<'tcx>,
154 placeholder_region: ty::Region<'tcx>,
155 error_region: Option<ty::Region<'tcx>>,
156 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
157
158 fn report_error(
159 &self,
160 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
161 placeholder: ty::PlaceholderRegion,
162 error_element: RegionElement,
163 cause: ObligationCause<'tcx>,
164 ) {
165 let tcx = mbcx.infcx.tcx;
166 let base_universe = self.base_universe();
167
168 let Some(adjusted_universe) =
169 placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
170 else {
171 mbcx.buffer_error(self.fallback_error(tcx, cause.span));
172 return;
173 };
174
175 let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
176 name: placeholder.name,
177 universe: adjusted_universe.into(),
178 }));
179
180 let error_region =
181 if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
182 let adjusted_universe =
183 error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
184 adjusted_universe.map(|adjusted| {
185 tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
186 name: error_placeholder.name,
187 universe: adjusted.into(),
188 }))
189 })
190 } else {
191 None
192 };
193
194 debug!(?placeholder_region);
195
196 let span = cause.span;
197 let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region);
198
199 if let Some(nice_error) = nice_error {
200 mbcx.buffer_error(nice_error);
201 } else {
202 mbcx.buffer_error(self.fallback_error(tcx, span));
203 }
204 }
205 }
206
207 struct PredicateQuery<'tcx> {
208 canonical_query:
209 Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
210 base_universe: ty::UniverseIndex,
211 }
212
213 impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
214 fn fallback_error(
215 &self,
216 tcx: TyCtxt<'tcx>,
217 span: Span,
218 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
219 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
220 err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
221 err
222 }
223
224 fn base_universe(&self) -> ty::UniverseIndex {
225 self.base_universe
226 }
227
228 fn nice_error(
229 &self,
230 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
231 cause: ObligationCause<'tcx>,
232 placeholder_region: ty::Region<'tcx>,
233 error_region: Option<ty::Region<'tcx>>,
234 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
235 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
236 cause.span,
237 &self.canonical_query,
238 |ref infcx, key, _| {
239 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
240 type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
241 try_extract_error_from_fulfill_cx(
242 fulfill_cx,
243 infcx,
244 placeholder_region,
245 error_region,
246 )
247 },
248 )
249 }
250 }
251
252 struct NormalizeQuery<'tcx, T> {
253 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
254 base_universe: ty::UniverseIndex,
255 }
256
257 impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
258 where
259 T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
260 {
261 fn fallback_error(
262 &self,
263 tcx: TyCtxt<'tcx>,
264 span: Span,
265 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
266 let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
267 err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
268 err
269 }
270
271 fn base_universe(&self) -> ty::UniverseIndex {
272 self.base_universe
273 }
274
275 fn nice_error(
276 &self,
277 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
278 cause: ObligationCause<'tcx>,
279 placeholder_region: ty::Region<'tcx>,
280 error_region: Option<ty::Region<'tcx>>,
281 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
282 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
283 cause.span,
284 &self.canonical_query,
285 |ref infcx, key, _| {
286 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
287
288 let mut selcx = SelectionContext::new(infcx);
289
290 // FIXME(lqd): Unify and de-duplicate the following with the actual
291 // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
292 // `ObligationCause`. The normalization results are currently different between
293 // `AtExt::normalize` used in the query and `normalize` called below: the former fails
294 // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
295 // after #85499 lands to see if its fixes have erased this difference.
296 let (param_env, value) = key.into_parts();
297 let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
298 &mut selcx,
299 param_env,
300 cause,
301 value.value,
302 );
303 fulfill_cx.register_predicate_obligations(infcx, obligations);
304
305 try_extract_error_from_fulfill_cx(
306 fulfill_cx,
307 infcx,
308 placeholder_region,
309 error_region,
310 )
311 },
312 )
313 }
314 }
315
316 struct AscribeUserTypeQuery<'tcx> {
317 canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
318 base_universe: ty::UniverseIndex,
319 }
320
321 impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
322 fn fallback_error(
323 &self,
324 tcx: TyCtxt<'tcx>,
325 span: Span,
326 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
327 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
328 // and is only the fallback when the nice error fails. Consider improving this some more.
329 tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
330 }
331
332 fn base_universe(&self) -> ty::UniverseIndex {
333 self.base_universe
334 }
335
336 fn nice_error(
337 &self,
338 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
339 cause: ObligationCause<'tcx>,
340 placeholder_region: ty::Region<'tcx>,
341 error_region: Option<ty::Region<'tcx>>,
342 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
343 mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
344 cause.span,
345 &self.canonical_query,
346 |ref infcx, key, _| {
347 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
348 type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
349 .ok()?;
350 try_extract_error_from_fulfill_cx(
351 fulfill_cx,
352 infcx,
353 placeholder_region,
354 error_region,
355 )
356 },
357 )
358 }
359 }
360
361 impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
362 fn fallback_error(
363 &self,
364 tcx: TyCtxt<'tcx>,
365 span: Span,
366 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
367 // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
368 // and is only the fallback when the nice error fails. Consider improving this some more.
369 tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!")
370 }
371
372 fn base_universe(&self) -> ty::UniverseIndex {
373 self.base_universe.unwrap()
374 }
375
376 fn nice_error(
377 &self,
378 mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
379 _cause: ObligationCause<'tcx>,
380 placeholder_region: ty::Region<'tcx>,
381 error_region: Option<ty::Region<'tcx>>,
382 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
383 try_extract_error_from_region_constraints(
384 mbcx.infcx,
385 placeholder_region,
386 error_region,
387 self.region_constraints.as_ref().unwrap(),
388 // We're using the original `InferCtxt` that we
389 // started MIR borrowchecking with, so the region
390 // constraints have already been taken. Use the data from
391 // our `mbcx` instead.
392 |vid| mbcx.regioncx.var_infos[vid].origin,
393 |vid| mbcx.regioncx.var_infos[vid].universe,
394 )
395 }
396 }
397
398 #[instrument(skip(fulfill_cx, infcx), level = "debug")]
399 fn try_extract_error_from_fulfill_cx<'tcx>(
400 mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
401 infcx: &InferCtxt<'_, 'tcx>,
402 placeholder_region: ty::Region<'tcx>,
403 error_region: Option<ty::Region<'tcx>>,
404 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
405 // We generally shouldn't have errors here because the query was
406 // already run, but there's no point using `delay_span_bug`
407 // when we're going to emit an error here anyway.
408 let _errors = fulfill_cx.select_all_or_error(infcx);
409 let region_constraints = infcx.with_region_constraints(|r| r.clone());
410 try_extract_error_from_region_constraints(
411 infcx,
412 placeholder_region,
413 error_region,
414 &region_constraints,
415 |vid| infcx.region_var_origin(vid),
416 |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
417 )
418 }
419
420 fn try_extract_error_from_region_constraints<'tcx>(
421 infcx: &InferCtxt<'_, 'tcx>,
422 placeholder_region: ty::Region<'tcx>,
423 error_region: Option<ty::Region<'tcx>>,
424 region_constraints: &RegionConstraintData<'tcx>,
425 mut region_var_origin: impl FnMut(RegionVid) -> RegionVariableOrigin,
426 mut universe_of_region: impl FnMut(RegionVid) -> UniverseIndex,
427 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
428 let (sub_region, cause) =
429 region_constraints.constraints.iter().find_map(|(constraint, cause)| {
430 match *constraint {
431 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
432 Some((sub, cause.clone()))
433 }
434 // FIXME: Should this check the universe of the var?
435 Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
436 Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone()))
437 }
438 _ => None,
439 }
440 })?;
441
442 debug!(?sub_region, "cause = {:#?}", cause);
443 let nice_error = match (error_region, *sub_region) {
444 (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
445 infcx,
446 RegionResolutionError::SubSupConflict(
447 vid,
448 region_var_origin(vid),
449 cause.clone(),
450 error_region,
451 cause.clone(),
452 placeholder_region,
453 vec![],
454 ),
455 ),
456 (Some(error_region), _) => NiceRegionError::new(
457 infcx,
458 RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
459 ),
460 // Note universe here is wrong...
461 (None, ty::ReVar(vid)) => NiceRegionError::new(
462 infcx,
463 RegionResolutionError::UpperBoundUniverseConflict(
464 vid,
465 region_var_origin(vid),
466 universe_of_region(vid),
467 cause.clone(),
468 placeholder_region,
469 ),
470 ),
471 (None, _) => NiceRegionError::new(
472 infcx,
473 RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
474 ),
475 };
476 nice_error.try_report_from_nll().or_else(|| {
477 if let SubregionOrigin::Subtype(trace) = cause {
478 Some(
479 infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
480 )
481 } else {
482 None
483 }
484 })
485 }