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