1 use hir::GenericParamKind;
3 fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
4 MultiSpan, SubdiagnosticMessage,
7 use rustc_hir::{FnRetTy, Ty};
8 use rustc_macros::{Diagnostic, Subdiagnostic};
9 use rustc_middle::ty::{Region, TyCtxt};
10 use rustc_span::symbol::kw;
11 use rustc_span::{symbol::Ident, BytePos, Span};
13 use crate::infer::error_reporting::{
14 need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
15 ObligationCauseAsDiagArg,
18 pub mod note_and_explain;
21 #[diag(infer_opaque_hidden_type)]
22 pub struct OpaqueHiddenTypeDiag {
27 pub opaque_type: Span,
29 pub hidden_type: Span,
33 #[diag(infer_type_annotations_needed, code = "E0282")]
34 pub struct AnnotationRequired<'a> {
37 pub source_kind: &'static str,
38 pub source_name: &'a str,
40 pub failure_span: Option<Span>,
42 pub bad_label: Option<InferenceBadError<'a>>,
44 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
46 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
49 // Copy of `AnnotationRequired` for E0283
51 #[diag(infer_type_annotations_needed, code = "E0283")]
52 pub struct AmbigousImpl<'a> {
55 pub source_kind: &'static str,
56 pub source_name: &'a str,
58 pub failure_span: Option<Span>,
60 pub bad_label: Option<InferenceBadError<'a>>,
62 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
64 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
67 // Copy of `AnnotationRequired` for E0284
69 #[diag(infer_type_annotations_needed, code = "E0284")]
70 pub struct AmbigousReturn<'a> {
73 pub source_kind: &'static str,
74 pub source_name: &'a str,
76 pub failure_span: Option<Span>,
78 pub bad_label: Option<InferenceBadError<'a>>,
80 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
82 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
86 #[diag(infer_need_type_info_in_generator, code = "E0698")]
87 pub struct NeedTypeInfoInGenerator<'a> {
90 pub generator_kind: GeneratorKindAsDiagArg,
92 pub bad_label: InferenceBadError<'a>,
95 // Used when a better one isn't available
96 #[derive(Subdiagnostic)]
97 #[label(infer_label_bad)]
98 pub struct InferenceBadError<'a> {
101 pub bad_kind: &'static str,
102 pub prefix_kind: UnderspecifiedArgKind,
103 pub has_parent: bool,
105 pub parent_prefix: &'a str,
106 pub parent_name: String,
110 #[derive(Subdiagnostic)]
111 pub enum SourceKindSubdiag<'a> {
113 infer_source_kind_subdiag_let,
115 code = ": {type_name}",
116 applicability = "has-placeholders"
124 x_kind: &'static str,
125 prefix_kind: UnderspecifiedArgKind,
129 #[label(infer_source_kind_subdiag_generic_label)]
136 parent_prefix: String,
140 infer_source_kind_subdiag_generic_suggestion,
143 applicability = "has-placeholders"
153 #[derive(Subdiagnostic)]
154 pub enum SourceKindMultiSuggestion<'a> {
155 #[multipart_suggestion(
156 infer_source_kind_fully_qualified,
158 applicability = "has-placeholders"
161 #[suggestion_part(code = "{def_path}({adjustment}")]
163 #[suggestion_part(code = "{successor_pos}")]
167 successor_pos: &'a str,
169 #[multipart_suggestion(
170 infer_source_kind_closure_return,
172 applicability = "has-placeholders"
175 #[suggestion_part(code = "{start_span_code}")]
177 start_span_code: String,
178 #[suggestion_part(code = " }}")]
179 end_span: Option<Span>,
183 impl<'a> SourceKindMultiSuggestion<'a> {
184 pub fn new_fully_qualified(
188 successor: (&'a str, BytePos),
190 Self::FullyQualified {
191 span_lo: span.shrink_to_lo(),
192 span_hi: span.shrink_to_hi().with_hi(successor.1),
195 successor_pos: successor.0,
199 pub fn new_closure_return(
201 data: &'a FnRetTy<'a>,
202 should_wrap_expr: Option<Span>,
204 let (arrow, post) = match data {
205 FnRetTy::DefaultReturn(_) => ("-> ", " "),
208 let (start_span, start_span_code, end_span) = match should_wrap_expr {
210 (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span))
212 None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None),
214 Self::ClosureReturn { start_span, start_span_code, end_span }
218 pub enum RegionOriginNote<'a> {
221 msg: DiagnosticMessage,
225 msg: DiagnosticMessage,
231 requirement: ObligationCauseAsDiagArg<'a>,
232 expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
236 impl AddToDiagnostic for RegionOriginNote<'_> {
237 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
239 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
241 let mut label_or_note = |span, msg: DiagnosticMessage| {
242 let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
243 let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
244 let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
245 if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
246 diag.span_label(span, msg);
247 } else if span_is_primary && expanded_sub_count == 0 {
250 diag.span_note(span, msg);
254 RegionOriginNote::Plain { span, msg } => {
255 label_or_note(span, msg);
257 RegionOriginNote::WithName { span, msg, name, continues } => {
258 label_or_note(span, msg);
259 diag.set_arg("name", name);
260 diag.set_arg("continues", continues);
262 RegionOriginNote::WithRequirement {
265 expected_found: Some((expected, found)),
267 label_or_note(span, fluent::infer_subtype);
268 diag.set_arg("requirement", requirement);
270 diag.note_expected_found(&"", expected, &"", found);
272 RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
273 // FIXME: this really should be handled at some earlier stage. Our
274 // handling of region checking when type errors are present is
276 label_or_note(span, fluent::infer_subtype_2);
277 diag.set_arg("requirement", requirement);
283 pub enum LifetimeMismatchLabels {
288 label_var1: Option<Ident>,
300 impl AddToDiagnostic for LifetimeMismatchLabels {
301 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
303 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
306 LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
307 diag.span_label(param_span, fluent::infer_declared_different);
308 diag.span_label(ret_span, fluent::infer_nothing);
309 diag.span_label(span, fluent::infer_data_returned);
310 diag.set_arg("label_var1_exists", label_var1.is_some());
311 diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
313 LifetimeMismatchLabels::Normal {
322 diag.span_label(ty_sup, fluent::infer_declared_multiple);
323 diag.span_label(ty_sub, fluent::infer_nothing);
324 diag.span_label(span, fluent::infer_data_lifetime_flow);
326 diag.span_label(ty_sup, fluent::infer_types_declared_different);
327 diag.span_label(ty_sub, fluent::infer_nothing);
328 diag.span_label(span, fluent::infer_data_flows);
329 diag.set_arg("label_var1_exists", label_var1.is_some());
332 label_var1.map(|x| x.to_string()).unwrap_or_default(),
334 diag.set_arg("label_var2_exists", label_var2.is_some());
337 label_var2.map(|x| x.to_string()).unwrap_or_default(),
345 pub struct AddLifetimeParamsSuggestion<'a> {
348 pub ty_sup: &'a Ty<'a>,
349 pub ty_sub: &'a Ty<'a>,
353 impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
354 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
356 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
358 let mut mk_suggestion = || {
360 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
361 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
362 ) = (self.ty_sub, self.ty_sup) else {
366 if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
370 let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
374 let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
376 let node = self.tcx.hir().get(hir_id);
377 let is_impl = matches!(&node, hir::Node::ImplItem(_));
378 let generics = match node {
379 hir::Node::Item(&hir::Item {
380 kind: hir::ItemKind::Fn(_, ref generics, ..),
383 | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
384 | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
388 let suggestion_param_name = generics
391 .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
392 .map(|p| p.name.ident().name)
393 .find(|i| *i != kw::UnderscoreLifetime);
394 let introduce_new = suggestion_param_name.is_none();
395 let suggestion_param_name =
396 suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
398 debug!(?lifetime_sup.span);
399 debug!(?lifetime_sub.span);
400 let make_suggestion = |span: rustc_span::Span| {
402 (span, format!("{}, ", suggestion_param_name))
403 } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
405 (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
407 (span, suggestion_param_name.clone())
410 let mut suggestions =
411 vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
414 let new_param_suggestion = if let Some(first) =
415 generics.params.iter().find(|p| !p.name.ident().span.is_empty())
417 (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
419 (generics.span, format!("<{}>", suggestion_param_name))
422 suggestions.push(new_param_suggestion);
425 diag.multipart_suggestion(
426 fluent::infer_lifetime_param_suggestion,
428 Applicability::MaybeIncorrect,
430 diag.set_arg("is_impl", is_impl);
433 if mk_suggestion() && self.add_note {
434 diag.note(fluent::infer_lifetime_param_suggestion_elided);
439 #[derive(Diagnostic)]
440 #[diag(infer_lifetime_mismatch, code = "E0623")]
441 pub struct LifetimeMismatch<'a> {
445 pub labels: LifetimeMismatchLabels,
447 pub suggestion: AddLifetimeParamsSuggestion<'a>,
450 pub struct IntroducesStaticBecauseUnmetLifetimeReq {
451 pub unmet_requirements: MultiSpan,
452 pub binding_span: Span,
455 impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
456 fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
458 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
460 self.unmet_requirements
461 .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
462 diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
466 // FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
467 #[derive(Subdiagnostic)]
468 pub enum DoesNotOutliveStaticFromImpl {
469 #[note(infer_does_not_outlive_static_from_impl)]
474 #[note(infer_does_not_outlive_static_from_impl)]
478 #[derive(Subdiagnostic)]
479 pub enum ImplicitStaticLifetimeSubdiag {
480 #[note(infer_implicit_static_lifetime_note)]
486 infer_implicit_static_lifetime_suggestion,
489 applicability = "maybe-incorrect"
497 #[derive(Diagnostic)]
498 #[diag(infer_mismatched_static_lifetime)]
499 pub struct MismatchedStaticLifetime<'a> {
501 pub cause_span: Span,
503 pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
505 pub expl: Option<note_and_explain::RegionExplanation<'a>>,
507 pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
508 #[subdiagnostic(eager)]
509 pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,