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};
14 use std::fmt::{self, Write};
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>> {
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
27 ///////////////////////////////////////////////////////////////////////////
28 // Check for errors from comparing trait failures -- first
29 // with two placeholders, then with one.
30 Some(RegionResolutionError::SubSupConflict(
33 SubregionOrigin::Subtype(TypeTrace {
35 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
37 sub_placeholder @ ty::RePlaceholder(_),
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))),
43 Some(sub_placeholder),
44 Some(sup_placeholder),
50 Some(RegionResolutionError::SubSupConflict(
53 SubregionOrigin::Subtype(TypeTrace {
55 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
57 sub_placeholder @ ty::RePlaceholder(_),
60 )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
61 Some(self.tcx().mk_region(ty::ReVar(*vid))),
63 Some(sub_placeholder),
70 Some(RegionResolutionError::SubSupConflict(
73 SubregionOrigin::Subtype(TypeTrace {
75 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
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))),
84 Some(*sup_placeholder),
90 Some(RegionResolutionError::SubSupConflict(
95 SubregionOrigin::Subtype(TypeTrace {
97 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
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))),
104 Some(*sup_placeholder),
110 Some(RegionResolutionError::ConcreteFailure(
111 SubregionOrigin::Subtype(TypeTrace {
113 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
115 sub_region @ ty::RePlaceholder(_),
116 sup_region @ ty::RePlaceholder(_),
117 )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
127 Some(RegionResolutionError::ConcreteFailure(
128 SubregionOrigin::Subtype(TypeTrace {
130 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
132 sub_region @ ty::RePlaceholder(_),
134 )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
144 Some(RegionResolutionError::ConcreteFailure(
145 SubregionOrigin::Subtype(TypeTrace {
147 values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
150 sup_region @ ty::RePlaceholder(_),
151 )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
165 // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
166 // --> /home/nmatsakis/tmp/foo.rs:12:5
168 // 12 | all::<&'static u32>();
169 // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
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(
176 vid: Option<ty::Region<'tcx>>,
177 cause: &ObligationCause<'tcx>,
178 sub_placeholder: Option<ty::Region<'tcx>>,
179 sup_placeholder: Option<ty::Region<'tcx>>,
181 expected_substs: SubstsRef<'tcx>,
182 actual_substs: SubstsRef<'tcx>,
183 ) -> DiagnosticBuilder<'me> {
185 "try_report_placeholders_trait(\
187 sub_placeholder={:?}, \
188 sup_placeholder={:?}, \
190 expected_substs={:?}, \
191 actual_substs={:?})",
192 vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
195 let mut err = self.tcx().sess.struct_span_err(
196 cause.span(self.tcx()),
198 "implementation of `{}` is not general enough",
199 self.tcx().def_path_str(trait_def_id),
204 ObligationCauseCode::ItemObligation(def_id) => {
206 "Due to a where-clause on `{}`,",
207 self.tcx().def_path_str(def_id),
213 let expected_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
214 def_id: trait_def_id,
215 substs: expected_substs,
217 let actual_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
218 def_id: trait_def_id,
219 substs: actual_substs,
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.
229 let mut has_sub = None;
230 let mut has_sup = None;
232 let mut actual_has_vid = None;
233 let mut expected_has_vid = None;
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);
239 } else if Some(r) == sup_placeholder && has_sup.is_none() {
240 has_sup = Some(counter);
244 if Some(r) == vid && expected_has_vid.is_none() {
245 expected_has_vid = Some(counter);
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);
257 let actual_self_ty_has_vid = self
259 .any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);
261 let expected_self_ty_has_vid = self
263 .any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);
265 let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
268 "try_report_placeholders_trait: actual_has_vid={:?}",
272 "try_report_placeholders_trait: expected_has_vid={:?}",
275 debug!("try_report_placeholders_trait: has_sub={:?}", has_sub);
276 debug!("try_report_placeholders_trait: has_sup={:?}", has_sup);
278 "try_report_placeholders_trait: actual_self_ty_has_vid={:?}",
279 actual_self_ty_has_vid
282 "try_report_placeholders_trait: expected_self_ty_has_vid={:?}",
283 expected_self_ty_has_vid
286 self.explain_actual_impl_that_was_found(
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(
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,
322 // HACK(eddyb) maybe move this in a more central location.
323 #[derive(Copy, Clone)]
324 struct Highlighted<'a, 'gcx, 'tcx, T> {
325 tcx: TyCtxt<'a, 'gcx, 'tcx>,
326 highlight: RegionHighlightMode,
330 impl<'a, 'gcx, 'tcx, T> Highlighted<'a, 'gcx, 'tcx, T> {
331 fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'a, 'gcx, 'tcx, U> {
334 highlight: self.highlight,
335 value: f(self.value),
340 impl<'a, 'gcx, 'tcx, T> fmt::Display for Highlighted<'a, 'gcx, 'tcx, T>
341 where T: for<'b, 'c> Print<'gcx, 'tcx,
342 FmtPrinter<'a, 'gcx, 'tcx, &'b mut fmt::Formatter<'c>>,
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347 let mut printer = ty::print::FmtPrinter::new(self.tcx, f, Namespace::TypeNS);
348 printer.region_highlight_mode = self.highlight;
350 self.value.print(printer)?;
355 // The weird thing here with the `maybe_highlighting_region` calls and the
356 // the match inside is meant to be like this:
358 // - The match checks whether the given things (placeholders, etc) appear
359 // in the types are about to print
360 // - Meanwhile, the `maybe_highlighting_region` calls set up
361 // highlights so that, if they do appear, we will replace
362 // them `'0` and whatever. (This replacement takes place
363 // inside the closure given to `maybe_highlighting_region`.)
365 // There is some duplication between the calls -- i.e., the
366 // `maybe_highlighting_region` checks if (e.g.) `has_sub` is
367 // None, an then we check again inside the closure, but this
368 // setup sort of minimized the number of calls and so form.
370 let highlight_trait_ref = |trait_ref| Highlighted {
372 highlight: RegionHighlightMode::default(),
376 let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
377 expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
378 expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
380 let passive_voice = match (has_sub, has_sup) {
381 (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
383 expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
384 match expected_has_vid {
386 None => any_self_ty_has_vid,
391 let mut note = if passive_voice {
393 "`{}` would have to be implemented for the type `{}`",
395 expected_trait_ref.map(|tr| tr.self_ty()),
399 "`{}` must implement `{}`",
400 expected_trait_ref.map(|tr| tr.self_ty()),
405 match (has_sub, has_sup) {
406 (Some(n1), Some(n2)) => {
408 ", for any two lifetimes `'{}` and `'{}`",
409 std::cmp::min(n1, n2),
410 std::cmp::max(n1, n2),
413 (Some(n), _) | (_, Some(n)) => {
415 ", for any lifetime `'{}`",
419 (None, None) => if let Some(n) = expected_has_vid {
421 ", for some specific lifetime `'{}`",
430 let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
431 actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
433 let passive_voice = match actual_has_vid {
434 Some(_) => any_self_ty_has_vid,
438 let mut note = if passive_voice {
440 "but `{}` is actually implemented for the type `{}`",
442 actual_trait_ref.map(|tr| tr.self_ty()),
446 "but `{}` actually implements `{}`",
447 actual_trait_ref.map(|tr| tr.self_ty()),
452 if let Some(n) = actual_has_vid {
453 let _ = write!(note, ", for some specific lifetime `'{}`", n);