*[false] {""}
}
infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
+
+infer_region_explanation = {$pref_kind ->
+ *[should_not_happen] [{$pref_kind}]
+ [empty] {""}
+}{$pref_kind ->
+ [empty] {""}
+ *[other] {" "}
+}{$desc_kind ->
+ *[should_not_happen] [{$desc_kind}]
+ [restatic] the static lifetime
+ [reempty] the empty lifetime
+ [reemptyuni] the empty lifetime in universe {$desc_arg}
+ [revar] lifetime {$desc_arg}
+
+ [as_defined] the lifetime `{$desc_arg}` as defined here
+ [as_defined_anon] the anonymous lifetime as defined here
+ [defined_here] the anonymous lifetime defined here
+ [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here
+ [defined_here_reg] the lifetime `{$desc_arg}` as defined here
+}{$suff_kind ->
+ *[should_not_happen] [{$suff_kind}]
+ [empty]{""}
+ [continues] ...
+}
+
+infer_mismatched_static_lifetime = incompatible lifetime on type
+infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_msl_introduces_static = introduces a `'static` lifetime requirement
+infer_msl_unmet_req = because this has an unmet lifetime requirement
+infer_msl_trait_note = this has an implicit `'static` lifetime requirement
+infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
+++ /dev/null
-use hir::GenericParamKind;
-use rustc_errors::{
- fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString,
-};
-use rustc_hir as hir;
-use rustc_hir::{FnRetTy, Ty};
-use rustc_macros::SessionDiagnostic;
-use rustc_middle::ty::{Region, TyCtxt};
-use rustc_span::symbol::kw;
-use rustc_span::{symbol::Ident, BytePos, Span};
-
-use crate::infer::error_reporting::{
- need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
- ObligationCauseAsDiagArg,
-};
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::opaque_hidden_type)]
-pub struct OpaqueHiddenTypeDiag {
- #[primary_span]
- #[label]
- pub span: Span,
- #[note(infer::opaque_type)]
- pub opaque_type: Span,
- #[note(infer::hidden_type)]
- pub hidden_type: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0282")]
-pub struct AnnotationRequired<'a> {
- #[primary_span]
- pub span: Span,
- pub source_kind: &'static str,
- pub source_name: &'a str,
- #[label]
- pub failure_span: Option<Span>,
- #[subdiagnostic]
- pub bad_label: Option<InferenceBadError<'a>>,
- #[subdiagnostic]
- pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
- #[subdiagnostic]
- pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-// Copy of `AnnotationRequired` for E0283
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0283")]
-pub struct AmbigousImpl<'a> {
- #[primary_span]
- pub span: Span,
- pub source_kind: &'static str,
- pub source_name: &'a str,
- #[label]
- pub failure_span: Option<Span>,
- #[subdiagnostic]
- pub bad_label: Option<InferenceBadError<'a>>,
- #[subdiagnostic]
- pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
- #[subdiagnostic]
- pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-// Copy of `AnnotationRequired` for E0284
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0284")]
-pub struct AmbigousReturn<'a> {
- #[primary_span]
- pub span: Span,
- pub source_kind: &'static str,
- pub source_name: &'a str,
- #[label]
- pub failure_span: Option<Span>,
- #[subdiagnostic]
- pub bad_label: Option<InferenceBadError<'a>>,
- #[subdiagnostic]
- pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
- #[subdiagnostic]
- pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::need_type_info_in_generator, code = "E0698")]
-pub struct NeedTypeInfoInGenerator<'a> {
- #[primary_span]
- pub span: Span,
- pub generator_kind: GeneratorKindAsDiagArg,
- #[subdiagnostic]
- pub bad_label: InferenceBadError<'a>,
-}
-
-// Used when a better one isn't available
-#[derive(SessionSubdiagnostic)]
-#[label(infer::label_bad)]
-pub struct InferenceBadError<'a> {
- #[primary_span]
- pub span: Span,
- pub bad_kind: &'static str,
- pub prefix_kind: UnderspecifiedArgKind,
- pub has_parent: bool,
- pub prefix: &'a str,
- pub parent_prefix: &'a str,
- pub parent_name: String,
- pub name: String,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum SourceKindSubdiag<'a> {
- #[suggestion_verbose(
- infer::source_kind_subdiag_let,
- code = ": {type_name}",
- applicability = "has-placeholders"
- )]
- LetLike {
- #[primary_span]
- span: Span,
- name: String,
- type_name: String,
- kind: &'static str,
- x_kind: &'static str,
- prefix_kind: UnderspecifiedArgKind,
- prefix: &'a str,
- arg_name: String,
- },
- #[label(infer::source_kind_subdiag_generic_label)]
- GenericLabel {
- #[primary_span]
- span: Span,
- is_type: bool,
- param_name: String,
- parent_exists: bool,
- parent_prefix: String,
- parent_name: String,
- },
- #[suggestion_verbose(
- infer::source_kind_subdiag_generic_suggestion,
- code = "::<{args}>",
- applicability = "has-placeholders"
- )]
- GenericSuggestion {
- #[primary_span]
- span: Span,
- arg_count: usize,
- args: String,
- },
-}
-
-// Has to be implemented manually because multipart suggestions are not supported by the derive macro.
-// Would be a part of `SourceKindSubdiag` otherwise.
-pub enum SourceKindMultiSuggestion<'a> {
- FullyQualified {
- span: Span,
- def_path: String,
- adjustment: &'a str,
- successor: (&'a str, BytePos),
- },
- ClosureReturn {
- ty_info: String,
- data: &'a FnRetTy<'a>,
- should_wrap_expr: Option<Span>,
- },
-}
-
-impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
- match self {
- Self::FullyQualified { span, def_path, adjustment, successor } => {
- let suggestion = vec![
- (span.shrink_to_lo(), format!("{def_path}({adjustment}")),
- (span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
- ];
- diag.multipart_suggestion_verbose(
- fluent::infer::source_kind_fully_qualified,
- suggestion,
- rustc_errors::Applicability::HasPlaceholders,
- );
- }
- Self::ClosureReturn { ty_info, data, should_wrap_expr } => {
- let (arrow, post) = match data {
- FnRetTy::DefaultReturn(_) => ("-> ", " "),
- _ => ("", ""),
- };
- let suggestion = match should_wrap_expr {
- Some(end_span) => vec![
- (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post)),
- (end_span, " }".to_string()),
- ],
- None => vec![(data.span(), format!("{}{}{}", arrow, ty_info, post))],
- };
- diag.multipart_suggestion_verbose(
- fluent::infer::source_kind_closure_return,
- suggestion,
- rustc_errors::Applicability::HasPlaceholders,
- );
- }
- }
- }
-}
-
-pub enum RegionOriginNote<'a> {
- Plain {
- span: Span,
- msg: DiagnosticMessage,
- },
- WithName {
- span: Span,
- msg: DiagnosticMessage,
- name: &'a str,
- continues: bool,
- },
- WithRequirement {
- span: Span,
- requirement: ObligationCauseAsDiagArg<'a>,
- expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
- },
-}
-
-impl AddSubdiagnostic for RegionOriginNote<'_> {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
- let mut label_or_note = |span, msg: DiagnosticMessage| {
- let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
- let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
- let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
- if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
- diag.span_label(span, msg);
- } else if span_is_primary && expanded_sub_count == 0 {
- diag.note(msg);
- } else {
- diag.span_note(span, msg);
- }
- };
- match self {
- RegionOriginNote::Plain { span, msg } => {
- label_or_note(span, msg);
- }
- RegionOriginNote::WithName { span, msg, name, continues } => {
- label_or_note(span, msg);
- diag.set_arg("name", name);
- diag.set_arg("continues", continues);
- }
- RegionOriginNote::WithRequirement {
- span,
- requirement,
- expected_found: Some((expected, found)),
- } => {
- label_or_note(span, fluent::infer::subtype);
- diag.set_arg("requirement", requirement);
-
- diag.note_expected_found(&"", expected, &"", found);
- }
- RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
- // FIXME: this really should be handled at some earlier stage. Our
- // handling of region checking when type errors are present is
- // *terrible*.
- label_or_note(span, fluent::infer::subtype_2);
- diag.set_arg("requirement", requirement);
- }
- };
- }
-}
-
-pub enum LifetimeMismatchLabels {
- InRet {
- param_span: Span,
- ret_span: Span,
- span: Span,
- label_var1: Option<Ident>,
- },
- Normal {
- hir_equal: bool,
- ty_sup: Span,
- ty_sub: Span,
- span: Span,
- label_var1: Option<Ident>,
- label_var2: Option<Ident>,
- },
-}
-
-impl AddSubdiagnostic for LifetimeMismatchLabels {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
- match self {
- LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
- diag.span_label(param_span, fluent::infer::declared_different);
- diag.span_label(ret_span, fluent::infer::nothing);
- diag.span_label(span, fluent::infer::data_returned);
- diag.set_arg("label_var1_exists", label_var1.is_some());
- diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
- }
- LifetimeMismatchLabels::Normal {
- hir_equal,
- ty_sup,
- ty_sub,
- span,
- label_var1,
- label_var2,
- } => {
- if hir_equal {
- diag.span_label(ty_sup, fluent::infer::declared_multiple);
- diag.span_label(ty_sub, fluent::infer::nothing);
- diag.span_label(span, fluent::infer::data_lifetime_flow);
- } else {
- diag.span_label(ty_sup, fluent::infer::types_declared_different);
- diag.span_label(ty_sub, fluent::infer::nothing);
- diag.span_label(span, fluent::infer::data_flows);
- diag.set_arg("label_var1_exists", label_var1.is_some());
- diag.set_arg(
- "label_var1",
- label_var1.map(|x| x.to_string()).unwrap_or_default(),
- );
- diag.set_arg("label_var2_exists", label_var2.is_some());
- diag.set_arg(
- "label_var2",
- label_var2.map(|x| x.to_string()).unwrap_or_default(),
- );
- }
- }
- }
- }
-}
-
-pub struct AddLifetimeParamsSuggestion<'a> {
- pub tcx: TyCtxt<'a>,
- pub sub: Region<'a>,
- pub ty_sup: &'a Ty<'a>,
- pub ty_sub: &'a Ty<'a>,
- pub add_note: bool,
-}
-
-impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
- let mut mk_suggestion = || {
- let (
- hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
- hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
- ) = (self.ty_sub, self.ty_sup) else {
- return false;
- };
-
- if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
- return false;
- };
-
- let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
- return false;
- };
-
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-
- let node = self.tcx.hir().get(hir_id);
- let is_impl = matches!(&node, hir::Node::ImplItem(_));
- let generics = match node {
- hir::Node::Item(&hir::Item {
- kind: hir::ItemKind::Fn(_, ref generics, ..),
- ..
- })
- | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
- | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
- _ => return false,
- };
-
- let suggestion_param_name = generics
- .params
- .iter()
- .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
- .map(|p| p.name.ident().name)
- .find(|i| *i != kw::UnderscoreLifetime);
- let introduce_new = suggestion_param_name.is_none();
- let suggestion_param_name =
- suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
-
- debug!(?lifetime_sup.span);
- debug!(?lifetime_sub.span);
- let make_suggestion = |span: rustc_span::Span| {
- if span.is_empty() {
- (span, format!("{}, ", suggestion_param_name))
- } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
- {
- (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
- } else {
- (span, suggestion_param_name.clone())
- }
- };
- let mut suggestions =
- vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
-
- if introduce_new {
- let new_param_suggestion = if let Some(first) =
- generics.params.iter().find(|p| !p.name.ident().span.is_empty())
- {
- (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
- } else {
- (generics.span, format!("<{}>", suggestion_param_name))
- };
-
- suggestions.push(new_param_suggestion);
- }
-
- diag.multipart_suggestion(
- fluent::infer::lifetime_param_suggestion,
- suggestions,
- Applicability::MaybeIncorrect,
- );
- diag.set_arg("is_impl", is_impl);
- true
- };
- if mk_suggestion() && self.add_note {
- diag.note(fluent::infer::lifetime_param_suggestion_elided);
- }
- }
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::lifetime_mismatch, code = "E0623")]
-pub struct LifetimeMismatch<'a> {
- #[primary_span]
- pub span: Span,
- #[subdiagnostic]
- pub labels: LifetimeMismatchLabels,
- #[subdiagnostic]
- pub suggestion: AddLifetimeParamsSuggestion<'a>,
-}
--- /dev/null
+use hir::GenericParamKind;
+use rustc_errors::{
+ fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString,
+};
+use rustc_hir as hir;
+use rustc_hir::{FnRetTy, Ty};
+use rustc_macros::SessionDiagnostic;
+use rustc_middle::ty::{Region, TyCtxt};
+use rustc_span::symbol::kw;
+use rustc_span::{symbol::Ident, BytePos, Span};
+
+use crate::infer::error_reporting::{
+ need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
+ ObligationCauseAsDiagArg,
+};
+
+pub mod note_and_explain;
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::opaque_hidden_type)]
+pub struct OpaqueHiddenTypeDiag {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[note(infer::opaque_type)]
+ pub opaque_type: Span,
+ #[note(infer::hidden_type)]
+ pub hidden_type: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0282")]
+pub struct AnnotationRequired<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub source_kind: &'static str,
+ pub source_name: &'a str,
+ #[label]
+ pub failure_span: Option<Span>,
+ #[subdiagnostic]
+ pub bad_label: Option<InferenceBadError<'a>>,
+ #[subdiagnostic]
+ pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+ #[subdiagnostic]
+ pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0283
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0283")]
+pub struct AmbigousImpl<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub source_kind: &'static str,
+ pub source_name: &'a str,
+ #[label]
+ pub failure_span: Option<Span>,
+ #[subdiagnostic]
+ pub bad_label: Option<InferenceBadError<'a>>,
+ #[subdiagnostic]
+ pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+ #[subdiagnostic]
+ pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0284
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0284")]
+pub struct AmbigousReturn<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub source_kind: &'static str,
+ pub source_name: &'a str,
+ #[label]
+ pub failure_span: Option<Span>,
+ #[subdiagnostic]
+ pub bad_label: Option<InferenceBadError<'a>>,
+ #[subdiagnostic]
+ pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+ #[subdiagnostic]
+ pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::need_type_info_in_generator, code = "E0698")]
+pub struct NeedTypeInfoInGenerator<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub generator_kind: GeneratorKindAsDiagArg,
+ #[subdiagnostic]
+ pub bad_label: InferenceBadError<'a>,
+}
+
+// Used when a better one isn't available
+#[derive(SessionSubdiagnostic)]
+#[label(infer::label_bad)]
+pub struct InferenceBadError<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub bad_kind: &'static str,
+ pub prefix_kind: UnderspecifiedArgKind,
+ pub has_parent: bool,
+ pub prefix: &'a str,
+ pub parent_prefix: &'a str,
+ pub parent_name: String,
+ pub name: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum SourceKindSubdiag<'a> {
+ #[suggestion_verbose(
+ infer::source_kind_subdiag_let,
+ code = ": {type_name}",
+ applicability = "has-placeholders"
+ )]
+ LetLike {
+ #[primary_span]
+ span: Span,
+ name: String,
+ type_name: String,
+ kind: &'static str,
+ x_kind: &'static str,
+ prefix_kind: UnderspecifiedArgKind,
+ prefix: &'a str,
+ arg_name: String,
+ },
+ #[label(infer::source_kind_subdiag_generic_label)]
+ GenericLabel {
+ #[primary_span]
+ span: Span,
+ is_type: bool,
+ param_name: String,
+ parent_exists: bool,
+ parent_prefix: String,
+ parent_name: String,
+ },
+ #[suggestion_verbose(
+ infer::source_kind_subdiag_generic_suggestion,
+ code = "::<{args}>",
+ applicability = "has-placeholders"
+ )]
+ GenericSuggestion {
+ #[primary_span]
+ span: Span,
+ arg_count: usize,
+ args: String,
+ },
+}
+
+// Has to be implemented manually because multipart suggestions are not supported by the derive macro.
+// Would be a part of `SourceKindSubdiag` otherwise.
+pub enum SourceKindMultiSuggestion<'a> {
+ FullyQualified {
+ span: Span,
+ def_path: String,
+ adjustment: &'a str,
+ successor: (&'a str, BytePos),
+ },
+ ClosureReturn {
+ ty_info: String,
+ data: &'a FnRetTy<'a>,
+ should_wrap_expr: Option<Span>,
+ },
+}
+
+impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> {
+ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+ match self {
+ Self::FullyQualified { span, def_path, adjustment, successor } => {
+ let suggestion = vec![
+ (span.shrink_to_lo(), format!("{def_path}({adjustment}")),
+ (span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
+ ];
+ diag.multipart_suggestion_verbose(
+ fluent::infer::source_kind_fully_qualified,
+ suggestion,
+ rustc_errors::Applicability::HasPlaceholders,
+ );
+ }
+ Self::ClosureReturn { ty_info, data, should_wrap_expr } => {
+ let (arrow, post) = match data {
+ FnRetTy::DefaultReturn(_) => ("-> ", " "),
+ _ => ("", ""),
+ };
+ let suggestion = match should_wrap_expr {
+ Some(end_span) => vec![
+ (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post)),
+ (end_span, " }".to_string()),
+ ],
+ None => vec![(data.span(), format!("{}{}{}", arrow, ty_info, post))],
+ };
+ diag.multipart_suggestion_verbose(
+ fluent::infer::source_kind_closure_return,
+ suggestion,
+ rustc_errors::Applicability::HasPlaceholders,
+ );
+ }
+ }
+ }
+}
+
+pub enum RegionOriginNote<'a> {
+ Plain {
+ span: Span,
+ msg: DiagnosticMessage,
+ },
+ WithName {
+ span: Span,
+ msg: DiagnosticMessage,
+ name: &'a str,
+ continues: bool,
+ },
+ WithRequirement {
+ span: Span,
+ requirement: ObligationCauseAsDiagArg<'a>,
+ expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
+ },
+}
+
+impl AddSubdiagnostic for RegionOriginNote<'_> {
+ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+ let mut label_or_note = |span, msg: DiagnosticMessage| {
+ let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
+ let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
+ let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
+ if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
+ diag.span_label(span, msg);
+ } else if span_is_primary && expanded_sub_count == 0 {
+ diag.note(msg);
+ } else {
+ diag.span_note(span, msg);
+ }
+ };
+ match self {
+ RegionOriginNote::Plain { span, msg } => {
+ label_or_note(span, msg);
+ }
+ RegionOriginNote::WithName { span, msg, name, continues } => {
+ label_or_note(span, msg);
+ diag.set_arg("name", name);
+ diag.set_arg("continues", continues);
+ }
+ RegionOriginNote::WithRequirement {
+ span,
+ requirement,
+ expected_found: Some((expected, found)),
+ } => {
+ label_or_note(span, fluent::infer::subtype);
+ diag.set_arg("requirement", requirement);
+
+ diag.note_expected_found(&"", expected, &"", found);
+ }
+ RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
+ // FIXME: this really should be handled at some earlier stage. Our
+ // handling of region checking when type errors are present is
+ // *terrible*.
+ label_or_note(span, fluent::infer::subtype_2);
+ diag.set_arg("requirement", requirement);
+ }
+ };
+ }
+}
+
+pub enum LifetimeMismatchLabels {
+ InRet {
+ param_span: Span,
+ ret_span: Span,
+ span: Span,
+ label_var1: Option<Ident>,
+ },
+ Normal {
+ hir_equal: bool,
+ ty_sup: Span,
+ ty_sub: Span,
+ span: Span,
+ label_var1: Option<Ident>,
+ label_var2: Option<Ident>,
+ },
+}
+
+impl AddSubdiagnostic for LifetimeMismatchLabels {
+ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+ match self {
+ LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
+ diag.span_label(param_span, fluent::infer::declared_different);
+ diag.span_label(ret_span, fluent::infer::nothing);
+ diag.span_label(span, fluent::infer::data_returned);
+ diag.set_arg("label_var1_exists", label_var1.is_some());
+ diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
+ }
+ LifetimeMismatchLabels::Normal {
+ hir_equal,
+ ty_sup,
+ ty_sub,
+ span,
+ label_var1,
+ label_var2,
+ } => {
+ if hir_equal {
+ diag.span_label(ty_sup, fluent::infer::declared_multiple);
+ diag.span_label(ty_sub, fluent::infer::nothing);
+ diag.span_label(span, fluent::infer::data_lifetime_flow);
+ } else {
+ diag.span_label(ty_sup, fluent::infer::types_declared_different);
+ diag.span_label(ty_sub, fluent::infer::nothing);
+ diag.span_label(span, fluent::infer::data_flows);
+ diag.set_arg("label_var1_exists", label_var1.is_some());
+ diag.set_arg(
+ "label_var1",
+ label_var1.map(|x| x.to_string()).unwrap_or_default(),
+ );
+ diag.set_arg("label_var2_exists", label_var2.is_some());
+ diag.set_arg(
+ "label_var2",
+ label_var2.map(|x| x.to_string()).unwrap_or_default(),
+ );
+ }
+ }
+ }
+ }
+}
+
+pub struct AddLifetimeParamsSuggestion<'a> {
+ pub tcx: TyCtxt<'a>,
+ pub sub: Region<'a>,
+ pub ty_sup: &'a Ty<'a>,
+ pub ty_sub: &'a Ty<'a>,
+ pub add_note: bool,
+}
+
+impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
+ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+ let mut mk_suggestion = || {
+ let (
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+ ) = (self.ty_sub, self.ty_sup) else {
+ return false;
+ };
+
+ if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
+ return false;
+ };
+
+ let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
+ return false;
+ };
+
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
+
+ let node = self.tcx.hir().get(hir_id);
+ let is_impl = matches!(&node, hir::Node::ImplItem(_));
+ let generics = match node {
+ hir::Node::Item(&hir::Item {
+ kind: hir::ItemKind::Fn(_, ref generics, ..),
+ ..
+ })
+ | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
+ | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+ _ => return false,
+ };
+
+ let suggestion_param_name = generics
+ .params
+ .iter()
+ .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+ .map(|p| p.name.ident().name)
+ .find(|i| *i != kw::UnderscoreLifetime);
+ let introduce_new = suggestion_param_name.is_none();
+ let suggestion_param_name =
+ suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+
+ debug!(?lifetime_sup.span);
+ debug!(?lifetime_sub.span);
+ let make_suggestion = |span: rustc_span::Span| {
+ if span.is_empty() {
+ (span, format!("{}, ", suggestion_param_name))
+ } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
+ {
+ (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
+ } else {
+ (span, suggestion_param_name.clone())
+ }
+ };
+ let mut suggestions =
+ vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
+
+ if introduce_new {
+ let new_param_suggestion = if let Some(first) =
+ generics.params.iter().find(|p| !p.name.ident().span.is_empty())
+ {
+ (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+ } else {
+ (generics.span, format!("<{}>", suggestion_param_name))
+ };
+
+ suggestions.push(new_param_suggestion);
+ }
+
+ diag.multipart_suggestion(
+ fluent::infer::lifetime_param_suggestion,
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ diag.set_arg("is_impl", is_impl);
+ true
+ };
+ if mk_suggestion() && self.add_note {
+ diag.note(fluent::infer::lifetime_param_suggestion_elided);
+ }
+ }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::lifetime_mismatch, code = "E0623")]
+pub struct LifetimeMismatch<'a> {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub labels: LifetimeMismatchLabels,
+ #[subdiagnostic]
+ pub suggestion: AddLifetimeParamsSuggestion<'a>,
+}
+
+pub mod mismatched_static_lifetime {
+ use rustc_errors::{self, fluent, AddSubdiagnostic, MultiSpan};
+ use rustc_span::Span;
+
+ use super::note_and_explain;
+
+ pub struct LabeledMultiSpan {
+ pub multi_span: MultiSpan,
+ pub binding_span: Span,
+ }
+
+ impl AddSubdiagnostic for LabeledMultiSpan {
+ fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
+ self.multi_span
+ .push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
+ diag.span_note(self.multi_span, fluent::infer::msl_unmet_req);
+ }
+ }
+
+ pub struct ImplNote {
+ pub impl_span: Option<Span>,
+ }
+
+ impl AddSubdiagnostic for ImplNote {
+ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+ match self.impl_span {
+ Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
+ None => diag.note(fluent::infer::msl_impl_note),
+ };
+ }
+ }
+
+ #[derive(SessionSubdiagnostic)]
+ pub enum TraitSubdiag {
+ #[note(infer::msl_trait_note)]
+ Note {
+ #[primary_span]
+ span: Span,
+ },
+ #[suggestion_verbose(
+ infer::msl_trait_sugg,
+ code = " + '_",
+ applicability = "maybe-incorrect"
+ )]
+ Sugg {
+ #[primary_span]
+ span: Span,
+ },
+ }
+
+ #[derive(SessionDiagnostic)]
+ #[diag(infer::mismatched_static_lifetime)]
+ pub struct MismatchedStaticLifetime<'a> {
+ #[primary_span]
+ pub cause_span: Span,
+ #[subdiagnostic]
+ pub multispan_subdiag: LabeledMultiSpan,
+ #[subdiagnostic]
+ pub expl: Option<note_and_explain::RegionExplanation<'a>>,
+ #[subdiagnostic]
+ pub impl_note: ImplNote,
+ #[subdiagnostic]
+ pub trait_subdiags: Vec<TraitSubdiag>,
+ }
+}
--- /dev/null
+use crate::infer::error_reporting::nice_region_error::find_anon_type;
+use rustc_errors::{self, fluent, AddSubdiagnostic};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::{symbol::kw, Span};
+
+#[derive(Default)]
+struct DescriptionCtx<'a> {
+ span: Option<Span>,
+ kind: &'a str,
+ arg: String,
+ num_arg: u32,
+}
+
+impl<'a> DescriptionCtx<'a> {
+ fn new<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ region: ty::Region<'tcx>,
+ alt_span: Option<Span>,
+ ) -> Option<Self> {
+ let mut me = DescriptionCtx::default();
+ me.span = alt_span;
+ match *region {
+ ty::ReEarlyBound(_) | ty::ReFree(_) => {
+ return Self::from_early_bound_and_free_regions(tcx, region);
+ }
+ ty::ReStatic => {
+ me.kind = "restatic";
+ }
+
+ ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty",
+
+ // uh oh, hope no user ever sees THIS
+ ty::ReEmpty(ui) => {
+ me.kind = "reemptyuni";
+ me.arg = format!("{:?}", ui);
+ }
+
+ ty::RePlaceholder(_) => return None,
+
+ // FIXME(#13998) RePlaceholder should probably print like
+ // ReFree rather than dumping Debug output on the user.
+ //
+ // We shouldn't really be having unification failures with ReVar
+ // and ReLateBound though.
+ ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+ me.kind = "revar";
+ me.arg = format!("{:?}", region);
+ }
+ };
+ Some(me)
+ }
+
+ fn from_early_bound_and_free_regions<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ region: ty::Region<'tcx>,
+ ) -> Option<Self> {
+ let mut me = DescriptionCtx::default();
+ let scope = region.free_region_binding_scope(tcx).expect_local();
+ match *region {
+ ty::ReEarlyBound(ref br) => {
+ let mut sp = tcx.def_span(scope);
+ if let Some(param) =
+ tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+ {
+ sp = param.span;
+ }
+ if br.has_name() {
+ me.kind = "as_defined";
+ me.arg = br.name.to_string();
+ } else {
+ me.kind = "as_defined_anon";
+ };
+ me.span = Some(sp)
+ }
+ ty::ReFree(ref fr) => {
+ if !fr.bound_region.is_named()
+ && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+ {
+ me.kind = "defined_here";
+ me.span = Some(ty.span);
+ } else {
+ match fr.bound_region {
+ ty::BoundRegionKind::BrNamed(_, name) => {
+ let mut sp = tcx.def_span(scope);
+ if let Some(param) =
+ tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+ {
+ sp = param.span;
+ }
+ if name == kw::UnderscoreLifetime {
+ me.kind = "as_defined_anon";
+ } else {
+ me.kind = "as_defined";
+ me.arg = name.to_string();
+ };
+ me.span = Some(sp);
+ }
+ ty::BrAnon(idx) => {
+ me.kind = "anon_num_here";
+ me.num_arg = idx+1;
+ me.span = Some(tcx.def_span(scope));
+ },
+ _ => {
+ me.kind = "defined_here_reg";
+ me.arg = region.to_string();
+ me.span = Some(tcx.def_span(scope));
+ },
+ }
+ }
+ }
+ _ => bug!(),
+ }
+ Some(me)
+ }
+
+ fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
+ diag.set_arg("desc_kind", self.kind);
+ diag.set_arg("desc_arg", self.arg);
+ diag.set_arg("desc_num_arg", self.num_arg);
+ }
+}
+
+pub enum PrefixKind {
+ Empty,
+}
+
+pub enum SuffixKind {
+ Continues,
+}
+
+impl PrefixKind {
+ fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
+ match self {
+ Self::Empty => diag.set_arg("pref_kind", "empty"),
+ };
+ }
+}
+
+impl SuffixKind {
+ fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
+ match self {
+ Self::Continues => diag.set_arg("suff_kind", "continues"),
+ };
+ }
+}
+
+pub struct RegionExplanation<'a> {
+ desc: DescriptionCtx<'a>,
+ prefix: PrefixKind,
+ suffix: SuffixKind,
+}
+
+impl RegionExplanation<'_> {
+ pub fn new<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ region: ty::Region<'tcx>,
+ alt_span: Option<Span>,
+ prefix: PrefixKind,
+ suffix: SuffixKind,
+ ) -> Option<Self> {
+ Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
+ }
+}
+
+impl AddSubdiagnostic for RegionExplanation<'_> {
+ fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+ if let Some(span) = self.desc.span {
+ diag.span_note(span, fluent::infer::region_explanation);
+ } else {
+ diag.note(fluent::infer::region_explanation);
+ }
+ self.desc.add_to(diag);
+ self.prefix.add_to(diag);
+ self.suffix.add_to(diag);
+ }
+}
//! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
//! to hold.
+use crate::errors::mismatched_static_lifetime::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
+use crate::errors::{mismatched_static_lifetime::LabeledMultiSpan, note_and_explain};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::infer::error_reporting::note_and_explain_region;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::ObligationCauseCode;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_middle::ty::TypeVisitor;
= *parent.code() else {
return None;
};
- let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
+
// FIXME: we should point at the lifetime
- let mut multi_span: MultiSpan = vec![binding_span].into();
- multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
- err.span_note(multi_span, "because this has an unmet lifetime requirement");
- note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
+ let multi_span: MultiSpan = vec![binding_span].into();
+ let multispan_subdiag = LabeledMultiSpan { multi_span, binding_span };
+
+ let expl = note_and_explain::RegionExplanation::new(
+ self.tcx(),
+ sup,
+ Some(binding_span),
+ note_and_explain::PrefixKind::Empty,
+ note_and_explain::SuffixKind::Continues,
+ );
+ let mut impl_span = None;
+ let mut trait_subdiags = Vec::new();
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
// If an impl is local, then maybe this isn't what they want. Try to
// be as helpful as possible with implicit lifetimes.
// there aren't trait objects or because none are implicit, then just
// write a single note on the impl itself.
- let impl_span = self.tcx().def_span(*impl_def_id);
- err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+ impl_span = Some(self.tcx().def_span(*impl_def_id));
} else {
// Otherwise, point at all implicit static lifetimes
- err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
for span in &traits {
- err.span_note(*span, "this has an implicit `'static` lifetime requirement");
+ trait_subdiags.push(TraitSubdiag::Note { span: *span });
// It would be nice to put this immediately under the above note, but they get
// pushed to the end.
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "consider relaxing the implicit `'static` requirement",
- " + '_",
- Applicability::MaybeIncorrect,
- );
+ trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
}
}
} else {
// Otherwise just point out the impl.
- let impl_span = self.tcx().def_span(*impl_def_id);
- err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+ impl_span = Some(self.tcx().def_span(*impl_def_id));
}
- let reported = err.emit();
+ let err = MismatchedStaticLifetime {
+ cause_span: cause.span,
+ multispan_subdiag,
+ expl,
+ impl_note: ImplNote { impl_span },
+ trait_subdiags,
+ };
+ let reported = self.tcx().sess.emit_err(err);
Some(reported)
}
}