• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::errors::{
2     note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
3     RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
4 };
5 use crate::fluent_generated as fluent;
6 use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
7 use crate::infer::{self, SubregionOrigin};
8 use rustc_errors::{
9     AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
10 };
11 use rustc_hir::def_id::{DefId, LocalDefId};
12 use rustc_middle::traits::ObligationCauseCode;
13 use rustc_middle::ty::error::TypeError;
14 use rustc_middle::ty::{self, IsSuggestable, Region, Ty};
15 use rustc_span::symbol::kw;
16 
17 use super::ObligationCauseAsDiagArg;
18 
19 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>)20     pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
21         match *origin {
22             infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
23                 span: trace.cause.span,
24                 requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
25                 expected_found: self.values_str(trace.values).map(|(e, f, _, _)| (e, f)),
26             }
27             .add_to_diagnostic(err),
28             infer::Reborrow(span) => {
29                 RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
30             }
31             infer::RelateObjectBound(span) => {
32                 RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
33                     .add_to_diagnostic(err);
34             }
35             infer::ReferenceOutlivesReferent(ty, span) => {
36                 RegionOriginNote::WithName {
37                     span,
38                     msg: fluent::infer_reference_outlives_referent,
39                     name: &self.ty_to_string(ty),
40                     continues: false,
41                 }
42                 .add_to_diagnostic(err);
43             }
44             infer::RelateParamBound(span, ty, opt_span) => {
45                 RegionOriginNote::WithName {
46                     span,
47                     msg: fluent::infer_relate_param_bound,
48                     name: &self.ty_to_string(ty),
49                     continues: opt_span.is_some(),
50                 }
51                 .add_to_diagnostic(err);
52                 if let Some(span) = opt_span {
53                     RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
54                         .add_to_diagnostic(err);
55                 }
56             }
57             infer::RelateRegionParamBound(span) => {
58                 RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
59                     .add_to_diagnostic(err);
60             }
61             infer::CompareImplItemObligation { span, .. } => {
62                 RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
63                     .add_to_diagnostic(err);
64             }
65             infer::CheckAssociatedTypeBounds { ref parent, .. } => {
66                 self.note_region_origin(err, &parent);
67             }
68             infer::AscribeUserTypeProvePredicate(span) => {
69                 RegionOriginNote::Plain {
70                     span,
71                     msg: fluent::infer_ascribe_user_type_prove_predicate,
72                 }
73                 .add_to_diagnostic(err);
74             }
75         }
76     }
77 
report_concrete_failure( &self, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>78     pub(super) fn report_concrete_failure(
79         &self,
80         origin: SubregionOrigin<'tcx>,
81         sub: Region<'tcx>,
82         sup: Region<'tcx>,
83     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
84         let mut err = match origin {
85             infer::Subtype(box trace) => {
86                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
87                 let mut err = self.report_and_explain_type_error(trace, terr);
88                 match (*sub, *sup) {
89                     (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
90                     (ty::RePlaceholder(_), _) => {
91                         note_and_explain_region(
92                             self.tcx,
93                             &mut err,
94                             "",
95                             sup,
96                             " doesn't meet the lifetime requirements",
97                             None,
98                         );
99                     }
100                     (_, ty::RePlaceholder(_)) => {
101                         note_and_explain_region(
102                             self.tcx,
103                             &mut err,
104                             "the required lifetime does not necessarily outlive ",
105                             sub,
106                             "",
107                             None,
108                         );
109                     }
110                     _ => {
111                         note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
112                         note_and_explain_region(
113                             self.tcx,
114                             &mut err,
115                             "...does not necessarily outlive ",
116                             sub,
117                             "",
118                             None,
119                         );
120                     }
121                 }
122                 err
123             }
124             infer::Reborrow(span) => {
125                 let reference_valid = note_and_explain::RegionExplanation::new(
126                     self.tcx,
127                     sub,
128                     None,
129                     note_and_explain::PrefixKind::RefValidFor,
130                     note_and_explain::SuffixKind::Continues,
131                 );
132                 let content_valid = note_and_explain::RegionExplanation::new(
133                     self.tcx,
134                     sup,
135                     None,
136                     note_and_explain::PrefixKind::ContentValidFor,
137                     note_and_explain::SuffixKind::Empty,
138                 );
139                 OutlivesContent {
140                     span,
141                     notes: reference_valid.into_iter().chain(content_valid).collect(),
142                 }
143                 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
144             }
145             infer::RelateObjectBound(span) => {
146                 let object_valid = note_and_explain::RegionExplanation::new(
147                     self.tcx,
148                     sub,
149                     None,
150                     note_and_explain::PrefixKind::TypeObjValidFor,
151                     note_and_explain::SuffixKind::Empty,
152                 );
153                 let pointer_valid = note_and_explain::RegionExplanation::new(
154                     self.tcx,
155                     sup,
156                     None,
157                     note_and_explain::PrefixKind::SourcePointerValidFor,
158                     note_and_explain::SuffixKind::Empty,
159                 );
160                 OutlivesBound {
161                     span,
162                     notes: object_valid.into_iter().chain(pointer_valid).collect(),
163                 }
164                 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
165             }
166             infer::RelateParamBound(span, ty, opt_span) => {
167                 let prefix = match *sub {
168                     ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
169                     _ => note_and_explain::PrefixKind::TypeOutlive,
170                 };
171                 let suffix = if opt_span.is_some() {
172                     note_and_explain::SuffixKind::ReqByBinding
173                 } else {
174                     note_and_explain::SuffixKind::Empty
175                 };
176                 let note = note_and_explain::RegionExplanation::new(
177                     self.tcx, sub, opt_span, prefix, suffix,
178                 );
179                 FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
180                     .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
181             }
182             infer::RelateRegionParamBound(span) => {
183                 let param_instantiated = note_and_explain::RegionExplanation::new(
184                     self.tcx,
185                     sup,
186                     None,
187                     note_and_explain::PrefixKind::LfParamInstantiatedWith,
188                     note_and_explain::SuffixKind::Empty,
189                 );
190                 let param_must_outlive = note_and_explain::RegionExplanation::new(
191                     self.tcx,
192                     sub,
193                     None,
194                     note_and_explain::PrefixKind::LfParamMustOutlive,
195                     note_and_explain::SuffixKind::Empty,
196                 );
197                 LfBoundNotSatisfied {
198                     span,
199                     notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
200                 }
201                 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
202             }
203             infer::ReferenceOutlivesReferent(ty, span) => {
204                 let pointer_valid = note_and_explain::RegionExplanation::new(
205                     self.tcx,
206                     sub,
207                     None,
208                     note_and_explain::PrefixKind::PointerValidFor,
209                     note_and_explain::SuffixKind::Empty,
210                 );
211                 let data_valid = note_and_explain::RegionExplanation::new(
212                     self.tcx,
213                     sup,
214                     None,
215                     note_and_explain::PrefixKind::DataValidFor,
216                     note_and_explain::SuffixKind::Empty,
217                 );
218                 RefLongerThanData {
219                     span,
220                     ty: self.resolve_vars_if_possible(ty),
221                     notes: pointer_valid.into_iter().chain(data_valid).collect(),
222                 }
223                 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
224             }
225             infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
226                 let mut err = self.report_extra_impl_obligation(
227                     span,
228                     impl_item_def_id,
229                     trait_item_def_id,
230                     &format!("`{}: {}`", sup, sub),
231                 );
232                 // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
233                 if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
234                     && generics.where_clause_span.contains(span)
235                 {
236                     self.suggest_copy_trait_method_bounds(
237                         trait_item_def_id,
238                         impl_item_def_id,
239                         &mut err,
240                     );
241                 }
242                 err
243             }
244             infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
245                 let mut err = self.report_concrete_failure(*parent, sub, sup);
246                 let trait_item_span = self.tcx.def_span(trait_item_def_id);
247                 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
248                 err.span_label(
249                     trait_item_span,
250                     format!("definition of `{}` from trait", item_name),
251                 );
252                 self.suggest_copy_trait_method_bounds(
253                     trait_item_def_id,
254                     impl_item_def_id,
255                     &mut err,
256                 );
257                 err
258             }
259             infer::AscribeUserTypeProvePredicate(span) => {
260                 let instantiated = note_and_explain::RegionExplanation::new(
261                     self.tcx,
262                     sup,
263                     None,
264                     note_and_explain::PrefixKind::LfInstantiatedWith,
265                     note_and_explain::SuffixKind::Empty,
266                 );
267                 let must_outlive = note_and_explain::RegionExplanation::new(
268                     self.tcx,
269                     sub,
270                     None,
271                     note_and_explain::PrefixKind::LfMustOutlive,
272                     note_and_explain::SuffixKind::Empty,
273                 );
274                 LfBoundNotSatisfied {
275                     span,
276                     notes: instantiated.into_iter().chain(must_outlive).collect(),
277                 }
278                 .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
279             }
280         };
281         if sub.is_error() || sup.is_error() {
282             err.delay_as_bug();
283         }
284         err
285     }
286 
suggest_copy_trait_method_bounds( &self, trait_item_def_id: DefId, impl_item_def_id: LocalDefId, err: &mut Diagnostic, )287     pub fn suggest_copy_trait_method_bounds(
288         &self,
289         trait_item_def_id: DefId,
290         impl_item_def_id: LocalDefId,
291         err: &mut Diagnostic,
292     ) {
293         // FIXME(compiler-errors): Right now this is only being used for region
294         // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
295         // but right now it's not really very smart when it comes to implicit `Sized`
296         // predicates and bounds on the trait itself.
297 
298         let Some(impl_def_id) =
299             self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; };
300         let Some(trait_ref) = self
301             .tcx
302             .impl_trait_ref(impl_def_id)
303             else { return; };
304         let trait_substs = trait_ref
305             .subst_identity()
306             // Replace the explicit self type with `Self` for better suggestion rendering
307             .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
308             .substs;
309         let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id)
310             .rebase_onto(self.tcx, impl_def_id, trait_substs);
311 
312         let Ok(trait_predicates) = self
313             .tcx
314             .explicit_predicates_of(trait_item_def_id)
315             .instantiate_own(self.tcx, trait_item_substs)
316             .map(|(pred, _)| {
317                 if pred.is_suggestable(self.tcx, false) {
318                     Ok(pred.to_string())
319                 } else {
320                     Err(())
321                 }
322             })
323             .collect::<Result<Vec<_>, ()>>() else { return; };
324 
325         let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
326 
327         let suggestion = if trait_predicates.is_empty() {
328             WhereClauseSuggestions::Remove { span: generics.where_clause_span }
329         } else {
330             let space = if generics.where_clause_span.is_empty() { " " } else { "" };
331             WhereClauseSuggestions::CopyPredicates {
332                 span: generics.where_clause_span,
333                 space,
334                 trait_predicates: trait_predicates.join(", "),
335             }
336         };
337         err.subdiagnostic(suggestion);
338     }
339 
report_placeholder_failure( &self, placeholder_origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>340     pub(super) fn report_placeholder_failure(
341         &self,
342         placeholder_origin: SubregionOrigin<'tcx>,
343         sub: Region<'tcx>,
344         sup: Region<'tcx>,
345     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
346         // I can't think how to do better than this right now. -nikomatsakis
347         debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
348         match placeholder_origin {
349             infer::Subtype(box ref trace)
350                 if matches!(
351                     &trace.cause.code().peel_derives(),
352                     ObligationCauseCode::BindingObligation(..)
353                         | ObligationCauseCode::ExprBindingObligation(..)
354                 ) =>
355             {
356                 // Hack to get around the borrow checker because trace.cause has an `Rc`.
357                 if let ObligationCauseCode::BindingObligation(_, span)
358                 | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
359                     &trace.cause.code().peel_derives()
360                 {
361                     let span = *span;
362                     let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
363                     err.span_note(span, "the lifetime requirement is introduced here");
364                     err
365                 } else {
366                     unreachable!()
367                 }
368             }
369             infer::Subtype(box trace) => {
370                 let terr = TypeError::RegionsPlaceholderMismatch;
371                 return self.report_and_explain_type_error(trace, terr);
372             }
373             _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
374         }
375     }
376 }
377