2024-07-21 19:20:41 +00:00
|
|
|
use std::path::PathBuf;
|
2024-07-28 22:13:50 +00:00
|
|
|
|
2024-11-09 19:16:43 +00:00
|
|
|
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
2023-06-28 18:08:21 +00:00
|
|
|
use rustc_errors::codes::*;
|
|
|
|
use rustc_errors::{
|
2024-07-21 19:20:41 +00:00
|
|
|
Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
|
|
|
|
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
2023-06-28 18:08:21 +00:00
|
|
|
};
|
2024-11-09 19:41:28 +00:00
|
|
|
use rustc_hir::def::DefKind;
|
2024-11-09 19:16:43 +00:00
|
|
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
2025-01-11 19:12:36 +00:00
|
|
|
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
|
2025-03-24 21:21:28 +00:00
|
|
|
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node};
|
2024-04-28 22:53:45 +00:00
|
|
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
2024-07-21 19:20:41 +00:00
|
|
|
use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
|
2025-01-10 20:09:10 +00:00
|
|
|
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, Region, Ty, TyCtxt};
|
2024-12-12 23:29:23 +00:00
|
|
|
use rustc_span::{BytePos, Ident, Span, Symbol, kw};
|
2024-07-21 19:20:41 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
use crate::fluent_generated as fluent;
|
|
|
|
|
|
|
|
pub mod note_and_explain;
|
2022-08-26 18:08:58 +00:00
|
|
|
|
2022-09-18 15:46:56 +00:00
|
|
|
#[derive(Diagnostic)]
|
2022-10-22 09:07:54 +00:00
|
|
|
#[diag(trait_selection_unable_to_construct_constant_value)]
|
2022-08-26 18:08:58 +00:00
|
|
|
pub struct UnableToConstructConstantValue<'a> {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
2022-09-22 10:34:23 +00:00
|
|
|
pub unevaluated: ty::UnevaluatedConst<'a>,
|
2022-08-26 18:08:58 +00:00
|
|
|
}
|
|
|
|
|
2022-09-18 15:46:56 +00:00
|
|
|
#[derive(Diagnostic)]
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-13 23:57:07 +00:00
|
|
|
#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = E0232)]
|
2022-08-26 18:08:58 +00:00
|
|
|
pub struct EmptyOnClauseInOnUnimplemented {
|
|
|
|
#[primary_span]
|
|
|
|
#[label]
|
|
|
|
pub span: Span,
|
|
|
|
}
|
|
|
|
|
2022-09-18 15:46:56 +00:00
|
|
|
#[derive(Diagnostic)]
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-13 23:57:07 +00:00
|
|
|
#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = E0232)]
|
2022-08-26 18:08:58 +00:00
|
|
|
pub struct InvalidOnClauseInOnUnimplemented {
|
|
|
|
#[primary_span]
|
|
|
|
#[label]
|
|
|
|
pub span: Span,
|
|
|
|
}
|
|
|
|
|
2022-09-18 15:46:56 +00:00
|
|
|
#[derive(Diagnostic)]
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-13 23:57:07 +00:00
|
|
|
#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = E0232)]
|
2022-08-26 18:08:58 +00:00
|
|
|
#[note]
|
|
|
|
pub struct NoValueInOnUnimplemented {
|
|
|
|
#[primary_span]
|
|
|
|
#[label]
|
|
|
|
pub span: Span,
|
|
|
|
}
|
|
|
|
|
2022-11-10 04:21:11 +00:00
|
|
|
pub struct NegativePositiveConflict<'tcx> {
|
2022-08-26 18:08:58 +00:00
|
|
|
pub impl_span: Span,
|
2022-11-10 04:21:11 +00:00
|
|
|
pub trait_desc: ty::TraitRef<'tcx>,
|
|
|
|
pub self_ty: Option<Ty<'tcx>>,
|
2022-08-26 18:08:58 +00:00
|
|
|
pub negative_impl_span: Result<Span, Symbol>,
|
|
|
|
pub positive_impl_span: Result<Span, Symbol>,
|
|
|
|
}
|
|
|
|
|
2024-03-06 00:02:56 +00:00
|
|
|
impl<G: EmissionGuarantee> Diagnostic<'_, G> for NegativePositiveConflict<'_> {
|
2022-10-31 15:14:29 +00:00
|
|
|
#[track_caller]
|
2024-06-18 10:35:56 +00:00
|
|
|
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
|
2024-02-22 23:20:45 +00:00
|
|
|
let mut diag = Diag::new(dcx, level, fluent::trait_selection_negative_positive_conflict);
|
2023-12-23 22:08:41 +00:00
|
|
|
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);
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-13 23:57:07 +00:00
|
|
|
diag.code(E0751);
|
2022-08-26 18:08:58 +00:00
|
|
|
match self.negative_impl_span {
|
|
|
|
Ok(span) => {
|
2022-10-13 09:13:02 +00:00
|
|
|
diag.span_label(span, fluent::trait_selection_negative_implementation_here);
|
2022-08-26 18:08:58 +00:00
|
|
|
}
|
|
|
|
Err(cname) => {
|
2022-10-13 09:13:02 +00:00
|
|
|
diag.note(fluent::trait_selection_negative_implementation_in_crate);
|
2023-12-23 22:08:41 +00:00
|
|
|
diag.arg("negative_impl_cname", cname.to_string());
|
2022-08-26 18:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
match self.positive_impl_span {
|
|
|
|
Ok(span) => {
|
2022-10-13 09:13:02 +00:00
|
|
|
diag.span_label(span, fluent::trait_selection_positive_implementation_here);
|
2022-08-26 18:08:58 +00:00
|
|
|
}
|
|
|
|
Err(cname) => {
|
2022-10-13 09:13:02 +00:00
|
|
|
diag.note(fluent::trait_selection_positive_implementation_in_crate);
|
2023-12-23 22:08:41 +00:00
|
|
|
diag.arg("positive_impl_cname", cname.to_string());
|
2022-08-26 18:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
diag
|
|
|
|
}
|
|
|
|
}
|
2023-03-21 00:46:52 +00:00
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_inherent_projection_normalization_overflow)]
|
|
|
|
pub struct InherentProjectionNormalizationOverflow {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
pub ty: String,
|
|
|
|
}
|
2023-06-28 18:08:21 +00:00
|
|
|
|
|
|
|
pub enum AdjustSignatureBorrow {
|
|
|
|
Borrow { to_borrow: Vec<(Span, String)> },
|
|
|
|
RemoveBorrow { remove_borrow: Vec<(Span, String)> },
|
|
|
|
}
|
|
|
|
|
2024-03-06 03:00:16 +00:00
|
|
|
impl Subdiagnostic for AdjustSignatureBorrow {
|
|
|
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
Reduce capabilities of `Diagnostic`.
Currently many diagnostic modifier methods are available on both
`Diagnostic` and `DiagnosticBuilder`. This commit removes most of them
from `Diagnostic`. To minimize the diff size, it keeps them within
`diagnostic.rs` but changes the surrounding `impl Diagnostic` block to
`impl DiagnosticBuilder`. (I intend to move things around later, to give
a more sensible code layout.)
`Diagnostic` keeps a few methods that it still needs, like `sub`,
`arg`, and `replace_args`.
The `forward!` macro, which defined two additional methods per call
(e.g. `note` and `with_note`), is replaced by the `with_fn!` macro,
which defines one additional method per call (e.g. `with_note`). It's
now also only used when necessary -- not all modifier methods currently
need a `with_*` form. (New ones can be easily added as necessary.)
All this also requires changing `trait AddToDiagnostic` so its methods
take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many
mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`.
There are three subdiagnostics -- `DelayedAtWithoutNewline`,
`DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` --
that are created within the diagnostics machinery and appended to
external diagnostics. These are handled at the `Diagnostic` level, which
means it's now hard to construct them via `derive(Diagnostic)`, so
instead we construct them by hand. This has no effect on what they look
like when printed.
There are lots of new `allow` markers for `untranslatable_diagnostics`
and `diagnostics_outside_of_impl`. This is because
`#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic`
modifier methods, but missing from the `DiagnosticBuilder` modifier
methods. They're now present.
2024-02-06 05:44:30 +00:00
|
|
|
self,
|
2024-02-22 23:20:45 +00:00
|
|
|
diag: &mut Diag<'_, G>,
|
2024-04-18 19:18:35 +00:00
|
|
|
_f: &F,
|
Reduce capabilities of `Diagnostic`.
Currently many diagnostic modifier methods are available on both
`Diagnostic` and `DiagnosticBuilder`. This commit removes most of them
from `Diagnostic`. To minimize the diff size, it keeps them within
`diagnostic.rs` but changes the surrounding `impl Diagnostic` block to
`impl DiagnosticBuilder`. (I intend to move things around later, to give
a more sensible code layout.)
`Diagnostic` keeps a few methods that it still needs, like `sub`,
`arg`, and `replace_args`.
The `forward!` macro, which defined two additional methods per call
(e.g. `note` and `with_note`), is replaced by the `with_fn!` macro,
which defines one additional method per call (e.g. `with_note`). It's
now also only used when necessary -- not all modifier methods currently
need a `with_*` form. (New ones can be easily added as necessary.)
All this also requires changing `trait AddToDiagnostic` so its methods
take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many
mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`.
There are three subdiagnostics -- `DelayedAtWithoutNewline`,
`DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` --
that are created within the diagnostics machinery and appended to
external diagnostics. These are handled at the `Diagnostic` level, which
means it's now hard to construct them via `derive(Diagnostic)`, so
instead we construct them by hand. This has no effect on what they look
like when printed.
There are lots of new `allow` markers for `untranslatable_diagnostics`
and `diagnostics_outside_of_impl`. This is because
`#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic`
modifier methods, but missing from the `DiagnosticBuilder` modifier
methods. They're now present.
2024-02-06 05:44:30 +00:00
|
|
|
) {
|
2023-06-28 18:08:21 +00:00
|
|
|
match self {
|
|
|
|
AdjustSignatureBorrow::Borrow { to_borrow } => {
|
2023-12-23 22:08:41 +00:00
|
|
|
diag.arg("len", to_borrow.len());
|
2023-06-28 18:08:21 +00:00
|
|
|
diag.multipart_suggestion_verbose(
|
|
|
|
fluent::trait_selection_adjust_signature_borrow,
|
|
|
|
to_borrow,
|
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
AdjustSignatureBorrow::RemoveBorrow { remove_borrow } => {
|
2023-12-23 22:08:41 +00:00
|
|
|
diag.arg("len", remove_borrow.len());
|
2023-06-28 18:08:21 +00:00
|
|
|
diag.multipart_suggestion_verbose(
|
|
|
|
fluent::trait_selection_adjust_signature_remove_borrow,
|
|
|
|
remove_borrow,
|
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-08-06 14:00:12 +00:00
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-13 23:57:07 +00:00
|
|
|
#[diag(trait_selection_closure_kind_mismatch, code = E0525)]
|
2023-08-06 14:00:12 +00:00
|
|
|
pub struct ClosureKindMismatch {
|
|
|
|
#[primary_span]
|
|
|
|
#[label]
|
|
|
|
pub closure_span: Span,
|
|
|
|
pub expected: ClosureKind,
|
|
|
|
pub found: ClosureKind,
|
|
|
|
#[label(trait_selection_closure_kind_requirement)]
|
|
|
|
pub cause_span: Span,
|
|
|
|
|
2024-02-14 23:52:57 +00:00
|
|
|
pub trait_prefix: &'static str,
|
|
|
|
|
2023-08-06 14:00:12 +00:00
|
|
|
#[subdiagnostic]
|
|
|
|
pub fn_once_label: Option<ClosureFnOnceLabel>,
|
|
|
|
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub fn_mut_label: Option<ClosureFnMutLabel>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[label(trait_selection_closure_fn_once_label)]
|
|
|
|
pub struct ClosureFnOnceLabel {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
pub place: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[label(trait_selection_closure_fn_mut_label)]
|
|
|
|
pub struct ClosureFnMutLabel {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
pub place: String,
|
|
|
|
}
|
2024-02-14 23:52:57 +00:00
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_async_closure_not_fn)]
|
|
|
|
pub(crate) struct AsyncClosureNotFn {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
pub kind: &'static str,
|
|
|
|
}
|
2024-07-21 19:20:41 +00:00
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_type_annotations_needed, code = E0282)]
|
|
|
|
pub struct AnnotationRequired<'a> {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
pub source_kind: &'static str,
|
|
|
|
pub source_name: &'a str,
|
|
|
|
#[label]
|
|
|
|
pub failure_span: Option<Span>,
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub bad_label: Option<InferenceBadError<'a>>,
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
|
|
|
|
#[note(trait_selection_full_type_written)]
|
2024-08-21 04:57:58 +00:00
|
|
|
pub was_written: bool,
|
2024-07-21 19:20:41 +00:00
|
|
|
pub path: PathBuf,
|
2024-08-21 03:17:47 +00:00
|
|
|
#[note(trait_selection_type_annotations_needed_error_time)]
|
|
|
|
pub time_version: bool,
|
2024-07-21 19:20:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy of `AnnotationRequired` for E0283
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_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]
|
|
|
|
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>>,
|
|
|
|
#[note(trait_selection_full_type_written)]
|
2024-08-21 04:57:58 +00:00
|
|
|
pub was_written: bool,
|
2024-07-21 19:20:41 +00:00
|
|
|
pub path: PathBuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy of `AnnotationRequired` for E0284
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_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]
|
|
|
|
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>>,
|
|
|
|
#[note(trait_selection_full_type_written)]
|
2024-08-21 04:57:58 +00:00
|
|
|
pub was_written: bool,
|
2024-07-21 19:20:41 +00:00
|
|
|
pub path: PathBuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used when a better one isn't available
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[label(trait_selection_label_bad)]
|
|
|
|
pub struct InferenceBadError<'a> {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
pub bad_kind: &'static str,
|
|
|
|
pub prefix_kind: UnderspecifiedArgKind,
|
|
|
|
pub has_parent: bool,
|
|
|
|
pub prefix: &'a str,
|
|
|
|
pub parent_prefix: &'a str,
|
|
|
|
pub parent_name: String,
|
|
|
|
pub name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
pub enum SourceKindSubdiag<'a> {
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_source_kind_subdiag_let,
|
|
|
|
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(trait_selection_source_kind_subdiag_generic_label)]
|
|
|
|
GenericLabel {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
is_type: bool,
|
|
|
|
param_name: String,
|
|
|
|
parent_exists: bool,
|
|
|
|
parent_prefix: String,
|
|
|
|
parent_name: String,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_source_kind_subdiag_generic_suggestion,
|
|
|
|
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(
|
|
|
|
trait_selection_source_kind_fully_qualified,
|
|
|
|
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(
|
|
|
|
trait_selection_source_kind_closure_return,
|
|
|
|
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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
_f: &F,
|
|
|
|
) {
|
|
|
|
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, fluent::trait_selection_subtype);
|
|
|
|
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, fluent::trait_selection_subtype_2);
|
|
|
|
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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
_f: &F,
|
|
|
|
) {
|
|
|
|
match self {
|
|
|
|
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
|
|
|
|
diag.span_label(param_span, fluent::trait_selection_declared_different);
|
|
|
|
diag.span_label(ret_span, fluent::trait_selection_nothing);
|
|
|
|
diag.span_label(span, fluent::trait_selection_data_returned);
|
|
|
|
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, fluent::trait_selection_declared_multiple);
|
|
|
|
diag.span_label(ty_sub, fluent::trait_selection_nothing);
|
|
|
|
diag.span_label(span, fluent::trait_selection_data_lifetime_flow);
|
|
|
|
} else {
|
|
|
|
diag.span_label(ty_sup, fluent::trait_selection_types_declared_different);
|
|
|
|
diag.span_label(ty_sub, fluent::trait_selection_nothing);
|
|
|
|
diag.span_label(span, fluent::trait_selection_data_flows);
|
|
|
|
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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
_f: &F,
|
|
|
|
) {
|
|
|
|
let mut mk_suggestion = || {
|
|
|
|
let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub)
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2024-12-06 13:23:18 +00:00
|
|
|
let node = self.tcx.hir_node_by_def_id(anon_reg.scope);
|
2024-07-21 19:20:41 +00:00
|
|
|
let is_impl = matches!(&node, hir::Node::ImplItem(_));
|
|
|
|
let (generics, parent_generics) = match node {
|
2025-02-20 18:28:48 +00:00
|
|
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. })
|
|
|
|
| hir::Node::TraitItem(hir::TraitItem { generics, .. })
|
|
|
|
| hir::Node::ImplItem(hir::ImplItem { generics, .. }) => (
|
2024-07-21 19:20:41 +00:00
|
|
|
generics,
|
2024-12-06 13:23:18 +00:00
|
|
|
match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope))
|
2024-07-21 19:20:41 +00:00
|
|
|
{
|
|
|
|
hir::Node::Item(hir::Item {
|
Move `hir::Item::ident` into `hir::ItemKind`.
`hir::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
Trait`, TraitAalis`.
- It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`,
`Impl`.
- For `Use`, it is non-empty for `UseKind::Single` and empty for
`UseKind::{Glob,ListStem}`.
All of this is quite non-obvious; the only documentation is a single
comment saying "The name might be a dummy name in case of anonymous
items". Some sites that handle items check for an empty ident, some
don't. This is a very C-like way of doing things, but this is Rust, we
have sum types, we can do this properly and never forget to check for
the exceptional case and never YOLO possibly empty identifiers (or
possibly dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- A similar transformation makes sense for `ast::Item`, but this is
already a big change. That can be done later.
- Lots of assertions are added to item lowering to ensure that
identifiers are empty/non-empty as expected. These will be removable
when `ast::Item` is done later.
- `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does.
- `lower_use_tree` is significantly simpler. No more confusing `&mut
Ident` to deal with.
- `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's
used with `unwrap` in a few places; sometimes it's hard to tell
exactly which item kinds might occur. None of these unwraps fail on
the test suite. It's conceivable that some might fail on alternative
input. We can deal with those if/when they happen.
- In `trait_path` the `find_map`/`if let` is replaced with a loop, and
things end up much clearer that way.
- `named_span` no longer checks for an empty name; instead the call site
now checks for a missing identifier if necessary.
- `maybe_inline_local` doesn't need the `glob` argument, it can be
computed in-function from the `renamed` argument.
- `arbitrary_source_item_ordering::check_mod` had a big `if` statement
that was just getting the ident from the item kinds that had one. It
could be mostly replaced by a single call to the new `ItemKind::ident`
method.
- `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size,
and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
|
|
|
kind: hir::ItemKind::Trait(_, _, _, generics, ..),
|
2024-07-21 19:20:41 +00:00
|
|
|
..
|
|
|
|
})
|
|
|
|
| hir::Node::Item(hir::Item {
|
2025-02-20 18:28:48 +00:00
|
|
|
kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
|
2024-07-21 19:20:41 +00:00
|
|
|
..
|
|
|
|
}) => 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 {
|
2025-01-11 19:12:36 +00:00
|
|
|
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
|
2025-03-24 21:21:28 +00:00
|
|
|
let make_suggestion = |lifetime: &hir::Lifetime| {
|
|
|
|
if lifetime.is_anon_in_path == IsAnonInPath::Yes
|
|
|
|
&& lifetime.ident.span.is_empty()
|
|
|
|
{
|
2024-07-21 19:20:41 +00:00
|
|
|
format!("{}, ", self.suggestion_param_name)
|
2025-03-24 21:21:28 +00:00
|
|
|
} else if lifetime.ident.name == kw::UnderscoreLifetime
|
|
|
|
&& lifetime.ident.span.is_empty()
|
|
|
|
{
|
2024-07-21 19:20:41 +00:00
|
|
|
format!("{} ", self.suggestion_param_name)
|
|
|
|
} else {
|
|
|
|
self.suggestion_param_name.clone()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
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)
|
2025-03-24 21:21:28 +00:00
|
|
|
if lifetime.is_anon_in_path == IsAnonInPath::Yes
|
2024-07-21 19:20:41 +00:00
|
|
|
)
|
|
|
|
}) {
|
|
|
|
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.ident.span,
|
2025-03-24 21:21:28 +00:00
|
|
|
make_suggestion(lifetime),
|
2024-07-21 19:20:41 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
|
2025-03-24 21:21:28 +00:00
|
|
|
self.suggestions.push((lifetime.ident.span, make_suggestion(lifetime)));
|
2024-07-21 19:20:41 +00:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
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
|
|
|
|
{
|
2025-01-18 22:45:41 +00:00
|
|
|
visitor.visit_ty_unambig(ty);
|
2024-07-21 19:20:41 +00:00
|
|
|
}
|
|
|
|
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" contrained in two steps.
|
2025-01-18 22:45:41 +00:00
|
|
|
visitor.visit_ty_unambig(self.ty_sup);
|
2024-07-21 19:20:41 +00:00
|
|
|
}
|
2025-01-18 22:45:41 +00:00
|
|
|
visitor.visit_ty_unambig(self.ty_sub);
|
2024-07-21 19:20:41 +00:00
|
|
|
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(
|
|
|
|
fluent::trait_selection_lifetime_param_suggestion,
|
|
|
|
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(fluent::trait_selection_lifetime_param_suggestion_elided);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
mut self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
_f: &F,
|
|
|
|
) {
|
|
|
|
self.unmet_requirements
|
|
|
|
.push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static);
|
|
|
|
diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
pub enum DoesNotOutliveStaticFromImpl {
|
|
|
|
#[note(trait_selection_does_not_outlive_static_from_impl)]
|
|
|
|
Spanned {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_does_not_outlive_static_from_impl)]
|
|
|
|
Unspanned,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
pub enum ImplicitStaticLifetimeSubdiag {
|
|
|
|
#[note(trait_selection_implicit_static_lifetime_note)]
|
|
|
|
Note {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_implicit_static_lifetime_suggestion,
|
|
|
|
style = "verbose",
|
|
|
|
code = " + '_",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
Sugg {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_mismatched_static_lifetime)]
|
|
|
|
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(trait_selection_explicit_lifetime_required_with_ident, code = E0621)]
|
|
|
|
WithIdent {
|
|
|
|
#[primary_span]
|
|
|
|
#[label]
|
|
|
|
span: Span,
|
|
|
|
simple_ident: Ident,
|
|
|
|
named: String,
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_explicit_lifetime_required_sugg_with_ident,
|
|
|
|
code = "{new_ty}",
|
|
|
|
applicability = "unspecified"
|
|
|
|
)]
|
|
|
|
new_ty_span: Span,
|
|
|
|
#[skip_arg]
|
|
|
|
new_ty: Ty<'a>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_explicit_lifetime_required_with_param_type, code = E0621)]
|
|
|
|
WithParamType {
|
|
|
|
#[primary_span]
|
|
|
|
#[label]
|
|
|
|
span: Span,
|
|
|
|
named: String,
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_explicit_lifetime_required_sugg_with_param_type,
|
|
|
|
code = "{new_ty}",
|
|
|
|
applicability = "unspecified"
|
|
|
|
)]
|
|
|
|
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<'_> {
|
Teach structured errors to display short `Ty`
Make it so that every structured error annotated with `#[derive(Diagnostic)]` that has a field of type `Ty<'_>`, the printing of that value into a `String` will look at the thread-local storage `TyCtxt` in order to shorten to a length appropriate with the terminal width. When this happen, the resulting error will have a note with the file where the full type name was written to.
```
error[E0618]: expected function, found `((..., ..., ..., ...), ..., ..., ...)``
--> long.rs:7:5
|
6 | fn foo(x: D) { //~ `x` has type `(...
| - `x` has type `((..., ..., ..., ...), ..., ..., ...)`
7 | x(); //~ ERROR expected function, found `(...
| ^--
| |
| call expression requires function
|
= note: the full name for the type has been written to 'long.long-type-14182675702747116984.txt'
= note: consider using `--verbose` to print the full type name to the console
```
2025-02-18 01:15:59 +00:00
|
|
|
fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
|
2024-07-21 19:20:41 +00:00
|
|
|
match self {
|
Teach structured errors to display short `Ty`
Make it so that every structured error annotated with `#[derive(Diagnostic)]` that has a field of type `Ty<'_>`, the printing of that value into a `String` will look at the thread-local storage `TyCtxt` in order to shorten to a length appropriate with the terminal width. When this happen, the resulting error will have a note with the file where the full type name was written to.
```
error[E0618]: expected function, found `((..., ..., ..., ...), ..., ..., ...)``
--> long.rs:7:5
|
6 | fn foo(x: D) { //~ `x` has type `(...
| - `x` has type `((..., ..., ..., ...), ..., ..., ...)`
7 | x(); //~ ERROR expected function, found `(...
| ^--
| |
| call expression requires function
|
= note: the full name for the type has been written to 'long.long-type-14182675702747116984.txt'
= note: consider using `--verbose` to print the full type name to the console
```
2025-02-18 01:15:59 +00:00
|
|
|
TyOrSig::Ty(ty) => ty.into_diag_arg(path),
|
|
|
|
TyOrSig::ClosureSig(sig) => sig.into_diag_arg(path),
|
2024-07-21 19:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
pub enum ActualImplExplNotes<'tcx> {
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_signature_two)]
|
|
|
|
ExpectedSignatureTwo {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
lifetime_2: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_signature_any)]
|
|
|
|
ExpectedSignatureAny {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_signature_some)]
|
|
|
|
ExpectedSignatureSome {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_signature_nothing)]
|
|
|
|
ExpectedSignatureNothing {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_passive_two)]
|
|
|
|
ExpectedPassiveTwo {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
lifetime_2: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_passive_any)]
|
|
|
|
ExpectedPassiveAny {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_passive_some)]
|
|
|
|
ExpectedPassiveSome {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_passive_nothing)]
|
|
|
|
ExpectedPassiveNothing {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_other_two)]
|
|
|
|
ExpectedOtherTwo {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
lifetime_2: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_other_any)]
|
|
|
|
ExpectedOtherAny {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_other_some)]
|
|
|
|
ExpectedOtherSome {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
lifetime_1: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_expected_other_nothing)]
|
|
|
|
ExpectedOtherNothing {
|
|
|
|
leading_ellipsis: bool,
|
|
|
|
ty_or_sig: TyOrSig<'tcx>,
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_but_actually_implements_trait)]
|
|
|
|
ButActuallyImplementsTrait {
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
has_lifetime: bool,
|
|
|
|
lifetime: usize,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_but_actually_implemented_for_ty)]
|
|
|
|
ButActuallyImplementedForTy {
|
|
|
|
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
|
|
|
has_lifetime: bool,
|
|
|
|
lifetime: usize,
|
|
|
|
ty: String,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_actual_impl_expl_but_actually_ty_implements)]
|
|
|
|
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(trait_selection_trait_placeholder_mismatch)]
|
|
|
|
pub struct TraitPlaceholderMismatch<'tcx> {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
#[label(trait_selection_label_satisfy)]
|
|
|
|
pub satisfy_span: Option<Span>,
|
|
|
|
#[label(trait_selection_label_where)]
|
|
|
|
pub where_span: Option<Span>,
|
|
|
|
#[label(trait_selection_label_dup)]
|
|
|
|
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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
f: &F,
|
|
|
|
) {
|
|
|
|
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, fluent::trait_selection_tid_consider_borrowing);
|
|
|
|
}
|
|
|
|
let msg = f(diag, fluent::trait_selection_tid_param_help.into());
|
|
|
|
diag.span_help(type_param_span, msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[help(trait_selection_tid_rel_help)]
|
|
|
|
pub struct RelationshipHelp;
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_trait_impl_diff)]
|
|
|
|
pub struct TraitImplDiff {
|
|
|
|
#[primary_span]
|
|
|
|
#[label(trait_selection_found)]
|
|
|
|
pub sp: Span,
|
|
|
|
#[label(trait_selection_expected)]
|
|
|
|
pub trait_sp: Span,
|
|
|
|
#[note(trait_selection_expected_found)]
|
|
|
|
pub note: (),
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub param_help: ConsiderBorrowingParamHelp,
|
|
|
|
#[subdiagnostic]
|
|
|
|
// Seems like subdiagnostics are always pushed to the end, so this one
|
|
|
|
// also has to be a subdiagnostic to maintain order.
|
|
|
|
pub rel_help: Option<RelationshipHelp>,
|
|
|
|
pub expected: String,
|
|
|
|
pub found: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DynTraitConstraintSuggestion {
|
|
|
|
pub span: Span,
|
|
|
|
pub ident: Ident,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Subdiagnostic for DynTraitConstraintSuggestion {
|
|
|
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
f: &F,
|
|
|
|
) {
|
|
|
|
let mut multi_span: MultiSpan = vec![self.span].into();
|
|
|
|
multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label);
|
|
|
|
multi_span
|
|
|
|
.push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement);
|
|
|
|
let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into());
|
|
|
|
diag.span_note(multi_span, msg);
|
|
|
|
let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into());
|
|
|
|
diag.span_suggestion_verbose(
|
|
|
|
self.span.shrink_to_hi(),
|
|
|
|
msg,
|
|
|
|
" + '_",
|
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_but_calling_introduces, code = E0772)]
|
|
|
|
pub struct ButCallingIntroduces {
|
|
|
|
#[label(trait_selection_label1)]
|
|
|
|
pub param_ty_span: Span,
|
|
|
|
#[primary_span]
|
|
|
|
#[label(trait_selection_label2)]
|
|
|
|
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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
mut self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
f: &F,
|
|
|
|
) {
|
|
|
|
for sp in self.spans {
|
|
|
|
self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here);
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.add_label {
|
|
|
|
self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by);
|
|
|
|
}
|
|
|
|
self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of);
|
|
|
|
let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into());
|
|
|
|
diag.span_note(self.span, msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_but_needs_to_satisfy, code = E0759)]
|
|
|
|
pub struct ButNeedsToSatisfy {
|
|
|
|
#[primary_span]
|
|
|
|
pub sp: Span,
|
|
|
|
#[label(trait_selection_influencer)]
|
|
|
|
pub influencer_point: Span,
|
|
|
|
#[label(trait_selection_used_here)]
|
|
|
|
pub spans: Vec<Span>,
|
|
|
|
#[label(trait_selection_require)]
|
|
|
|
pub require_span_as_label: Option<Span>,
|
|
|
|
#[note(trait_selection_require)]
|
|
|
|
pub require_span_as_note: Option<Span>,
|
|
|
|
#[note(trait_selection_introduced_by_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(trait_selection_outlives_content, code = E0312)]
|
|
|
|
pub struct OutlivesContent<'a> {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_outlives_bound, code = E0476)]
|
|
|
|
pub struct OutlivesBound<'a> {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_fulfill_req_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(trait_selection_lf_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(trait_selection_ref_longer_than_data, 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(
|
|
|
|
trait_selection_where_remove,
|
|
|
|
code = "",
|
|
|
|
applicability = "machine-applicable",
|
|
|
|
style = "verbose"
|
|
|
|
)]
|
|
|
|
Remove {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_where_copy_predicates,
|
|
|
|
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(
|
|
|
|
trait_selection_srs_remove_and_box,
|
|
|
|
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(
|
|
|
|
trait_selection_srs_remove,
|
|
|
|
style = "short",
|
|
|
|
code = "",
|
|
|
|
applicability = "machine-applicable"
|
|
|
|
)]
|
|
|
|
Remove {
|
|
|
|
#[primary_span]
|
|
|
|
sp: Span,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_srs_add,
|
|
|
|
style = "verbose",
|
|
|
|
code = "{code}",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
Add {
|
|
|
|
#[primary_span]
|
|
|
|
sp: Span,
|
|
|
|
code: String,
|
|
|
|
ident: Ident,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_srs_add_one)]
|
|
|
|
AddOne {
|
|
|
|
#[primary_span]
|
|
|
|
spans: MultiSpan,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
pub enum ConsiderAddingAwait {
|
|
|
|
#[help(trait_selection_await_both_futures)]
|
|
|
|
BothFuturesHelp,
|
|
|
|
#[multipart_suggestion(trait_selection_await_both_futures, applicability = "maybe-incorrect")]
|
|
|
|
BothFuturesSugg {
|
|
|
|
#[suggestion_part(code = ".await")]
|
|
|
|
first: Span,
|
|
|
|
#[suggestion_part(code = ".await")]
|
|
|
|
second: Span,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_await_future,
|
|
|
|
code = ".await",
|
|
|
|
style = "verbose",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
FutureSugg {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_await_note)]
|
|
|
|
FutureSuggNote {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[multipart_suggestion(
|
|
|
|
trait_selection_await_future,
|
|
|
|
style = "verbose",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
FutureSuggMultiple {
|
|
|
|
#[suggestion_part(code = ".await")]
|
|
|
|
spans: Vec<Span>,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
pub enum PlaceholderRelationLfNotSatisfied {
|
|
|
|
#[diag(trait_selection_lf_bound_not_satisfied)]
|
|
|
|
HasBoth {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[note(trait_selection_prlf_defined_with_sub)]
|
|
|
|
sub_span: Span,
|
|
|
|
#[note(trait_selection_prlf_must_outlive_with_sup)]
|
|
|
|
sup_span: Span,
|
|
|
|
sub_symbol: Symbol,
|
|
|
|
sup_symbol: Symbol,
|
|
|
|
#[note(trait_selection_prlf_known_limitation)]
|
|
|
|
note: (),
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_lf_bound_not_satisfied)]
|
|
|
|
HasSub {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[note(trait_selection_prlf_defined_with_sub)]
|
|
|
|
sub_span: Span,
|
|
|
|
#[note(trait_selection_prlf_must_outlive_without_sup)]
|
|
|
|
sup_span: Span,
|
|
|
|
sub_symbol: Symbol,
|
|
|
|
#[note(trait_selection_prlf_known_limitation)]
|
|
|
|
note: (),
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_lf_bound_not_satisfied)]
|
|
|
|
HasSup {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[note(trait_selection_prlf_defined_without_sub)]
|
|
|
|
sub_span: Span,
|
|
|
|
#[note(trait_selection_prlf_must_outlive_with_sup)]
|
|
|
|
sup_span: Span,
|
|
|
|
sup_symbol: Symbol,
|
|
|
|
#[note(trait_selection_prlf_known_limitation)]
|
|
|
|
note: (),
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_lf_bound_not_satisfied)]
|
|
|
|
HasNone {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[note(trait_selection_prlf_defined_without_sub)]
|
|
|
|
sub_span: Span,
|
|
|
|
#[note(trait_selection_prlf_must_outlive_without_sup)]
|
|
|
|
sup_span: Span,
|
|
|
|
#[note(trait_selection_prlf_known_limitation)]
|
|
|
|
note: (),
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_lf_bound_not_satisfied)]
|
|
|
|
OnlyPrimarySpan {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[note(trait_selection_prlf_known_limitation)]
|
|
|
|
note: (),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
#[diag(trait_selection_opaque_captures_lifetime, code = E0700)]
|
|
|
|
pub struct OpaqueCapturesLifetime<'tcx> {
|
|
|
|
#[primary_span]
|
|
|
|
pub span: Span,
|
|
|
|
#[label]
|
|
|
|
pub opaque_ty_span: Span,
|
|
|
|
pub opaque_ty: Ty<'tcx>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
pub enum FunctionPointerSuggestion<'a> {
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_fps_use_ref,
|
2025-02-02 00:45:40 +00:00
|
|
|
code = "&",
|
2024-07-21 19:20:41 +00:00
|
|
|
style = "verbose",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
UseRef {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_fps_remove_ref,
|
|
|
|
code = "{fn_name}",
|
|
|
|
style = "verbose",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
RemoveRef {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[skip_arg]
|
|
|
|
fn_name: String,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_fps_cast,
|
|
|
|
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(
|
|
|
|
trait_selection_fps_cast,
|
2025-02-02 00:45:40 +00:00
|
|
|
code = " as {sig}",
|
2024-07-21 19:20:41 +00:00
|
|
|
style = "verbose",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
Cast {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[skip_arg]
|
|
|
|
sig: Binder<'a, FnSig<'a>>,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_fps_cast_both,
|
2025-02-02 00:45:40 +00:00
|
|
|
code = " as {found_sig}",
|
2024-07-21 19:20:41 +00:00
|
|
|
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(
|
|
|
|
trait_selection_fps_cast_both,
|
|
|
|
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(trait_selection_fps_items_are_distinct)]
|
|
|
|
pub struct FnItemsAreDistinct;
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[note(trait_selection_fn_uniq_types)]
|
|
|
|
pub struct FnUniqTypes;
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[help(trait_selection_fn_consider_casting)]
|
|
|
|
pub struct FnConsiderCasting {
|
|
|
|
pub casting: String,
|
|
|
|
}
|
|
|
|
|
2024-11-23 15:47:45 +00:00
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[help(trait_selection_fn_consider_casting_both)]
|
|
|
|
pub struct FnConsiderCastingBoth<'a> {
|
|
|
|
pub sig: Binder<'a, FnSig<'a>>,
|
|
|
|
}
|
|
|
|
|
2024-07-21 19:20:41 +00:00
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
pub enum SuggestAccessingField<'a> {
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_suggest_accessing_field,
|
|
|
|
code = "{snippet}.{name}",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
Safe {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
snippet: String,
|
|
|
|
name: Symbol,
|
|
|
|
ty: Ty<'a>,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_suggest_accessing_field,
|
|
|
|
code = "unsafe {{ {snippet}.{name} }}",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
Unsafe {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
snippet: String,
|
|
|
|
name: Symbol,
|
|
|
|
ty: Ty<'a>,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
#[multipart_suggestion(trait_selection_stp_wrap_one, 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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
f: &F,
|
|
|
|
) {
|
|
|
|
diag.arg("path", self.path);
|
|
|
|
let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into());
|
|
|
|
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(
|
|
|
|
trait_selection_meant_byte_literal,
|
|
|
|
code = "b'{code}'",
|
|
|
|
applicability = "machine-applicable"
|
|
|
|
)]
|
|
|
|
MeantByteLiteral {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
code: String,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_meant_char_literal,
|
|
|
|
code = "'{code}'",
|
|
|
|
applicability = "machine-applicable"
|
|
|
|
)]
|
|
|
|
MeantCharLiteral {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
code: String,
|
|
|
|
},
|
2024-07-23 02:06:16 +00:00
|
|
|
#[multipart_suggestion(trait_selection_meant_str_literal, applicability = "machine-applicable")]
|
2024-07-21 19:20:41 +00:00
|
|
|
MeantStrLiteral {
|
|
|
|
#[suggestion_part(code = "\"")]
|
|
|
|
start: Span,
|
|
|
|
#[suggestion_part(code = "\"")]
|
|
|
|
end: Span,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_consider_specifying_length,
|
|
|
|
code = "{length}",
|
|
|
|
applicability = "maybe-incorrect"
|
|
|
|
)]
|
|
|
|
ConsiderSpecifyingLength {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
length: u64,
|
|
|
|
},
|
|
|
|
#[note(trait_selection_try_cannot_convert)]
|
|
|
|
TryCannotConvert { found: String, expected: String },
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_tuple_trailing_comma,
|
|
|
|
code = ",",
|
|
|
|
applicability = "machine-applicable"
|
|
|
|
)]
|
|
|
|
TupleOnlyComma {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[multipart_suggestion(
|
|
|
|
trait_selection_tuple_trailing_comma,
|
|
|
|
applicability = "machine-applicable"
|
|
|
|
)]
|
|
|
|
TupleAlsoParentheses {
|
|
|
|
#[suggestion_part(code = "(")]
|
|
|
|
span_low: Span,
|
|
|
|
#[suggestion_part(code = ",)")]
|
|
|
|
span_high: Span,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_suggest_add_let_for_letchains,
|
|
|
|
style = "verbose",
|
|
|
|
applicability = "machine-applicable",
|
|
|
|
code = "let "
|
|
|
|
)]
|
|
|
|
AddLetForLetChains {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Diagnostic)]
|
|
|
|
pub enum ObligationCauseFailureCode {
|
|
|
|
#[diag(trait_selection_oc_method_compat, code = E0308)]
|
|
|
|
MethodCompat {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_type_compat, code = E0308)]
|
|
|
|
TypeCompat {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_const_compat, code = E0308)]
|
|
|
|
ConstCompat {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_try_compat, code = E0308)]
|
|
|
|
TryCompat {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_match_compat, code = E0308)]
|
|
|
|
MatchCompat {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_if_else_different, code = E0308)]
|
|
|
|
IfElseDifferent {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_no_else, code = E0317)]
|
|
|
|
NoElse {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_no_diverge, code = E0308)]
|
|
|
|
NoDiverge {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_fn_main_correct_type, code = E0580)]
|
|
|
|
FnMainCorrectType {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)]
|
|
|
|
FnLangCorrectType {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
lang_item_name: Symbol,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_intrinsic_correct_type, code = E0308)]
|
|
|
|
IntrinsicCorrectType {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_method_correct_type, code = E0308)]
|
|
|
|
MethodCorrectType {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_closure_selfref, code = E0644)]
|
|
|
|
ClosureSelfref {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
},
|
2024-09-23 17:46:23 +00:00
|
|
|
#[diag(trait_selection_oc_cant_coerce_force_inline, code = E0308)]
|
|
|
|
CantCoerceForceInline {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_cant_coerce_intrinsic, code = E0308)]
|
|
|
|
CantCoerceIntrinsic {
|
2024-07-21 19:20:41 +00:00
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
#[diag(trait_selection_oc_generic, code = E0308)]
|
|
|
|
Generic {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
#[subdiagnostic]
|
|
|
|
subdiags: Vec<TypeErrorAdditionalDiags>,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subdiagnostic)]
|
|
|
|
pub enum AddPreciseCapturing {
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_precise_capturing_new,
|
|
|
|
style = "verbose",
|
|
|
|
code = " + use<{concatenated_bounds}>",
|
|
|
|
applicability = "machine-applicable"
|
|
|
|
)]
|
|
|
|
New {
|
|
|
|
#[primary_span]
|
|
|
|
span: Span,
|
|
|
|
new_lifetime: Symbol,
|
|
|
|
concatenated_bounds: String,
|
|
|
|
},
|
|
|
|
#[suggestion(
|
|
|
|
trait_selection_precise_capturing_existing,
|
|
|
|
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_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
_f: &F,
|
|
|
|
) {
|
|
|
|
diag.arg("new_lifetime", self.new_lifetime);
|
|
|
|
diag.multipart_suggestion_verbose(
|
|
|
|
fluent::trait_selection_precise_capturing_new_but_apit,
|
|
|
|
self.suggs,
|
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
);
|
2024-11-09 19:41:28 +00:00
|
|
|
diag.span_note(
|
|
|
|
self.apit_spans,
|
|
|
|
fluent::trait_selection_warn_removing_apit_params_for_undercapture,
|
|
|
|
);
|
2024-07-21 19:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
2024-11-09 19:16:43 +00:00
|
|
|
|
2024-11-09 19:41:28 +00:00
|
|
|
/// 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.
|
2024-11-09 19:16:43 +00:00
|
|
|
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);
|
2024-11-09 19:41:28 +00:00
|
|
|
|
2024-11-09 19:16:43 +00:00
|
|
|
let fresh_param = next_fresh_param();
|
2024-11-09 19:41:28 +00:00
|
|
|
|
2024-11-09 19:16:43 +00:00
|
|
|
// Suggest renaming.
|
|
|
|
suggs.push((span, fresh_param.to_string()));
|
2024-11-09 19:41:28 +00:00
|
|
|
|
2024-11-09 19:16:43 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2024-11-09 19:41:28 +00:00
|
|
|
|
2025-02-02 23:45:49 +00:00
|
|
|
let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
|
2024-11-09 19:16:43 +00:00
|
|
|
// This shouldn't happen, but don't ICE.
|
|
|
|
return None;
|
|
|
|
};
|
2024-11-09 19:41:28 +00:00
|
|
|
|
2024-11-09 19:16:43 +00:00
|
|
|
// 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(", ");
|
|
|
|
|
2024-12-10 20:41:24 +00:00
|
|
|
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
|
2025-02-20 20:54:35 +00:00
|
|
|
.hir_parent_iter(opaque_hir_id)
|
2024-12-10 20:41:24 +00:00
|
|
|
.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}")));
|
2024-11-09 19:16:43 +00:00
|
|
|
|
2024-11-09 19:41:28 +00:00
|
|
|
Some(AddPreciseCapturingForOvercapture { suggs, apit_spans })
|
2024-11-09 19:16:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct AddPreciseCapturingForOvercapture {
|
|
|
|
pub suggs: Vec<(Span, String)>,
|
|
|
|
pub apit_spans: Vec<Span>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Subdiagnostic for AddPreciseCapturingForOvercapture {
|
|
|
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
|
|
|
self,
|
|
|
|
diag: &mut Diag<'_, G>,
|
|
|
|
_f: &F,
|
|
|
|
) {
|
2024-11-12 02:54:42 +00:00
|
|
|
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
|
|
|
|
};
|
2024-11-09 19:16:43 +00:00
|
|
|
diag.multipart_suggestion_verbose(
|
|
|
|
fluent::trait_selection_precise_capturing_overcaptures,
|
|
|
|
self.suggs,
|
2024-11-12 02:54:42 +00:00
|
|
|
applicability,
|
2024-11-09 19:16:43 +00:00
|
|
|
);
|
|
|
|
if !self.apit_spans.is_empty() {
|
2024-11-09 19:41:28 +00:00
|
|
|
diag.span_note(
|
|
|
|
self.apit_spans,
|
|
|
|
fluent::trait_selection_warn_removing_apit_params_for_overcapture,
|
|
|
|
);
|
2024-11-09 19:16:43 +00:00
|
|
|
}
|
|
|
|
}
|
2024-11-09 19:41:28 +00:00
|
|
|
}
|