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