Move IntoDiagArg earlier in the dependency chains

`rustc_errors` depends on numerous crates, solely to implement its
`IntoDiagArg` trait on types from those crates. Many crates depend on
`rustc_errors`, and it's on the critical path.

We can't swap things around to make all of those crates depend on
`rustc_errors` instead, because `rustc_errors` would end up in
dependency cycles.

Instead, move `IntoDiagArg` into `rustc_error_messages`, which has far
fewer dependencies, and then have most of these crates depend on
`rustc_error_messages`.

This allows `rustc_errors` to drop dependencies on several crates,
including the large `rustc_target`.

(This doesn't fully reduce dependency chains yet, as `rustc_errors`
still depends on `rustc_hir` which depends on `rustc_target`. That will
get fixed in a subsequent commit.)
This commit is contained in:
Josh Triplett
2025-08-14 00:28:44 -07:00
parent 040a98af70
commit b65fab6299
23 changed files with 425 additions and 395 deletions

View File

@@ -23,6 +23,9 @@ use rustc_span::Span;
use tracing::{instrument, trace};
pub use unic_langid::{LanguageIdentifier, langid};
mod diagnostic_impls;
pub use diagnostic_impls::DiagArgFromDisplay;
pub type FluentBundle =
IntoDynSyncSend<fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>>;
@@ -589,3 +592,53 @@ pub fn fluent_value_from_str_list_sep_by_and(l: Vec<Cow<'_, str>>) -> FluentValu
FluentValue::Custom(Box::new(FluentStrListSepByAnd(l)))
}
/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
/// `DiagArg` are converted to `FluentArgs` (consuming the collection) at the start of diagnostic
/// emission.
pub type DiagArg<'iter> = (&'iter DiagArgName, &'iter DiagArgValue);
/// Name of a diagnostic argument.
pub type DiagArgName = Cow<'static, str>;
/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum DiagArgValue {
Str(Cow<'static, str>),
// This gets converted to a `FluentNumber`, which is an `f64`. An `i32`
// safely fits in an `f64`. Any integers bigger than that will be converted
// to strings in `into_diag_arg` and stored using the `Str` variant.
Number(i32),
StrListSepByAnd(Vec<Cow<'static, str>>),
}
/// Converts a value of a type into a `DiagArg` (typically a field of an `Diag` struct).
/// Implemented as a custom trait rather than `From` so that it is implemented on the type being
/// converted rather than on `DiagArgValue`, which enables types from other `rustc_*` crates to
/// implement this.
pub trait IntoDiagArg {
/// Convert `Self` into a `DiagArgValue` suitable for rendering in a diagnostic.
///
/// It takes a `path` where "long values" could be written to, if the `DiagArgValue` is too big
/// for displaying on the terminal. This path comes from the `Diag` itself. When rendering
/// values that come from `TyCtxt`, like `Ty<'_>`, they can use `TyCtxt::short_string`. If a
/// value has no shortening logic that could be used, the argument can be safely ignored.
fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue;
}
impl IntoDiagArg for DiagArgValue {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
self
}
}
impl From<DiagArgValue> for FluentValue<'static> {
fn from(val: DiagArgValue) -> Self {
match val {
DiagArgValue::Str(s) => From::from(s),
DiagArgValue::Number(n) => From::from(n),
DiagArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l),
}
}
}