diff options
Diffstat (limited to 'compiler/rustc_errors')
| -rw-r--r-- | compiler/rustc_errors/src/diagnostic.rs | 51 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/emitter.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/lib.rs | 67 |
3 files changed, 74 insertions, 61 deletions
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 797dcd7b4d1..29a74ed3f4e 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::panic; +use std::path::PathBuf; use std::thread::panicking; use rustc_data_structures::fx::FxIndexMap; @@ -301,6 +302,7 @@ pub struct DiagInner { pub is_lint: Option<IsLint>, + pub long_ty_path: Option<PathBuf>, /// With `-Ztrack_diagnostics` enabled, /// we print where in rustc this error was emitted. pub(crate) emitted_at: DiagLocation, @@ -324,6 +326,7 @@ impl DiagInner { args: Default::default(), sort_span: DUMMY_SP, is_lint: None, + long_ty_path: None, emitted_at: DiagLocation::caller(), } } @@ -641,7 +644,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { found_label: &dyn fmt::Display, found: DiagStyledString, ) -> &mut Self { - self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") + self.note_expected_found_extra( + expected_label, + expected, + found_label, + found, + DiagStyledString::normal(""), + DiagStyledString::normal(""), + ) } #[rustc_lint_diagnostics] @@ -651,8 +661,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { expected: DiagStyledString, found_label: &dyn fmt::Display, found: DiagStyledString, - expected_extra: &dyn fmt::Display, - found_extra: &dyn fmt::Display, + expected_extra: DiagStyledString, + found_extra: DiagStyledString, ) -> &mut Self { let expected_label = expected_label.to_string(); let expected_label = if expected_label.is_empty() { @@ -677,10 +687,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { expected_label ))]; msg.extend(expected.0); - msg.push(StringPart::normal(format!("`{expected_extra}\n"))); + msg.push(StringPart::normal(format!("`"))); + msg.extend(expected_extra.0); + msg.push(StringPart::normal(format!("\n"))); msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label))); msg.extend(found.0); - msg.push(StringPart::normal(format!("`{found_extra}"))); + msg.push(StringPart::normal(format!("`"))); + msg.extend(found_extra.0); // For now, just attach these as notes. self.highlighted_note(msg); @@ -1293,9 +1306,37 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on /// `self`. fn take_diag(&mut self) -> DiagInner { + if let Some(path) = &self.long_ty_path { + self.note(format!( + "the full name for the type has been written to '{}'", + path.display() + )); + self.note("consider using `--verbose` to print the full type name to the console"); + } Box::into_inner(self.diag.take().unwrap()) } + /// This method allows us to access the path of the file where "long types" are written to. + /// + /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set, + /// and if it has been then we add a note mentioning the file where the "long types" were + /// written to. + /// + /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing + /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that + /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the + /// user where we wrote the file to is only printed once at most, *and* it makes it much harder + /// to forget to set it. + /// + /// If the diagnostic hasn't been created before a "short ty string" is created, then you should + /// ensure that this method is called to set it `*diag.long_ty_path() = path`. + /// + /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a + /// scope, `diag.long_ty_path()` should be called once somewhere close by. + pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> { + &mut self.long_ty_path + } + /// Most `emit_producing_guarantee` functions use this as a starting point. fn emit_producing_nothing(mut self) { let diag = self.take_diag(); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 991dfa1821a..d0b4211c351 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -35,8 +35,8 @@ use crate::snippet::{ use crate::styled_buffer::StyledBuffer; use crate::translation::{Translate, to_fluent_args}; use crate::{ - CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, - Level, MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl, + CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level, + MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl, }; /// Default column width, used in tests and when terminal dimensions cannot be determined. @@ -537,11 +537,10 @@ impl Emitter for HumanEmitter { } /// An emitter that does nothing when emitting a non-fatal diagnostic. -/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent +/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent /// failures of rustc, as witnessed e.g. in issue #89358. pub struct SilentEmitter { - pub fallback_bundle: LazyFallbackBundle, - pub fatal_dcx: DiagCtxt, + pub fatal_emitter: Box<dyn Emitter + DynSend>, pub fatal_note: Option<String>, pub emit_fatal_diagnostic: bool, } @@ -552,9 +551,7 @@ impl Translate for SilentEmitter { } fn fallback_fluent_bundle(&self) -> &FluentBundle { - // Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be - // used but the lock prevents this. - &self.fallback_bundle + self.fatal_emitter.fallback_fluent_bundle() } } @@ -563,12 +560,12 @@ impl Emitter for SilentEmitter { None } - fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) { + fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) { if self.emit_fatal_diagnostic && diag.level == Level::Fatal { if let Some(fatal_note) = &self.fatal_note { diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new()); } - self.fatal_dcx.handle().emit_diagnostic(diag); + self.fatal_emitter.emit_diagnostic(diag, registry); } } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 549729548f5..7a02e0dd2f0 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -59,13 +59,13 @@ use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sync::{DynSend, Lock}; pub use rustc_error_messages::{ DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_lint_defs::LintExpectationId; -pub use rustc_lint_defs::{Applicability, pluralize}; +pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -676,57 +676,44 @@ impl DiagCtxt { Self { inner: Lock::new(DiagCtxtInner::new(emitter)) } } - pub fn make_silent( - &self, - fallback_bundle: LazyFallbackBundle, - fatal_note: Option<String>, - emit_fatal_diagnostic: bool, - ) { - self.wrap_emitter(|old_dcx| { - Box::new(emitter::SilentEmitter { - fallback_bundle, - fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) }, - fatal_note, - emit_fatal_diagnostic, - }) - }); - } - - fn wrap_emitter<F>(&self, f: F) - where - F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>, - { - // A empty type that implements `Emitter` so that a `DiagCtxtInner` can be constructed - // to temporarily swap in place of the real one, which will be used in constructing - // its replacement. + pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) { + // An empty type that implements `Emitter` to temporarily swap in place of the real one, + // which will be used in constructing its replacement. struct FalseEmitter; impl Emitter for FalseEmitter { fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } fn source_map(&self) -> Option<&SourceMap> { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } } impl translation::Translate for FalseEmitter { fn fluent_bundle(&self) -> Option<&FluentBundle> { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } fn fallback_fluent_bundle(&self) -> &FluentBundle { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } } let mut inner = self.inner.borrow_mut(); - let mut prev_dcx = DiagCtxtInner::new(Box::new(FalseEmitter)); - std::mem::swap(&mut *inner, &mut prev_dcx); - let new_emitter = f(prev_dcx); - let mut new_dcx = DiagCtxtInner::new(new_emitter); - std::mem::swap(&mut *inner, &mut new_dcx); + let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>; + std::mem::swap(&mut inner.emitter, &mut prev_emitter); + let new_emitter = Box::new(emitter::SilentEmitter { + fatal_emitter: prev_emitter, + fatal_note, + emit_fatal_diagnostic, + }); + inner.emitter = new_emitter; + } + + pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) { + self.inner.borrow_mut().emitter = emitter; } /// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`. @@ -1999,18 +1986,6 @@ pub fn a_or_an(s: &str) -> &'static str { } } -/// Grammatical tool for displaying messages to end users in a nice form. -/// -/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c" -pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String { - match v { - [] => "".to_string(), - [a] => a.to_string(), - [a, b] => format!("{a} and {b}"), - [a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)), - } -} - #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum TerminalUrl { No, |
