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}
;
6 use rustc_data_structures
::intern
::Interned
;
7 use rustc_errors
::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}
;
8 use rustc_hir
::def
::Namespace
;
9 use rustc_hir
::def_id
::DefId
;
10 use rustc_middle
::ty
::error
::ExpectedFound
;
11 use rustc_middle
::ty
::print
::{FmtPrinter, Print, RegionHighlightMode}
;
12 use rustc_middle
::ty
::subst
::SubstsRef
;
13 use rustc_middle
::ty
::{self, RePlaceholder, ReVar, Region, TyCtxt}
;
15 use std
::fmt
::{self, Write}
;
17 impl<'tcx
> NiceRegionError
<'_
, 'tcx
> {
18 /// When given a `ConcreteFailure` for a function with arguments containing a named region and
19 /// an anonymous region, emit a descriptive diagnostic error.
20 pub(super) fn try_report_placeholder_conflict(
22 ) -> Option
<DiagnosticBuilder
<'tcx
, ErrorGuaranteed
>> {
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
30 ///////////////////////////////////////////////////////////////////////////
31 // Check for errors from comparing trait failures -- first
32 // with two placeholders, then with one.
33 Some(RegionResolutionError
::SubSupConflict(
36 SubregionOrigin
::Subtype(box TypeTrace { cause, values }
),
37 sub_placeholder @
Region(Interned(RePlaceholder(_
), _
)),
39 sup_placeholder @
Region(Interned(RePlaceholder(_
), _
)),
41 )) => self.try_report_trait_placeholder_mismatch(
42 Some(self.tcx().mk_region(ReVar(*vid
))),
44 Some(*sub_placeholder
),
45 Some(*sup_placeholder
),
49 Some(RegionResolutionError
::SubSupConflict(
52 SubregionOrigin
::Subtype(box TypeTrace { cause, values }
),
53 sub_placeholder @
Region(Interned(RePlaceholder(_
), _
)),
57 )) => self.try_report_trait_placeholder_mismatch(
58 Some(self.tcx().mk_region(ReVar(*vid
))),
60 Some(*sub_placeholder
),
65 Some(RegionResolutionError
::SubSupConflict(
68 SubregionOrigin
::Subtype(box TypeTrace { cause, values }
),
71 sup_placeholder @
Region(Interned(RePlaceholder(_
), _
)),
73 )) => self.try_report_trait_placeholder_mismatch(
74 Some(self.tcx().mk_region(ReVar(*vid
))),
77 Some(*sup_placeholder
),
81 Some(RegionResolutionError
::SubSupConflict(
86 SubregionOrigin
::Subtype(box TypeTrace { cause, values }
),
87 sup_placeholder @
Region(Interned(RePlaceholder(_
), _
)),
89 )) => self.try_report_trait_placeholder_mismatch(
90 Some(self.tcx().mk_region(ReVar(*vid
))),
93 Some(*sup_placeholder
),
97 Some(RegionResolutionError
::UpperBoundUniverseConflict(
101 SubregionOrigin
::Subtype(box TypeTrace { cause, values }
),
102 sup_placeholder @
Region(Interned(RePlaceholder(_
), _
)),
103 )) => self.try_report_trait_placeholder_mismatch(
104 Some(self.tcx().mk_region(ReVar(*vid
))),
107 Some(*sup_placeholder
),
111 Some(RegionResolutionError
::ConcreteFailure(
112 SubregionOrigin
::Subtype(box TypeTrace { cause, values }
),
113 sub_region @
Region(Interned(RePlaceholder(_
), _
)),
114 sup_region @
Region(Interned(RePlaceholder(_
), _
)),
115 )) => self.try_report_trait_placeholder_mismatch(
123 Some(RegionResolutionError
::ConcreteFailure(
124 SubregionOrigin
::Subtype(box TypeTrace { cause, values }
),
125 sub_region @
Region(Interned(RePlaceholder(_
), _
)),
127 )) => self.try_report_trait_placeholder_mismatch(
128 (!sup_region
.has_name()).then_some(*sup_region
),
135 Some(RegionResolutionError
::ConcreteFailure(
136 SubregionOrigin
::Subtype(box TypeTrace { cause, values }
),
138 sup_region @
Region(Interned(RePlaceholder(_
), _
)),
139 )) => self.try_report_trait_placeholder_mismatch(
140 (!sub_region
.has_name()).then_some(*sub_region
),
151 fn try_report_trait_placeholder_mismatch(
153 vid
: Option
<Region
<'tcx
>>,
154 cause
: &ObligationCause
<'tcx
>,
155 sub_placeholder
: Option
<Region
<'tcx
>>,
156 sup_placeholder
: Option
<Region
<'tcx
>>,
157 value_pairs
: &ValuePairs
<'tcx
>,
158 ) -> Option
<DiagnosticBuilder
<'tcx
, ErrorGuaranteed
>> {
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
=>
163 (expected
.substs
, found
.substs
, expected
.def_id
)
165 ValuePairs
::PolyTraitRefs(ExpectedFound { expected, found }
)
166 if expected
.def_id() == found
.def_id() =>
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())
176 Some(self.report_trait_placeholder_mismatch(
187 // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
188 // --> /home/nmatsakis/tmp/foo.rs:12:5
190 // 12 | all::<&'static u32>();
191 // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
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`.
196 #[instrument(level = "debug", skip(self))]
197 fn report_trait_placeholder_mismatch(
199 vid
: Option
<Region
<'tcx
>>,
200 cause
: &ObligationCause
<'tcx
>,
201 sub_placeholder
: Option
<Region
<'tcx
>>,
202 sup_placeholder
: Option
<Region
<'tcx
>>,
204 expected_substs
: SubstsRef
<'tcx
>,
205 actual_substs
: SubstsRef
<'tcx
>,
206 ) -> DiagnosticBuilder
<'tcx
, ErrorGuaranteed
> {
207 let span
= cause
.span();
209 "implementation of `{}` is not general enough",
210 self.tcx().def_path_str(trait_def_id
),
212 let mut err
= self.tcx().sess
.struct_span_err(span
, &msg
);
214 let leading_ellipsis
= if let ObligationCauseCode
::ItemObligation(def_id
)
215 | ObligationCauseCode
::ExprItemObligation(def_id
, ..) =
218 err
.span_label(span
, "doesn't satisfy where-clause");
220 self.tcx().def_span(def_id
),
221 &format
!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id
)),
225 err
.span_label(span
, &msg
);
229 let expected_trait_ref
= self.cx
.resolve_vars_if_possible(ty
::TraitRef
{
230 def_id
: trait_def_id
,
231 substs
: expected_substs
,
233 let actual_trait_ref
= self
235 .resolve_vars_if_possible(ty
::TraitRef { def_id: trait_def_id, substs: actual_substs }
);
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.
244 let mut has_sub
= None
;
245 let mut has_sup
= None
;
247 let mut actual_has_vid
= None
;
248 let mut expected_has_vid
= None
;
250 self.tcx().for_each_free_region(&expected_trait_ref
, |r
| {
251 if Some(r
) == sub_placeholder
&& has_sub
.is_none() {
252 has_sub
= Some(counter
);
254 } else if Some(r
) == sup_placeholder
&& has_sup
.is_none() {
255 has_sup
= Some(counter
);
259 if Some(r
) == vid
&& expected_has_vid
.is_none() {
260 expected_has_vid
= Some(counter
);
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
);
272 let actual_self_ty_has_vid
=
273 self.tcx().any_free_region_meets(&actual_trait_ref
.self_ty(), |r
| Some(r
) == vid
);
275 let expected_self_ty_has_vid
=
276 self.tcx().any_free_region_meets(&expected_trait_ref
.self_ty(), |r
| Some(r
) == vid
);
278 let any_self_ty_has_vid
= actual_self_ty_has_vid
|| expected_self_ty_has_vid
;
285 ?actual_self_ty_has_vid
,
286 ?expected_self_ty_has_vid
,
289 self.explain_actual_impl_that_was_found(
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(
314 err
: &mut Diagnostic
,
315 sub_placeholder
: Option
<Region
<'tcx
>>,
316 sup_placeholder
: Option
<Region
<'tcx
>>,
317 has_sub
: Option
<usize>,
318 has_sup
: Option
<usize>,
319 expected_trait_ref
: ty
::TraitRef
<'tcx
>,
320 actual_trait_ref
: ty
::TraitRef
<'tcx
>,
321 vid
: Option
<Region
<'tcx
>>,
322 expected_has_vid
: Option
<usize>,
323 actual_has_vid
: Option
<usize>,
324 any_self_ty_has_vid
: bool
,
325 leading_ellipsis
: bool
,
327 // HACK(eddyb) maybe move this in a more central location.
328 #[derive(Copy, Clone)]
329 struct Highlighted
<'tcx
, T
> {
331 highlight
: RegionHighlightMode
<'tcx
>,
335 impl<'tcx
, T
> Highlighted
<'tcx
, T
> {
336 fn map
<U
>(self, f
: impl FnOnce(T
) -> U
) -> Highlighted
<'tcx
, U
> {
337 Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
341 impl<'tcx
, T
> fmt
::Display
for Highlighted
<'tcx
, T
>
345 FmtPrinter
<'a
, 'tcx
>,
347 Output
= FmtPrinter
<'a
, 'tcx
>,
350 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
351 let mut printer
= ty
::print
::FmtPrinter
::new(self.tcx
, Namespace
::TypeNS
);
352 printer
.region_highlight_mode
= self.highlight
;
354 let s
= self.value
.print(printer
)?
.into_buffer();
359 // The weird thing here with the `maybe_highlighting_region` calls and the
360 // the match inside is meant to be like this:
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`.)
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.
374 let highlight_trait_ref
= |trait_ref
| Highlighted
{
376 highlight
: RegionHighlightMode
::new(self.tcx()),
380 let same_self_type
= actual_trait_ref
.self_ty() == expected_trait_ref
.self_ty();
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
);
386 let passive_voice
= match (has_sub
, has_sup
) {
387 (Some(_
), _
) | (_
, Some(_
)) => any_self_ty_has_vid
,
389 expected_trait_ref
.highlight
.maybe_highlighting_region(vid
, expected_has_vid
);
390 match expected_has_vid
{
392 None
=> any_self_ty_has_vid
,
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
);
401 if self_ty
.value
.is_closure()
402 && self.tcx().is_fn_trait(expected_trait_ref
.value
.def_id
)
404 let closure_sig
= self_ty
.map(|closure
| {
405 if let ty
::Closure(_
, substs
) = closure
.kind() {
406 self.tcx().signature_unclosure(
407 substs
.as_closure().sig(),
408 rustc_hir
::Unsafety
::Normal
,
411 bug
!("type is not longer closure");
416 "{}closure with signature `{}` must implement `{}`",
417 if leading_ellipsis { "..." }
else { "" }
,
419 expected_trait_ref
.map(|tr
| tr
.print_only_trait_path()),
423 "{}`{}` must implement `{}`",
424 if leading_ellipsis { "..." }
else { "" }
,
426 expected_trait_ref
.map(|tr
| tr
.print_only_trait_path()),
429 } else if passive_voice
{
431 "{}`{}` would have to be implemented for the type `{}`",
432 if leading_ellipsis { "..." }
else { "" }
,
433 expected_trait_ref
.map(|tr
| tr
.print_only_trait_path()),
434 expected_trait_ref
.map(|tr
| tr
.self_ty()),
438 "{}`{}` must implement `{}`",
439 if leading_ellipsis { "..." }
else { "" }
,
440 expected_trait_ref
.map(|tr
| tr
.self_ty()),
441 expected_trait_ref
.map(|tr
| tr
.print_only_trait_path()),
445 match (has_sub
, has_sup
) {
446 (Some(n1
), Some(n2
)) => {
449 ", for any two lifetimes `'{}` and `'{}`...",
450 std
::cmp
::min(n1
, n2
),
451 std
::cmp
::max(n1
, n2
),
454 (Some(n
), _
) | (_
, Some(n
)) => {
455 let _
= write
!(note
, ", for any lifetime `'{}`...", n
,);
458 if let Some(n
) = expected_has_vid
{
459 let _
= write
!(note
, ", for some specific lifetime `'{}`...", n
,);
467 let mut actual_trait_ref
= highlight_trait_ref(actual_trait_ref
);
468 actual_trait_ref
.highlight
.maybe_highlighting_region(vid
, actual_has_vid
);
470 let passive_voice
= match actual_has_vid
{
471 Some(_
) => any_self_ty_has_vid
,
475 let mut note
= if same_self_type
{
477 "...but it actually implements `{}`",
478 actual_trait_ref
.map(|tr
| tr
.print_only_trait_path()),
480 } else if passive_voice
{
482 "...but `{}` is actually implemented for the type `{}`",
483 actual_trait_ref
.map(|tr
| tr
.print_only_trait_path()),
484 actual_trait_ref
.map(|tr
| tr
.self_ty()),
488 "...but `{}` actually implements `{}`",
489 actual_trait_ref
.map(|tr
| tr
.self_ty()),
490 actual_trait_ref
.map(|tr
| tr
.print_only_trait_path()),
494 if let Some(n
) = actual_has_vid
{
495 let _
= write
!(note
, ", for some specific lifetime `'{}`", n
);