mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
2196 lines
73 KiB
Rust
2196 lines
73 KiB
Rust
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,
|
|
}
|