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