Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

errors: simplify referring to fluent attributes #97357

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 66 additions & 6 deletions compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,48 @@ pub fn fallback_fluent_bundle(
/// Identifier for the Fluent message/attribute corresponding to a diagnostic message.
type FluentId = Cow<'static, str>;

/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both
/// translatable and non-translatable diagnostic messages.
///
/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent
/// message so messages of this type must be combined with a `DiagnosticMessage` (using
/// `DiagnosticMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from
/// the `SessionSubdiagnostic` derive refer to Fluent identifiers directly.
pub enum SubdiagnosticMessage {
/// Non-translatable diagnostic message.
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
Str(String),
/// Identifier of a Fluent message. Instances of this variant are generated by the
/// `SessionSubdiagnostic` derive.
FluentIdentifier(FluentId),
/// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an
/// actual translated message. Instances of this variant are generated by the `fluent_messages`
/// macro.
///
/// <https://projectfluent.org/fluent/guide/attributes.html>
FluentAttr(FluentId),
}

impl SubdiagnosticMessage {
/// Create a `SubdiagnosticMessage` for the provided Fluent attribute.
pub fn attr(id: impl Into<FluentId>) -> Self {
SubdiagnosticMessage::FluentAttr(id.into())
}

/// Create a `SubdiagnosticMessage` for the provided Fluent identifier.
pub fn message(id: impl Into<FluentId>) -> Self {
SubdiagnosticMessage::FluentIdentifier(id.into())
}
}

/// `From` impl that enables existing diagnostic calls to functions which now take
/// `impl Into<SubdiagnosticMessage>` to continue to work as before.
impl<S: Into<String>> From<S> for SubdiagnosticMessage {
fn from(s: S) -> Self {
SubdiagnosticMessage::Str(s.into())
}
}

/// Abstraction over a message in a diagnostic to support both translatable and non-translatable
/// diagnostic messages.
///
Expand All @@ -252,6 +294,29 @@ pub enum DiagnosticMessage {
}

impl DiagnosticMessage {
/// Given a `SubdiagnosticMessage` which may contain a Fluent attribute, create a new
/// `DiagnosticMessage` that combines that attribute with the Fluent identifier of `self`.
///
/// - If the `SubdiagnosticMessage` is non-translatable then return the message as a
/// `DiagnosticMessage`.
/// - If `self` is non-translatable then return `self`'s message.
pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
let attr = match sub {
SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s.clone()),
SubdiagnosticMessage::FluentIdentifier(id) => {
return DiagnosticMessage::FluentIdentifier(id, None);
}
SubdiagnosticMessage::FluentAttr(attr) => attr,
};

match self {
DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
DiagnosticMessage::FluentIdentifier(id, _) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this ever happen where then _ is Some already?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't as the code is written right now, but it wouldn't be much of a problem if it did. I considered adding a panic or something like that.

DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
}
}
}

/// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that
/// this diagnostic message is of the legacy, non-translatable variety. Panics if this
/// assumption does not hold.
Expand All @@ -266,14 +331,9 @@ impl DiagnosticMessage {
}

/// Create a `DiagnosticMessage` for the provided Fluent identifier.
pub fn fluent(id: impl Into<FluentId>) -> Self {
pub fn new(id: impl Into<FluentId>) -> Self {
DiagnosticMessage::FluentIdentifier(id.into(), None)
}

/// Create a `DiagnosticMessage` for the provided Fluent identifier and attribute.
pub fn fluent_attr(id: impl Into<FluentId>, attr: impl Into<FluentId>) -> Self {
DiagnosticMessage::FluentIdentifier(id.into(), Some(attr.into()))
}
}

/// `From` impl that enables existing diagnostic calls to functions which now take
Expand Down
Loading