| use rustc_ast::Path; | |
| use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; | |
| use rustc_errors::codes::*; | |
| use rustc_errors::{ | |
| Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, | |
| EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, | |
| }; | |
| use rustc_hir::def::DefKind; | |
| use rustc_hir::def_id::{DefId, LocalDefId}; | |
| use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; | |
| use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node}; | |
| use rustc_macros::{Diagnostic, Subdiagnostic}; | |
| use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; | |
| use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, GenericArg, Region, Ty, TyCtxt}; | |
| use rustc_span::{BytePos, Ident, Span, Symbol, kw}; | |
| use crate::error_reporting::infer::ObligationCauseAsDiagArg; | |
| use crate::error_reporting::infer::need_type_info::UnderspecifiedArgKind; | |
| use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; | |
| pub mod note_and_explain; | |
| #[derive(Diagnostic)] | |
| #[diag("unable to construct a constant value for the unevaluated constant {$unevaluated}")] | |
| pub struct UnableToConstructConstantValue<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| pub unevaluated: ty::UnevaluatedConst<'a>, | |
| } | |
| #[derive(Diagnostic)] | |
| pub enum InvalidOnClause { | |
| #[diag("empty `on`-clause in `#[rustc_on_unimplemented]`", code = E0232)] | |
| Empty { | |
| #[primary_span] | |
| #[label("empty `on`-clause here")] | |
| span: Span, | |
| }, | |
| #[diag("expected a single predicate in `not(..)`", code = E0232)] | |
| ExpectedOnePredInNot { | |
| #[primary_span] | |
| #[label("unexpected quantity of predicates here")] | |
| span: Span, | |
| }, | |
| #[diag("literals inside `on`-clauses are not supported", code = E0232)] | |
| UnsupportedLiteral { | |
| #[primary_span] | |
| #[label("unexpected literal here")] | |
| span: Span, | |
| }, | |
| #[diag("expected an identifier inside this `on`-clause", code = E0232)] | |
| ExpectedIdentifier { | |
| #[primary_span] | |
| #[label("expected an identifier here, not `{$path}`")] | |
| span: Span, | |
| path: Path, | |
| }, | |
| #[diag("this predicate is invalid", code = E0232)] | |
| InvalidPredicate { | |
| #[primary_span] | |
| #[label("expected one of `any`, `all` or `not` here, not `{$invalid_pred}`")] | |
| span: Span, | |
| invalid_pred: Symbol, | |
| }, | |
| #[diag("invalid flag in `on`-clause", code = E0232)] | |
| InvalidFlag { | |
| #[primary_span] | |
| #[label( | |
| "expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}`" | |
| )] | |
| span: Span, | |
| invalid_flag: Symbol, | |
| }, | |
| #[diag("invalid name in `on`-clause", code = E0232)] | |
| InvalidName { | |
| #[primary_span] | |
| #[label( | |
| "expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `{$invalid_name}`" | |
| )] | |
| span: Span, | |
| invalid_name: Symbol, | |
| }, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("this attribute must have a value", code = E0232)] | |
| #[note("e.g. `#[rustc_on_unimplemented(message=\"foo\")]`")] | |
| pub struct NoValueInOnUnimplemented { | |
| #[primary_span] | |
| #[label("expected value here")] | |
| pub span: Span, | |
| } | |
| pub struct NegativePositiveConflict<'tcx> { | |
| pub impl_span: Span, | |
| pub trait_desc: ty::TraitRef<'tcx>, | |
| pub self_ty: Option<Ty<'tcx>>, | |
| pub negative_impl_span: Result<Span, Symbol>, | |
| pub positive_impl_span: Result<Span, Symbol>, | |
| } | |
| impl<G: EmissionGuarantee> Diagnostic<'_, G> for NegativePositiveConflict<'_> { | |
| #[track_caller] | |
| fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { | |
| let mut diag = Diag::new( | |
| dcx, | |
| level, | |
| msg!( | |
| "found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> | |
| [none] {\"\"} | |
| *[default] {\" \"}for type `{$self_desc}` | |
| }:" | |
| ), | |
| ); | |
| diag.arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); | |
| diag.arg("self_desc", self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string())); | |
| diag.span(self.impl_span); | |
| diag.code(E0751); | |
| match self.negative_impl_span { | |
| Ok(span) => { | |
| diag.span_label(span, msg!("negative implementation here")); | |
| } | |
| Err(cname) => { | |
| diag.note(msg!("negative implementation in crate `{$negative_impl_cname}`")); | |
| diag.arg("negative_impl_cname", cname.to_string()); | |
| } | |
| } | |
| match self.positive_impl_span { | |
| Ok(span) => { | |
| diag.span_label(span, msg!("positive implementation here")); | |
| } | |
| Err(cname) => { | |
| diag.note(msg!("positive implementation in crate `{$positive_impl_cname}`")); | |
| diag.arg("positive_impl_cname", cname.to_string()); | |
| } | |
| } | |
| diag | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("overflow evaluating associated type `{$ty}`")] | |
| pub struct InherentProjectionNormalizationOverflow { | |
| #[primary_span] | |
| pub span: Span, | |
| pub ty: String, | |
| } | |
| pub enum AdjustSignatureBorrow { | |
| Borrow { to_borrow: Vec<(Span, String)> }, | |
| RemoveBorrow { remove_borrow: Vec<(Span, String)> }, | |
| } | |
| impl Subdiagnostic for AdjustSignatureBorrow { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| match self { | |
| AdjustSignatureBorrow::Borrow { to_borrow } => { | |
| diag.arg("borrow_len", to_borrow.len()); | |
| diag.multipart_suggestion_verbose( | |
| msg!( | |
| "consider adjusting the signature so it borrows its {$borrow_len -> | |
| [one] argument | |
| *[other] arguments | |
| }" | |
| ), | |
| to_borrow, | |
| Applicability::MaybeIncorrect, | |
| ); | |
| } | |
| AdjustSignatureBorrow::RemoveBorrow { remove_borrow } => { | |
| diag.arg("remove_borrow_len", remove_borrow.len()); | |
| diag.multipart_suggestion_verbose( | |
| msg!( | |
| "consider adjusting the signature so it does not borrow its {$remove_borrow_len -> | |
| [one] argument | |
| *[other] arguments | |
| }" | |
| ), | |
| remove_borrow, | |
| Applicability::MaybeIncorrect, | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("expected a closure that implements the `{$trait_prefix}{$expected}` trait, but this closure only implements `{$trait_prefix}{$found}`", code = E0525)] | |
| pub struct ClosureKindMismatch { | |
| #[primary_span] | |
| #[label("this closure implements `{$trait_prefix}{$found}`, not `{$trait_prefix}{$expected}`")] | |
| pub closure_span: Span, | |
| pub expected: ClosureKind, | |
| pub found: ClosureKind, | |
| #[label("the requirement to implement `{$trait_prefix}{$expected}` derives from here")] | |
| pub cause_span: Span, | |
| pub trait_prefix: &'static str, | |
| #[subdiagnostic] | |
| pub fn_once_label: Option<ClosureFnOnceLabel>, | |
| #[subdiagnostic] | |
| pub fn_mut_label: Option<ClosureFnMutLabel>, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[label( | |
| "closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment" | |
| )] | |
| pub struct ClosureFnOnceLabel { | |
| #[primary_span] | |
| pub span: Span, | |
| pub place: String, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[label("closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here")] | |
| pub struct ClosureFnMutLabel { | |
| #[primary_span] | |
| pub span: Span, | |
| pub place: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "{$coro_kind}closure does not implement `{$kind}` because it captures state from its environment" | |
| )] | |
| pub(crate) struct CoroClosureNotFn { | |
| #[primary_span] | |
| pub span: Span, | |
| pub kind: &'static str, | |
| pub coro_kind: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("{$source_kind -> | |
| [closure] type annotations needed for the closure `{$source_name}` | |
| [normal] type annotations needed for `{$source_name}` | |
| *[other] 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("type must be known at this point")] | |
| 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(Diagnostic)] | |
| #[diag("{$source_kind -> | |
| [closure] type annotations needed for the closure `{$source_name}` | |
| [normal] type annotations needed for `{$source_name}` | |
| *[other] type annotations needed | |
| }", code = E0283)] | |
| pub struct AmbiguousImpl<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| pub source_kind: &'static str, | |
| pub source_name: &'a str, | |
| #[label("type must be known at this point")] | |
| 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(Diagnostic)] | |
| #[diag("{$source_kind -> | |
| [closure] type annotations needed for the closure `{$source_name}` | |
| [normal] type annotations needed for `{$source_name}` | |
| *[other] type annotations needed | |
| }", code = E0284)] | |
| pub struct AmbiguousReturn<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| pub source_kind: &'static str, | |
| pub source_name: &'a str, | |
| #[label("type must be known at this point")] | |
| 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>>, | |
| } | |
| // Used when a better one isn't available | |
| #[derive(Subdiagnostic)] | |
| #[label( | |
| "{$bad_kind -> | |
| *[other] cannot infer type | |
| [more_info] cannot infer {$prefix_kind -> | |
| *[type] type for {$prefix} | |
| [const_with_param] the value of const parameter | |
| [const] the value of the constant | |
| } `{$name}`{$has_parent -> | |
| [true] {\" \"}declared on the {$parent_prefix} `{$parent_name}` | |
| *[false] {\"\"} | |
| } | |
| }" | |
| )] | |
| 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(Subdiagnostic)] | |
| pub enum SourceKindSubdiag<'a> { | |
| #[suggestion( | |
| "{$kind -> | |
| [with_pattern] consider giving `{$name}` an explicit type | |
| [closure] consider giving this closure parameter an explicit type | |
| *[other] consider giving this pattern a type | |
| }{$x_kind -> | |
| [has_name] , where the {$prefix_kind -> | |
| *[type] type for {$prefix} | |
| [const_with_param] value of const parameter | |
| [const] value of the constant | |
| } `{$arg_name}` is specified | |
| [underscore] , where the placeholders `_` are specified | |
| *[empty] {\"\"} | |
| }", | |
| style = "verbose", | |
| 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( | |
| "cannot infer {$is_type -> | |
| [true] type | |
| *[false] the value | |
| } of the {$is_type -> | |
| [true] type | |
| *[false] const | |
| } {$parent_exists -> | |
| [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` | |
| *[false] parameter {$param_name} | |
| }" | |
| )] | |
| GenericLabel { | |
| #[primary_span] | |
| span: Span, | |
| is_type: bool, | |
| param_name: String, | |
| parent_exists: bool, | |
| parent_prefix: String, | |
| parent_name: String, | |
| }, | |
| #[suggestion( | |
| "consider specifying the generic {$arg_count -> | |
| [one] argument | |
| *[other] arguments | |
| }", | |
| style = "verbose", | |
| code = "::<{args}>", | |
| applicability = "has-placeholders" | |
| )] | |
| GenericSuggestion { | |
| #[primary_span] | |
| span: Span, | |
| arg_count: usize, | |
| args: String, | |
| }, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum SourceKindMultiSuggestion<'a> { | |
| #[multipart_suggestion( | |
| "try using a fully qualified path to specify the expected types", | |
| style = "verbose", | |
| applicability = "has-placeholders" | |
| )] | |
| FullyQualified { | |
| #[suggestion_part(code = "{def_path}({adjustment}")] | |
| span_lo: Span, | |
| #[suggestion_part(code = "{successor_pos}")] | |
| span_hi: Span, | |
| def_path: String, | |
| adjustment: &'a str, | |
| successor_pos: &'a str, | |
| }, | |
| #[multipart_suggestion( | |
| "try giving this closure an explicit return type", | |
| style = "verbose", | |
| applicability = "has-placeholders" | |
| )] | |
| ClosureReturn { | |
| #[suggestion_part(code = "{start_span_code}")] | |
| start_span: Span, | |
| start_span_code: String, | |
| #[suggestion_part(code = " }}")] | |
| end_span: Option<Span>, | |
| }, | |
| } | |
| impl<'a> SourceKindMultiSuggestion<'a> { | |
| pub fn new_fully_qualified( | |
| span: Span, | |
| def_path: String, | |
| adjustment: &'a str, | |
| successor: (&'a str, BytePos), | |
| ) -> Self { | |
| Self::FullyQualified { | |
| span_lo: span.shrink_to_lo(), | |
| span_hi: span.shrink_to_hi().with_hi(successor.1), | |
| def_path, | |
| adjustment, | |
| successor_pos: successor.0, | |
| } | |
| } | |
| pub fn new_closure_return( | |
| ty_info: String, | |
| data: &'a FnRetTy<'a>, | |
| should_wrap_expr: Option<Span>, | |
| ) -> Self { | |
| let arrow = match data { | |
| FnRetTy::DefaultReturn(_) => " -> ", | |
| _ => "", | |
| }; | |
| let (start_span, start_span_code, end_span) = match should_wrap_expr { | |
| Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)), | |
| None => (data.span(), format!("{arrow}{ty_info}"), None), | |
| }; | |
| Self::ClosureReturn { start_span, start_span_code, end_span } | |
| } | |
| } | |
| pub enum RegionOriginNote<'a> { | |
| Plain { | |
| span: Span, | |
| msg: DiagMessage, | |
| }, | |
| WithName { | |
| span: Span, | |
| msg: DiagMessage, | |
| name: &'a str, | |
| continues: bool, | |
| }, | |
| WithRequirement { | |
| span: Span, | |
| requirement: ObligationCauseAsDiagArg<'a>, | |
| expected_found: Option<(DiagStyledString, DiagStyledString)>, | |
| }, | |
| } | |
| impl Subdiagnostic for RegionOriginNote<'_> { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| let mut label_or_note = |span, msg: DiagMessage| { | |
| 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.arg("name", name); | |
| diag.arg("continues", continues); | |
| } | |
| RegionOriginNote::WithRequirement { | |
| span, | |
| requirement, | |
| expected_found: Some((expected, found)), | |
| } => { | |
| label_or_note( | |
| span, | |
| msg!( | |
| "...so that the {$requirement -> | |
| [method_compat] method type is compatible with trait | |
| [type_compat] associated type is compatible with trait | |
| [const_compat] const is compatible with trait | |
| [expr_assignable] expression is assignable | |
| [if_else_different] `if` and `else` have incompatible types | |
| [no_else] `if` missing an `else` returns `()` | |
| [fn_main_correct_type] `main` function has the correct type | |
| [fn_lang_correct_type] lang item function has the correct type | |
| [intrinsic_correct_type] intrinsic has the correct type | |
| [method_correct_type] method receiver has the correct type | |
| *[other] types are compatible | |
| }" | |
| ), | |
| ); | |
| diag.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, | |
| msg!( | |
| "...so that {$requirement -> | |
| [method_compat] method type is compatible with trait | |
| [type_compat] associated type is compatible with trait | |
| [const_compat] const is compatible with trait | |
| [expr_assignable] expression is assignable | |
| [if_else_different] `if` and `else` have incompatible types | |
| [no_else] `if` missing an `else` returns `()` | |
| [fn_main_correct_type] `main` function has the correct type | |
| [fn_lang_correct_type] lang item function has the correct type | |
| [intrinsic_correct_type] intrinsic has the correct type | |
| [method_correct_type] method receiver has the correct type | |
| *[other] types are compatible | |
| }" | |
| ), | |
| ); | |
| diag.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, | |
| sup: Option<Ident>, | |
| sub: Option<Ident>, | |
| }, | |
| } | |
| impl Subdiagnostic for LifetimeMismatchLabels { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| match self { | |
| LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { | |
| diag.span_label(param_span, msg!("this parameter and the return type are declared with different lifetimes...")); | |
| diag.span_label(ret_span, msg!("{\"\"}")); | |
| diag.span_label( | |
| span, | |
| msg!( | |
| "...but data{$label_var1_exists -> | |
| [true] {\" \"}from `{$label_var1}` | |
| *[false] {\"\"} | |
| } is returned here" | |
| ), | |
| ); | |
| diag.arg("label_var1_exists", label_var1.is_some()); | |
| diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); | |
| } | |
| LifetimeMismatchLabels::Normal { | |
| hir_equal, | |
| ty_sup, | |
| ty_sub, | |
| span, | |
| sup: label_var1, | |
| sub: label_var2, | |
| } => { | |
| if hir_equal { | |
| diag.span_label( | |
| ty_sup, | |
| msg!("this type is declared with multiple lifetimes..."), | |
| ); | |
| diag.span_label(ty_sub, msg!("{\"\"}")); | |
| diag.span_label( | |
| span, | |
| msg!("...but data with one lifetime flows into the other here"), | |
| ); | |
| } else { | |
| diag.span_label( | |
| ty_sup, | |
| msg!("these two types are declared with different lifetimes..."), | |
| ); | |
| diag.span_label(ty_sub, msg!("{\"\"}")); | |
| diag.span_label( | |
| span, | |
| msg!( | |
| "...but data{$label_var1_exists -> | |
| [true] {\" \"}from `{$label_var1}` | |
| *[false] {\"\"} | |
| } flows{$label_var2_exists -> | |
| [true] {\" \"}into `{$label_var2}` | |
| *[false] {\"\"} | |
| } here" | |
| ), | |
| ); | |
| diag.arg("label_var1_exists", label_var1.is_some()); | |
| diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); | |
| diag.arg("label_var2_exists", label_var2.is_some()); | |
| diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default()); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| pub struct AddLifetimeParamsSuggestion<'a> { | |
| pub tcx: TyCtxt<'a>, | |
| pub generic_param_scope: LocalDefId, | |
| pub sub: Region<'a>, | |
| pub ty_sup: &'a hir::Ty<'a>, | |
| pub ty_sub: &'a hir::Ty<'a>, | |
| pub add_note: bool, | |
| } | |
| impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| let mut mk_suggestion = || { | |
| let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) | |
| else { | |
| return false; | |
| }; | |
| let node = self.tcx.hir_node_by_def_id(anon_reg.scope); | |
| let is_impl = matches!(&node, hir::Node::ImplItem(_)); | |
| let (generics, parent_generics) = match node { | |
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) | |
| | hir::Node::TraitItem(hir::TraitItem { generics, .. }) | |
| | hir::Node::ImplItem(hir::ImplItem { generics, .. }) => ( | |
| generics, | |
| match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope)) | |
| { | |
| hir::Node::Item(hir::Item { | |
| kind: hir::ItemKind::Trait(_, _, _, _, generics, ..), | |
| .. | |
| }) | |
| | hir::Node::Item(hir::Item { | |
| kind: hir::ItemKind::Impl(hir::Impl { generics, .. }), | |
| .. | |
| }) => Some(generics), | |
| _ => None, | |
| }, | |
| ), | |
| _ => 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 mut default = "'a".to_string(); | |
| if let Some(parent_generics) = parent_generics { | |
| let used: FxHashSet<_> = parent_generics | |
| .params | |
| .iter() | |
| .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) | |
| .map(|p| p.name.ident().name) | |
| .filter(|i| *i != kw::UnderscoreLifetime) | |
| .map(|l| l.to_string()) | |
| .collect(); | |
| if let Some(lt) = | |
| ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it)) | |
| { | |
| // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc | |
| // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is | |
| // likely to be an over-constraining lifetime requirement, so we always add a | |
| // lifetime to the `fn`. | |
| default = lt; | |
| } | |
| } | |
| let suggestion_param_name = | |
| suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default); | |
| struct ImplicitLifetimeFinder { | |
| suggestions: Vec<(Span, String)>, | |
| suggestion_param_name: String, | |
| } | |
| impl<'v> Visitor<'v> for ImplicitLifetimeFinder { | |
| fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { | |
| match ty.kind { | |
| hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { | |
| for segment in path.segments { | |
| if let Some(args) = segment.args { | |
| if args.args.iter().all(|arg| { | |
| matches!( | |
| arg, | |
| hir::GenericArg::Lifetime(lifetime) | |
| if lifetime.is_implicit() | |
| ) | |
| }) { | |
| self.suggestions.push(( | |
| segment.ident.span.shrink_to_hi(), | |
| format!( | |
| "<{}>", | |
| args.args | |
| .iter() | |
| .map(|_| self.suggestion_param_name.clone()) | |
| .collect::<Vec<_>>() | |
| .join(", ") | |
| ), | |
| )); | |
| } else { | |
| for arg in args.args { | |
| if let hir::GenericArg::Lifetime(lifetime) = arg | |
| && lifetime.is_anonymous() | |
| { | |
| self.suggestions.push( | |
| lifetime | |
| .suggestion(&self.suggestion_param_name), | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { | |
| self.suggestions.push(lifetime.suggestion(&self.suggestion_param_name)); | |
| } | |
| _ => {} | |
| } | |
| walk_ty(self, ty); | |
| } | |
| } | |
| let mut visitor = ImplicitLifetimeFinder { | |
| suggestions: vec![], | |
| suggestion_param_name: suggestion_param_name.clone(), | |
| }; | |
| if let Some(fn_decl) = node.fn_decl() | |
| && let hir::FnRetTy::Return(ty) = fn_decl.output | |
| { | |
| visitor.visit_ty_unambig(ty); | |
| } | |
| if visitor.suggestions.is_empty() { | |
| // Do not suggest constraining the `&self` param, but rather the return type. | |
| // If that is wrong (because it is not sufficient), a follow up error will tell the | |
| // user to fix it. This way we lower the chances of *over* constraining, but still | |
| // get the cake of "correctly" constrained in two steps. | |
| visitor.visit_ty_unambig(self.ty_sup); | |
| } | |
| visitor.visit_ty_unambig(self.ty_sub); | |
| if visitor.suggestions.is_empty() { | |
| return false; | |
| } | |
| 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}>")) | |
| }; | |
| visitor.suggestions.push(new_param_suggestion); | |
| } | |
| diag.multipart_suggestion_verbose( | |
| msg!( | |
| "consider {$is_reuse -> | |
| [true] reusing | |
| *[false] introducing | |
| } a named lifetime parameter{$is_impl -> | |
| [true] {\" \"}and update trait if needed | |
| *[false] {\"\"} | |
| }" | |
| ), | |
| visitor.suggestions, | |
| Applicability::MaybeIncorrect, | |
| ); | |
| diag.arg("is_impl", is_impl); | |
| diag.arg("is_reuse", !introduce_new); | |
| true | |
| }; | |
| if mk_suggestion() && self.add_note { | |
| diag.note(msg!("each elided lifetime in input position becomes a distinct lifetime")); | |
| } | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("lifetime mismatch", code = E0623)] | |
| pub struct LifetimeMismatch<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| #[subdiagnostic] | |
| pub labels: LifetimeMismatchLabels, | |
| #[subdiagnostic] | |
| pub suggestion: AddLifetimeParamsSuggestion<'a>, | |
| } | |
| pub struct IntroducesStaticBecauseUnmetLifetimeReq { | |
| pub unmet_requirements: MultiSpan, | |
| pub binding_span: Span, | |
| } | |
| impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { | |
| fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) { | |
| self.unmet_requirements.push_span_label( | |
| self.binding_span, | |
| msg!("introduces a `'static` lifetime requirement"), | |
| ); | |
| diag.span_note( | |
| self.unmet_requirements, | |
| msg!("because this has an unmet lifetime requirement"), | |
| ); | |
| } | |
| } | |
| // FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that | |
| #[derive(Subdiagnostic)] | |
| pub enum DoesNotOutliveStaticFromImpl { | |
| #[note( | |
| "...does not necessarily outlive the static lifetime introduced by the compatible `impl`" | |
| )] | |
| Spanned { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[note( | |
| "...does not necessarily outlive the static lifetime introduced by the compatible `impl`" | |
| )] | |
| Unspanned, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum ImplicitStaticLifetimeSubdiag { | |
| #[note("this has an implicit `'static` lifetime requirement")] | |
| Note { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[suggestion( | |
| "consider relaxing the implicit `'static` requirement", | |
| style = "verbose", | |
| code = " + '_", | |
| applicability = "maybe-incorrect" | |
| )] | |
| Sugg { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("incompatible lifetime on type")] | |
| pub struct MismatchedStaticLifetime<'a> { | |
| #[primary_span] | |
| pub cause_span: Span, | |
| #[subdiagnostic] | |
| pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq, | |
| #[subdiagnostic] | |
| pub expl: Option<note_and_explain::RegionExplanation<'a>>, | |
| #[subdiagnostic] | |
| pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl, | |
| #[subdiagnostic] | |
| pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>, | |
| } | |
| #[derive(Diagnostic)] | |
| pub enum ExplicitLifetimeRequired<'a> { | |
| #[diag("explicit lifetime required in the type of `{$simple_ident}`", code = E0621)] | |
| WithIdent { | |
| #[primary_span] | |
| #[label("lifetime `{$named}` required")] | |
| span: Span, | |
| simple_ident: Ident, | |
| named: String, | |
| #[suggestion( | |
| "add explicit lifetime `{$named}` to the type of `{$simple_ident}`", | |
| code = "{new_ty}", | |
| applicability = "unspecified", | |
| style = "verbose" | |
| )] | |
| new_ty_span: Span, | |
| #[skip_arg] | |
| new_ty: Ty<'a>, | |
| }, | |
| #[diag("explicit lifetime required in parameter type", code = E0621)] | |
| WithParamType { | |
| #[primary_span] | |
| #[label("lifetime `{$named}` required")] | |
| span: Span, | |
| named: String, | |
| #[suggestion( | |
| "add explicit lifetime `{$named}` to type", | |
| code = "{new_ty}", | |
| applicability = "unspecified", | |
| style = "verbose" | |
| )] | |
| new_ty_span: Span, | |
| #[skip_arg] | |
| new_ty: Ty<'a>, | |
| }, | |
| } | |
| pub enum TyOrSig<'tcx> { | |
| Ty(Highlighted<'tcx, Ty<'tcx>>), | |
| ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>), | |
| } | |
| impl IntoDiagArg for TyOrSig<'_> { | |
| fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue { | |
| match self { | |
| TyOrSig::Ty(ty) => ty.into_diag_arg(path), | |
| TyOrSig::ClosureSig(sig) => sig.into_diag_arg(path), | |
| } | |
| } | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum ActualImplExplNotes<'tcx> { | |
| #[note("{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...")] | |
| ExpectedSignatureTwo { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| lifetime_2: usize, | |
| }, | |
| #[note("{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...")] | |
| ExpectedSignatureAny { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| }, | |
| #[note("{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...")] | |
| ExpectedSignatureSome { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| }, | |
| #[note( | |
| "{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }closure with signature `{$ty_or_sig}` must implement `{$trait_path}`" | |
| )] | |
| ExpectedSignatureNothing { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| }, | |
| #[note("{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...")] | |
| ExpectedPassiveTwo { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| lifetime_2: usize, | |
| }, | |
| #[note("{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...")] | |
| ExpectedPassiveAny { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| }, | |
| #[note("{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...")] | |
| ExpectedPassiveSome { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| }, | |
| #[note( | |
| "{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`" | |
| )] | |
| ExpectedPassiveNothing { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| }, | |
| #[note("{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...")] | |
| ExpectedOtherTwo { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| lifetime_2: usize, | |
| }, | |
| #[note( | |
| "{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`..." | |
| )] | |
| ExpectedOtherAny { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| }, | |
| #[note( | |
| "{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`..." | |
| )] | |
| ExpectedOtherSome { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| }, | |
| #[note( | |
| "{$leading_ellipsis -> | |
| [true] ... | |
| *[false] {\"\"} | |
| }`{$ty_or_sig}` must implement `{$trait_path}`" | |
| )] | |
| ExpectedOtherNothing { | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| }, | |
| #[note( | |
| "...but it actually implements `{$trait_path}`{$has_lifetime -> | |
| [true] , for some specific lifetime `'{$lifetime}` | |
| *[false] {\"\"} | |
| }" | |
| )] | |
| ButActuallyImplementsTrait { | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| has_lifetime: bool, | |
| lifetime: usize, | |
| }, | |
| #[note( | |
| "...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime -> | |
| [true] , for some specific lifetime `'{$lifetime}` | |
| *[false] {\"\"} | |
| }" | |
| )] | |
| ButActuallyImplementedForTy { | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| has_lifetime: bool, | |
| lifetime: usize, | |
| ty: String, | |
| }, | |
| #[note( | |
| "...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime -> | |
| [true] , for some specific lifetime `'{$lifetime}` | |
| *[false] {\"\"} | |
| }" | |
| )] | |
| ButActuallyTyImplements { | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| has_lifetime: bool, | |
| lifetime: usize, | |
| ty: String, | |
| }, | |
| } | |
| pub enum ActualImplExpectedKind { | |
| Signature, | |
| Passive, | |
| Other, | |
| } | |
| pub enum ActualImplExpectedLifetimeKind { | |
| Two, | |
| Any, | |
| Some, | |
| Nothing, | |
| } | |
| impl<'tcx> ActualImplExplNotes<'tcx> { | |
| pub fn new_expected( | |
| kind: ActualImplExpectedKind, | |
| lt_kind: ActualImplExpectedLifetimeKind, | |
| leading_ellipsis: bool, | |
| ty_or_sig: TyOrSig<'tcx>, | |
| trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, | |
| lifetime_1: usize, | |
| lifetime_2: usize, | |
| ) -> Self { | |
| match (kind, lt_kind) { | |
| (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => { | |
| Self::ExpectedSignatureTwo { | |
| leading_ellipsis, | |
| ty_or_sig, | |
| trait_path, | |
| lifetime_1, | |
| lifetime_2, | |
| } | |
| } | |
| (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => { | |
| Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } | |
| } | |
| (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => { | |
| Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } | |
| } | |
| (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => { | |
| Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path } | |
| } | |
| (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => { | |
| Self::ExpectedPassiveTwo { | |
| leading_ellipsis, | |
| ty_or_sig, | |
| trait_path, | |
| lifetime_1, | |
| lifetime_2, | |
| } | |
| } | |
| (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => { | |
| Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } | |
| } | |
| (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => { | |
| Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } | |
| } | |
| (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => { | |
| Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path } | |
| } | |
| (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => { | |
| Self::ExpectedOtherTwo { | |
| leading_ellipsis, | |
| ty_or_sig, | |
| trait_path, | |
| lifetime_1, | |
| lifetime_2, | |
| } | |
| } | |
| (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => { | |
| Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } | |
| } | |
| (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => { | |
| Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } | |
| } | |
| (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => { | |
| Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path } | |
| } | |
| } | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("implementation of `{$trait_def_id}` is not general enough")] | |
| pub struct TraitPlaceholderMismatch<'tcx> { | |
| #[primary_span] | |
| pub span: Span, | |
| #[label("doesn't satisfy where-clause")] | |
| pub satisfy_span: Option<Span>, | |
| #[label("due to a where-clause on `{$def_id}`...")] | |
| pub where_span: Option<Span>, | |
| #[label("implementation of `{$trait_def_id}` is not general enough")] | |
| pub dup_span: Option<Span>, | |
| pub def_id: String, | |
| pub trait_def_id: String, | |
| #[subdiagnostic] | |
| pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>, | |
| } | |
| pub struct ConsiderBorrowingParamHelp { | |
| pub spans: Vec<Span>, | |
| } | |
| impl Subdiagnostic for ConsiderBorrowingParamHelp { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| let mut type_param_span: MultiSpan = self.spans.clone().into(); | |
| for &span in &self.spans { | |
| // Seems like we can't call f() here as Into<DiagMessage> is required | |
| type_param_span | |
| .push_span_label(span, msg!("consider borrowing this type parameter in the trait")); | |
| } | |
| let msg = diag.eagerly_translate(msg!("the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`")); | |
| diag.span_help(type_param_span, msg); | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`impl` item signature doesn't match `trait` item signature")] | |
| pub struct TraitImplDiff { | |
| #[primary_span] | |
| #[label("found `{$found}`")] | |
| pub sp: Span, | |
| #[label("expected `{$expected}`")] | |
| pub trait_sp: Span, | |
| #[note( | |
| "expected signature `{$expected}` | |
| {\" \"}found signature `{$found}`" | |
| )] | |
| pub note: (), | |
| #[subdiagnostic] | |
| pub param_help: ConsiderBorrowingParamHelp, | |
| #[help( | |
| "verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output" | |
| )] | |
| pub rel_help: bool, | |
| pub expected: String, | |
| pub found: String, | |
| } | |
| pub struct DynTraitConstraintSuggestion { | |
| pub span: Span, | |
| pub ident: Ident, | |
| } | |
| impl Subdiagnostic for DynTraitConstraintSuggestion { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| let mut multi_span: MultiSpan = vec![self.span].into(); | |
| multi_span.push_span_label( | |
| self.span, | |
| msg!("this has an implicit `'static` lifetime requirement"), | |
| ); | |
| multi_span.push_span_label( | |
| self.ident.span, | |
| msg!("calling this method introduces the `impl`'s `'static` requirement"), | |
| ); | |
| let msg = diag.eagerly_translate(msg!("the used `impl` has a `'static` requirement")); | |
| diag.span_note(multi_span, msg); | |
| let msg = | |
| diag.eagerly_translate(msg!("consider relaxing the implicit `'static` requirement")); | |
| diag.span_suggestion_verbose( | |
| self.span.shrink_to_hi(), | |
| msg, | |
| " + '_", | |
| Applicability::MaybeIncorrect, | |
| ); | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("{$has_param_name -> | |
| [true] `{$param_name}` | |
| *[false] `fn` parameter | |
| } has {$lifetime_kind -> | |
| [true] lifetime `{$lifetime}` | |
| *[false] an anonymous lifetime `'_` | |
| } but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement", code = E0772)] | |
| pub struct ButCallingIntroduces { | |
| #[label( | |
| "{$has_lifetime -> | |
| [true] lifetime `{$lifetime}` | |
| *[false] an anonymous lifetime `'_` | |
| }" | |
| )] | |
| pub param_ty_span: Span, | |
| #[primary_span] | |
| #[label("...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path -> | |
| [true] `impl` of `{$impl_path}` | |
| *[false] inherent `impl` | |
| }")] | |
| pub cause_span: Span, | |
| pub has_param_name: bool, | |
| pub param_name: String, | |
| pub has_lifetime: bool, | |
| pub lifetime: String, | |
| pub assoc_item: Symbol, | |
| pub has_impl_path: bool, | |
| pub impl_path: String, | |
| } | |
| pub struct ReqIntroducedLocations { | |
| pub span: MultiSpan, | |
| pub spans: Vec<Span>, | |
| pub fn_decl_span: Span, | |
| pub cause_span: Span, | |
| pub add_label: bool, | |
| } | |
| impl Subdiagnostic for ReqIntroducedLocations { | |
| fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) { | |
| for sp in self.spans { | |
| self.span.push_span_label(sp, msg!("`'static` requirement introduced here")); | |
| } | |
| if self.add_label { | |
| self.span.push_span_label( | |
| self.fn_decl_span, | |
| msg!("requirement introduced by this return type"), | |
| ); | |
| } | |
| self.span.push_span_label(self.cause_span, msg!("because of this returned expression")); | |
| let msg = diag.eagerly_translate(msg!( | |
| "\"`'static` lifetime requirement introduced by the return type" | |
| )); | |
| diag.span_note(self.span, msg); | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("{$has_param_name -> | |
| [true] `{$param_name}` | |
| *[false] `fn` parameter | |
| } has {$has_lifetime -> | |
| [true] lifetime `{$lifetime}` | |
| *[false] an anonymous lifetime `'_` | |
| } but it needs to satisfy a `'static` lifetime requirement", code = E0759)] | |
| pub struct ButNeedsToSatisfy { | |
| #[primary_span] | |
| pub sp: Span, | |
| #[label( | |
| "this data with {$has_lifetime -> | |
| [true] lifetime `{$lifetime}` | |
| *[false] an anonymous lifetime `'_` | |
| }..." | |
| )] | |
| pub influencer_point: Span, | |
| #[label("...is used here...")] | |
| pub spans: Vec<Span>, | |
| #[label( | |
| "{$spans_empty -> | |
| *[true] ...is used and required to live as long as `'static` here | |
| [false] ...and is required to live as long as `'static` here | |
| }" | |
| )] | |
| pub require_span_as_label: Option<Span>, | |
| #[note( | |
| "{$spans_empty -> | |
| *[true] ...is used and required to live as long as `'static` here | |
| [false] ...and is required to live as long as `'static` here | |
| }" | |
| )] | |
| pub require_span_as_note: Option<Span>, | |
| #[note("`'static` lifetime requirement introduced by this bound")] | |
| pub bound: Option<Span>, | |
| pub has_param_name: bool, | |
| pub param_name: String, | |
| pub spans_empty: bool, | |
| pub has_lifetime: bool, | |
| pub lifetime: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("lifetime of reference outlives lifetime of borrowed content...", code = E0312)] | |
| pub struct OutlivesContent<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| #[subdiagnostic] | |
| pub notes: Vec<note_and_explain::RegionExplanation<'a>>, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("lifetime of the source pointer does not outlive lifetime bound of the object type", code = E0476)] | |
| pub struct OutlivesBound<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| #[subdiagnostic] | |
| pub notes: Vec<note_and_explain::RegionExplanation<'a>>, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("the type `{$ty}` does not fulfill the required lifetime", code = E0477)] | |
| pub struct FulfillReqLifetime<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| pub ty: Ty<'a>, | |
| #[subdiagnostic] | |
| pub note: Option<note_and_explain::RegionExplanation<'a>>, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("lifetime bound not satisfied", code = E0478)] | |
| pub struct LfBoundNotSatisfied<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| #[subdiagnostic] | |
| pub notes: Vec<note_and_explain::RegionExplanation<'a>>, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("in type `{$ty}`, reference has a longer lifetime than the data it references", code = E0491)] | |
| pub struct RefLongerThanData<'a> { | |
| #[primary_span] | |
| pub span: Span, | |
| pub ty: Ty<'a>, | |
| #[subdiagnostic] | |
| pub notes: Vec<note_and_explain::RegionExplanation<'a>>, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum WhereClauseSuggestions { | |
| #[suggestion( | |
| "remove the `where` clause", | |
| code = "", | |
| applicability = "machine-applicable", | |
| style = "verbose" | |
| )] | |
| Remove { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[suggestion( | |
| "copy the `where` clause predicates from the trait", | |
| code = "{space}where {trait_predicates}", | |
| applicability = "machine-applicable", | |
| style = "verbose" | |
| )] | |
| CopyPredicates { | |
| #[primary_span] | |
| span: Span, | |
| space: &'static str, | |
| trait_predicates: String, | |
| }, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum SuggestRemoveSemiOrReturnBinding { | |
| #[multipart_suggestion( | |
| "consider removing this semicolon and boxing the expressions", | |
| applicability = "machine-applicable" | |
| )] | |
| RemoveAndBox { | |
| #[suggestion_part(code = "Box::new(")] | |
| first_lo: Span, | |
| #[suggestion_part(code = ")")] | |
| first_hi: Span, | |
| #[suggestion_part(code = "Box::new(")] | |
| second_lo: Span, | |
| #[suggestion_part(code = ")")] | |
| second_hi: Span, | |
| #[suggestion_part(code = "")] | |
| sp: Span, | |
| }, | |
| #[suggestion( | |
| "consider removing this semicolon", | |
| style = "short", | |
| code = "", | |
| applicability = "machine-applicable" | |
| )] | |
| Remove { | |
| #[primary_span] | |
| sp: Span, | |
| }, | |
| #[suggestion( | |
| "consider returning the local binding `{$ident}`", | |
| style = "verbose", | |
| code = "{code}", | |
| applicability = "maybe-incorrect" | |
| )] | |
| Add { | |
| #[primary_span] | |
| sp: Span, | |
| code: String, | |
| ident: Ident, | |
| }, | |
| #[note("consider returning one of these bindings")] | |
| AddOne { | |
| #[primary_span] | |
| spans: MultiSpan, | |
| }, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum ConsiderAddingAwait { | |
| #[help("consider `await`ing on both `Future`s")] | |
| BothFuturesHelp, | |
| #[multipart_suggestion( | |
| "consider `await`ing on both `Future`s", | |
| applicability = "maybe-incorrect" | |
| )] | |
| BothFuturesSugg { | |
| #[suggestion_part(code = ".await")] | |
| first: Span, | |
| #[suggestion_part(code = ".await")] | |
| second: Span, | |
| }, | |
| #[suggestion( | |
| "consider `await`ing on the `Future`", | |
| code = ".await", | |
| style = "verbose", | |
| applicability = "maybe-incorrect" | |
| )] | |
| FutureSugg { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[note("calling an async function returns a future")] | |
| FutureSuggNote { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[multipart_suggestion( | |
| "consider `await`ing on the `Future`", | |
| style = "verbose", | |
| applicability = "maybe-incorrect" | |
| )] | |
| FutureSuggMultiple { | |
| #[suggestion_part(code = ".await")] | |
| spans: Vec<Span>, | |
| }, | |
| } | |
| #[derive(Diagnostic)] | |
| pub enum PlaceholderRelationLfNotSatisfied { | |
| #[diag("lifetime bound not satisfied")] | |
| HasBoth { | |
| #[primary_span] | |
| span: Span, | |
| #[note("the lifetime `{$sub_symbol}` defined here...")] | |
| sub_span: Span, | |
| #[note("...must outlive the lifetime `{$sup_symbol}` defined here")] | |
| sup_span: Span, | |
| sub_symbol: Symbol, | |
| sup_symbol: Symbol, | |
| #[note( | |
| "this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)" | |
| )] | |
| note: (), | |
| }, | |
| #[diag("lifetime bound not satisfied")] | |
| HasSub { | |
| #[primary_span] | |
| span: Span, | |
| #[note("the lifetime `{$sub_symbol}` defined here...")] | |
| sub_span: Span, | |
| #[note("...must outlive the lifetime defined here")] | |
| sup_span: Span, | |
| sub_symbol: Symbol, | |
| #[note( | |
| "this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)" | |
| )] | |
| note: (), | |
| }, | |
| #[diag("lifetime bound not satisfied")] | |
| HasSup { | |
| #[primary_span] | |
| span: Span, | |
| #[note("the lifetime defined here...")] | |
| sub_span: Span, | |
| #[note("...must outlive the lifetime `{$sup_symbol}` defined here")] | |
| sup_span: Span, | |
| sup_symbol: Symbol, | |
| #[note( | |
| "this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)" | |
| )] | |
| note: (), | |
| }, | |
| #[diag("lifetime bound not satisfied")] | |
| HasNone { | |
| #[primary_span] | |
| span: Span, | |
| #[note("the lifetime defined here...")] | |
| sub_span: Span, | |
| #[note("...must outlive the lifetime defined here")] | |
| sup_span: Span, | |
| #[note( | |
| "this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)" | |
| )] | |
| note: (), | |
| }, | |
| #[diag("lifetime bound not satisfied")] | |
| OnlyPrimarySpan { | |
| #[primary_span] | |
| span: Span, | |
| #[note( | |
| "this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)" | |
| )] | |
| note: (), | |
| }, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds", code = E0700)] | |
| pub struct OpaqueCapturesLifetime<'tcx> { | |
| #[primary_span] | |
| pub span: Span, | |
| #[label("opaque type defined here")] | |
| pub opaque_ty_span: Span, | |
| pub opaque_ty: Ty<'tcx>, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum FunctionPointerSuggestion<'a> { | |
| #[suggestion( | |
| "consider using a reference", | |
| code = "&", | |
| style = "verbose", | |
| applicability = "maybe-incorrect" | |
| )] | |
| UseRef { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[suggestion( | |
| "consider removing the reference", | |
| code = "{fn_name}", | |
| style = "verbose", | |
| applicability = "maybe-incorrect" | |
| )] | |
| RemoveRef { | |
| #[primary_span] | |
| span: Span, | |
| #[skip_arg] | |
| fn_name: String, | |
| }, | |
| #[suggestion( | |
| "consider casting to a fn pointer", | |
| code = "&({fn_name} as {sig})", | |
| style = "verbose", | |
| applicability = "maybe-incorrect" | |
| )] | |
| CastRef { | |
| #[primary_span] | |
| span: Span, | |
| #[skip_arg] | |
| fn_name: String, | |
| #[skip_arg] | |
| sig: Binder<'a, FnSig<'a>>, | |
| }, | |
| #[suggestion( | |
| "consider casting to a fn pointer", | |
| code = " as {sig}", | |
| style = "verbose", | |
| applicability = "maybe-incorrect" | |
| )] | |
| Cast { | |
| #[primary_span] | |
| span: Span, | |
| #[skip_arg] | |
| sig: Binder<'a, FnSig<'a>>, | |
| }, | |
| #[suggestion( | |
| "consider casting both fn items to fn pointers using `as {$expected_sig}`", | |
| code = " as {found_sig}", | |
| style = "hidden", | |
| applicability = "maybe-incorrect" | |
| )] | |
| CastBoth { | |
| #[primary_span] | |
| span: Span, | |
| #[skip_arg] | |
| found_sig: Binder<'a, FnSig<'a>>, | |
| expected_sig: Binder<'a, FnSig<'a>>, | |
| }, | |
| #[suggestion( | |
| "consider casting both fn items to fn pointers using `as {$expected_sig}`", | |
| code = "&({fn_name} as {found_sig})", | |
| style = "hidden", | |
| applicability = "maybe-incorrect" | |
| )] | |
| CastBothRef { | |
| #[primary_span] | |
| span: Span, | |
| #[skip_arg] | |
| fn_name: String, | |
| #[skip_arg] | |
| found_sig: Binder<'a, FnSig<'a>>, | |
| expected_sig: Binder<'a, FnSig<'a>>, | |
| }, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[note("fn items are distinct from fn pointers")] | |
| pub struct FnItemsAreDistinct; | |
| #[derive(Subdiagnostic)] | |
| #[note("different fn items have unique types, even if their signatures are the same")] | |
| pub struct FnUniqTypes; | |
| #[derive(Subdiagnostic)] | |
| #[help("consider casting the fn item to a fn pointer: `{$casting}`")] | |
| pub struct FnConsiderCasting { | |
| pub casting: String, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[help("consider casting both fn items to fn pointers using `as {$sig}`")] | |
| pub struct FnConsiderCastingBoth<'a> { | |
| pub sig: Binder<'a, FnSig<'a>>, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum SuggestAccessingField<'a> { | |
| #[suggestion( | |
| "you might have meant to use field `{$name}` whose type is `{$ty}`", | |
| code = "{snippet}.{name}", | |
| applicability = "maybe-incorrect", | |
| style = "verbose" | |
| )] | |
| Safe { | |
| #[primary_span] | |
| span: Span, | |
| snippet: String, | |
| name: Symbol, | |
| ty: Ty<'a>, | |
| }, | |
| #[suggestion( | |
| "you might have meant to use field `{$name}` whose type is `{$ty}`", | |
| code = "unsafe {{ {snippet}.{name} }}", | |
| applicability = "maybe-incorrect", | |
| style = "verbose" | |
| )] | |
| Unsafe { | |
| #[primary_span] | |
| span: Span, | |
| snippet: String, | |
| name: Symbol, | |
| ty: Ty<'a>, | |
| }, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[multipart_suggestion( | |
| "try wrapping the pattern in `{$variant}`", | |
| applicability = "maybe-incorrect" | |
| )] | |
| pub struct SuggestTuplePatternOne { | |
| pub variant: String, | |
| #[suggestion_part(code = "{variant}(")] | |
| pub span_low: Span, | |
| #[suggestion_part(code = ")")] | |
| pub span_high: Span, | |
| } | |
| pub struct SuggestTuplePatternMany { | |
| pub path: String, | |
| pub cause_span: Span, | |
| pub compatible_variants: Vec<String>, | |
| } | |
| impl Subdiagnostic for SuggestTuplePatternMany { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| diag.arg("path", self.path); | |
| let message = | |
| diag.eagerly_translate(msg!("try wrapping the pattern in a variant of `{$path}`")); | |
| diag.multipart_suggestions( | |
| message, | |
| self.compatible_variants.into_iter().map(|variant| { | |
| vec![ | |
| (self.cause_span.shrink_to_lo(), format!("{variant}(")), | |
| (self.cause_span.shrink_to_hi(), ")".to_string()), | |
| ] | |
| }), | |
| rustc_errors::Applicability::MaybeIncorrect, | |
| ); | |
| } | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum TypeErrorAdditionalDiags { | |
| #[suggestion( | |
| "if you meant to write a byte literal, prefix with `b`", | |
| code = "b'{code}'", | |
| applicability = "machine-applicable" | |
| )] | |
| MeantByteLiteral { | |
| #[primary_span] | |
| span: Span, | |
| code: String, | |
| }, | |
| #[suggestion( | |
| "if you meant to write a `char` literal, use single quotes", | |
| code = "'{code}'", | |
| applicability = "machine-applicable" | |
| )] | |
| MeantCharLiteral { | |
| #[primary_span] | |
| span: Span, | |
| code: String, | |
| }, | |
| #[multipart_suggestion( | |
| "if you meant to write a string literal, use double quotes", | |
| applicability = "machine-applicable" | |
| )] | |
| MeantStrLiteral { | |
| #[suggestion_part(code = "\"")] | |
| start: Span, | |
| #[suggestion_part(code = "\"")] | |
| end: Span, | |
| }, | |
| #[suggestion( | |
| "consider specifying the actual array length", | |
| code = "{length}", | |
| applicability = "maybe-incorrect" | |
| )] | |
| ConsiderSpecifyingLength { | |
| #[primary_span] | |
| span: Span, | |
| length: u64, | |
| }, | |
| #[note("`?` operator cannot convert from `{$found}` to `{$expected}`")] | |
| TryCannotConvert { found: String, expected: String }, | |
| #[suggestion( | |
| "use a trailing comma to create a tuple with one element", | |
| code = ",", | |
| applicability = "machine-applicable" | |
| )] | |
| TupleOnlyComma { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[multipart_suggestion( | |
| "use a trailing comma to create a tuple with one element", | |
| applicability = "machine-applicable" | |
| )] | |
| TupleAlsoParentheses { | |
| #[suggestion_part(code = "(")] | |
| span_low: Span, | |
| #[suggestion_part(code = ",)")] | |
| span_high: Span, | |
| }, | |
| #[suggestion( | |
| "consider adding `let`", | |
| style = "verbose", | |
| applicability = "machine-applicable", | |
| code = "let " | |
| )] | |
| AddLetForLetChains { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| } | |
| #[derive(Diagnostic)] | |
| pub enum ObligationCauseFailureCode { | |
| #[diag("method not compatible with trait", code = E0308)] | |
| MethodCompat { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("type not compatible with trait", code = E0308)] | |
| TypeCompat { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("const not compatible with trait", code = E0308)] | |
| ConstCompat { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("`?` operator has incompatible types", code = E0308)] | |
| TryCompat { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("`match` arms have incompatible types", code = E0308)] | |
| MatchCompat { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("`if` and `else` have incompatible types", code = E0308)] | |
| IfElseDifferent { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("`if` may be missing an `else` clause", code = E0317)] | |
| NoElse { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[diag("`else` clause of `let...else` does not diverge", code = E0308)] | |
| NoDiverge { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("`main` function has wrong type", code = E0580)] | |
| FnMainCorrectType { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[diag( | |
| "{$lang_item_name -> | |
| [panic_impl] `#[panic_handler]` | |
| *[lang_item_name] lang item `{$lang_item_name}` | |
| } function has wrong type" | |
| , code = E0308)] | |
| FnLangCorrectType { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| lang_item_name: Symbol, | |
| }, | |
| #[diag("intrinsic has wrong type", code = E0308)] | |
| IntrinsicCorrectType { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("mismatched `self` parameter type", code = E0308)] | |
| MethodCorrectType { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("closure/coroutine type that references itself", code = E0644)] | |
| ClosureSelfref { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| #[diag("cannot coerce functions which must be inlined to function pointers", code = E0308)] | |
| CantCoerceForceInline { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("cannot coerce intrinsics to function pointers", code = E0308)] | |
| CantCoerceIntrinsic { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| #[diag("mismatched types", code = E0308)] | |
| Generic { | |
| #[primary_span] | |
| span: Span, | |
| #[subdiagnostic] | |
| subdiags: Vec<TypeErrorAdditionalDiags>, | |
| }, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub enum AddPreciseCapturing { | |
| #[suggestion( | |
| "add a `use<...>` bound to explicitly capture `{$new_lifetime}`", | |
| style = "verbose", | |
| code = " + use<{concatenated_bounds}>", | |
| applicability = "machine-applicable" | |
| )] | |
| New { | |
| #[primary_span] | |
| span: Span, | |
| new_lifetime: Symbol, | |
| concatenated_bounds: String, | |
| }, | |
| #[suggestion( | |
| "add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it", | |
| style = "verbose", | |
| code = "{pre}{new_lifetime}{post}", | |
| applicability = "machine-applicable" | |
| )] | |
| Existing { | |
| #[primary_span] | |
| span: Span, | |
| new_lifetime: Symbol, | |
| pre: &'static str, | |
| post: &'static str, | |
| }, | |
| } | |
| pub struct AddPreciseCapturingAndParams { | |
| pub suggs: Vec<(Span, String)>, | |
| pub new_lifetime: Symbol, | |
| pub apit_spans: Vec<Span>, | |
| } | |
| impl Subdiagnostic for AddPreciseCapturingAndParams { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| diag.arg("new_lifetime", self.new_lifetime); | |
| diag.multipart_suggestion_verbose( | |
| msg!("add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate"), | |
| self.suggs, | |
| Applicability::MaybeIncorrect, | |
| ); | |
| diag.span_note( | |
| self.apit_spans, | |
| msg!("you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable"), | |
| ); | |
| } | |
| } | |
| /// Given a set of captured `DefId` for an RPIT (opaque_def_id) and a given | |
| /// function (fn_def_id), try to suggest adding `+ use<...>` to capture just | |
| /// the specified parameters. If one of those parameters is an APIT, then try | |
| /// to suggest turning it into a regular type parameter. | |
| pub fn impl_trait_overcapture_suggestion<'tcx>( | |
| tcx: TyCtxt<'tcx>, | |
| opaque_def_id: LocalDefId, | |
| fn_def_id: LocalDefId, | |
| captured_args: FxIndexSet<DefId>, | |
| ) -> Option<AddPreciseCapturingForOvercapture> { | |
| let generics = tcx.generics_of(fn_def_id); | |
| let mut captured_lifetimes = FxIndexSet::default(); | |
| let mut captured_non_lifetimes = FxIndexSet::default(); | |
| let mut synthetics = vec![]; | |
| for arg in captured_args { | |
| if tcx.def_kind(arg) == DefKind::LifetimeParam { | |
| captured_lifetimes.insert(tcx.item_name(arg)); | |
| } else { | |
| let idx = generics.param_def_id_to_index(tcx, arg).expect("expected arg in scope"); | |
| let param = generics.param_at(idx as usize, tcx); | |
| if param.kind.is_synthetic() { | |
| synthetics.push((tcx.def_span(arg), param.name)); | |
| } else { | |
| captured_non_lifetimes.insert(tcx.item_name(arg)); | |
| } | |
| } | |
| } | |
| let mut next_fresh_param = || { | |
| ["T", "U", "V", "W", "X", "Y", "A", "B", "C"] | |
| .into_iter() | |
| .map(Symbol::intern) | |
| .chain((0..).map(|i| Symbol::intern(&format!("T{i}")))) | |
| .find(|s| captured_non_lifetimes.insert(*s)) | |
| .unwrap() | |
| }; | |
| let mut suggs = vec![]; | |
| let mut apit_spans = vec![]; | |
| if !synthetics.is_empty() { | |
| let mut new_params = String::new(); | |
| for (i, (span, name)) in synthetics.into_iter().enumerate() { | |
| apit_spans.push(span); | |
| let fresh_param = next_fresh_param(); | |
| // Suggest renaming. | |
| suggs.push((span, fresh_param.to_string())); | |
| // Super jank. Turn `impl Trait` into `T: Trait`. | |
| // | |
| // This currently involves stripping the `impl` from the name of | |
| // the parameter, since APITs are always named after how they are | |
| // rendered in the AST. This sucks! But to recreate the bound list | |
| // from the APIT itself would be miserable, so we're stuck with | |
| // this for now! | |
| if i > 0 { | |
| new_params += ", "; | |
| } | |
| let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start(); | |
| new_params += fresh_param.as_str(); | |
| new_params += ": "; | |
| new_params += name_as_bounds; | |
| } | |
| let Some(generics) = tcx.hir_get_generics(fn_def_id) else { | |
| // This shouldn't happen, but don't ICE. | |
| return None; | |
| }; | |
| // Add generics or concatenate to the end of the list. | |
| suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() { | |
| (params_span, format!(", {new_params}")) | |
| } else { | |
| (generics.span, format!("<{new_params}>")) | |
| }); | |
| } | |
| let concatenated_bounds = captured_lifetimes | |
| .into_iter() | |
| .chain(captured_non_lifetimes) | |
| .map(|sym| sym.to_string()) | |
| .collect::<Vec<_>>() | |
| .join(", "); | |
| let opaque_hir_id = tcx.local_def_id_to_hir_id(opaque_def_id); | |
| // FIXME: This is a bit too conservative, since it ignores parens already written in AST. | |
| let (lparen, rparen) = match tcx | |
| .hir_parent_iter(opaque_hir_id) | |
| .nth(1) | |
| .expect("expected ty to have a parent always") | |
| .1 | |
| { | |
| Node::PathSegment(segment) | |
| if segment.args().paren_sugar_output().is_some_and(|ty| ty.hir_id == opaque_hir_id) => | |
| { | |
| ("(", ")") | |
| } | |
| Node::Ty(ty) => match ty.kind { | |
| rustc_hir::TyKind::Ptr(_) | rustc_hir::TyKind::Ref(..) => ("(", ")"), | |
| // FIXME: RPITs are not allowed to be nested in `impl Fn() -> ...`, | |
| // but we eventually could support that, and that would necessitate | |
| // making this more sophisticated. | |
| _ => ("", ""), | |
| }, | |
| _ => ("", ""), | |
| }; | |
| let rpit_span = tcx.def_span(opaque_def_id); | |
| if !lparen.is_empty() { | |
| suggs.push((rpit_span.shrink_to_lo(), lparen.to_string())); | |
| } | |
| suggs.push((rpit_span.shrink_to_hi(), format!(" + use<{concatenated_bounds}>{rparen}"))); | |
| Some(AddPreciseCapturingForOvercapture { suggs, apit_spans }) | |
| } | |
| pub struct AddPreciseCapturingForOvercapture { | |
| pub suggs: Vec<(Span, String)>, | |
| pub apit_spans: Vec<Span>, | |
| } | |
| impl Subdiagnostic for AddPreciseCapturingForOvercapture { | |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { | |
| let applicability = if self.apit_spans.is_empty() { | |
| Applicability::MachineApplicable | |
| } else { | |
| // If there are APIT that are converted to regular parameters, | |
| // then this may make the API turbofishable in ways that were | |
| // not intended. | |
| Applicability::MaybeIncorrect | |
| }; | |
| diag.multipart_suggestion_verbose( | |
| msg!("use the precise capturing `use<...>` syntax to make the captures explicit"), | |
| self.suggs, | |
| applicability, | |
| ); | |
| if !self.apit_spans.is_empty() { | |
| diag.span_note( | |
| self.apit_spans, | |
| msg!("you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable"), | |
| ); | |
| } | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("expected generic {$kind} parameter, found `{$arg}`", code = E0792)] | |
| pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { | |
| pub arg: GenericArg<'tcx>, | |
| pub kind: &'a str, | |
| #[primary_span] | |
| pub span: Span, | |
| #[label("{STREQ($arg, \"'static\") -> | |
| [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type | |
| *[other] this generic parameter must be used with a generic {$kind} parameter | |
| }")] | |
| pub param_span: Span, | |
| } |