Skip to main content

rustc_error_messages/
lib.rs

1// tidy-alphabetical-start
2#![allow(internal_features)]
3#![feature(rustc_attrs)]
4// tidy-alphabetical-end
5
6use std::borrow::Cow;
7use std::error::Error;
8use std::path::Path;
9use std::sync::{Arc, LazyLock};
10use std::{fmt, fs, io};
11
12use fluent_bundle::FluentResource;
13pub use fluent_bundle::types::FluentType;
14pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue};
15use fluent_syntax::parser::ParserError;
16use intl_memoizer::concurrent::IntlLangMemoizer;
17use rustc_data_structures::sync::{DynSend, IntoDynSyncSend};
18use rustc_macros::{Decodable, Encodable};
19use rustc_span::Span;
20use tracing::{instrument, trace};
21pub use unic_langid::{LanguageIdentifier, langid};
22
23mod diagnostic_impls;
24pub use diagnostic_impls::DiagArgFromDisplay;
25
26pub type FluentBundle =
27    IntoDynSyncSend<fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>>;
28
29fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle {
30    IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new_concurrent(locales))
31}
32
33#[derive(#[automatically_derived]
impl ::core::fmt::Debug for TranslationBundleError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            TranslationBundleError::ReadFtl(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ReadFtl", &__self_0),
            TranslationBundleError::ParseFtl(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ParseFtl", &__self_0),
            TranslationBundleError::AddResource(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "AddResource", &__self_0),
            TranslationBundleError::MissingLocale =>
                ::core::fmt::Formatter::write_str(f, "MissingLocale"),
            TranslationBundleError::ReadLocalesDir(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ReadLocalesDir", &__self_0),
            TranslationBundleError::ReadLocalesDirEntry(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ReadLocalesDirEntry", &__self_0),
            TranslationBundleError::LocaleIsNotDir =>
                ::core::fmt::Formatter::write_str(f, "LocaleIsNotDir"),
        }
    }
}Debug)]
34pub enum TranslationBundleError {
35    /// Failed to read from `.ftl` file.
36    ReadFtl(io::Error),
37    /// Failed to parse contents of `.ftl` file.
38    ParseFtl(ParserError),
39    /// Failed to add `FluentResource` to `FluentBundle`.
40    AddResource(FluentError),
41    /// `$sysroot/share/locale/$locale` does not exist.
42    MissingLocale,
43    /// Cannot read directory entries of `$sysroot/share/locale/$locale`.
44    ReadLocalesDir(io::Error),
45    /// Cannot read directory entry of `$sysroot/share/locale/$locale`.
46    ReadLocalesDirEntry(io::Error),
47    /// `$sysroot/share/locale/$locale` is not a directory.
48    LocaleIsNotDir,
49}
50
51impl fmt::Display for TranslationBundleError {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        match self {
54            TranslationBundleError::ReadFtl(e) => f.write_fmt(format_args!("could not read ftl file: {0}", e))write!(f, "could not read ftl file: {e}"),
55            TranslationBundleError::ParseFtl(e) => {
56                f.write_fmt(format_args!("could not parse ftl file: {0}", e))write!(f, "could not parse ftl file: {e}")
57            }
58            TranslationBundleError::AddResource(e) => f.write_fmt(format_args!("failed to add resource: {0}", e))write!(f, "failed to add resource: {e}"),
59            TranslationBundleError::MissingLocale => f.write_fmt(format_args!("missing locale directory"))write!(f, "missing locale directory"),
60            TranslationBundleError::ReadLocalesDir(e) => {
61                f.write_fmt(format_args!("could not read locales dir: {0}", e))write!(f, "could not read locales dir: {e}")
62            }
63            TranslationBundleError::ReadLocalesDirEntry(e) => {
64                f.write_fmt(format_args!("could not read locales dir entry: {0}", e))write!(f, "could not read locales dir entry: {e}")
65            }
66            TranslationBundleError::LocaleIsNotDir => {
67                f.write_fmt(format_args!("`$sysroot/share/locales/$locale` is not a directory"))write!(f, "`$sysroot/share/locales/$locale` is not a directory")
68            }
69        }
70    }
71}
72
73impl Error for TranslationBundleError {
74    fn source(&self) -> Option<&(dyn Error + 'static)> {
75        match self {
76            TranslationBundleError::ReadFtl(e) => Some(e),
77            TranslationBundleError::ParseFtl(e) => Some(e),
78            TranslationBundleError::AddResource(e) => Some(e),
79            TranslationBundleError::MissingLocale => None,
80            TranslationBundleError::ReadLocalesDir(e) => Some(e),
81            TranslationBundleError::ReadLocalesDirEntry(e) => Some(e),
82            TranslationBundleError::LocaleIsNotDir => None,
83        }
84    }
85}
86
87impl From<(FluentResource, Vec<ParserError>)> for TranslationBundleError {
88    fn from((_, mut errs): (FluentResource, Vec<ParserError>)) -> Self {
89        TranslationBundleError::ParseFtl(errs.pop().expect("failed ftl parse with no errors"))
90    }
91}
92
93impl From<Vec<FluentError>> for TranslationBundleError {
94    fn from(mut errs: Vec<FluentError>) -> Self {
95        TranslationBundleError::AddResource(
96            errs.pop().expect("failed adding resource to bundle with no errors"),
97        )
98    }
99}
100
101/// Returns Fluent bundle with the user's locale resources from
102/// `$sysroot/share/locale/$requested_locale/*.ftl`.
103///
104/// If `-Z additional-ftl-path` was provided, load that resource and add it  to the bundle
105/// (overriding any conflicting messages).
106#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("fluent_bundle",
                                    "rustc_error_messages", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                    ::tracing_core::__macro_support::Option::Some(106u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                    ::tracing_core::field::FieldSet::new(&["sysroot_candidates",
                                                    "requested_locale", "additional_ftl_path",
                                                    "with_directionality_markers"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&sysroot_candidates)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&requested_locale)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&additional_ftl_path)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&with_directionality_markers
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return:
                    Result<Option<Arc<FluentBundle>>, TranslationBundleError> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            if requested_locale.is_none() && additional_ftl_path.is_none() {
                return Ok(None);
            }
            let fallback_locale =
                {
                    #[allow(dead_code)]
                    enum ProcMacroHack { Value = ("\"en-US\"", 0).1, }
                    macro_rules! proc_macro_call {
                        () =>
                        {
                            unsafe
                            {
                                $crate :: LanguageIdentifier ::
                                from_raw_parts_unchecked(unsafe
                                {
                                    $crate :: subtags :: Language ::
                                    from_raw_unchecked(28261u64)
                                }, None,
                                Some(unsafe
                                {
                                    $crate :: subtags :: Region :: from_raw_unchecked(21333u32)
                                }), None)
                            }
                        }
                    }
                    unsafe {
                        ::unic_langid_macros::LanguageIdentifier::from_raw_parts_unchecked(unsafe
                                {
                                ::unic_langid_macros::subtags::Language::from_raw_unchecked(28261u64)
                            }, None,
                            Some(unsafe {
                                    ::unic_langid_macros::subtags::Region::from_raw_unchecked(21333u32)
                                }), None)
                    }
                };
            let requested_fallback_locale =
                requested_locale.as_ref() == Some(&fallback_locale);
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_error_messages/src/lib.rs:119",
                                    "rustc_error_messages", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                    ::tracing_core::__macro_support::Option::Some(119u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                    ::tracing_core::field::FieldSet::new(&["requested_fallback_locale"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&requested_fallback_locale)
                                                        as &dyn Value))])
                        });
                } else { ; }
            };
            if requested_fallback_locale && additional_ftl_path.is_none() {
                return Ok(None);
            }
            let locale = requested_locale.clone().unwrap_or(fallback_locale);
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_error_messages/src/lib.rs:126",
                                    "rustc_error_messages", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                    ::tracing_core::__macro_support::Option::Some(126u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                    ::tracing_core::field::FieldSet::new(&["locale"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&locale) as
                                                        &dyn Value))])
                        });
                } else { ; }
            };
            let mut bundle =
                new_bundle(<[_]>::into_vec(::alloc::boxed::box_new([locale])));
            register_functions(&mut bundle);
            bundle.set_use_isolating(with_directionality_markers);
            if let Some(requested_locale) = requested_locale {
                let mut found_resources = false;
                for sysroot in sysroot_candidates {
                    let mut sysroot = sysroot.to_path_buf();
                    sysroot.push("share");
                    sysroot.push("locale");
                    sysroot.push(requested_locale.to_string());
                    {
                        use ::tracing::__macro_support::Callsite as _;
                        static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                            {
                                static META: ::tracing::Metadata<'static> =
                                    {
                                        ::tracing_core::metadata::Metadata::new("event compiler/rustc_error_messages/src/lib.rs:147",
                                            "rustc_error_messages", ::tracing::Level::TRACE,
                                            ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                            ::tracing_core::__macro_support::Option::Some(147u32),
                                            ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                            ::tracing_core::field::FieldSet::new(&["sysroot"],
                                                ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                            ::tracing::metadata::Kind::EVENT)
                                    };
                                ::tracing::callsite::DefaultCallsite::new(&META)
                            };
                        let enabled =
                            ::tracing::Level::TRACE <=
                                        ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                    ::tracing::Level::TRACE <=
                                        ::tracing::level_filters::LevelFilter::current() &&
                                {
                                    let interest = __CALLSITE.interest();
                                    !interest.is_never() &&
                                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                            interest)
                                };
                        if enabled {
                            (|value_set: ::tracing::field::ValueSet|
                                        {
                                            let meta = __CALLSITE.metadata();
                                            ::tracing::Event::dispatch(meta, &value_set);
                                            ;
                                        })({
                                    #[allow(unused_imports)]
                                    use ::tracing::field::{debug, display, Value};
                                    let mut iter = __CALLSITE.metadata().fields().iter();
                                    __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                        ::tracing::__macro_support::Option::Some(&debug(&sysroot) as
                                                                &dyn Value))])
                                });
                        } else { ; }
                    };
                    if !sysroot.exists() {
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                {
                                    static META: ::tracing::Metadata<'static> =
                                        {
                                            ::tracing_core::metadata::Metadata::new("event compiler/rustc_error_messages/src/lib.rs:150",
                                                "rustc_error_messages", ::tracing::Level::TRACE,
                                                ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                                ::tracing_core::__macro_support::Option::Some(150u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                                ::tracing_core::field::FieldSet::new(&["message"],
                                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                ::tracing::metadata::Kind::EVENT)
                                        };
                                    ::tracing::callsite::DefaultCallsite::new(&META)
                                };
                            let enabled =
                                ::tracing::Level::TRACE <=
                                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                        ::tracing::Level::TRACE <=
                                            ::tracing::level_filters::LevelFilter::current() &&
                                    {
                                        let interest = __CALLSITE.interest();
                                        !interest.is_never() &&
                                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                interest)
                                    };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet|
                                            {
                                                let meta = __CALLSITE.metadata();
                                                ::tracing::Event::dispatch(meta, &value_set);
                                                ;
                                            })({
                                        #[allow(unused_imports)]
                                        use ::tracing::field::{debug, display, Value};
                                        let mut iter = __CALLSITE.metadata().fields().iter();
                                        __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&format_args!("skipping")
                                                                    as &dyn Value))])
                                    });
                            } else { ; }
                        };
                        continue;
                    }
                    if !sysroot.is_dir() {
                        return Err(TranslationBundleError::LocaleIsNotDir);
                    }
                    for entry in
                        sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)?
                        {
                        let entry =
                            entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?;
                        let path = entry.path();
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                {
                                    static META: ::tracing::Metadata<'static> =
                                        {
                                            ::tracing_core::metadata::Metadata::new("event compiler/rustc_error_messages/src/lib.rs:161",
                                                "rustc_error_messages", ::tracing::Level::TRACE,
                                                ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                                ::tracing_core::__macro_support::Option::Some(161u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                                ::tracing_core::field::FieldSet::new(&["path"],
                                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                ::tracing::metadata::Kind::EVENT)
                                        };
                                    ::tracing::callsite::DefaultCallsite::new(&META)
                                };
                            let enabled =
                                ::tracing::Level::TRACE <=
                                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                        ::tracing::Level::TRACE <=
                                            ::tracing::level_filters::LevelFilter::current() &&
                                    {
                                        let interest = __CALLSITE.interest();
                                        !interest.is_never() &&
                                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                interest)
                                    };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet|
                                            {
                                                let meta = __CALLSITE.metadata();
                                                ::tracing::Event::dispatch(meta, &value_set);
                                                ;
                                            })({
                                        #[allow(unused_imports)]
                                        use ::tracing::field::{debug, display, Value};
                                        let mut iter = __CALLSITE.metadata().fields().iter();
                                        __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&debug(&path) as
                                                                    &dyn Value))])
                                    });
                            } else { ; }
                        };
                        if path.extension().and_then(|s| s.to_str()) != Some("ftl")
                            {
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_error_messages/src/lib.rs:163",
                                                    "rustc_error_messages", ::tracing::Level::TRACE,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(163u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                                    ::tracing_core::field::FieldSet::new(&["message"],
                                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::TRACE <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&format_args!("skipping")
                                                                        as &dyn Value))])
                                        });
                                } else { ; }
                            };
                            continue;
                        }
                        let resource_str =
                            fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?;
                        let resource =
                            FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                {
                                    static META: ::tracing::Metadata<'static> =
                                        {
                                            ::tracing_core::metadata::Metadata::new("event compiler/rustc_error_messages/src/lib.rs:171",
                                                "rustc_error_messages", ::tracing::Level::TRACE,
                                                ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                                ::tracing_core::__macro_support::Option::Some(171u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                                ::tracing_core::field::FieldSet::new(&["resource"],
                                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                ::tracing::metadata::Kind::EVENT)
                                        };
                                    ::tracing::callsite::DefaultCallsite::new(&META)
                                };
                            let enabled =
                                ::tracing::Level::TRACE <=
                                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                        ::tracing::Level::TRACE <=
                                            ::tracing::level_filters::LevelFilter::current() &&
                                    {
                                        let interest = __CALLSITE.interest();
                                        !interest.is_never() &&
                                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                interest)
                                    };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet|
                                            {
                                                let meta = __CALLSITE.metadata();
                                                ::tracing::Event::dispatch(meta, &value_set);
                                                ;
                                            })({
                                        #[allow(unused_imports)]
                                        use ::tracing::field::{debug, display, Value};
                                        let mut iter = __CALLSITE.metadata().fields().iter();
                                        __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&debug(&resource)
                                                                    as &dyn Value))])
                                    });
                            } else { ; }
                        };
                        bundle.add_resource(resource).map_err(TranslationBundleError::from)?;
                        found_resources = true;
                    }
                }
                if !found_resources {
                    return Err(TranslationBundleError::MissingLocale);
                }
            }
            if let Some(additional_ftl_path) = additional_ftl_path {
                let resource_str =
                    fs::read_to_string(additional_ftl_path).map_err(TranslationBundleError::ReadFtl)?;
                let resource =
                    FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
                {
                    use ::tracing::__macro_support::Callsite as _;
                    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                        {
                            static META: ::tracing::Metadata<'static> =
                                {
                                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_error_messages/src/lib.rs:187",
                                        "rustc_error_messages", ::tracing::Level::TRACE,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                        ::tracing_core::__macro_support::Option::Some(187u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                        ::tracing_core::field::FieldSet::new(&["resource"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::EVENT)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let enabled =
                        ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            {
                                let interest = __CALLSITE.interest();
                                !interest.is_never() &&
                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                        interest)
                            };
                    if enabled {
                        (|value_set: ::tracing::field::ValueSet|
                                    {
                                        let meta = __CALLSITE.metadata();
                                        ::tracing::Event::dispatch(meta, &value_set);
                                        ;
                                    })({
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&debug(&resource)
                                                            as &dyn Value))])
                            });
                    } else { ; }
                };
                bundle.add_resource_overriding(resource);
            }
            let bundle = Arc::new(bundle);
            Ok(Some(bundle))
        }
    }
}#[instrument(level = "trace")]
107pub fn fluent_bundle(
108    sysroot_candidates: &[&Path],
109    requested_locale: Option<LanguageIdentifier>,
110    additional_ftl_path: Option<&Path>,
111    with_directionality_markers: bool,
112) -> Result<Option<Arc<FluentBundle>>, TranslationBundleError> {
113    if requested_locale.is_none() && additional_ftl_path.is_none() {
114        return Ok(None);
115    }
116
117    let fallback_locale = langid!("en-US");
118    let requested_fallback_locale = requested_locale.as_ref() == Some(&fallback_locale);
119    trace!(?requested_fallback_locale);
120    if requested_fallback_locale && additional_ftl_path.is_none() {
121        return Ok(None);
122    }
123    // If there is only `-Z additional-ftl-path`, assume locale is "en-US", otherwise use user
124    // provided locale.
125    let locale = requested_locale.clone().unwrap_or(fallback_locale);
126    trace!(?locale);
127    let mut bundle = new_bundle(vec![locale]);
128
129    // Add convenience functions available to ftl authors.
130    register_functions(&mut bundle);
131
132    // Fluent diagnostics can insert directionality isolation markers around interpolated variables
133    // indicating that there may be a shift from right-to-left to left-to-right text (or
134    // vice-versa). These are disabled because they are sometimes visible in the error output, but
135    // may be worth investigating in future (for example: if type names are left-to-right and the
136    // surrounding diagnostic messages are right-to-left, then these might be helpful).
137    bundle.set_use_isolating(with_directionality_markers);
138
139    // If the user requests the default locale then don't try to load anything.
140    if let Some(requested_locale) = requested_locale {
141        let mut found_resources = false;
142        for sysroot in sysroot_candidates {
143            let mut sysroot = sysroot.to_path_buf();
144            sysroot.push("share");
145            sysroot.push("locale");
146            sysroot.push(requested_locale.to_string());
147            trace!(?sysroot);
148
149            if !sysroot.exists() {
150                trace!("skipping");
151                continue;
152            }
153
154            if !sysroot.is_dir() {
155                return Err(TranslationBundleError::LocaleIsNotDir);
156            }
157
158            for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? {
159                let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?;
160                let path = entry.path();
161                trace!(?path);
162                if path.extension().and_then(|s| s.to_str()) != Some("ftl") {
163                    trace!("skipping");
164                    continue;
165                }
166
167                let resource_str =
168                    fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?;
169                let resource =
170                    FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
171                trace!(?resource);
172                bundle.add_resource(resource).map_err(TranslationBundleError::from)?;
173                found_resources = true;
174            }
175        }
176
177        if !found_resources {
178            return Err(TranslationBundleError::MissingLocale);
179        }
180    }
181
182    if let Some(additional_ftl_path) = additional_ftl_path {
183        let resource_str =
184            fs::read_to_string(additional_ftl_path).map_err(TranslationBundleError::ReadFtl)?;
185        let resource =
186            FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
187        trace!(?resource);
188        bundle.add_resource_overriding(resource);
189    }
190
191    let bundle = Arc::new(bundle);
192    Ok(Some(bundle))
193}
194
195fn register_functions(bundle: &mut FluentBundle) {
196    bundle
197        .add_function("STREQ", |positional, _named| match positional {
198            [FluentValue::String(a), FluentValue::String(b)] => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}", (a == b)))
    })format!("{}", (a == b)).into(),
199            _ => FluentValue::Error,
200        })
201        .expect("Failed to add a function to the bundle.");
202}
203
204/// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily
205/// evaluated fluent bundle.
206pub type LazyFallbackBundle =
207    Arc<LazyLock<FluentBundle, Box<dyn FnOnce() -> FluentBundle + DynSend>>>;
208
209/// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
210#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("fallback_fluent_bundle",
                                    "rustc_error_messages", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_error_messages/src/lib.rs"),
                                    ::tracing_core::__macro_support::Option::Some(210u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_error_messages"),
                                    ::tracing_core::field::FieldSet::new(&["with_directionality_markers"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&with_directionality_markers
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: LazyFallbackBundle = loop {};
            return __tracing_attr_fake_return;
        }
        {
            Arc::new(LazyLock::new(Box::new(move ||
                            {
                                let mut fallback_bundle =
                                    new_bundle(<[_]>::into_vec(::alloc::boxed::box_new([{
                                                            #[allow(dead_code)]
                                                            enum ProcMacroHack { Value = ("\"en-US\"", 0).1, }
                                                            macro_rules! proc_macro_call {
                                                                () =>
                                                                {
                                                                    unsafe
                                                                    {
                                                                        $crate :: LanguageIdentifier ::
                                                                        from_raw_parts_unchecked(unsafe
                                                                        {
                                                                            $crate :: subtags :: Language ::
                                                                            from_raw_unchecked(28261u64)
                                                                        }, None,
                                                                        Some(unsafe
                                                                        {
                                                                            $crate :: subtags :: Region :: from_raw_unchecked(21333u32)
                                                                        }), None)
                                                                    }
                                                                }
                                                            }
                                                            unsafe {
                                                                ::unic_langid_macros::LanguageIdentifier::from_raw_parts_unchecked(unsafe
                                                                        {
                                                                        ::unic_langid_macros::subtags::Language::from_raw_unchecked(28261u64)
                                                                    }, None,
                                                                    Some(unsafe {
                                                                            ::unic_langid_macros::subtags::Region::from_raw_unchecked(21333u32)
                                                                        }), None)
                                                            }
                                                        }])));
                                register_functions(&mut fallback_bundle);
                                fallback_bundle.set_use_isolating(with_directionality_markers);
                                for resource in resources {
                                    let resource =
                                        FluentResource::try_new(resource.to_string()).expect("failed to parse fallback fluent resource");
                                    fallback_bundle.add_resource_overriding(resource);
                                }
                                fallback_bundle
                            })))
        }
    }
}#[instrument(level = "trace", skip(resources))]
211pub fn fallback_fluent_bundle(
212    resources: Vec<&'static str>,
213    with_directionality_markers: bool,
214) -> LazyFallbackBundle {
215    Arc::new(LazyLock::new(Box::new(move || {
216        let mut fallback_bundle = new_bundle(vec![langid!("en-US")]);
217
218        register_functions(&mut fallback_bundle);
219
220        // See comment in `fluent_bundle`.
221        fallback_bundle.set_use_isolating(with_directionality_markers);
222
223        for resource in resources {
224            let resource = FluentResource::try_new(resource.to_string())
225                .expect("failed to parse fallback fluent resource");
226            fallback_bundle.add_resource_overriding(resource);
227        }
228
229        fallback_bundle
230    })))
231}
232
233/// Identifier for the Fluent message/attribute corresponding to a diagnostic message.
234type FluentId = Cow<'static, str>;
235
236/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both
237/// translatable and non-translatable diagnostic messages.
238///
239/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent
240/// message so messages of this type must be combined with a `DiagMessage` (using
241/// `DiagMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from
242/// the `Subdiagnostic` derive refer to Fluent identifiers directly.
243#[rustc_diagnostic_item = "SubdiagMessage"]
244pub enum SubdiagMessage {
245    /// Non-translatable diagnostic message.
246    Str(Cow<'static, str>),
247    /// Identifier of a Fluent message. Instances of this variant are generated by the
248    /// `Subdiagnostic` derive.
249    FluentIdentifier(FluentId),
250    /// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an
251    /// actual translated message. Instances of this variant are generated by the `fluent_messages`
252    /// macro.
253    ///
254    /// <https://projectfluent.org/fluent/guide/attributes.html>
255    FluentAttr(FluentId),
256}
257
258impl From<String> for SubdiagMessage {
259    fn from(s: String) -> Self {
260        SubdiagMessage::Str(Cow::Owned(s))
261    }
262}
263impl From<&'static str> for SubdiagMessage {
264    fn from(s: &'static str) -> Self {
265        SubdiagMessage::Str(Cow::Borrowed(s))
266    }
267}
268impl From<Cow<'static, str>> for SubdiagMessage {
269    fn from(s: Cow<'static, str>) -> Self {
270        SubdiagMessage::Str(s)
271    }
272}
273
274/// Abstraction over a message in a diagnostic to support both translatable and non-translatable
275/// diagnostic messages.
276///
277/// Intended to be removed once diagnostics are entirely translatable.
278#[derive(#[automatically_derived]
impl ::core::clone::Clone for DiagMessage {
    #[inline]
    fn clone(&self) -> DiagMessage {
        match self {
            DiagMessage::Str(__self_0) =>
                DiagMessage::Str(::core::clone::Clone::clone(__self_0)),
            DiagMessage::FluentIdentifier(__self_0, __self_1) =>
                DiagMessage::FluentIdentifier(::core::clone::Clone::clone(__self_0),
                    ::core::clone::Clone::clone(__self_1)),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for DiagMessage {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            DiagMessage::Str(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Str",
                    &__self_0),
            DiagMessage::FluentIdentifier(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "FluentIdentifier", __self_0, &__self_1),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for DiagMessage {
    #[inline]
    fn eq(&self, other: &DiagMessage) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (DiagMessage::Str(__self_0), DiagMessage::Str(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (DiagMessage::FluentIdentifier(__self_0, __self_1),
                    DiagMessage::FluentIdentifier(__arg1_0, __arg1_1)) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for DiagMessage {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Cow<'static, str>>;
        let _: ::core::cmp::AssertParamIsEq<FluentId>;
        let _: ::core::cmp::AssertParamIsEq<Option<FluentId>>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for DiagMessage {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            DiagMessage::Str(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            DiagMessage::FluentIdentifier(__self_0, __self_1) => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            }
        }
    }
}Hash, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for DiagMessage {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        DiagMessage::Str(ref __binding_0) => { 0usize }
                        DiagMessage::FluentIdentifier(ref __binding_0,
                            ref __binding_1) => {
                            1usize
                        }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    DiagMessage::Str(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    DiagMessage::FluentIdentifier(ref __binding_0,
                        ref __binding_1) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for DiagMessage {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        DiagMessage::Str(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => {
                        DiagMessage::FluentIdentifier(::rustc_serialize::Decodable::decode(__decoder),
                            ::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `DiagMessage`, expected 0..2, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable)]
279#[rustc_diagnostic_item = "DiagMessage"]
280pub enum DiagMessage {
281    /// Non-translatable diagnostic message or a message that has been translated eagerly.
282    ///
283    /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
284    /// be instantiated multiple times with different values. These subdiagnostics' messages
285    /// are translated when they are added to the parent diagnostic. This is one of the ways
286    /// this variant of `DiagMessage` is produced.
287    Str(Cow<'static, str>),
288    /// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
289    /// message. Yet to be translated.
290    ///
291    /// <https://projectfluent.org/fluent/guide/hello.html>
292    /// <https://projectfluent.org/fluent/guide/attributes.html>
293    FluentIdentifier(FluentId, Option<FluentId>),
294}
295
296impl DiagMessage {
297    /// Given a `SubdiagMessage` which may contain a Fluent attribute, create a new
298    /// `DiagMessage` that combines that attribute with the Fluent identifier of `self`.
299    ///
300    /// - If the `SubdiagMessage` is non-translatable then return the message as a `DiagMessage`.
301    /// - If `self` is non-translatable then return `self`'s message.
302    pub fn with_subdiagnostic_message(&self, sub: SubdiagMessage) -> Self {
303        let attr = match sub {
304            SubdiagMessage::Str(s) => return DiagMessage::Str(s),
305            SubdiagMessage::FluentIdentifier(id) => {
306                return DiagMessage::FluentIdentifier(id, None);
307            }
308            SubdiagMessage::FluentAttr(attr) => attr,
309        };
310
311        match self {
312            DiagMessage::Str(s) => DiagMessage::Str(s.clone()),
313            DiagMessage::FluentIdentifier(id, _) => {
314                DiagMessage::FluentIdentifier(id.clone(), Some(attr))
315            }
316        }
317    }
318
319    pub fn as_str(&self) -> Option<&str> {
320        match self {
321            DiagMessage::Str(s) => Some(s),
322            DiagMessage::FluentIdentifier(_, _) => None,
323        }
324    }
325}
326
327impl From<String> for DiagMessage {
328    fn from(s: String) -> Self {
329        DiagMessage::Str(Cow::Owned(s))
330    }
331}
332impl From<&'static str> for DiagMessage {
333    fn from(s: &'static str) -> Self {
334        DiagMessage::Str(Cow::Borrowed(s))
335    }
336}
337impl From<Cow<'static, str>> for DiagMessage {
338    fn from(s: Cow<'static, str>) -> Self {
339        DiagMessage::Str(s)
340    }
341}
342
343/// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but
344/// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagMessage` and the
345/// subdiagnostic derive refers to typed identifiers that are `DiagMessage`s, so need to be
346/// able to convert between these, as much as they'll be converted back into `DiagMessage`
347/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive.
348impl From<DiagMessage> for SubdiagMessage {
349    fn from(val: DiagMessage) -> Self {
350        match val {
351            DiagMessage::Str(s) => SubdiagMessage::Str(s),
352            DiagMessage::FluentIdentifier(id, None) => SubdiagMessage::FluentIdentifier(id),
353            // There isn't really a sensible behaviour for this because it loses information but
354            // this is the most sensible of the behaviours.
355            DiagMessage::FluentIdentifier(_, Some(attr)) => SubdiagMessage::FluentAttr(attr),
356        }
357    }
358}
359
360/// A span together with some additional data.
361#[derive(#[automatically_derived]
impl ::core::clone::Clone for SpanLabel {
    #[inline]
    fn clone(&self) -> SpanLabel {
        SpanLabel {
            span: ::core::clone::Clone::clone(&self.span),
            is_primary: ::core::clone::Clone::clone(&self.is_primary),
            label: ::core::clone::Clone::clone(&self.label),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for SpanLabel {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "SpanLabel",
            "span", &self.span, "is_primary", &self.is_primary, "label",
            &&self.label)
    }
}Debug)]
362pub struct SpanLabel {
363    /// The span we are going to include in the final snippet.
364    pub span: Span,
365
366    /// Is this a primary span? This is the "locus" of the message,
367    /// and is indicated with a `^^^^` underline, versus `----`.
368    pub is_primary: bool,
369
370    /// What label should we attach to this span (if any)?
371    pub label: Option<DiagMessage>,
372}
373
374/// A collection of `Span`s.
375///
376/// Spans have two orthogonal attributes:
377///
378/// - They can be *primary spans*. In this case they are the locus of
379///   the error, and would be rendered with `^^^`.
380/// - They can have a *label*. In this case, the label is written next
381///   to the mark in the snippet when we render.
382#[derive(#[automatically_derived]
impl ::core::clone::Clone for MultiSpan {
    #[inline]
    fn clone(&self) -> MultiSpan {
        MultiSpan {
            primary_spans: ::core::clone::Clone::clone(&self.primary_spans),
            span_labels: ::core::clone::Clone::clone(&self.span_labels),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for MultiSpan {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "MultiSpan",
            "primary_spans", &self.primary_spans, "span_labels",
            &&self.span_labels)
    }
}Debug, #[automatically_derived]
impl ::core::hash::Hash for MultiSpan {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.primary_spans, state);
        ::core::hash::Hash::hash(&self.span_labels, state)
    }
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for MultiSpan {
    #[inline]
    fn eq(&self, other: &MultiSpan) -> bool {
        self.primary_spans == other.primary_spans &&
            self.span_labels == other.span_labels
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for MultiSpan {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Vec<Span>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<(Span, DiagMessage)>>;
    }
}Eq, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for MultiSpan {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    MultiSpan {
                        primary_spans: ref __binding_0, span_labels: ref __binding_1
                        } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for MultiSpan {
            fn decode(__decoder: &mut __D) -> Self {
                MultiSpan {
                    primary_spans: ::rustc_serialize::Decodable::decode(__decoder),
                    span_labels: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };Decodable)]
383pub struct MultiSpan {
384    primary_spans: Vec<Span>,
385    span_labels: Vec<(Span, DiagMessage)>,
386}
387
388impl MultiSpan {
389    #[inline]
390    pub fn new() -> MultiSpan {
391        MultiSpan { primary_spans: ::alloc::vec::Vec::new()vec![], span_labels: ::alloc::vec::Vec::new()vec![] }
392    }
393
394    pub fn from_span(primary_span: Span) -> MultiSpan {
395        MultiSpan { primary_spans: <[_]>::into_vec(::alloc::boxed::box_new([primary_span]))vec![primary_span], span_labels: ::alloc::vec::Vec::new()vec![] }
396    }
397
398    pub fn from_spans(mut vec: Vec<Span>) -> MultiSpan {
399        vec.sort();
400        MultiSpan { primary_spans: vec, span_labels: ::alloc::vec::Vec::new()vec![] }
401    }
402
403    pub fn push_span_label(&mut self, span: Span, label: impl Into<DiagMessage>) {
404        self.span_labels.push((span, label.into()));
405    }
406
407    /// Selects the first primary span (if any).
408    pub fn primary_span(&self) -> Option<Span> {
409        self.primary_spans.first().cloned()
410    }
411
412    /// Returns all primary spans.
413    pub fn primary_spans(&self) -> &[Span] {
414        &self.primary_spans
415    }
416
417    /// Returns `true` if any of the primary spans are displayable.
418    pub fn has_primary_spans(&self) -> bool {
419        !self.is_dummy()
420    }
421
422    /// Returns `true` if this contains only a dummy primary span with any hygienic context.
423    pub fn is_dummy(&self) -> bool {
424        self.primary_spans.iter().all(|sp| sp.is_dummy())
425    }
426
427    /// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
428    /// display well (like std macros). Returns whether replacements occurred.
429    pub fn replace(&mut self, before: Span, after: Span) -> bool {
430        let mut replacements_occurred = false;
431        for primary_span in &mut self.primary_spans {
432            if *primary_span == before {
433                *primary_span = after;
434                replacements_occurred = true;
435            }
436        }
437        for span_label in &mut self.span_labels {
438            if span_label.0 == before {
439                span_label.0 = after;
440                replacements_occurred = true;
441            }
442        }
443        replacements_occurred
444    }
445
446    /// Returns the strings to highlight. We always ensure that there
447    /// is an entry for each of the primary spans -- for each primary
448    /// span `P`, if there is at least one label with span `P`, we return
449    /// those labels (marked as primary). But otherwise we return
450    /// `SpanLabel` instances with empty labels.
451    pub fn span_labels(&self) -> Vec<SpanLabel> {
452        let is_primary = |span| self.primary_spans.contains(&span);
453
454        let mut span_labels = self
455            .span_labels
456            .iter()
457            .map(|&(span, ref label)| SpanLabel {
458                span,
459                is_primary: is_primary(span),
460                label: Some(label.clone()),
461            })
462            .collect::<Vec<_>>();
463
464        for &span in &self.primary_spans {
465            if !span_labels.iter().any(|sl| sl.span == span) {
466                span_labels.push(SpanLabel { span, is_primary: true, label: None });
467            }
468        }
469
470        span_labels
471    }
472
473    /// Returns `true` if any of the span labels is displayable.
474    pub fn has_span_labels(&self) -> bool {
475        self.span_labels.iter().any(|(sp, _)| !sp.is_dummy())
476    }
477
478    /// Clone this `MultiSpan` without keeping any of the span labels - sometimes a `MultiSpan` is
479    /// to be re-used in another diagnostic, but includes `span_labels` which have translated
480    /// messages. These translated messages would fail to translate without their diagnostic
481    /// arguments which are unlikely to be cloned alongside the `Span`.
482    pub fn clone_ignoring_labels(&self) -> Self {
483        Self { primary_spans: self.primary_spans.clone(), ..MultiSpan::new() }
484    }
485}
486
487impl From<Span> for MultiSpan {
488    fn from(span: Span) -> MultiSpan {
489        MultiSpan::from_span(span)
490    }
491}
492
493impl From<Vec<Span>> for MultiSpan {
494    fn from(spans: Vec<Span>) -> MultiSpan {
495        MultiSpan::from_spans(spans)
496    }
497}
498
499fn icu_locale_from_unic_langid(lang: LanguageIdentifier) -> Option<icu_locale::Locale> {
500    icu_locale::Locale::try_from_str(&lang.to_string()).ok()
501}
502
503pub fn fluent_value_from_str_list_sep_by_and(l: Vec<Cow<'_, str>>) -> FluentValue<'_> {
504    // Fluent requires 'static value here for its AnyEq usages.
505    #[derive(#[automatically_derived]
impl ::core::clone::Clone for FluentStrListSepByAnd {
    #[inline]
    fn clone(&self) -> FluentStrListSepByAnd {
        FluentStrListSepByAnd(::core::clone::Clone::clone(&self.0))
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for FluentStrListSepByAnd {
    #[inline]
    fn eq(&self, other: &FluentStrListSepByAnd) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for FluentStrListSepByAnd {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "FluentStrListSepByAnd", &&self.0)
    }
}Debug)]
506    struct FluentStrListSepByAnd(Vec<String>);
507
508    impl FluentType for FluentStrListSepByAnd {
509        fn duplicate(&self) -> Box<dyn FluentType + Send> {
510            Box::new(self.clone())
511        }
512
513        fn as_string(&self, intls: &intl_memoizer::IntlLangMemoizer) -> Cow<'static, str> {
514            let result = intls
515                .with_try_get::<MemoizableListFormatter, _, _>((), |list_formatter| {
516                    list_formatter.format_to_string(self.0.iter())
517                })
518                .unwrap();
519            Cow::Owned(result)
520        }
521
522        fn as_string_threadsafe(
523            &self,
524            intls: &intl_memoizer::concurrent::IntlLangMemoizer,
525        ) -> Cow<'static, str> {
526            let result = intls
527                .with_try_get::<MemoizableListFormatter, _, _>((), |list_formatter| {
528                    list_formatter.format_to_string(self.0.iter())
529                })
530                .unwrap();
531            Cow::Owned(result)
532        }
533    }
534
535    struct MemoizableListFormatter(icu_list::ListFormatter);
536
537    impl std::ops::Deref for MemoizableListFormatter {
538        type Target = icu_list::ListFormatter;
539        fn deref(&self) -> &Self::Target {
540            &self.0
541        }
542    }
543
544    impl intl_memoizer::Memoizable for MemoizableListFormatter {
545        type Args = ();
546        type Error = ();
547
548        fn construct(lang: LanguageIdentifier, _args: Self::Args) -> Result<Self, Self::Error>
549        where
550            Self: Sized,
551        {
552            let locale = icu_locale_from_unic_langid(lang)
553                .unwrap_or_else(|| rustc_baked_icu_data::supported_locales::EN);
554            let list_formatter = icu_list::ListFormatter::try_new_and_unstable(
555                &rustc_baked_icu_data::BakedDataProvider,
556                locale.into(),
557                icu_list::options::ListFormatterOptions::default()
558                    .with_length(icu_list::options::ListLength::Wide),
559            )
560            .expect("Failed to create list formatter");
561
562            Ok(MemoizableListFormatter(list_formatter))
563        }
564    }
565
566    let l = l.into_iter().map(|x| x.into_owned()).collect();
567
568    FluentValue::Custom(Box::new(FluentStrListSepByAnd(l)))
569}
570
571/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
572/// `DiagArg` are converted to `FluentArgs` (consuming the collection) at the start of diagnostic
573/// emission.
574pub type DiagArg<'iter> = (&'iter DiagArgName, &'iter DiagArgValue);
575
576/// Name of a diagnostic argument.
577pub type DiagArgName = Cow<'static, str>;
578
579/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
580/// to a `FluentValue` by the emitter to be used in diagnostic translation.
581#[derive(#[automatically_derived]
impl ::core::clone::Clone for DiagArgValue {
    #[inline]
    fn clone(&self) -> DiagArgValue {
        match self {
            DiagArgValue::Str(__self_0) =>
                DiagArgValue::Str(::core::clone::Clone::clone(__self_0)),
            DiagArgValue::Number(__self_0) =>
                DiagArgValue::Number(::core::clone::Clone::clone(__self_0)),
            DiagArgValue::StrListSepByAnd(__self_0) =>
                DiagArgValue::StrListSepByAnd(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for DiagArgValue {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            DiagArgValue::Str(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Str",
                    &__self_0),
            DiagArgValue::Number(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Number",
                    &__self_0),
            DiagArgValue::StrListSepByAnd(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "StrListSepByAnd", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for DiagArgValue {
    #[inline]
    fn eq(&self, other: &DiagArgValue) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (DiagArgValue::Str(__self_0), DiagArgValue::Str(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (DiagArgValue::Number(__self_0),
                    DiagArgValue::Number(__arg1_0)) => __self_0 == __arg1_0,
                (DiagArgValue::StrListSepByAnd(__self_0),
                    DiagArgValue::StrListSepByAnd(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for DiagArgValue {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Cow<'static, str>>;
        let _: ::core::cmp::AssertParamIsEq<i32>;
        let _: ::core::cmp::AssertParamIsEq<Vec<Cow<'static, str>>>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for DiagArgValue {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            DiagArgValue::Str(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            DiagArgValue::Number(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            DiagArgValue::StrListSepByAnd(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
        }
    }
}Hash, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for DiagArgValue {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        DiagArgValue::Str(ref __binding_0) => { 0usize }
                        DiagArgValue::Number(ref __binding_0) => { 1usize }
                        DiagArgValue::StrListSepByAnd(ref __binding_0) => { 2usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    DiagArgValue::Str(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    DiagArgValue::Number(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    DiagArgValue::StrListSepByAnd(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for DiagArgValue {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        DiagArgValue::Str(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => {
                        DiagArgValue::Number(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    2usize => {
                        DiagArgValue::StrListSepByAnd(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `DiagArgValue`, expected 0..3, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable)]
582pub enum DiagArgValue {
583    Str(Cow<'static, str>),
584    // This gets converted to a `FluentNumber`, which is an `f64`. An `i32`
585    // safely fits in an `f64`. Any integers bigger than that will be converted
586    // to strings in `into_diag_arg` and stored using the `Str` variant.
587    Number(i32),
588    StrListSepByAnd(Vec<Cow<'static, str>>),
589}
590
591/// Converts a value of a type into a `DiagArg` (typically a field of an `Diag` struct).
592/// Implemented as a custom trait rather than `From` so that it is implemented on the type being
593/// converted rather than on `DiagArgValue`, which enables types from other `rustc_*` crates to
594/// implement this.
595pub trait IntoDiagArg {
596    /// Convert `Self` into a `DiagArgValue` suitable for rendering in a diagnostic.
597    ///
598    /// It takes a `path` where "long values" could be written to, if the `DiagArgValue` is too big
599    /// for displaying on the terminal. This path comes from the `Diag` itself. When rendering
600    /// values that come from `TyCtxt`, like `Ty<'_>`, they can use `TyCtxt::short_string`. If a
601    /// value has no shortening logic that could be used, the argument can be safely ignored.
602    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue;
603}
604
605impl IntoDiagArg for DiagArgValue {
606    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
607        self
608    }
609}
610
611impl From<DiagArgValue> for FluentValue<'static> {
612    fn from(val: DiagArgValue) -> Self {
613        match val {
614            DiagArgValue::Str(s) => From::from(s),
615            DiagArgValue::Number(n) => From::from(n),
616            DiagArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l),
617        }
618    }
619}