]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_infer/src/infer/error_reporting/note.rs
07a9eff2dbefe485bd08f3dbaacc6124352f5c9c
[rustc.git] / compiler / rustc_infer / src / infer / error_reporting / note.rs
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};
15 use rustc_span::symbol::kw;
16
17 use super::ObligationCauseAsDiagArg;
18
19 impl<'tcx> TypeErrCtxt<'_, '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
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
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, self.tcx.mk_ty_param(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
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 }