Rollup merge of #102623 - davidtwco:translation-eager, r=compiler-errors
translation: eager translation
Part of #100717. See [Zulip thread](295010720
) for additional context.
- **Store diagnostic arguments in a `HashMap`**: Eager translation will enable subdiagnostics to be translated multiple times with different arguments - this requires the ability to replace the value of one argument with a new value, which is better suited to a `HashMap` than the previous storage, a `Vec`.
- **Add `AddToDiagnostic::add_to_diagnostic_with`**: `AddToDiagnostic::add_to_diagnostic_with` is similar to the previous `AddToDiagnostic::add_to_diagnostic` but takes a function that can be used by the caller to modify diagnostic messages originating from the subdiagnostic (such as performing translation eagerly). `add_to_diagnostic` now just calls `add_to_diagnostic_with` with an empty closure.
- **Add `DiagnosticMessage::Eager`**: Add variant of `DiagnosticMessage` for eagerly translated messages
(messages in the target language which don't need translated by the emitter during emission). Also adds `eager_subdiagnostic` function which is intended to be invoked by the diagnostic derive for subdiagnostic fields which are marked as needing eager translation.
- **Support `#[subdiagnostic(eager)]`**: Add support for `eager` argument to the `subdiagnostic` attribute which generates a call to `eager_subdiagnostic`.
- **Finish migrating `rustc_query_system`**: Using eager translation, migrate the remaining repeated cycle stack diagnostic.
- **Split formatting initialization and use in diagnostic derives**: Diagnostic derives have previously had to take special care when ordering the generated code so that fields were not used after a move.
This is unlikely for most fields because a field is either annotated with a subdiagnostic attribute and is thus likely a `Span` and copiable, or is a argument, in which case it is only used once by `set_arg`
anyway.
However, format strings for code in suggestions can result in fields being used after being moved if not ordered carefully. As a result, the derive currently puts `set_arg` calls last (just before emission), such as:
let diag = { /* create diagnostic */ };
diag.span_suggestion_with_style(
span,
fluent::crate::slug,
format!("{}", __binding_0),
Applicability::Unknown,
SuggestionStyle::ShowAlways
);
/* + other subdiagnostic additions */
diag.set_arg("foo", __binding_0);
/* + other `set_arg` calls */
diag.emit();
For eager translation, this doesn't work, as the message being translated eagerly can assume that all arguments are available - so arguments _must_ be set first.
Format strings for suggestion code are now separated into two parts - an initialization line that performs the formatting into a variable, and a usage in the subdiagnostic addition.
By separating these parts, the initialization can happen before arguments are set, preserving the desired order so that code compiles, while still enabling arguments to be set before subdiagnostics are added.
let diag = { /* create diagnostic */ };
let __code_0 = format!("{}", __binding_0);
/* + other formatting */
diag.set_arg("foo", __binding_0);
/* + other `set_arg` calls */
diag.span_suggestion_with_style(
span,
fluent::crate::slug,
__code_0,
Applicability::Unknown,
SuggestionStyle::ShowAlways
);
/* + other subdiagnostic additions */
diag.emit();
- **Remove field ordering logic in diagnostic derive:** Following the approach taken in earlier commits to separate formatting initialization from use in the subdiagnostic derive, simplify the diagnostic derive by removing the field-ordering logic that previously solved this problem.
r? ```@compiler-errors```
This commit is contained in:
commit
dc9f6f3243
26 changed files with 540 additions and 236 deletions
|
@ -277,6 +277,18 @@ pub enum SubdiagnosticMessage {
|
|||
/// Non-translatable diagnostic message.
|
||||
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
|
||||
Str(String),
|
||||
/// Translatable message which has already been translated eagerly.
|
||||
///
|
||||
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
|
||||
/// be instantiated multiple times with different values. As translation normally happens
|
||||
/// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
|
||||
/// the setting of diagnostic arguments in the derived code will overwrite previous variable
|
||||
/// values and only the final value will be set when translation occurs - resulting in
|
||||
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
|
||||
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
|
||||
/// stores messages which have been translated eagerly.
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Eager(String),
|
||||
/// Identifier of a Fluent message. Instances of this variant are generated by the
|
||||
/// `Subdiagnostic` derive.
|
||||
FluentIdentifier(FluentId),
|
||||
|
@ -304,8 +316,20 @@ impl<S: Into<String>> From<S> for SubdiagnosticMessage {
|
|||
#[rustc_diagnostic_item = "DiagnosticMessage"]
|
||||
pub enum DiagnosticMessage {
|
||||
/// Non-translatable diagnostic message.
|
||||
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Str(String),
|
||||
/// Translatable message which has already been translated eagerly.
|
||||
///
|
||||
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
|
||||
/// be instantiated multiple times with different values. As translation normally happens
|
||||
/// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
|
||||
/// the setting of diagnostic arguments in the derived code will overwrite previous variable
|
||||
/// values and only the final value will be set when translation occurs - resulting in
|
||||
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
|
||||
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
|
||||
/// stores messages which have been translated eagerly.
|
||||
// FIXME(#100717): can a `Cow<'static, str>` be used here?
|
||||
Eager(String),
|
||||
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
|
||||
/// message.
|
||||
///
|
||||
|
@ -324,6 +348,7 @@ impl DiagnosticMessage {
|
|||
pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
|
||||
let attr = match sub {
|
||||
SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
|
||||
SubdiagnosticMessage::Eager(s) => return DiagnosticMessage::Eager(s),
|
||||
SubdiagnosticMessage::FluentIdentifier(id) => {
|
||||
return DiagnosticMessage::FluentIdentifier(id, None);
|
||||
}
|
||||
|
@ -332,6 +357,7 @@ impl DiagnosticMessage {
|
|||
|
||||
match self {
|
||||
DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
|
||||
DiagnosticMessage::Eager(s) => DiagnosticMessage::Eager(s.clone()),
|
||||
DiagnosticMessage::FluentIdentifier(id, _) => {
|
||||
DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
|
||||
}
|
||||
|
@ -367,6 +393,7 @@ impl Into<SubdiagnosticMessage> for DiagnosticMessage {
|
|||
fn into(self) -> SubdiagnosticMessage {
|
||||
match self {
|
||||
DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
|
||||
DiagnosticMessage::Eager(s) => SubdiagnosticMessage::Eager(s),
|
||||
DiagnosticMessage::FluentIdentifier(id, None) => {
|
||||
SubdiagnosticMessage::FluentIdentifier(id)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue