]>
Commit | Line | Data |
---|---|---|
136023e0 XL |
1 | //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate |
2 | //! to hold. | |
3 | ||
4 | use crate::infer::error_reporting::nice_region_error::NiceRegionError; | |
5 | use crate::infer::error_reporting::note_and_explain_region; | |
6 | use crate::infer::lexical_region_resolve::RegionResolutionError; | |
7 | use crate::infer::{SubregionOrigin, TypeTrace}; | |
8 | use crate::traits::ObligationCauseCode; | |
9 | use rustc_data_structures::stable_set::FxHashSet; | |
10 | use rustc_errors::{Applicability, ErrorReported}; | |
11 | use rustc_hir as hir; | |
12 | use rustc_hir::intravisit::Visitor; | |
13 | use rustc_middle::ty::{self, TypeVisitor}; | |
14 | use rustc_span::MultiSpan; | |
15 | ||
16 | impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { | |
17 | pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorReported> { | |
18 | let error = self.error.as_ref()?; | |
19 | debug!("try_report_mismatched_static_lifetime {:?}", error); | |
20 | ||
21 | let (origin, sub, sup) = match error.clone() { | |
22 | RegionResolutionError::ConcreteFailure(origin, sub, sup) => (origin, sub, sup), | |
23 | _ => return None, | |
24 | }; | |
25 | if *sub != ty::RegionKind::ReStatic { | |
26 | return None; | |
27 | } | |
28 | let cause = match origin { | |
29 | SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) => cause, | |
30 | _ => return None, | |
31 | }; | |
32 | let (parent, impl_def_id) = match &cause.code { | |
33 | ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id), | |
34 | _ => return None, | |
35 | }; | |
36 | let binding_span = match **parent { | |
37 | ObligationCauseCode::BindingObligation(_def_id, binding_span) => binding_span, | |
38 | _ => return None, | |
39 | }; | |
40 | let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type"); | |
41 | // FIXME: we should point at the lifetime | |
42 | let mut multi_span: MultiSpan = vec![binding_span].into(); | |
43 | multi_span | |
44 | .push_span_label(binding_span, "introduces a `'static` lifetime requirement".into()); | |
45 | err.span_note(multi_span, "because this has an unmet lifetime requirement"); | |
94222f64 | 46 | note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span)); |
136023e0 XL |
47 | if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) { |
48 | // If an impl is local, then maybe this isn't what they want. Try to | |
49 | // be as helpful as possible with implicit lifetimes. | |
50 | ||
51 | // First, let's get the hir self type of the impl | |
52 | let impl_self_ty = match impl_node { | |
53 | hir::Node::Item(hir::Item { | |
54 | kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }), | |
55 | .. | |
56 | }) => self_ty, | |
57 | _ => bug!("Node not an impl."), | |
58 | }; | |
59 | ||
60 | // Next, let's figure out the set of trait objects with implict static bounds | |
61 | let ty = self.tcx().type_of(*impl_def_id); | |
62 | let mut v = super::static_impl_trait::TraitObjectVisitor(FxHashSet::default()); | |
63 | v.visit_ty(ty); | |
64 | let mut traits = vec![]; | |
65 | for matching_def_id in v.0 { | |
66 | let mut hir_v = | |
67 | super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id); | |
68 | hir_v.visit_ty(&impl_self_ty); | |
69 | } | |
70 | ||
71 | if traits.is_empty() { | |
72 | // If there are no trait object traits to point at, either because | |
73 | // there aren't trait objects or because none are implicit, then just | |
74 | // write a single note on the impl itself. | |
75 | ||
76 | let impl_span = self.tcx().def_span(*impl_def_id); | |
77 | err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); | |
78 | } else { | |
79 | // Otherwise, point at all implicit static lifetimes | |
80 | ||
81 | err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); | |
82 | for span in &traits { | |
83 | err.span_note(*span, "this has an implicit `'static` lifetime requirement"); | |
84 | // It would be nice to put this immediately under the above note, but they get | |
85 | // pushed to the end. | |
86 | err.span_suggestion_verbose( | |
87 | span.shrink_to_hi(), | |
88 | "consider relaxing the implicit `'static` requirement", | |
89 | " + '_".to_string(), | |
90 | Applicability::MaybeIncorrect, | |
91 | ); | |
92 | } | |
93 | } | |
94 | } else { | |
95 | // Otherwise just point out the impl. | |
96 | ||
97 | let impl_span = self.tcx().def_span(*impl_def_id); | |
98 | err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); | |
99 | } | |
100 | err.emit(); | |
101 | Some(ErrorReported) | |
102 | } | |
103 | } |