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