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