Skip to content

Commit

Permalink
errors: lazily load fallback fluent bundle
Browse files Browse the repository at this point in the history
Loading the fallback bundle in compilation sessions that won't go on to
emit any errors unnecessarily degrades compile time performance, so
lazily create the Fluent bundle when it is first required.

Signed-off-by: David Wood <david.wood@huawei.com>
  • Loading branch information
davidtwco committed Apr 13, 2022
1 parent f6cef57 commit 9bfe0e3
Show file tree
Hide file tree
Showing 19 changed files with 94 additions and 81 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1731,7 +1731,7 @@ impl Emitter for SharedEmitter {
None
}

fn fallback_fluent_bundle(&self) -> &Lrc<rustc_errors::FluentBundle> {
fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
panic!("shared emitter attempted to translate a diagnostic");
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1173,7 +1173,7 @@ static DEFAULT_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
/// hook.
pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle");
rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
rustc_errors::ColorConfig::Auto,
None,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/parser.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
parser-struct-literal-body-without-path =
struct literal body without path
.suggestion = you might have forgotten to add the struct literal inside the block
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
parser-struct-literal-body-without-path =
struct literal body without path
.suggestion = you might have forgotten to add the struct literal inside the block
typeck-field-multiply-specified-in-initializer =
field `{$ident}` specified more than once
.label = used more than once
Expand Down
40 changes: 29 additions & 11 deletions compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![feature(let_chains)]
#![feature(once_cell)]
#![feature(path_try_exists)]
#![feature(type_alias_impl_trait)]

use fluent_bundle::FluentResource;
use fluent_syntax::parser::ParserError;
Expand All @@ -14,6 +16,11 @@ use std::io;
use std::path::{Path, PathBuf};
use tracing::{instrument, trace};

#[cfg(not(parallel_compiler))]
use std::lazy::Lazy;
#[cfg(parallel_compiler)]
use std::lazy::SyncLazy as Lazy;

#[cfg(parallel_compiler)]
use intl_memoizer::concurrent::IntlLangMemoizer;
#[cfg(not(parallel_compiler))]
Expand All @@ -22,7 +29,8 @@ use intl_memoizer::IntlLangMemoizer;
pub use fluent_bundle::{FluentArgs, FluentError, FluentValue};
pub use unic_langid::{langid, LanguageIdentifier};

static FALLBACK_FLUENT_RESOURCE: &'static str = include_str!("../locales/en-US/diagnostics.ftl");
pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] =
&[include_str!("../locales/en-US/typeck.ftl"), include_str!("../locales/en-US/parser.ftl")];

pub type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>;

Expand Down Expand Up @@ -192,20 +200,30 @@ pub fn fluent_bundle(
Ok(Some(bundle))
}

/// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily
/// evaluated fluent bundle.
pub type LazyFallbackBundle = Lrc<Lazy<FluentBundle, impl FnOnce() -> FluentBundle>>;

/// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
#[instrument(level = "trace")]
pub fn fallback_fluent_bundle(
resources: &'static [&'static str],
with_directionality_markers: bool,
) -> Result<Lrc<FluentBundle>, TranslationBundleError> {
let fallback_resource = FluentResource::try_new(FALLBACK_FLUENT_RESOURCE.to_string())
.map_err(TranslationBundleError::from)?;
trace!(?fallback_resource);
let mut fallback_bundle = new_bundle(vec![langid!("en-US")]);
// See comment in `fluent_bundle`.
fallback_bundle.set_use_isolating(with_directionality_markers);
fallback_bundle.add_resource(fallback_resource).map_err(TranslationBundleError::from)?;
let fallback_bundle = Lrc::new(fallback_bundle);
Ok(fallback_bundle)
) -> LazyFallbackBundle {
Lrc::new(Lazy::new(move || {
let mut fallback_bundle = new_bundle(vec![langid!("en-US")]);
// See comment in `fluent_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");
trace!(?resource);
fallback_bundle.add_resource_overriding(resource);
}

fallback_bundle
}))
}

/// Identifier for the Fluent message/attribute corresponding to a diagnostic message.
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
use crate::emitter::FileWithAnnotatedLines;
use crate::snippet::Line;
use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle, Level,
MultiSpan, Style, SubDiagnostic,
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
};
use annotate_snippets::display_list::{DisplayList, FormatOptions};
use annotate_snippets::snippet::*;
Expand All @@ -22,7 +22,7 @@ use rustc_span::SourceFile;
pub struct AnnotateSnippetEmitterWriter {
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,

/// If true, hides the longer explanation text
short_message: bool,
Expand Down Expand Up @@ -67,8 +67,8 @@ impl Emitter for AnnotateSnippetEmitterWriter {
self.fluent_bundle.as_ref()
}

fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
&self.fallback_bundle
fn fallback_fluent_bundle(&self) -> &FluentBundle {
&**self.fallback_bundle
}

fn should_show_explain(&self) -> bool {
Expand Down Expand Up @@ -101,7 +101,7 @@ impl AnnotateSnippetEmitterWriter {
pub fn new(
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
short_message: bool,
macro_backtrace: bool,
) -> Self {
Expand Down
19 changes: 10 additions & 9 deletions compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Styl
use crate::styled_buffer::StyledBuffer;
use crate::{
CodeSuggestion, Diagnostic, DiagnosticArg, DiagnosticId, DiagnosticMessage, FluentBundle,
Handler, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight,
SuggestionStyle,
};

use rustc_lint_defs::pluralize;
Expand Down Expand Up @@ -60,7 +61,7 @@ impl HumanReadableErrorType {
dst: Box<dyn Write + Send>,
source_map: Option<Lrc<SourceMap>>,
bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
teach: bool,
terminal_width: Option<usize>,
macro_backtrace: bool,
Expand Down Expand Up @@ -233,7 +234,7 @@ pub trait Emitter {
/// Return `FluentBundle` with localized diagnostics for the default locale of the compiler.
/// Used when the user has not requested a specific language or when a localized diagnostic is
/// unavailable for the requested locale.
fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle>;
fn fallback_fluent_bundle(&self) -> &FluentBundle;

/// Convert diagnostic arguments (a rustc internal type that exists to implement
/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
Expand Down Expand Up @@ -579,8 +580,8 @@ impl Emitter for EmitterWriter {
self.fluent_bundle.as_ref()
}

fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
&self.fallback_bundle
fn fallback_fluent_bundle(&self) -> &FluentBundle {
&**self.fallback_bundle
}

fn emit_diagnostic(&mut self, diag: &Diagnostic) {
Expand Down Expand Up @@ -635,7 +636,7 @@ impl Emitter for SilentEmitter {
None
}

fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
fn fallback_fluent_bundle(&self) -> &FluentBundle {
panic!("silent emitter attempted to translate message")
}

Expand Down Expand Up @@ -695,7 +696,7 @@ pub struct EmitterWriter {
dst: Destination,
sm: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
short_message: bool,
teach: bool,
ui_testing: bool,
Expand All @@ -716,7 +717,7 @@ impl EmitterWriter {
color_config: ColorConfig,
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
short_message: bool,
teach: bool,
terminal_width: Option<usize>,
Expand All @@ -740,7 +741,7 @@ impl EmitterWriter {
dst: Box<dyn Write + Send>,
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
short_message: bool,
teach: bool,
colored: bool,
Expand Down
16 changes: 9 additions & 7 deletions compiler/rustc_errors/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
use crate::DiagnosticId;
use crate::ToolMetadata;
use crate::{CodeSuggestion, FluentBundle, MultiSpan, SpanLabel, SubDiagnostic};
use crate::{
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
};
use rustc_lint_defs::Applicability;

use rustc_data_structures::sync::Lrc;
Expand All @@ -38,7 +40,7 @@ pub struct JsonEmitter {
registry: Option<Registry>,
sm: Lrc<SourceMap>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
pretty: bool,
ui_testing: bool,
json_rendered: HumanReadableErrorType,
Expand All @@ -51,7 +53,7 @@ impl JsonEmitter {
registry: Option<Registry>,
source_map: Lrc<SourceMap>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
pretty: bool,
json_rendered: HumanReadableErrorType,
terminal_width: Option<usize>,
Expand All @@ -75,7 +77,7 @@ impl JsonEmitter {
pretty: bool,
json_rendered: HumanReadableErrorType,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
terminal_width: Option<usize>,
macro_backtrace: bool,
) -> JsonEmitter {
Expand All @@ -97,7 +99,7 @@ impl JsonEmitter {
registry: Option<Registry>,
source_map: Lrc<SourceMap>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
pretty: bool,
json_rendered: HumanReadableErrorType,
terminal_width: Option<usize>,
Expand Down Expand Up @@ -192,8 +194,8 @@ impl Emitter for JsonEmitter {
self.fluent_bundle.as_ref()
}

fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
&self.fallback_bundle
fn fallback_fluent_bundle(&self) -> &FluentBundle {
&**self.fallback_bundle
}

fn should_show_explain(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_errors/src/json/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned());
let fallback_bundle =
crate::fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle");
crate::fallback_fluent_bundle(rustc_error_messages::DEFAULT_LOCALE_RESOURCES, false);

let output = Arc::new(Mutex::new(Vec::new()));
let je = JsonEmitter::new(
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use rustc_data_structures::sync::{self, Lock, Lrc};
use rustc_data_structures::AtomicRef;
pub use rustc_error_messages::{
fallback_fluent_bundle, fluent_bundle, DiagnosticMessage, FluentBundle, LanguageIdentifier,
MultiSpan, SpanLabel,
LazyFallbackBundle, MultiSpan, SpanLabel, DEFAULT_LOCALE_RESOURCES,
};
pub use rustc_lint_defs::{pluralize, Applicability};
use rustc_serialize::json::Json;
Expand Down Expand Up @@ -547,7 +547,7 @@ impl Handler {
treat_err_as_bug: Option<NonZeroUsize>,
sm: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
) -> Self {
Self::with_tty_emitter_and_flags(
color_config,
Expand All @@ -562,7 +562,7 @@ impl Handler {
color_config: ColorConfig,
sm: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
flags: HandlerFlags,
) -> Self {
let emitter = Box::new(EmitterWriter::stderr(
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_expand/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
create_default_session_if_not_set_then(|_| {
let output = Arc::new(Mutex::new(Vec::new()));

let fallback_bundle = rustc_errors::fallback_fluent_bundle(false)
.expect("failed to load fallback fluent bundle");
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());

Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_session/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,7 @@ pub struct ParseSess {
impl ParseSess {
/// Used for testing.
pub fn new(file_path_mapping: FilePathMapping) -> Self {
let fallback_bundle =
fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle");
let fallback_bundle = fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
let sm = Lrc::new(SourceMap::new(file_path_mapping));
let handler = Handler::with_tty_emitter(
ColorConfig::Auto,
Expand Down Expand Up @@ -211,8 +210,7 @@ impl ParseSess {
}

pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
let fallback_bundle =
fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle");
let fallback_bundle = fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let fatal_handler =
Handler::with_tty_emitter(ColorConfig::Auto, false, None, None, None, fallback_bundle);
Expand Down
22 changes: 7 additions & 15 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry;
use rustc_errors::{
fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee,
ErrorGuaranteed, FluentBundle, MultiSpan,
ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan,
};
use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
Expand Down Expand Up @@ -1080,7 +1080,7 @@ fn default_emitter(
registry: rustc_errors::registry::Registry,
source_map: Lrc<SourceMap>,
bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
fallback_bundle: LazyFallbackBundle,
emitter_dest: Option<Box<dyn Write + Send>>,
) -> Box<dyn Emitter + sync::Send> {
let macro_backtrace = sopts.debugging_opts.macro_backtrace;
Expand Down Expand Up @@ -1215,17 +1215,10 @@ pub fn build_session(
hash_kind,
));

let fallback_bundle =
match fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers) {
Ok(bundle) => bundle,
Err(e) => {
early_error(
sopts.error_format,
&format!("failed to load fallback fluent bundle: {e}"),
);
}
};

let fallback_bundle = fallback_fluent_bundle(
rustc_errors::DEFAULT_LOCALE_RESOURCES,
sopts.debugging_opts.translate_directionality_markers,
);
let emitter =
default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest);

Expand Down Expand Up @@ -1460,8 +1453,7 @@ pub enum IncrCompSession {
}

fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler {
let fallback_bundle =
fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle");
let fallback_bundle = fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
let emitter: Box<dyn Emitter + sync::Send> = match output {
config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ crate fn new_handler(
debugging_opts: &DebuggingOptions,
) -> rustc_errors::Handler {
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(false).expect("failed to load fallback fluent bundle");
rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
let emitter: Box<dyn Emitter + sync::Send> = match error_format {
ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
Expand Down
Loading

0 comments on commit 9bfe0e3

Please sign in to comment.