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