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};
9 use crate::ty::error::ExpectedFound;
10 use crate::ty::subst::SubstsRef;
11 use crate::util::ppaux::RegionHighlightMode;
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>> {
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
24 ///////////////////////////////////////////////////////////////////////////
25 // Check for errors from comparing trait failures -- first
26 // with two placeholders, then with one.
27 Some(RegionResolutionError::SubSupConflict(
30 SubregionOrigin::Subtype(TypeTrace {
32 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
34 sub_placeholder @ ty::RePlaceholder(_),
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))),
40 Some(sub_placeholder),
41 Some(sup_placeholder),
47 Some(RegionResolutionError::SubSupConflict(
50 SubregionOrigin::Subtype(TypeTrace {
52 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
54 sub_placeholder @ ty::RePlaceholder(_),
57 )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
58 Some(self.tcx().mk_region(ty::ReVar(*vid))),
60 Some(sub_placeholder),
67 Some(RegionResolutionError::SubSupConflict(
70 SubregionOrigin::Subtype(TypeTrace {
72 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
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))),
81 Some(*sup_placeholder),
87 Some(RegionResolutionError::SubSupConflict(
92 SubregionOrigin::Subtype(TypeTrace {
94 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
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))),
101 Some(*sup_placeholder),
107 Some(RegionResolutionError::ConcreteFailure(
108 SubregionOrigin::Subtype(TypeTrace {
110 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
112 sub_region @ ty::RePlaceholder(_),
113 sup_region @ ty::RePlaceholder(_),
114 )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
124 Some(RegionResolutionError::ConcreteFailure(
125 SubregionOrigin::Subtype(TypeTrace {
127 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
129 sub_region @ ty::RePlaceholder(_),
131 )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
141 Some(RegionResolutionError::ConcreteFailure(
142 SubregionOrigin::Subtype(TypeTrace {
144 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
147 sup_region @ ty::RePlaceholder(_),
148 )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
162 // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
163 // --> /home/nmatsakis/tmp/foo.rs:12:5
165 // 12 | all::<&'static u32>();
166 // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
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(
173 vid: Option<ty::Region<'tcx>>,
174 cause: &ObligationCause<'tcx>,
175 sub_placeholder: Option<ty::Region<'tcx>>,
176 sup_placeholder: Option<ty::Region<'tcx>>,
178 expected_substs: SubstsRef<'tcx>,
179 actual_substs: SubstsRef<'tcx>,
180 ) -> DiagnosticBuilder<'me> {
182 "try_report_placeholders_trait(\
184 sub_placeholder={:?}, \
185 sup_placeholder={:?}, \
187 expected_substs={:?}, \
188 actual_substs={:?})",
189 vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
192 let mut err = self.tcx().sess.struct_span_err(
193 cause.span(&self.tcx()),
195 "implementation of `{}` is not general enough",
196 self.tcx().item_path_str(trait_def_id),
201 ObligationCauseCode::ItemObligation(def_id) => {
203 "Due to a where-clause on `{}`,",
204 self.tcx().item_path_str(def_id),
210 let expected_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
211 def_id: trait_def_id,
212 substs: expected_substs,
214 let actual_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
215 def_id: trait_def_id,
216 substs: actual_substs,
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.
226 let mut has_sub = None;
227 let mut has_sup = None;
229 let mut actual_has_vid = None;
230 let mut expected_has_vid = None;
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);
236 } else if Some(r) == sup_placeholder && has_sup.is_none() {
237 has_sup = Some(counter);
241 if Some(r) == vid && expected_has_vid.is_none() {
242 expected_has_vid = Some(counter);
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);
254 let actual_self_ty_has_vid = self
256 .any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
258 let expected_self_ty_has_vid = self
260 .any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);
262 let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
265 "try_report_placeholders_trait: actual_has_vid={:?}",
269 "try_report_placeholders_trait: expected_has_vid={:?}",
272 debug!("try_report_placeholders_trait: has_sub={:?}", has_sub);
273 debug!("try_report_placeholders_trait: has_sup={:?}", has_sup);
275 "try_report_placeholders_trait: actual_self_ty_has_vid={:?}",
276 actual_self_ty_has_vid
279 "try_report_placeholders_trait: expected_self_ty_has_vid={:?}",
280 expected_self_ty_has_vid
283 self.explain_actual_impl_that_was_found(
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(
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,
319 // The weird thing here with the `maybe_highlighting_region` calls and the
320 // the match inside is meant to be like this:
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`.)
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.
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 {
340 "`{}` would have to be implemented for the type `{}`, \
341 for any two lifetimes `'{}` and `'{}`",
343 expected_trait_ref.self_ty(),
344 std::cmp::min(n1, n2),
345 std::cmp::max(n1, n2),
349 "`{}` must implement `{}`, \
350 for any two lifetimes `'{}` and `'{}`",
351 expected_trait_ref.self_ty(),
353 std::cmp::min(n1, n2),
354 std::cmp::max(n1, n2),
358 (Some(n), _) | (_, Some(n)) => {
359 if any_self_ty_has_vid {
361 "`{}` would have to be implemented for the type `{}`, \
362 for any lifetime `'{}`",
364 expected_trait_ref.self_ty(),
369 "`{}` must implement `{}`, for any lifetime `'{}`",
370 expected_trait_ref.self_ty(),
376 (None, None) => RegionHighlightMode::maybe_highlighting_region(
380 if let Some(n) = expected_has_vid {
382 "`{}` would have to be implemented for the type `{}`, \
383 for some specific lifetime `'{}`",
385 expected_trait_ref.self_ty(),
389 if any_self_ty_has_vid {
391 "`{}` would have to be implemented for the type `{}`",
393 expected_trait_ref.self_ty(),
397 "`{}` must implement `{}`",
398 expected_trait_ref.self_ty(),
409 RegionHighlightMode::maybe_highlighting_region(
412 || match actual_has_vid {
414 if any_self_ty_has_vid {
416 "but `{}` is actually implemented for the type `{}`, \
417 for some specific lifetime `'{}`",
419 actual_trait_ref.self_ty(),
424 "but `{}` actually implements `{}`, for some specific lifetime `'{}`",
425 actual_trait_ref.self_ty(),
434 "but `{}` is actually implemented for the type `{}`",
436 actual_trait_ref.self_ty(),