]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / error_reporting / nice_region_error / placeholder_error.rs
CommitLineData
9c376795
FG
1use crate::errors::{
2 ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
3 TraitPlaceholderMismatch, TyOrSig,
4};
9fa01778
XL
5use crate::infer::error_reporting::nice_region_error::NiceRegionError;
6use crate::infer::lexical_region_resolve::RegionResolutionError;
7use crate::infer::ValuePairs;
8use crate::infer::{SubregionOrigin, TypeTrace};
9use crate::traits::{ObligationCause, ObligationCauseCode};
5099ac24 10use rustc_data_structures::intern::Interned;
9c376795 11use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
dfeec247
XL
12use rustc_hir::def::Namespace;
13use rustc_hir::def_id::DefId;
ba9703b0
XL
14use rustc_middle::ty::error::ExpectedFound;
15use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
16use rustc_middle::ty::subst::SubstsRef;
9ffffee4 17use rustc_middle::ty::{self, RePlaceholder, Region, TyCtxt};
532ac7d7 18
9c376795
FG
19use std::fmt;
20
21// HACK(eddyb) maybe move this in a more central location.
22#[derive(Copy, Clone)]
23pub struct Highlighted<'tcx, T> {
24 tcx: TyCtxt<'tcx>,
25 highlight: RegionHighlightMode<'tcx>,
26 value: T,
27}
28
29impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
30where
31 T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
32{
33 fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
34 rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
35 }
36}
37
38impl<'tcx, T> Highlighted<'tcx, T> {
39 fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
40 Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
41 }
42}
43
44impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
45where
46 T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
47{
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
50 printer.region_highlight_mode = self.highlight;
51
52 let s = self.value.print(printer)?.into_buffer();
53 f.write_str(&s)
54 }
55}
0731742a 56
a2a8927a 57impl<'tcx> NiceRegionError<'_, 'tcx> {
0731742a 58 /// When given a `ConcreteFailure` for a function with arguments containing a named region and
9fa01778 59 /// an anonymous region, emit a descriptive diagnostic error.
5e7ed085
FG
60 pub(super) fn try_report_placeholder_conflict(
61 &self,
62 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
0731742a
XL
63 match &self.error {
64 ///////////////////////////////////////////////////////////////////////////
65 // NB. The ordering of cases in this match is very
66 // sensitive, because we are often matching against
67 // specific cases and then using an `_` to match all
68 // others.
69
70 ///////////////////////////////////////////////////////////////////////////
71 // Check for errors from comparing trait failures -- first
72 // with two placeholders, then with one.
73 Some(RegionResolutionError::SubSupConflict(
74 vid,
75 _,
6a06907d 76 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 77 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
0731742a 78 _,
5099ac24 79 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
a2a8927a 80 _,
6a06907d 81 )) => self.try_report_trait_placeholder_mismatch(
9ffffee4 82 Some(self.tcx().mk_re_var(*vid)),
9fa01778 83 cause,
5099ac24
FG
84 Some(*sub_placeholder),
85 Some(*sup_placeholder),
6a06907d
XL
86 values,
87 ),
0731742a
XL
88
89 Some(RegionResolutionError::SubSupConflict(
90 vid,
91 _,
6a06907d 92 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 93 sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
0731742a
XL
94 _,
95 _,
a2a8927a 96 _,
6a06907d 97 )) => self.try_report_trait_placeholder_mismatch(
9ffffee4 98 Some(self.tcx().mk_re_var(*vid)),
9fa01778 99 cause,
5099ac24 100 Some(*sub_placeholder),
9fa01778 101 None,
6a06907d
XL
102 values,
103 ),
0731742a
XL
104
105 Some(RegionResolutionError::SubSupConflict(
106 vid,
107 _,
6a06907d 108 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
0731742a
XL
109 _,
110 _,
5099ac24 111 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
a2a8927a 112 _,
6a06907d 113 )) => self.try_report_trait_placeholder_mismatch(
9ffffee4 114 Some(self.tcx().mk_re_var(*vid)),
9fa01778
XL
115 cause,
116 None,
117 Some(*sup_placeholder),
6a06907d
XL
118 values,
119 ),
9fa01778
XL
120
121 Some(RegionResolutionError::SubSupConflict(
122 vid,
123 _,
124 _,
125 _,
6a06907d 126 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 127 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
a2a8927a 128 _,
6a06907d 129 )) => self.try_report_trait_placeholder_mismatch(
9ffffee4 130 Some(self.tcx().mk_re_var(*vid)),
9fa01778
XL
131 cause,
132 None,
133 Some(*sup_placeholder),
6a06907d
XL
134 values,
135 ),
0731742a 136
74b04a01
XL
137 Some(RegionResolutionError::UpperBoundUniverseConflict(
138 vid,
139 _,
140 _,
6a06907d 141 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 142 sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
6a06907d 143 )) => self.try_report_trait_placeholder_mismatch(
9ffffee4 144 Some(self.tcx().mk_re_var(*vid)),
74b04a01
XL
145 cause,
146 None,
147 Some(*sup_placeholder),
6a06907d
XL
148 values,
149 ),
74b04a01 150
0731742a 151 Some(RegionResolutionError::ConcreteFailure(
6a06907d 152 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24
FG
153 sub_region @ Region(Interned(RePlaceholder(_), _)),
154 sup_region @ Region(Interned(RePlaceholder(_), _)),
6a06907d 155 )) => self.try_report_trait_placeholder_mismatch(
9fa01778
XL
156 None,
157 cause,
158 Some(*sub_region),
159 Some(*sup_region),
6a06907d
XL
160 values,
161 ),
0731742a
XL
162
163 Some(RegionResolutionError::ConcreteFailure(
6a06907d 164 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
5099ac24 165 sub_region @ Region(Interned(RePlaceholder(_), _)),
0731742a 166 sup_region,
6a06907d 167 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 168 (!sup_region.has_name()).then_some(*sup_region),
9fa01778 169 cause,
5099ac24 170 Some(*sub_region),
9fa01778 171 None,
6a06907d
XL
172 values,
173 ),
0731742a
XL
174
175 Some(RegionResolutionError::ConcreteFailure(
6a06907d 176 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
0731742a 177 sub_region,
5099ac24 178 sup_region @ Region(Interned(RePlaceholder(_), _)),
6a06907d 179 )) => self.try_report_trait_placeholder_mismatch(
5099ac24 180 (!sub_region.has_name()).then_some(*sub_region),
9fa01778
XL
181 cause,
182 None,
5099ac24 183 Some(*sup_region),
6a06907d
XL
184 values,
185 ),
0731742a
XL
186
187 _ => None,
188 }
189 }
190
6a06907d
XL
191 fn try_report_trait_placeholder_mismatch(
192 &self,
5099ac24 193 vid: Option<Region<'tcx>>,
6a06907d 194 cause: &ObligationCause<'tcx>,
5099ac24
FG
195 sub_placeholder: Option<Region<'tcx>>,
196 sup_placeholder: Option<Region<'tcx>>,
6a06907d 197 value_pairs: &ValuePairs<'tcx>,
5e7ed085 198 ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
6a06907d
XL
199 let (expected_substs, found_substs, trait_def_id) = match value_pairs {
200 ValuePairs::TraitRefs(ExpectedFound { expected, found })
201 if expected.def_id == found.def_id =>
202 {
203 (expected.substs, found.substs, expected.def_id)
204 }
205 ValuePairs::PolyTraitRefs(ExpectedFound { expected, found })
206 if expected.def_id() == found.def_id() =>
207 {
208 // It's possible that the placeholders come from a binder
209 // outside of this value pair. Use `no_bound_vars` as a
210 // simple heuristic for that.
211 (expected.no_bound_vars()?.substs, found.no_bound_vars()?.substs, expected.def_id())
212 }
213 _ => return None,
214 };
215
216 Some(self.report_trait_placeholder_mismatch(
217 vid,
218 cause,
219 sub_placeholder,
220 sup_placeholder,
221 trait_def_id,
222 expected_substs,
223 found_substs,
224 ))
225 }
226
0731742a
XL
227 // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
228 // --> /home/nmatsakis/tmp/foo.rs:12:5
229 // |
230 // 12 | all::<&'static u32>();
231 // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
232 // |
233 // = note: Due to a where-clause on the function `all`,
234 // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
235 // = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
6a06907d
XL
236 #[instrument(level = "debug", skip(self))]
237 fn report_trait_placeholder_mismatch(
0731742a 238 &self,
5099ac24 239 vid: Option<Region<'tcx>>,
0731742a 240 cause: &ObligationCause<'tcx>,
5099ac24
FG
241 sub_placeholder: Option<Region<'tcx>>,
242 sup_placeholder: Option<Region<'tcx>>,
0731742a 243 trait_def_id: DefId,
532ac7d7
XL
244 expected_substs: SubstsRef<'tcx>,
245 actual_substs: SubstsRef<'tcx>,
5e7ed085 246 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
064997fb 247 let span = cause.span();
0731742a 248
9c376795
FG
249 let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
250 if let ObligationCauseCode::ItemObligation(def_id)
251 | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
252 {
253 (
254 true,
255 Some(span),
256 Some(self.tcx().def_span(def_id)),
257 None,
258 self.tcx().def_path_str(def_id),
259 )
260 } else {
261 (false, None, None, Some(span), String::new())
262 };
263
49aad941
FG
264 let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new(
265 self.cx.tcx,
266 trait_def_id,
267 expected_substs,
268 ));
269 let actual_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new(
270 self.cx.tcx,
271 trait_def_id,
272 actual_substs,
273 ));
0731742a
XL
274
275 // Search the expected and actual trait references to see (a)
276 // whether the sub/sup placeholders appear in them (sometimes
277 // you have a trait ref like `T: Foo<fn(&u8)>`, where the
278 // placeholder was created as part of an inner type) and (b)
279 // whether the inference variable appears. In each case,
280 // assign a counter value in each case if so.
281 let mut counter = 0;
282 let mut has_sub = None;
283 let mut has_sup = None;
0731742a 284
9fa01778
XL
285 let mut actual_has_vid = None;
286 let mut expected_has_vid = None;
287
288 self.tcx().for_each_free_region(&expected_trait_ref, |r| {
0731742a
XL
289 if Some(r) == sub_placeholder && has_sub.is_none() {
290 has_sub = Some(counter);
291 counter += 1;
292 } else if Some(r) == sup_placeholder && has_sup.is_none() {
293 has_sup = Some(counter);
294 counter += 1;
295 }
9fa01778
XL
296
297 if Some(r) == vid && expected_has_vid.is_none() {
298 expected_has_vid = Some(counter);
299 counter += 1;
300 }
0731742a
XL
301 });
302
9fa01778
XL
303 self.tcx().for_each_free_region(&actual_trait_ref, |r| {
304 if Some(r) == vid && actual_has_vid.is_none() {
305 actual_has_vid = Some(counter);
0731742a
XL
306 counter += 1;
307 }
308 });
309
dfeec247
XL
310 let actual_self_ty_has_vid =
311 self.tcx().any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
0731742a 312
dfeec247
XL
313 let expected_self_ty_has_vid =
314 self.tcx().any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);
9fa01778
XL
315
316 let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
317
9fa01778 318 debug!(
6a06907d
XL
319 ?actual_has_vid,
320 ?expected_has_vid,
321 ?has_sub,
322 ?has_sup,
323 ?actual_self_ty_has_vid,
324 ?expected_self_ty_has_vid,
9fa01778
XL
325 );
326
9c376795 327 let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
9fa01778
XL
328 sub_placeholder,
329 sup_placeholder,
330 has_sub,
331 has_sup,
332 expected_trait_ref,
333 actual_trait_ref,
334 vid,
335 expected_has_vid,
336 actual_has_vid,
337 any_self_ty_has_vid,
e1599b0c 338 leading_ellipsis,
9fa01778
XL
339 );
340
9c376795
FG
341 self.tcx().sess.create_err(TraitPlaceholderMismatch {
342 span,
343 satisfy_span,
344 where_span,
345 dup_span,
346 def_id,
347 trait_def_id: self.tcx().def_path_str(trait_def_id),
348 actual_impl_expl_notes,
349 })
9fa01778
XL
350 }
351
352 /// Add notes with details about the expected and actual trait refs, with attention to cases
353 /// when placeholder regions are involved: either the trait or the self type containing
354 /// them needs to be mentioned the closest to the placeholders.
355 /// This makes the error messages read better, however at the cost of some complexity
356 /// due to the number of combinations we have to deal with.
357 fn explain_actual_impl_that_was_found(
358 &self,
5099ac24
FG
359 sub_placeholder: Option<Region<'tcx>>,
360 sup_placeholder: Option<Region<'tcx>>,
9fa01778
XL
361 has_sub: Option<usize>,
362 has_sup: Option<usize>,
532ac7d7
XL
363 expected_trait_ref: ty::TraitRef<'tcx>,
364 actual_trait_ref: ty::TraitRef<'tcx>,
5099ac24 365 vid: Option<Region<'tcx>>,
9fa01778
XL
366 expected_has_vid: Option<usize>,
367 actual_has_vid: Option<usize>,
368 any_self_ty_has_vid: bool,
e1599b0c 369 leading_ellipsis: bool,
9c376795 370 ) -> Vec<ActualImplExplNotes<'tcx>> {
9fa01778
XL
371 // The weird thing here with the `maybe_highlighting_region` calls and the
372 // the match inside is meant to be like this:
373 //
374 // - The match checks whether the given things (placeholders, etc) appear
375 // in the types are about to print
376 // - Meanwhile, the `maybe_highlighting_region` calls set up
377 // highlights so that, if they do appear, we will replace
9c376795 378 // them `'0` and whatever. (This replacement takes place
9fa01778
XL
379 // inside the closure given to `maybe_highlighting_region`.)
380 //
381 // There is some duplication between the calls -- i.e., the
382 // `maybe_highlighting_region` checks if (e.g.) `has_sub` is
383 // None, an then we check again inside the closure, but this
384 // setup sort of minimized the number of calls and so form.
385
532ac7d7
XL
386 let highlight_trait_ref = |trait_ref| Highlighted {
387 tcx: self.tcx(),
5099ac24 388 highlight: RegionHighlightMode::new(self.tcx()),
532ac7d7
XL
389 value: trait_ref,
390 };
9fa01778 391
6a06907d
XL
392 let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();
393
532ac7d7
XL
394 let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
395 expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
396 expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
0731742a 397
9c376795
FG
398 let passive_voice = match (has_sub, has_sup) {
399 (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
400 (None, None) => {
401 expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
402 match expected_has_vid {
403 Some(_) => true,
404 None => any_self_ty_has_vid,
6a06907d 405 }
9c376795
FG
406 }
407 };
408
409 let (kind, ty_or_sig, trait_path) = if same_self_type {
410 let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
411 self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
412
413 if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
414 {
415 let closure_sig = self_ty.map(|closure| {
416 if let ty::Closure(_, substs) = closure.kind() {
417 self.tcx().signature_unclosure(
418 substs.as_closure().sig(),
419 rustc_hir::Unsafety::Normal,
420 )
421 } else {
422 bug!("type is not longer closure");
423 }
424 });
425 (
426 ActualImplExpectedKind::Signature,
427 TyOrSig::ClosureSig(closure_sig),
60c5eb7d 428 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
532ac7d7
XL
429 )
430 } else {
9c376795
FG
431 (
432 ActualImplExpectedKind::Other,
433 TyOrSig::Ty(self_ty),
60c5eb7d 434 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
532ac7d7 435 )
9c376795
FG
436 }
437 } else if passive_voice {
438 (
439 ActualImplExpectedKind::Passive,
440 TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
441 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
442 )
443 } else {
444 (
445 ActualImplExpectedKind::Other,
446 TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
447 expected_trait_ref.map(|tr| tr.print_only_trait_path()),
448 )
449 };
532ac7d7 450
9c376795
FG
451 let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
452 (Some(n1), Some(n2)) => {
453 (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
454 }
455 (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
456 (None, None) => {
457 if let Some(n) = expected_has_vid {
458 (ActualImplExpectedLifetimeKind::Some, n, 0)
459 } else {
460 (ActualImplExpectedLifetimeKind::Nothing, 0, 0)
532ac7d7 461 }
532ac7d7 462 }
9c376795 463 };
532ac7d7 464
9c376795
FG
465 let note_1 = ActualImplExplNotes::new_expected(
466 kind,
467 lt_kind,
468 leading_ellipsis,
469 ty_or_sig,
470 trait_path,
471 lifetime_1,
472 lifetime_2,
473 );
532ac7d7
XL
474
475 let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
476 actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
532ac7d7 477
9c376795
FG
478 let passive_voice = match actual_has_vid {
479 Some(_) => any_self_ty_has_vid,
480 None => true,
481 };
532ac7d7 482
9c376795
FG
483 let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
484 let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
485 let has_lifetime = actual_has_vid.is_some();
486 let lifetime = actual_has_vid.unwrap_or_default();
487
488 let note_2 = if same_self_type {
489 ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
490 } else if passive_voice {
491 ActualImplExplNotes::ButActuallyImplementedForTy {
492 trait_path,
493 ty,
494 has_lifetime,
495 lifetime,
532ac7d7 496 }
9c376795
FG
497 } else {
498 ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
499 };
532ac7d7 500
9c376795 501 vec![note_1, note_2]
0731742a
XL
502 }
503}