1
Fork 0

Rollup merge of #95512 - davidtwco:diagnostic-translation, r=oli-obk

diagnostics: translation infrastructure

An implementation of the infrastructure required to have translatable diagnostic messages.

- Introduces a `DiagnosticMessage` type which can represent both the current non-translatable messages and identifiers for [Fluent](https://projectfluent.org/).
- Modifies current diagnostic API so that existing calls still work but `DiagnosticMessage`s can be provided too.
- Adds support for always loading a "fallback bundle" containing the English diagnostic messages, which are used when a `DiagnosticMessage::FluentIdentifier` is used in a diagnostic being emitted.
- Adds support for loading a "primary bundle" which contains the user's preferred language translation, and is used preferentially when it contains a diagnostic message being emitted. Primary bundles are loaded either from the path provided to `-Ztranslate-alternate-ftl` (for testing), or from the sysroot at `$sysroot/locale/$locale/*.ftl` given a locale with `-Ztranslate-lang` (which is parsed as a language identifier).
- Adds "diagnostic args" which enable normally-interpolated variables to be made available as variables for Fluent messages to use.
- Updates `#[derive(SessionDiagnostic)]` so that it can only be used for translatable diagnostics and update the handful of diagnostics which used the derive to be translatable.

For example, the following diagnostic...

```rust
#[derive(SessionDiagnostic)]
#[error = "E0195"]
pub struct LifetimesOrBoundsMismatchOnTrait {
    #[message = "lifetime parameters or bounds on {item_kind} `{ident}` do not match the trait declaration"]
    #[label = "lifetimes do not match {item_kind} in trait"]
    pub span: Span,
    #[label = "lifetimes in impl do not match this {item_kind} in trait"]
    pub generics_span: Option<Span>,
    pub item_kind: &'static str,
    pub ident: Ident,
}
```

...becomes...

```rust
#[derive(SessionDiagnostic)]
#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")]
pub struct LifetimesOrBoundsMismatchOnTrait {
    #[primary_span]
    #[label]
    pub span: Span,
    #[label = "generics-label"]
    pub generics_span: Option<Span>,
    pub item_kind: &'static str,
    pub ident: Ident,
}
```

```fluent
typeck-lifetimes-or-bounds-mismatch-on-trait =
    lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
    .label = lifetimes do not match {$item_kind} in trait
    .generics-label = lifetimes in impl do not match this {$item_kind} in trait
```

r? `@estebank`
cc `@oli-obk` `@Manishearth`
This commit is contained in:
Dylan DPC 2022-04-05 09:33:22 +02:00 committed by GitHub
commit d4730244d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
101 changed files with 2916 additions and 1076 deletions

View file

@ -1,6 +1,6 @@
use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed, MultiSpan};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::{MultiSpan, Span};
use rustc_span::Span;
impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
crate fn cannot_move_when_borrowed(

View file

@ -1,7 +1,7 @@
use either::Either;
use rustc_const_eval::util::CallKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
@ -15,7 +15,7 @@ use rustc_middle::mir::{
use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::symbol::sym;
use rustc_span::{BytePos, MultiSpan, Span};
use rustc_span::{BytePos, Span};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::TraitEngineExt as _;

View file

@ -109,7 +109,7 @@ impl RegionName {
*span,
format!("lifetime `{}` represents this closure's body", self),
);
diag.note(&note);
diag.note(note);
}
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy(
span,

View file

@ -7,11 +7,11 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{token, BlockCheckMode, UnsafeSource};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, Applicability, PResult};
use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
use rustc_expand::base::{self, *};
use rustc_parse_format as parse;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{InnerSpan, MultiSpan, Span};
use rustc_span::{InnerSpan, Span};
use smallvec::SmallVec;
use std::borrow::Cow;
@ -446,7 +446,9 @@ impl<'a, 'b> Context<'a, 'b> {
.iter()
.filter(|fmt| fmt.precision_span.is_some())
.count();
e.span_label(span, &format!(
e.span_label(
span,
&format!(
"this precision flag adds an extra required argument at position {}, \
which is why there {} expected",
pos,
@ -455,7 +457,8 @@ impl<'a, 'b> Context<'a, 'b> {
} else {
format!("are {} arguments", count)
},
));
),
);
if let Some(arg) = self.args.get(pos) {
e.span_label(
arg.span,

View file

@ -1707,23 +1707,33 @@ impl SharedEmitter {
impl Emitter for SharedEmitter {
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
let fluent_args = self.to_fluent_args(diag.args());
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
msg: diag.message(),
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
code: diag.code.clone(),
lvl: diag.level(),
})));
for child in &diag.children {
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
msg: child.message(),
msg: self.translate_messages(&child.message, &fluent_args).to_string(),
code: None,
lvl: child.level,
})));
}
drop(self.sender.send(SharedEmitterMessage::AbortIfErrors));
}
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None
}
fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
None
}
fn fallback_fluent_bundle(&self) -> &Lrc<rustc_errors::FluentBundle> {
panic!("shared emitter attempted to translate a diagnostic");
}
}
impl SharedEmitterMain {
@ -1754,9 +1764,9 @@ impl SharedEmitterMain {
let msg = msg.strip_prefix("error: ").unwrap_or(&msg);
let mut err = match level {
Level::Error { lint: false } => sess.struct_err(&msg).forget_guarantee(),
Level::Warning => sess.struct_warn(&msg),
Level::Note => sess.struct_note_without_error(&msg),
Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(),
Level::Warning => sess.struct_warn(msg),
Level::Note => sess.struct_note_without_error(msg),
_ => bug!("Invalid inline asm diagnostic level"),
};

View file

@ -1172,9 +1172,13 @@ static DEFAULT_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
/// When `install_ice_hook` is called, this function will be called as the panic
/// 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");
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
rustc_errors::ColorConfig::Auto,
None,
None,
fallback_bundle,
false,
false,
None,
@ -1209,7 +1213,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
}
for note in &xs {
handler.note_without_error(note);
handler.note_without_error(note.as_ref());
}
// If backtraces are enabled, also print the query stack

View file

@ -0,0 +1,18 @@
[package]
name = "rustc_error_messages"
version = "0.0.0"
edition = "2021"
[lib]
doctest = false
[dependencies]
fluent-bundle = "0.15.2"
fluent-syntax = "0.11"
intl-memoizer = "0.5.1"
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
rustc_macros = { path = "../rustc_macros" }
tracing = "0.1"
unic-langid = { version = "0.9.0", features = ["macros"] }

View file

@ -0,0 +1,87 @@
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
.previous-use-label = first use of `{$ident}`
typeck-unrecognized-atomic-operation =
unrecognized atomic operation function: `{$op}`
.label = unrecognized atomic operation
typeck-wrong-number-of-generic-arguments-to-intrinsic =
intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected}
.label = expected {$expected} {$descr} {$expected ->
[one] parameter
*[other] parameters
}
typeck-unrecognized-intrinsic-function =
unrecognized intrinsic function: `{$name}`
.label = unrecognized intrinsic
typeck-lifetimes-or-bounds-mismatch-on-trait =
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait
.generics-label = lifetimes in impl do not match this {$item_kind} in trait
typeck-drop-impl-on-wrong-item =
the `Drop` trait may only be implemented for structs, enums, and unions
.label = must be a struct, enum, or union
typeck-field-already-declared =
field `{$field_name}` is already declared
.label = field already declared
.previous-decl-label = `{$field_name}` first declared here
typeck-copy-impl-on-type-with-dtor =
the trait `Copy` may not be implemented for this type; the type has a destructor
.label = `Copy` not allowed on types with destructors
typeck-multiple-relaxed-default-bounds =
type parameter has more than one relaxed default bound, only one is supported
typeck-copy-impl-on-non-adt =
the trait `Copy` may not be implemented for this type
.label = type is not a structure or enumeration
typeck-trait-object-declared-with-no-traits =
at least one trait is required for an object type
typeck-ambiguous-lifetime-bound =
ambiguous lifetime bound, explicit lifetime bound required
typeck-assoc-type-binding-not-allowed =
associated type bindings are not allowed here
.label = associated type not allowed here
typeck-functional-record-update-on-non-struct =
functional record update syntax requires a struct
typeck-typeof-reserved-keyword-used =
`typeof` is a reserved keyword but unimplemented
.label = reserved keyword
typeck-return-stmt-outside-of-fn-body =
return statement outside of function body
.encl-body-label = the return is part of this body...
.encl-fn-label = ...not the enclosing function body
typeck-yield-expr-outside-of-generator =
yield expression outside of generator literal
typeck-struct-expr-non-exhaustive =
cannot create non-exhaustive {$what} using struct expression
typeck-method-call-on-unknown-type =
the type of this value must be known to call a method on a raw pointer on it
typeck-value-of-associated-struct-already-specified =
the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
.label = re-bound here
.previous-bound-label = `{$item_name}` bound here first
typeck-address-of-temporary-taken = cannot take address of a temporary
.label = temporary value

View file

@ -0,0 +1,390 @@
#![feature(let_chains)]
#![feature(path_try_exists)]
use fluent_bundle::FluentResource;
use fluent_syntax::parser::ParserError;
use rustc_data_structures::sync::Lrc;
use rustc_macros::{Decodable, Encodable};
use rustc_span::Span;
use std::borrow::Cow;
use std::error::Error;
use std::fmt;
use std::fs;
use std::io;
use std::path::Path;
use tracing::{instrument, trace};
#[cfg(parallel_compiler)]
use intl_memoizer::concurrent::IntlLangMemoizer;
#[cfg(not(parallel_compiler))]
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 type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>;
#[cfg(parallel_compiler)]
fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle {
FluentBundle::new_concurrent(locales)
}
#[cfg(not(parallel_compiler))]
fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle {
FluentBundle::new(locales)
}
#[derive(Debug)]
pub enum TranslationBundleError {
/// Failed to read from `.ftl` file.
ReadFtl(io::Error),
/// Failed to parse contents of `.ftl` file.
ParseFtl(ParserError),
/// Failed to add `FluentResource` to `FluentBundle`.
AddResource(FluentError),
/// `$sysroot/share/locale/$locale` does not exist.
MissingLocale(io::Error),
/// Cannot read directory entries of `$sysroot/share/locale/$locale`.
ReadLocalesDir(io::Error),
/// Cannot read directory entry of `$sysroot/share/locale/$locale`.
ReadLocalesDirEntry(io::Error),
/// `$sysroot/share/locale/$locale` is not a directory.
LocaleIsNotDir,
}
impl fmt::Display for TranslationBundleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TranslationBundleError::ReadFtl(e) => write!(f, "could not read ftl file: {}", e),
TranslationBundleError::ParseFtl(e) => {
write!(f, "could not parse ftl file: {}", e)
}
TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {}", e),
TranslationBundleError::MissingLocale(e) => {
write!(f, "missing locale directory: {}", e)
}
TranslationBundleError::ReadLocalesDir(e) => {
write!(f, "could not read locales dir: {}", e)
}
TranslationBundleError::ReadLocalesDirEntry(e) => {
write!(f, "could not read locales dir entry: {}", e)
}
TranslationBundleError::LocaleIsNotDir => {
write!(f, "`$sysroot/share/locales/$locale` is not a directory")
}
}
}
}
impl Error for TranslationBundleError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
TranslationBundleError::ReadFtl(e) => Some(e),
TranslationBundleError::ParseFtl(e) => Some(e),
TranslationBundleError::AddResource(e) => Some(e),
TranslationBundleError::MissingLocale(e) => Some(e),
TranslationBundleError::ReadLocalesDir(e) => Some(e),
TranslationBundleError::ReadLocalesDirEntry(e) => Some(e),
TranslationBundleError::LocaleIsNotDir => None,
}
}
}
impl From<(FluentResource, Vec<ParserError>)> for TranslationBundleError {
fn from((_, mut errs): (FluentResource, Vec<ParserError>)) -> Self {
TranslationBundleError::ParseFtl(errs.pop().expect("failed ftl parse with no errors"))
}
}
impl From<Vec<FluentError>> for TranslationBundleError {
fn from(mut errs: Vec<FluentError>) -> Self {
TranslationBundleError::AddResource(
errs.pop().expect("failed adding resource to bundle with no errors"),
)
}
}
/// Returns Fluent bundle with the user's locale resources from
/// `$sysroot/share/locale/$requested_locale/*.ftl`.
///
/// If `-Z additional-ftl-path` was provided, load that resource and add it to the bundle
/// (overriding any conflicting messages).
#[instrument(level = "trace")]
pub fn fluent_bundle(
sysroot: &Path,
requested_locale: Option<LanguageIdentifier>,
additional_ftl_path: Option<&Path>,
with_directionality_markers: bool,
) -> Result<Option<Lrc<FluentBundle>>, TranslationBundleError> {
if requested_locale.is_none() && additional_ftl_path.is_none() {
return Ok(None);
}
let fallback_locale = langid!("en-US");
let requested_fallback_locale = requested_locale.as_ref() == Some(&fallback_locale);
// If there is only `-Z additional-ftl-path`, assume locale is "en-US", otherwise use user
// provided locale.
let locale = requested_locale.clone().unwrap_or(fallback_locale);
trace!(?locale);
let mut bundle = new_bundle(vec![locale]);
// Fluent diagnostics can insert directionality isolation markers around interpolated variables
// indicating that there may be a shift from right-to-left to left-to-right text (or
// vice-versa). These are disabled because they are sometimes visible in the error output, but
// may be worth investigating in future (for example: if type names are left-to-right and the
// surrounding diagnostic messages are right-to-left, then these might be helpful).
bundle.set_use_isolating(with_directionality_markers);
// If the user requests the default locale then don't try to load anything.
if !requested_fallback_locale && let Some(requested_locale) = requested_locale {
let mut sysroot = sysroot.to_path_buf();
sysroot.push("share");
sysroot.push("locale");
sysroot.push(requested_locale.to_string());
trace!(?sysroot);
let _ = sysroot.try_exists().map_err(TranslationBundleError::MissingLocale)?;
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();
trace!(?path);
if path.extension().and_then(|s| s.to_str()) != Some("ftl") {
trace!("skipping");
continue;
}
let resource_str =
fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?;
let resource =
FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
trace!(?resource);
bundle.add_resource(resource).map_err(TranslationBundleError::from)?;
}
}
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)?;
trace!(?resource);
bundle.add_resource_overriding(resource);
}
let bundle = Lrc::new(bundle);
Ok(Some(bundle))
}
/// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
#[instrument(level = "trace")]
pub fn fallback_fluent_bundle(
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)
}
/// Identifier for the Fluent message/attribute corresponding to a diagnostic message.
type FluentId = Cow<'static, str>;
/// Abstraction over a message in a diagnostic to support both translatable and non-translatable
/// diagnostic messages.
///
/// Intended to be removed once diagnostics are entirely translatable.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum DiagnosticMessage {
/// Non-translatable diagnostic message.
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
Str(String),
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
/// message.
///
/// <https://projectfluent.org/fluent/guide/hello.html>
/// <https://projectfluent.org/fluent/guide/attributes.html>
FluentIdentifier(FluentId, Option<FluentId>),
}
impl DiagnosticMessage {
/// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that
/// this diagnostic message is of the legacy, non-translatable variety. Panics if this
/// assumption does not hold.
///
/// Don't use this - it exists to support some places that do comparison with diagnostic
/// strings.
pub fn expect_str(&self) -> &str {
match self {
DiagnosticMessage::Str(s) => s,
_ => panic!("expected non-translatable diagnostic message"),
}
}
/// Create a `DiagnosticMessage` for the provided Fluent identifier.
pub fn fluent(id: impl Into<FluentId>) -> Self {
DiagnosticMessage::FluentIdentifier(id.into(), None)
}
/// Create a `DiagnosticMessage` for the provided Fluent identifier and attribute.
pub fn fluent_attr(id: impl Into<FluentId>, attr: impl Into<FluentId>) -> Self {
DiagnosticMessage::FluentIdentifier(id.into(), Some(attr.into()))
}
}
/// `From` impl that enables existing diagnostic calls to functions which now take
/// `impl Into<DiagnosticMessage>` to continue to work as before.
impl<S: Into<String>> From<S> for DiagnosticMessage {
fn from(s: S) -> Self {
DiagnosticMessage::Str(s.into())
}
}
/// A span together with some additional data.
#[derive(Clone, Debug)]
pub struct SpanLabel {
/// The span we are going to include in the final snippet.
pub span: Span,
/// Is this a primary span? This is the "locus" of the message,
/// and is indicated with a `^^^^` underline, versus `----`.
pub is_primary: bool,
/// What label should we attach to this span (if any)?
pub label: Option<DiagnosticMessage>,
}
/// A collection of `Span`s.
///
/// Spans have two orthogonal attributes:
///
/// - They can be *primary spans*. In this case they are the locus of
/// the error, and would be rendered with `^^^`.
/// - They can have a *label*. In this case, the label is written next
/// to the mark in the snippet when we render.
#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)]
pub struct MultiSpan {
primary_spans: Vec<Span>,
span_labels: Vec<(Span, DiagnosticMessage)>,
}
impl MultiSpan {
#[inline]
pub fn new() -> MultiSpan {
MultiSpan { primary_spans: vec![], span_labels: vec![] }
}
pub fn from_span(primary_span: Span) -> MultiSpan {
MultiSpan { primary_spans: vec![primary_span], span_labels: vec![] }
}
pub fn from_spans(mut vec: Vec<Span>) -> MultiSpan {
vec.sort();
MultiSpan { primary_spans: vec, span_labels: vec![] }
}
pub fn push_span_label(&mut self, span: Span, label: impl Into<DiagnosticMessage>) {
self.span_labels.push((span, label.into()));
}
/// Selects the first primary span (if any).
pub fn primary_span(&self) -> Option<Span> {
self.primary_spans.first().cloned()
}
/// Returns all primary spans.
pub fn primary_spans(&self) -> &[Span] {
&self.primary_spans
}
/// Returns `true` if any of the primary spans are displayable.
pub fn has_primary_spans(&self) -> bool {
self.primary_spans.iter().any(|sp| !sp.is_dummy())
}
/// Returns `true` if this contains only a dummy primary span with any hygienic context.
pub fn is_dummy(&self) -> bool {
let mut is_dummy = true;
for span in &self.primary_spans {
if !span.is_dummy() {
is_dummy = false;
}
}
is_dummy
}
/// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
/// display well (like std macros). Returns whether replacements occurred.
pub fn replace(&mut self, before: Span, after: Span) -> bool {
let mut replacements_occurred = false;
for primary_span in &mut self.primary_spans {
if *primary_span == before {
*primary_span = after;
replacements_occurred = true;
}
}
for span_label in &mut self.span_labels {
if span_label.0 == before {
span_label.0 = after;
replacements_occurred = true;
}
}
replacements_occurred
}
/// Returns the strings to highlight. We always ensure that there
/// is an entry for each of the primary spans -- for each primary
/// span `P`, if there is at least one label with span `P`, we return
/// those labels (marked as primary). But otherwise we return
/// `SpanLabel` instances with empty labels.
pub fn span_labels(&self) -> Vec<SpanLabel> {
let is_primary = |span| self.primary_spans.contains(&span);
let mut span_labels = self
.span_labels
.iter()
.map(|&(span, ref label)| SpanLabel {
span,
is_primary: is_primary(span),
label: Some(label.clone()),
})
.collect::<Vec<_>>();
for &span in &self.primary_spans {
if !span_labels.iter().any(|sl| sl.span == span) {
span_labels.push(SpanLabel { span, is_primary: true, label: None });
}
}
span_labels
}
/// Returns `true` if any of the span labels is displayable.
pub fn has_span_labels(&self) -> bool {
self.span_labels.iter().any(|(sp, _)| !sp.is_dummy())
}
}
impl From<Span> for MultiSpan {
fn from(span: Span) -> MultiSpan {
MultiSpan::from_span(span)
}
}
impl From<Vec<Span>> for MultiSpan {
fn from(spans: Vec<Span>) -> MultiSpan {
MultiSpan::from_spans(spans)
}
}

View file

@ -8,6 +8,7 @@ doctest = false
[dependencies]
tracing = "0.1"
rustc_error_messages = { path = "../rustc_error_messages" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
rustc_macros = { path = "../rustc_macros" }

View file

@ -7,16 +7,23 @@
use crate::emitter::FileWithAnnotatedLines;
use crate::snippet::Line;
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Emitter, Level, SubDiagnostic};
use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle, Level,
MultiSpan, Style, SubDiagnostic,
};
use annotate_snippets::display_list::{DisplayList, FormatOptions};
use annotate_snippets::snippet::*;
use rustc_data_structures::sync::Lrc;
use rustc_error_messages::FluentArgs;
use rustc_span::source_map::SourceMap;
use rustc_span::{MultiSpan, SourceFile};
use rustc_span::SourceFile;
/// Generates diagnostics using annotate-snippet
pub struct AnnotateSnippetEmitterWriter {
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
/// If true, hides the longer explanation text
short_message: bool,
/// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs.
@ -28,8 +35,10 @@ pub struct AnnotateSnippetEmitterWriter {
impl Emitter for AnnotateSnippetEmitterWriter {
/// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
let fluent_args = self.to_fluent_args(diag.args());
let mut children = diag.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag);
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
&self.source_map,
@ -41,7 +50,8 @@ impl Emitter for AnnotateSnippetEmitterWriter {
self.emit_messages_default(
&diag.level,
diag.message(),
&diag.message,
&fluent_args,
&diag.code,
&primary_span,
&children,
@ -53,6 +63,14 @@ impl Emitter for AnnotateSnippetEmitterWriter {
self.source_map.as_ref()
}
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
self.fluent_bundle.as_ref()
}
fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
&self.fallback_bundle
}
fn should_show_explain(&self) -> bool {
!self.short_message
}
@ -82,10 +100,19 @@ fn annotation_type_for_level(level: Level) -> AnnotationType {
impl AnnotateSnippetEmitterWriter {
pub fn new(
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
short_message: bool,
macro_backtrace: bool,
) -> Self {
Self { source_map, short_message, ui_testing: false, macro_backtrace }
Self {
source_map,
fluent_bundle,
fallback_bundle,
short_message,
ui_testing: false,
macro_backtrace,
}
}
/// Allows to modify `Self` to enable or disable the `ui_testing` flag.
@ -99,12 +126,14 @@ impl AnnotateSnippetEmitterWriter {
fn emit_messages_default(
&mut self,
level: &Level,
message: String,
messages: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
code: &Option<DiagnosticId>,
msp: &MultiSpan,
_children: &[SubDiagnostic],
_suggestions: &[CodeSuggestion],
) {
let message = self.translate_messages(messages, args);
if let Some(source_map) = &self.source_map {
// Make sure our primary file comes first
let primary_lo = if let Some(ref primary_span) = msp.primary_span().as_ref() {
@ -120,8 +149,7 @@ impl AnnotateSnippetEmitterWriter {
// should be done if it happens
return;
};
let mut annotated_files =
FileWithAnnotatedLines::collect_annotations(msp, &self.source_map);
let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp);
if let Ok(pos) =
annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name))
{

View file

@ -1,15 +1,16 @@
use crate::snippet::Style;
use crate::CodeSuggestion;
use crate::Level;
use crate::Substitution;
use crate::SubstitutionPart;
use crate::SuggestionStyle;
use crate::ToolMetadata;
use crate::{
CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart,
SuggestionStyle, ToolMetadata,
};
use rustc_data_structures::stable_map::FxHashMap;
use rustc_error_messages::FluentValue;
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_serialize::json::Json;
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
@ -18,6 +19,66 @@ use std::hash::{Hash, Hasher};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub struct SuggestionsDisabled;
/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
/// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
/// diagnostic emission.
pub type DiagnosticArg<'source> = (Cow<'source, str>, DiagnosticArgValue<'source>);
/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum DiagnosticArgValue<'source> {
Str(Cow<'source, str>),
Number(usize),
}
/// Converts a value of a type into a `DiagnosticArg` (typically a field of a `SessionDiagnostic`
/// struct). Implemented as a custom trait rather than `From` so that it is implemented on the type
/// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*`
/// crates to implement this.
pub trait IntoDiagnosticArg {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
}
impl IntoDiagnosticArg for String {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self))
}
}
impl IntoDiagnosticArg for Symbol {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
self.to_ident_string().into_diagnostic_arg()
}
}
impl IntoDiagnosticArg for Ident {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
self.to_string().into_diagnostic_arg()
}
}
impl<'a> IntoDiagnosticArg for &'a str {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
self.to_string().into_diagnostic_arg()
}
}
impl IntoDiagnosticArg for usize {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Number(self)
}
}
impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
fn into(self) -> FluentValue<'source> {
match self {
DiagnosticArgValue::Str(s) => From::from(s),
DiagnosticArgValue::Number(n) => From::from(n),
}
}
}
#[must_use]
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct Diagnostic {
@ -25,11 +86,12 @@ pub struct Diagnostic {
// outside of what methods in this crate themselves allow.
crate level: Level,
pub message: Vec<(String, Style)>,
pub message: Vec<(DiagnosticMessage, Style)>,
pub code: Option<DiagnosticId>,
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
args: Vec<DiagnosticArg<'static>>,
/// This is not used for highlighting or rendering any error message. Rather, it can be used
/// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
@ -52,7 +114,7 @@ pub enum DiagnosticId {
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
pub struct SubDiagnostic {
pub level: Level,
pub message: Vec<(String, Style)>,
pub message: Vec<(DiagnosticMessage, Style)>,
pub span: MultiSpan,
pub render_span: Option<MultiSpan>,
}
@ -105,18 +167,23 @@ impl StringPart {
}
impl Diagnostic {
pub fn new(level: Level, message: &str) -> Self {
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
Diagnostic::new_with_code(level, None, message)
}
pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
pub fn new_with_code<M: Into<DiagnosticMessage>>(
level: Level,
code: Option<DiagnosticId>,
message: M,
) -> Self {
Diagnostic {
level,
message: vec![(message.to_owned(), Style::NoStyle)],
message: vec![(message.into(), Style::NoStyle)],
code,
span: MultiSpan::new(),
children: vec![],
suggestions: Ok(vec![]),
args: vec![],
sort_span: DUMMY_SP,
is_lint: false,
}
@ -210,7 +277,7 @@ impl Diagnostic {
///
/// This span is *not* considered a ["primary span"][`MultiSpan`]; only
/// the `Span` supplied when creating the diagnostic is primary.
pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
pub fn span_label(&mut self, span: Span, label: impl Into<DiagnosticMessage>) -> &mut Self {
self.span.push_span_label(span, label.into());
self
}
@ -234,7 +301,7 @@ impl Diagnostic {
self.set_span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
self.span_label(after, label);
self.span.push_span_label(after, label);
}
}
self
@ -328,52 +395,67 @@ impl Diagnostic {
}
/// Add a note attached to this diagnostic.
pub fn note(&mut self, msg: &str) -> &mut Self {
pub fn note(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
self.sub(Level::Note, msg, MultiSpan::new(), None);
self
}
pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
pub fn highlighted_note<M: Into<DiagnosticMessage>>(
&mut self,
msg: Vec<(M, Style)>,
) -> &mut Self {
self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
self
}
/// Prints the span with a note above it.
/// This is like [`Diagnostic::note()`], but it gets its own span.
pub fn note_once(&mut self, msg: &str) -> &mut Self {
pub fn note_once(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
self.sub(Level::OnceNote, msg, MultiSpan::new(), None);
self
}
/// Prints the span with a note above it.
/// This is like [`Diagnostic::note()`], but it gets its own span.
pub fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
pub fn span_note<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<DiagnosticMessage>,
) -> &mut Self {
self.sub(Level::Note, msg, sp.into(), None);
self
}
/// Prints the span with a note above it.
/// This is like [`Diagnostic::note()`], but it gets its own span.
pub fn span_note_once<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
pub fn span_note_once<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<DiagnosticMessage>,
) -> &mut Self {
self.sub(Level::OnceNote, msg, sp.into(), None);
self
}
/// Add a warning attached to this diagnostic.
pub fn warn(&mut self, msg: &str) -> &mut Self {
pub fn warn(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
self.sub(Level::Warning, msg, MultiSpan::new(), None);
self
}
/// Prints the span with a warning above it.
/// This is like [`Diagnostic::warn()`], but it gets its own span.
pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
pub fn span_warn<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<DiagnosticMessage>,
) -> &mut Self {
self.sub(Level::Warning, msg, sp.into(), None);
self
}
/// Add a help message attached to this diagnostic.
pub fn help(&mut self, msg: &str) -> &mut Self {
pub fn help(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
self.sub(Level::Help, msg, MultiSpan::new(), None);
self
}
@ -386,7 +468,11 @@ impl Diagnostic {
/// Prints the span with some help above it.
/// This is like [`Diagnostic::help()`], but it gets its own span.
pub fn span_help<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
pub fn span_help<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<DiagnosticMessage>,
) -> &mut Self {
self.sub(Level::Help, msg, sp.into(), None);
self
}
@ -422,7 +508,7 @@ impl Diagnostic {
/// In other words, multiple changes need to be applied as part of this suggestion.
pub fn multipart_suggestion(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
@ -438,7 +524,7 @@ impl Diagnostic {
/// In other words, multiple changes need to be applied as part of this suggestion.
pub fn multipart_suggestion_verbose(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
@ -452,7 +538,7 @@ impl Diagnostic {
/// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
pub fn multipart_suggestion_with_style(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
style: SuggestionStyle,
@ -465,7 +551,7 @@ impl Diagnostic {
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect(),
}],
msg: msg.to_owned(),
msg: msg.into(),
style,
applicability,
tool_metadata: Default::default(),
@ -481,7 +567,7 @@ impl Diagnostic {
/// improve understandability.
pub fn tool_only_multipart_suggestion(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
@ -493,7 +579,7 @@ impl Diagnostic {
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect(),
}],
msg: msg.to_owned(),
msg: msg.into(),
style: SuggestionStyle::CompletelyHidden,
applicability,
tool_metadata: Default::default(),
@ -521,7 +607,7 @@ impl Diagnostic {
pub fn span_suggestion(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self {
@ -539,7 +625,7 @@ impl Diagnostic {
pub fn span_suggestion_with_style(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
style: SuggestionStyle,
@ -548,7 +634,7 @@ impl Diagnostic {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion, span: sp }],
}],
msg: msg.to_owned(),
msg: msg.into(),
style,
applicability,
tool_metadata: Default::default(),
@ -560,7 +646,7 @@ impl Diagnostic {
pub fn span_suggestion_verbose(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self {
@ -579,7 +665,7 @@ impl Diagnostic {
pub fn span_suggestions(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestions: impl Iterator<Item = String>,
applicability: Applicability,
) -> &mut Self {
@ -591,7 +677,7 @@ impl Diagnostic {
.collect();
self.push_suggestion(CodeSuggestion {
substitutions,
msg: msg.to_owned(),
msg: msg.into(),
style: SuggestionStyle::ShowCode,
applicability,
tool_metadata: Default::default(),
@ -603,7 +689,7 @@ impl Diagnostic {
/// See also [`Diagnostic::span_suggestion()`].
pub fn multipart_suggestions(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestions: impl Iterator<Item = Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self {
@ -616,7 +702,7 @@ impl Diagnostic {
.collect(),
})
.collect(),
msg: msg.to_owned(),
msg: msg.into(),
style: SuggestionStyle::ShowCode,
applicability,
tool_metadata: Default::default(),
@ -630,7 +716,7 @@ impl Diagnostic {
pub fn span_suggestion_short(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self {
@ -653,7 +739,7 @@ impl Diagnostic {
pub fn span_suggestion_hidden(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self {
@ -674,7 +760,7 @@ impl Diagnostic {
pub fn tool_only_span_suggestion(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self {
@ -692,13 +778,13 @@ impl Diagnostic {
/// the suggestion in a tool-specific way, as it may not even directly involve Rust code.
pub fn tool_only_suggestion_with_metadata(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
applicability: Applicability,
tool_metadata: Json,
) {
self.push_suggestion(CodeSuggestion {
substitutions: vec![],
msg: msg.to_owned(),
msg: msg.into(),
style: SuggestionStyle::CompletelyHidden,
applicability,
tool_metadata: ToolMetadata::new(tool_metadata),
@ -732,16 +818,25 @@ impl Diagnostic {
self.code.clone()
}
pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self {
pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
self.message[0] = (msg.into(), Style::NoStyle);
self
}
pub fn message(&self) -> String {
self.message.iter().map(|i| i.0.as_str()).collect::<String>()
pub fn args(&self) -> &[DiagnosticArg<'static>] {
&self.args
}
pub fn styled_message(&self) -> &Vec<(String, Style)> {
pub fn set_arg(
&mut self,
name: impl Into<Cow<'static, str>>,
arg: DiagnosticArgValue<'static>,
) -> &mut Self {
self.args.push((name.into(), arg.into()));
self
}
pub fn styled_message(&self) -> &Vec<(DiagnosticMessage, Style)> {
&self.message
}
@ -752,13 +847,13 @@ impl Diagnostic {
pub fn sub(
&mut self,
level: Level,
message: &str,
message: impl Into<DiagnosticMessage>,
span: MultiSpan,
render_span: Option<MultiSpan>,
) {
let sub = SubDiagnostic {
level,
message: vec![(message.to_owned(), Style::NoStyle)],
message: vec![(message.into(), Style::NoStyle)],
span,
render_span,
};
@ -767,13 +862,14 @@ impl Diagnostic {
/// Convenience function for internal use, clients should use one of the
/// public methods above.
fn sub_with_highlights(
fn sub_with_highlights<M: Into<DiagnosticMessage>>(
&mut self,
level: Level,
message: Vec<(String, Style)>,
mut message: Vec<(M, Style)>,
span: MultiSpan,
render_span: Option<MultiSpan>,
) {
let message = message.drain(..).map(|m| (m.0.into(), m.1)).collect();
let sub = SubDiagnostic { level, message, span, render_span };
self.children.push(sub);
}
@ -783,7 +879,7 @@ impl Diagnostic {
&self,
) -> (
&Level,
&Vec<(String, Style)>,
&Vec<(DiagnosticMessage, Style)>,
&Option<DiagnosticId>,
&MultiSpan,
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
@ -814,13 +910,3 @@ impl PartialEq for Diagnostic {
self.keys() == other.keys()
}
}
impl SubDiagnostic {
pub fn message(&self) -> String {
self.message.iter().map(|i| i.0.as_str()).collect::<String>()
}
pub fn styled_message(&self) -> &Vec<(String, Style)> {
&self.message
}
}

View file

@ -1,8 +1,10 @@
use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString, ErrorGuaranteed};
use crate::{Handler, Level, StashKey};
use crate::diagnostic::DiagnosticArgValue;
use crate::{Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed};
use crate::{Handler, Level, MultiSpan, StashKey};
use rustc_lint_defs::Applicability;
use rustc_span::{MultiSpan, Span};
use rustc_span::Span;
use std::borrow::Cow;
use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
@ -99,7 +101,10 @@ mod sealed_level_is_error {
impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
crate fn new_guaranteeing_error<const L: Level>(handler: &'a Handler, message: &str) -> Self
crate fn new_guaranteeing_error<M: Into<DiagnosticMessage>, const L: Level>(
handler: &'a Handler,
message: M,
) -> Self
where
(): sealed_level_is_error::IsError<L>,
{
@ -163,7 +168,11 @@ impl EmissionGuarantee for ErrorGuaranteed {
impl<'a> DiagnosticBuilder<'a, ()> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
crate fn new(handler: &'a Handler, level: Level, message: &str) -> Self {
crate fn new<M: Into<DiagnosticMessage>>(
handler: &'a Handler,
level: Level,
message: M,
) -> Self {
let diagnostic = Diagnostic::new_with_code(level, None, message);
Self::new_diagnostic(handler, diagnostic)
}
@ -201,7 +210,7 @@ impl EmissionGuarantee for () {
impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
crate fn new_fatal(handler: &'a Handler, message: &str) -> Self {
crate fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
Self::new_diagnostic_fatal(handler, diagnostic)
}
@ -346,7 +355,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
}
// Take the `Diagnostic` by replacing it with a dummy.
let dummy = Diagnostic::new(Level::Allow, "");
let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::Str("".to_string()));
let diagnostic = std::mem::replace(&mut *self.inner.diagnostic, dummy);
// Disable the ICE on `Drop`.
@ -399,7 +408,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
/// the diagnostic was constructed. However, the label span is *not* considered a
/// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
/// primary.
pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self);
pub fn span_label(&mut self, span: Span, label: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(
/// Labels all the given spans with the provided label.
@ -434,25 +443,25 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
found: DiagnosticStyledString,
) -> &mut Self);
forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
forward!(pub fn note_once(&mut self, msg: &str) -> &mut Self);
forward!(pub fn note(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn note_once(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn span_note(
&mut self,
sp: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> &mut Self);
forward!(pub fn span_note_once(
&mut self,
sp: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> &mut Self);
forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
forward!(pub fn warn(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn span_warn(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> &mut Self);
forward!(pub fn help(&mut self, msg: &str) -> &mut Self);
forward!(pub fn help(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn span_help(
&mut self,
sp: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> &mut Self);
forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self);
forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
@ -461,67 +470,67 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
forward!(pub fn multipart_suggestion(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn multipart_suggestion_verbose(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn tool_only_multipart_suggestion(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestions(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestions: impl Iterator<Item = String>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn multipart_suggestions(
&mut self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestions: impl Iterator<Item = Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion_short(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion_verbose(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn span_suggestion_hidden(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self);
forward!(pub fn tool_only_span_suggestion(
&mut self,
sp: Span,
msg: &str,
msg: impl Into<DiagnosticMessage>,
suggestion: String,
applicability: Applicability,
) -> &mut Self);
@ -529,6 +538,11 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
forward!(pub fn set_primary_message(&mut self, msg: impl Into<String>) -> &mut Self);
forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
forward!(pub fn set_arg(
&mut self,
name: impl Into<Cow<'static, str>>,
arg: DiagnosticArgValue<'static>,
) -> &mut Self);
}
impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> {
@ -547,7 +561,9 @@ impl Drop for DiagnosticBuilderInner<'_> {
if !panicking() {
handler.emit_diagnostic(&mut Diagnostic::new(
Level::Bug,
"the following error was constructed but not emitted",
DiagnosticMessage::Str(
"the following error was constructed but not emitted".to_string(),
),
));
handler.emit_diagnostic(&mut self.diagnostic);
panic!();

View file

@ -10,19 +10,20 @@
use Destination::*;
use rustc_span::source_map::SourceMap;
use rustc_span::{MultiSpan, SourceFile, Span};
use rustc_span::{SourceFile, Span};
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, Handler, Level, SubDiagnostic, SubstitutionHighlight,
SuggestionStyle,
CodeSuggestion, Diagnostic, DiagnosticArg, DiagnosticId, DiagnosticMessage, FluentBundle,
Handler, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
};
use rustc_lint_defs::pluralize;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_error_messages::FluentArgs;
use rustc_span::hygiene::{ExpnKind, MacroKind};
use std::borrow::Cow;
use std::cmp::{max, min, Reverse};
@ -58,13 +59,25 @@ impl HumanReadableErrorType {
self,
dst: Box<dyn Write + Send>,
source_map: Option<Lrc<SourceMap>>,
bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
teach: bool,
terminal_width: Option<usize>,
macro_backtrace: bool,
) -> EmitterWriter {
let (short, color_config) = self.unzip();
let color = color_config.suggests_using_colors();
EmitterWriter::new(dst, source_map, short, teach, color, terminal_width, macro_backtrace)
EmitterWriter::new(
dst,
source_map,
bundle,
fallback_bundle,
short,
teach,
color,
terminal_width,
macro_backtrace,
)
}
}
@ -212,6 +225,74 @@ pub trait Emitter {
fn source_map(&self) -> Option<&Lrc<SourceMap>>;
/// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
/// language was requested by the user then this will be `None` and `fallback_fluent_bundle`
/// should be used.
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>>;
/// 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>;
/// Convert diagnostic arguments (a rustc internal type that exists to implement
/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
///
/// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
/// passed around as a reference thereafter.
fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
FromIterator::from_iter(args.to_vec().drain(..))
}
/// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
fn translate_messages(
&self,
messages: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
) -> Cow<'_, str> {
Cow::Owned(
messages.iter().map(|(m, _)| self.translate_message(m, args)).collect::<String>(),
)
}
/// Convert a `DiagnosticMessage` to a string, performing translation if necessary.
fn translate_message<'a>(
&'a self,
message: &'a DiagnosticMessage,
args: &'a FluentArgs<'_>,
) -> Cow<'_, str> {
trace!(?message, ?args);
let (identifier, attr) = match message {
DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
};
let bundle = match self.fluent_bundle() {
Some(bundle) if bundle.has_message(&identifier) => bundle,
_ => self.fallback_fluent_bundle(),
};
let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle");
let value = match attr {
Some(attr) => {
message.get_attribute(attr).expect("missing attribute in fluent message").value()
}
None => message.value().expect("missing value in fluent message"),
};
let mut err = vec![];
let translated = bundle.format_pattern(value, Some(&args), &mut err);
trace!(?translated, ?err);
debug_assert!(
err.is_empty(),
"identifier: {:?}, args: {:?}, errors: {:?}",
identifier,
args,
err
);
translated
}
/// Formats the substitutions of the primary_span
///
/// There are a lot of conditions to this method, but in short:
@ -225,10 +306,12 @@ pub trait Emitter {
fn primary_span_formatted<'a>(
&mut self,
diag: &'a Diagnostic,
fluent_args: &FluentArgs<'_>,
) -> (MultiSpan, &'a [CodeSuggestion]) {
let mut primary_span = diag.span.clone();
let suggestions = diag.suggestions.as_ref().map_or(&[][..], |suggestions| &suggestions[..]);
if let Some((sugg, rest)) = suggestions.split_first() {
let msg = self.translate_message(&sugg.msg, fluent_args);
if rest.is_empty() &&
// ^ if there is only one suggestion
// don't display multi-suggestions as labels
@ -236,7 +319,7 @@ pub trait Emitter {
// don't display multipart suggestions as labels
sugg.substitutions[0].parts.len() == 1 &&
// don't display long messages as labels
sugg.msg.split_whitespace().count() < 10 &&
msg.split_whitespace().count() < 10 &&
// don't display multiline suggestions as labels
!sugg.substitutions[0].parts[0].snippet.contains('\n') &&
![
@ -252,12 +335,12 @@ pub trait Emitter {
let msg = if substitution.is_empty() || sugg.style.hide_inline() {
// This substitution is only removal OR we explicitly don't want to show the
// code inline (`hide_inline`). Therefore, we don't show the substitution.
format!("help: {}", sugg.msg)
format!("help: {}", &msg)
} else {
// Show the default suggestion text with the substitution
format!(
"help: {}{}: `{}`",
sugg.msg,
&msg,
if self
.source_map()
.map(|sm| is_case_difference(
@ -333,7 +416,7 @@ pub trait Emitter {
children.push(SubDiagnostic {
level: Level::Note,
message: vec![(msg, Style::NoStyle)],
message: vec![(DiagnosticMessage::Str(msg), Style::NoStyle)],
span: MultiSpan::new(),
render_span: None,
});
@ -492,9 +575,19 @@ impl Emitter for EmitterWriter {
self.sm.as_ref()
}
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
self.fluent_bundle.as_ref()
}
fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
&self.fallback_bundle
}
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
let fluent_args = self.to_fluent_args(diag.args());
let mut children = diag.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag);
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
debug!("emit_diagnostic: suggestions={:?}", suggestions);
self.fix_multispans_in_extern_macros_and_render_macro_backtrace(
@ -507,7 +600,8 @@ impl Emitter for EmitterWriter {
self.emit_messages_default(
&diag.level,
&diag.styled_message(),
&diag.message,
&fluent_args,
&diag.code,
&primary_span,
&children,
@ -536,6 +630,15 @@ impl Emitter for SilentEmitter {
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None
}
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
None
}
fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
panic!("silent emitter attempted to translate message")
}
fn emit_diagnostic(&mut self, d: &Diagnostic) {
if d.level == Level::Fatal {
let mut d = d.clone();
@ -591,6 +694,8 @@ impl ColorConfig {
pub struct EmitterWriter {
dst: Destination,
sm: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
short_message: bool,
teach: bool,
ui_testing: bool,
@ -610,6 +715,8 @@ impl EmitterWriter {
pub fn stderr(
color_config: ColorConfig,
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
short_message: bool,
teach: bool,
terminal_width: Option<usize>,
@ -619,6 +726,8 @@ impl EmitterWriter {
EmitterWriter {
dst,
sm: source_map,
fluent_bundle,
fallback_bundle,
short_message,
teach,
ui_testing: false,
@ -630,6 +739,8 @@ impl EmitterWriter {
pub fn new(
dst: Box<dyn Write + Send>,
source_map: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
short_message: bool,
teach: bool,
colored: bool,
@ -639,6 +750,8 @@ impl EmitterWriter {
EmitterWriter {
dst: Raw(dst, colored),
sm: source_map,
fluent_bundle,
fallback_bundle,
short_message,
teach,
ui_testing: false,
@ -1176,7 +1289,8 @@ impl EmitterWriter {
fn msg_to_buffer(
&self,
buffer: &mut StyledBuffer,
msg: &[(String, Style)],
msg: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
padding: usize,
label: &str,
override_style: Option<Style>,
@ -1229,6 +1343,7 @@ impl EmitterWriter {
// very *weird* formats
// see?
for &(ref text, ref style) in msg.iter() {
let text = self.translate_message(text, args);
let lines = text.split('\n').collect::<Vec<_>>();
if lines.len() > 1 {
for (i, line) in lines.iter().enumerate() {
@ -1239,7 +1354,7 @@ impl EmitterWriter {
buffer.append(line_number, line, style_or_override(*style, override_style));
}
} else {
buffer.append(line_number, text, style_or_override(*style, override_style));
buffer.append(line_number, &text, style_or_override(*style, override_style));
}
}
}
@ -1247,7 +1362,8 @@ impl EmitterWriter {
fn emit_message_default(
&mut self,
msp: &MultiSpan,
msg: &[(String, Style)],
msg: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
code: &Option<DiagnosticId>,
level: &Level,
max_line_num_len: usize,
@ -1266,7 +1382,7 @@ impl EmitterWriter {
buffer.append(0, level.to_str(), Style::MainHeaderMsg);
buffer.append(0, ": ", Style::NoStyle);
}
self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None);
self.msg_to_buffer(&mut buffer, msg, args, max_line_num_len, "note", None);
} else {
let mut label_width = 0;
// The failure note level itself does not provide any useful diagnostic information
@ -1287,8 +1403,9 @@ impl EmitterWriter {
label_width += 2;
}
for &(ref text, _) in msg.iter() {
let text = self.translate_message(text, args);
// Account for newlines to align output to its label.
for (line, text) in normalize_whitespace(text).lines().enumerate() {
for (line, text) in normalize_whitespace(&text).lines().enumerate() {
buffer.append(
0 + line,
&format!(
@ -1302,7 +1419,7 @@ impl EmitterWriter {
}
}
let mut annotated_files = FileWithAnnotatedLines::collect_annotations(msp, &self.sm);
let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp);
// Make sure our primary file comes first
let (primary_lo, sm) = if let (Some(sm), Some(ref primary_span)) =
@ -1586,6 +1703,7 @@ impl EmitterWriter {
fn emit_suggestion_default(
&mut self,
suggestion: &CodeSuggestion,
args: &FluentArgs<'_>,
level: &Level,
max_line_num_len: usize,
) -> io::Result<()> {
@ -1612,6 +1730,7 @@ impl EmitterWriter {
self.msg_to_buffer(
&mut buffer,
&[(suggestion.msg.to_owned(), Style::NoStyle)],
args,
max_line_num_len,
"suggestion",
Some(Style::HeaderMsg),
@ -1852,7 +1971,8 @@ impl EmitterWriter {
fn emit_messages_default(
&mut self,
level: &Level,
message: &[(String, Style)],
message: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
code: &Option<DiagnosticId>,
span: &MultiSpan,
children: &[SubDiagnostic],
@ -1865,7 +1985,7 @@ impl EmitterWriter {
num_decimal_digits(n)
};
match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
match self.emit_message_default(span, message, args, code, level, max_line_num_len, false) {
Ok(()) => {
if !children.is_empty()
|| suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden)
@ -1888,7 +2008,8 @@ impl EmitterWriter {
let span = child.render_span.as_ref().unwrap_or(&child.span);
if let Err(err) = self.emit_message_default(
&span,
&child.styled_message(),
&child.message,
args,
&None,
&child.level,
max_line_num_len,
@ -1904,6 +2025,7 @@ impl EmitterWriter {
if let Err(e) = self.emit_message_default(
&MultiSpan::new(),
&[(sugg.msg.to_owned(), Style::HeaderMsg)],
args,
&None,
&Level::Help,
max_line_num_len,
@ -1912,7 +2034,7 @@ impl EmitterWriter {
panic!("failed to emit error: {}", e);
}
} else if let Err(e) =
self.emit_suggestion_default(sugg, &Level::Help, max_line_num_len)
self.emit_suggestion_default(sugg, args, &Level::Help, max_line_num_len)
{
panic!("failed to emit error: {}", e);
};
@ -1938,8 +2060,9 @@ impl FileWithAnnotatedLines {
/// Preprocess all the annotations so that they are grouped by file and by line number
/// This helps us quickly iterate over the whole message (including secondary file spans)
pub fn collect_annotations(
emitter: &dyn Emitter,
args: &FluentArgs<'_>,
msp: &MultiSpan,
source_map: &Option<Lrc<SourceMap>>,
) -> Vec<FileWithAnnotatedLines> {
fn add_annotation_to_file(
file_vec: &mut Vec<FileWithAnnotatedLines>,
@ -1974,7 +2097,7 @@ impl FileWithAnnotatedLines {
let mut output = vec![];
let mut multiline_annotations = vec![];
if let Some(ref sm) = source_map {
if let Some(ref sm) = emitter.source_map() {
for span_label in msp.span_labels() {
if span_label.span.is_dummy() {
continue;
@ -2001,7 +2124,10 @@ impl FileWithAnnotatedLines {
start_col: lo.col_display,
end_col: hi.col_display,
is_primary: span_label.is_primary,
label: span_label.label,
label: span_label
.label
.as_ref()
.map(|m| emitter.translate_message(m, args).to_string()),
overlaps_exactly: false,
};
multiline_annotations.push((lo.file, ml));
@ -2010,7 +2136,10 @@ impl FileWithAnnotatedLines {
start_col: lo.col_display,
end_col: hi.col_display,
is_primary: span_label.is_primary,
label: span_label.label,
label: span_label
.label
.as_ref()
.map(|m| emitter.translate_message(m, args).to_string()),
annotation_type: AnnotationType::Singleline,
};
add_annotation_to_file(&mut output, lo.file, lo.line, ann);

View file

@ -15,12 +15,13 @@ use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
use crate::DiagnosticId;
use crate::ToolMetadata;
use crate::{CodeSuggestion, SubDiagnostic};
use crate::{CodeSuggestion, FluentBundle, MultiSpan, SpanLabel, SubDiagnostic};
use rustc_lint_defs::Applicability;
use rustc_data_structures::sync::Lrc;
use rustc_error_messages::FluentArgs;
use rustc_span::hygiene::ExpnData;
use rustc_span::{MultiSpan, Span, SpanLabel};
use rustc_span::Span;
use std::io::{self, Write};
use std::path::Path;
use std::sync::{Arc, Mutex};
@ -36,6 +37,8 @@ pub struct JsonEmitter {
dst: Box<dyn Write + Send>,
registry: Option<Registry>,
sm: Lrc<SourceMap>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
pretty: bool,
ui_testing: bool,
json_rendered: HumanReadableErrorType,
@ -47,6 +50,8 @@ impl JsonEmitter {
pub fn stderr(
registry: Option<Registry>,
source_map: Lrc<SourceMap>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
pretty: bool,
json_rendered: HumanReadableErrorType,
terminal_width: Option<usize>,
@ -56,6 +61,8 @@ impl JsonEmitter {
dst: Box::new(io::BufWriter::new(io::stderr())),
registry,
sm: source_map,
fluent_bundle,
fallback_bundle,
pretty,
ui_testing: false,
json_rendered,
@ -67,6 +74,8 @@ impl JsonEmitter {
pub fn basic(
pretty: bool,
json_rendered: HumanReadableErrorType,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
terminal_width: Option<usize>,
macro_backtrace: bool,
) -> JsonEmitter {
@ -74,6 +83,8 @@ impl JsonEmitter {
JsonEmitter::stderr(
None,
Lrc::new(SourceMap::new(file_path_mapping)),
fluent_bundle,
fallback_bundle,
pretty,
json_rendered,
terminal_width,
@ -85,6 +96,8 @@ impl JsonEmitter {
dst: Box<dyn Write + Send>,
registry: Option<Registry>,
source_map: Lrc<SourceMap>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
pretty: bool,
json_rendered: HumanReadableErrorType,
terminal_width: Option<usize>,
@ -94,6 +107,8 @@ impl JsonEmitter {
dst,
registry,
sm: source_map,
fluent_bundle,
fallback_bundle,
pretty,
ui_testing: false,
json_rendered,
@ -173,6 +188,14 @@ impl Emitter for JsonEmitter {
Some(&self.sm)
}
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
self.fluent_bundle.as_ref()
}
fn fallback_fluent_bundle(&self) -> &Lrc<FluentBundle> {
&self.fallback_bundle
}
fn should_show_explain(&self) -> bool {
!matches!(self.json_rendered, HumanReadableErrorType::Short(_))
}
@ -345,14 +368,18 @@ struct UnusedExterns<'a, 'b, 'c> {
impl Diagnostic {
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
let sugg = diag.suggestions.iter().flatten().map(|sugg| Diagnostic {
message: sugg.msg.clone(),
code: None,
level: "help",
spans: DiagnosticSpan::from_suggestion(sugg, je),
children: vec![],
rendered: None,
tool_metadata: sugg.tool_metadata.clone(),
let args = je.to_fluent_args(diag.args());
let sugg = diag.suggestions.iter().flatten().map(|sugg| {
let translated_message = je.translate_message(&sugg.msg, &args);
Diagnostic {
message: translated_message.to_string(),
code: None,
level: "help",
spans: DiagnosticSpan::from_suggestion(sugg, &args, je),
children: vec![],
rendered: None,
tool_metadata: sugg.tool_metadata.clone(),
}
});
// generate regular command line output and store it in the json
@ -375,6 +402,8 @@ impl Diagnostic {
.new_emitter(
Box::new(buf),
Some(je.sm.clone()),
je.fluent_bundle.clone(),
je.fallback_bundle.clone(),
false,
je.terminal_width,
je.macro_backtrace,
@ -384,15 +413,16 @@ impl Diagnostic {
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
let output = String::from_utf8(output).unwrap();
let translated_message = je.translate_messages(&diag.message, &args);
Diagnostic {
message: diag.message(),
message: translated_message.to_string(),
code: DiagnosticCode::map_opt_string(diag.code.clone(), je),
level: diag.level.to_str(),
spans: DiagnosticSpan::from_multispan(&diag.span, je),
spans: DiagnosticSpan::from_multispan(&diag.span, &args, je),
children: diag
.children
.iter()
.map(|c| Diagnostic::from_sub_diagnostic(c, je))
.map(|c| Diagnostic::from_sub_diagnostic(c, &args, je))
.chain(sugg)
.collect(),
rendered: Some(output),
@ -400,16 +430,21 @@ impl Diagnostic {
}
}
fn from_sub_diagnostic(diag: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic {
fn from_sub_diagnostic(
diag: &SubDiagnostic,
args: &FluentArgs<'_>,
je: &JsonEmitter,
) -> Diagnostic {
let translated_message = je.translate_messages(&diag.message, args);
Diagnostic {
message: diag.message(),
message: translated_message.to_string(),
code: None,
level: diag.level.to_str(),
spans: diag
.render_span
.as_ref()
.map(|sp| DiagnosticSpan::from_multispan(sp, je))
.unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, je)),
.map(|sp| DiagnosticSpan::from_multispan(sp, args, je))
.unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, args, je)),
children: vec![],
rendered: None,
tool_metadata: ToolMetadata::default(),
@ -421,9 +456,16 @@ impl DiagnosticSpan {
fn from_span_label(
span: SpanLabel,
suggestion: Option<(&String, Applicability)>,
args: &FluentArgs<'_>,
je: &JsonEmitter,
) -> DiagnosticSpan {
Self::from_span_etc(span.span, span.is_primary, span.label, suggestion, je)
Self::from_span_etc(
span.span,
span.is_primary,
span.label.as_ref().map(|m| je.translate_message(m, args)).map(|m| m.to_string()),
suggestion,
je,
)
}
fn from_span_etc(
@ -486,14 +528,22 @@ impl DiagnosticSpan {
}
}
fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
fn from_multispan(
msp: &MultiSpan,
args: &FluentArgs<'_>,
je: &JsonEmitter,
) -> Vec<DiagnosticSpan> {
msp.span_labels()
.into_iter()
.map(|span_str| Self::from_span_label(span_str, None, je))
.map(|span_str| Self::from_span_label(span_str, None, args, je))
.collect()
}
fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
fn from_suggestion(
suggestion: &CodeSuggestion,
args: &FluentArgs<'_>,
je: &JsonEmitter,
) -> Vec<DiagnosticSpan> {
suggestion
.substitutions
.iter()
@ -504,6 +554,7 @@ impl DiagnosticSpan {
DiagnosticSpan::from_span_label(
span_label,
Some((&suggestion_inner.snippet, suggestion.applicability)),
args,
je,
)
})

View file

@ -39,12 +39,16 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
rustc_span::create_default_session_globals_then(|| {
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");
let output = Arc::new(Mutex::new(Vec::new()));
let je = JsonEmitter::new(
Box::new(Shared { data: output.clone() }),
None,
sm,
None,
fallback_bundle,
true,
HumanReadableErrorType::Short(ColorConfig::Never),
None,

View file

@ -31,11 +31,15 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::stable_hasher::StableHasher;
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,
};
pub use rustc_lint_defs::{pluralize, Applicability};
use rustc_serialize::json::Json;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::source_map::SourceMap;
use rustc_span::{Loc, MultiSpan, Span};
use rustc_span::{Loc, Span};
use std::borrow::Cow;
use std::hash::{Hash, Hasher};
@ -55,6 +59,7 @@ mod lock;
pub mod registry;
mod snippet;
mod styled_buffer;
pub use snippet::Style;
pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a, ErrorGuaranteed>>;
@ -145,7 +150,7 @@ pub struct CodeSuggestion {
/// ]
/// ```
pub substitutions: Vec<Substitution>,
pub msg: String,
pub msg: DiagnosticMessage,
/// Visual representation of this suggestion.
pub style: SuggestionStyle,
/// Whether or not the suggestion is approximate
@ -400,7 +405,10 @@ impl fmt::Display for ExplicitBug {
impl error::Error for ExplicitBug {}
pub use diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic};
pub use diagnostic::{
Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString,
IntoDiagnosticArg, SubDiagnostic,
};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
use std::backtrace::Backtrace;
@ -538,10 +546,14 @@ impl Handler {
can_emit_warnings: bool,
treat_err_as_bug: Option<NonZeroUsize>,
sm: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
) -> Self {
Self::with_tty_emitter_and_flags(
color_config,
sm,
fluent_bundle,
fallback_bundle,
HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
)
}
@ -549,11 +561,15 @@ impl Handler {
pub fn with_tty_emitter_and_flags(
color_config: ColorConfig,
sm: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
flags: HandlerFlags,
) -> Self {
let emitter = Box::new(EmitterWriter::stderr(
color_config,
sm,
fluent_bundle,
fallback_bundle,
false,
false,
None,
@ -658,7 +674,7 @@ impl Handler {
pub fn struct_span_warn(
&self,
span: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
let mut result = self.struct_warn(msg);
result.set_span(span);
@ -669,7 +685,7 @@ impl Handler {
pub fn struct_span_allow(
&self,
span: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
let mut result = self.struct_allow(msg);
result.set_span(span);
@ -681,7 +697,7 @@ impl Handler {
pub fn struct_span_warn_with_code(
&self,
span: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ()> {
let mut result = self.struct_span_warn(span, msg);
@ -694,17 +710,21 @@ impl Handler {
/// Attempting to `.emit()` the builder will only emit if either:
/// * `can_emit_warnings` is `true`
/// * `is_force_warn` was set in `DiagnosticId::Lint`
pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Warning, msg)
}
/// Construct a builder at the `Allow` level with the `msg`.
pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Allow, msg)
}
/// Construct a builder at the `Expect` level with the `msg`.
pub fn struct_expect(&self, msg: &str, id: LintExpectationId) -> DiagnosticBuilder<'_, ()> {
pub fn struct_expect(
&self,
msg: impl Into<DiagnosticMessage>,
id: LintExpectationId,
) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Expect(id), msg)
}
@ -712,7 +732,7 @@ impl Handler {
pub fn struct_span_err(
&self,
span: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut result = self.struct_err(msg);
result.set_span(span);
@ -723,7 +743,7 @@ impl Handler {
pub fn struct_span_err_with_code(
&self,
span: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut result = self.struct_span_err(span, msg);
@ -733,20 +753,23 @@ impl Handler {
/// Construct a builder at the `Error` level with the `msg`.
// FIXME: This method should be removed (every error should have an associated error code).
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
DiagnosticBuilder::new_guaranteeing_error::<{ Level::Error { lint: false } }>(self, msg)
pub fn struct_err(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
DiagnosticBuilder::new_guaranteeing_error::<_, { Level::Error { lint: false } }>(self, msg)
}
/// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
#[doc(hidden)]
pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn struct_err_lint(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
}
/// Construct a builder at the `Error` level with the `msg` and the `code`.
pub fn struct_err_with_code(
&self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut result = self.struct_err(msg);
@ -754,11 +777,22 @@ impl Handler {
result
}
/// Construct a builder at the `Warn` level with the `msg` and the `code`.
pub fn struct_warn_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ()> {
let mut result = self.struct_warn(msg);
result.code(code);
result
}
/// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
pub fn struct_span_fatal(
&self,
span: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, !> {
let mut result = self.struct_fatal(msg);
result.set_span(span);
@ -769,7 +803,7 @@ impl Handler {
pub fn struct_span_fatal_with_code(
&self,
span: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, !> {
let mut result = self.struct_span_fatal(span, msg);
@ -778,21 +812,24 @@ impl Handler {
}
/// Construct a builder at the `Error` level with the `msg`.
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, !> {
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
DiagnosticBuilder::new_fatal(self, msg)
}
/// Construct a builder at the `Help` level with the `msg`.
pub fn struct_help(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Help, msg)
}
/// Construct a builder at the `Note` level with the `msg`.
pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn struct_note_without_error(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Note, msg)
}
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
FatalError.raise()
}
@ -800,80 +837,106 @@ impl Handler {
pub fn span_fatal_with_code(
&self,
span: impl Into<MultiSpan>,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> ! {
self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
FatalError.raise()
}
pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> ErrorGuaranteed {
pub fn span_err(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span).unwrap()
}
pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
pub fn span_err_with_code(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) {
self.emit_diag_at_span(
Diagnostic::new_with_code(Error { lint: false }, Some(code), msg),
span,
);
}
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
}
pub fn span_warn_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
pub fn span_warn_with_code(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) {
self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
}
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
self.inner.borrow_mut().span_bug(span, msg)
}
#[track_caller]
pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ErrorGuaranteed {
pub fn delay_span_bug(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
self.inner.borrow_mut().delay_span_bug(span, msg)
}
// FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
// where the explanation of what "good path" is (also, it should be renamed).
pub fn delay_good_path_bug(&self, msg: &str) {
pub fn delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>) {
self.inner.borrow_mut().delay_good_path_bug(msg)
}
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
}
pub fn span_note_without_error(&self, span: impl Into<MultiSpan>, msg: &str) {
pub fn span_note_without_error(
&self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) {
self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
}
pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn span_note_diag(
&self,
span: Span,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
let mut db = DiagnosticBuilder::new(self, Note, msg);
db.set_span(span);
db
}
// NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread
pub fn fatal(&self, msg: &str) -> FatalError {
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> FatalError {
self.inner.borrow_mut().fatal(msg)
}
pub fn err(&self, msg: &str) -> ErrorGuaranteed {
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.inner.borrow_mut().err(msg)
}
pub fn warn(&self, msg: &str) {
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
let mut db = DiagnosticBuilder::new(self, Warning, msg);
db.emit();
}
pub fn note_without_error(&self, msg: &str) {
pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
DiagnosticBuilder::new(self, Note, msg).emit();
}
pub fn bug(&self, msg: &str) -> ! {
pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.inner.borrow_mut().bug(msg)
}
@ -1143,7 +1206,10 @@ impl HandlerInner {
match (errors.len(), warnings.len()) {
(0, 0) => return,
(0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(Level::Warning, &warnings)),
(0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(
Level::Warning,
DiagnosticMessage::Str(warnings.to_owned()),
)),
(_, 0) => {
let _ = self.fatal(&errors);
}
@ -1218,7 +1284,7 @@ impl HandlerInner {
}
}
fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
panic::panic_any(ExplicitBug);
}
@ -1228,7 +1294,11 @@ impl HandlerInner {
}
#[track_caller]
fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ErrorGuaranteed {
fn delay_span_bug(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
// FIXME: Would be nice to increment err_count in a more coherent way.
@ -1244,7 +1314,7 @@ impl HandlerInner {
// FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
// where the explanation of what "good path" is (also, it should be renamed).
fn delay_good_path_bug(&mut self, msg: &str) {
fn delay_good_path_bug(&mut self, msg: impl Into<DiagnosticMessage>) {
let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
if self.flags.report_delayed_bugs {
self.emit_diagnostic(&mut diagnostic);
@ -1253,33 +1323,37 @@ impl HandlerInner {
self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
}
fn failure(&mut self, msg: &str) {
fn failure(&mut self, msg: impl Into<DiagnosticMessage>) {
self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg));
}
fn fatal(&mut self, msg: &str) -> FatalError {
fn fatal(&mut self, msg: impl Into<DiagnosticMessage>) -> FatalError {
self.emit(Fatal, msg);
FatalError
}
fn err(&mut self, msg: &str) -> ErrorGuaranteed {
fn err(&mut self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.emit(Error { lint: false }, msg)
}
/// Emit an error; level should be `Error` or `Fatal`.
fn emit(&mut self, level: Level, msg: &str) -> ErrorGuaranteed {
fn emit(&mut self, level: Level, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
if self.treat_err_as_bug() {
self.bug(msg);
}
self.emit_diagnostic(&mut Diagnostic::new(level, msg)).unwrap()
}
fn bug(&mut self, msg: &str) -> ! {
fn bug(&mut self, msg: impl Into<DiagnosticMessage>) -> ! {
self.emit_diagnostic(&mut Diagnostic::new(Bug, msg));
panic::panic_any(ExplicitBug);
}
fn flush_delayed(&mut self, bugs: impl IntoIterator<Item = Diagnostic>, explanation: &str) {
fn flush_delayed(
&mut self,
bugs: impl IntoIterator<Item = Diagnostic>,
explanation: impl Into<DiagnosticMessage> + Copy,
) {
let mut no_bugs = true;
for mut bug in bugs {
if no_bugs {

View file

@ -10,7 +10,7 @@ use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::BuiltinLintDiagnostics;
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
@ -20,7 +20,7 @@ use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_span::{Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
use std::default::Default;

View file

@ -109,10 +109,11 @@ use crate::mbe::{KleeneToken, TokenTree};
use rustc_ast::token::{DelimToken, Token, TokenKind};
use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::MultiSpan;
use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
use rustc_session::parse::ParseSess;
use rustc_span::symbol::kw;
use rustc_span::{symbol::MacroRulesNormalizedIdent, MultiSpan, Span};
use rustc_span::{symbol::MacroRulesNormalizedIdent, Span};
use smallvec::SmallVec;
@ -249,7 +250,7 @@ fn check_binders(
if let Some(prev_info) = binders.get(&name) {
// 1. The meta-variable is already bound in the current LHS: This is an error.
let mut span = MultiSpan::from_span(span);
span.push_span_label(prev_info.span, "previous declaration".into());
span.push_span_label(prev_info.span, "previous declaration");
buffer_lint(sess, span, node_id, "duplicate matcher binding");
} else if get_binder_info(macros, binders, name).is_none() {
// 2. The meta-variable is free: This is a binder.
@ -621,7 +622,7 @@ fn ops_is_prefix(
for (i, binder) in binder_ops.iter().enumerate() {
if i >= occurrence_ops.len() {
let mut span = MultiSpan::from_span(span);
span.push_span_label(binder.span, "expected repetition".into());
span.push_span_label(binder.span, "expected repetition");
let message = &format!("variable '{}' is still repeating at this depth", name);
buffer_lint(sess, span, node_id, message);
return;
@ -629,8 +630,8 @@ fn ops_is_prefix(
let occurrence = &occurrence_ops[i];
if occurrence.op != binder.op {
let mut span = MultiSpan::from_span(span);
span.push_span_label(binder.span, "expected repetition".into());
span.push_span_label(occurrence.span, "conflicting repetition".into());
span.push_span_label(binder.span, "expected repetition");
span.push_span_label(occurrence.span, "conflicting repetition");
let message = "meta-variable repeats with different Kleene operator";
buffer_lint(sess, span, node_id, message);
return;

View file

@ -68,17 +68,18 @@ fn emit_frag_parse_err(
arm_span: Span,
kind: AstFragmentKind,
) {
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
// FIXME(davidtwco): avoid depending on the error message text
if parser.token == token::Eof && e.message[0].0.expect_str().ends_with(", found `<eof>`") {
if !e.span.is_dummy() {
// early end of macro arm (#52866)
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
}
let msg = &e.message[0];
e.message[0] = (
format!(
rustc_errors::DiagnosticMessage::Str(format!(
"macro expansion ends with an incomplete expression: {}",
msg.0.replace(", found `<eof>`", ""),
),
msg.0.expect_str().replace(", found `<eof>`", ""),
)),
msg.1,
);
}

View file

@ -128,13 +128,15 @@ fn parse_ident<'sess>(
sess: &'sess ParseSess,
span: Span,
) -> PResult<'sess, Ident> {
let err_fn = |msg| sess.span_diagnostic.struct_span_err(span, msg);
if let Some(tt) = iter.next() && let TokenTree::Token(token) = tt {
if let Some((elem, false)) = token.ident() {
return Ok(elem);
}
let token_str = pprust::token_to_string(&token);
let mut err = err_fn(&format!("expected identifier, found `{}`", &token_str));
let mut err = sess.span_diagnostic.struct_span_err(
span,
&format!("expected identifier, found `{}`", &token_str)
);
err.span_suggestion(
token.span,
&format!("try removing `{}`", &token_str),
@ -143,7 +145,7 @@ fn parse_ident<'sess>(
);
return Err(err);
}
Err(err_fn("expected identifier"))
Err(sess.span_diagnostic.struct_span_err(span, "expected identifier"))
}
/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the

View file

@ -7,13 +7,13 @@ use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Diagnostic, PResult};
use rustc_errors::{Diagnostic, MultiSpan, PResult};
use rustc_parse::lexer::nfc_normalize;
use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
use rustc_session::parse::ParseSess;
use rustc_span::def_id::CrateNum;
use rustc_span::symbol::{self, kw, sym, Symbol};
use rustc_span::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
use pm::bridge::{server, TokenTree};
use pm::{Delimiter, Level, LineColumn, Spacing};

View file

@ -4,11 +4,11 @@ use rustc_parse::{new_parser_from_source_str, parser::Parser, source_file_to_str
use rustc_session::parse::ParseSess;
use rustc_span::create_default_session_if_not_set_then;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{BytePos, MultiSpan, Span};
use rustc_span::{BytePos, Span};
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
use rustc_errors::{Handler, PResult};
use rustc_errors::{Handler, MultiSpan, PResult};
use std::io;
use std::io::prelude::*;
@ -127,6 +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 source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
@ -142,6 +144,8 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
let emitter = EmitterWriter::new(
Box::new(Shared { data: output.clone() }),
Some(source_map.clone()),
None,
fallback_bundle,
false,
false,
false,

View file

@ -11,6 +11,7 @@ rustc_target = { path = "../rustc_target" }
rustc_feature = { path = "../rustc_feature" }
rustc_macros = { path = "../rustc_macros" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_error_messages = { path = "../rustc_error_messages" }
rustc_index = { path = "../rustc_index" }
rustc_span = { path = "../rustc_span" }
rustc_serialize = { path = "../rustc_serialize" }

View file

@ -13,12 +13,13 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_error_messages::MultiSpan;
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{def_id::LocalDefId, BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP};
use rustc_target::asm::InlineAsmRegOrRegClass;
use rustc_target::spec::abi::Abi;

View file

@ -59,7 +59,7 @@ use crate::traits::{
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
@ -72,7 +72,7 @@ use rustc_middle::ty::{
subst::{GenericArgKind, Subst, SubstsRef},
Binder, List, Region, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::ops::ControlFlow;
use std::{cmp, fmt, iter};
@ -2075,7 +2075,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
diag.span_suggestion(
span,
msg,
*msg,
format!("{}.as_ref()", snippet),
Applicability::MachineApplicable,
);

View file

@ -7,11 +7,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::ObligationCauseCode;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::{Applicability, ErrorGuaranteed};
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_middle::ty::TypeVisitor;
use rustc_span::MultiSpan;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaranteed> {
@ -42,8 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
// FIXME: we should point at the lifetime
let mut multi_span: MultiSpan = vec![binding_span].into();
multi_span
.push_span_label(binding_span, "introduces a `'static` lifetime requirement".into());
multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
err.span_note(multi_span, "because this has an unmet lifetime requirement");
note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {

View file

@ -5,7 +5,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
@ -13,7 +13,7 @@ use rustc_middle::ty::{
self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable, TypeVisitor,
};
use rustc_span::symbol::Ident;
use rustc_span::{MultiSpan, Span};
use rustc_span::Span;
use std::ops::ControlFlow;

View file

@ -4,7 +4,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, Subtype};
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
use rustc_errors::ErrorGuaranteed;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
@ -12,8 +12,7 @@ use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::{MultiSpan, Span, Symbol};
use rustc_span::{Span, Symbol};
use std::ops::ControlFlow;

View file

@ -7,7 +7,7 @@ use rustc_middle::ty::{self, Region};
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
let mut label_or_note = |span, msg| {
let mut label_or_note = |span, msg: &str| {
let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count();
let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count();
let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span);

View file

@ -2,11 +2,11 @@ use super::ObjectSafetyViolation;
use crate::infer::InferCtxt;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::TyCtxt;
use rustc_span::{MultiSpan, Span};
use rustc_span::Span;
use std::fmt;
use std::iter;

View file

@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::parallel;
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{Applicability, ErrorGuaranteed, PResult};
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult};
use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
use rustc_hir::Crate;
@ -35,7 +35,7 @@ use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{FileName, MultiSpan};
use rustc_span::FileName;
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
use tempfile::Builder as TempFileBuilder;

View file

@ -31,7 +31,7 @@ use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust::{self, expr_to_string};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, Diagnostic, DiagnosticStyledString};
use rustc_errors::{Applicability, Diagnostic, DiagnosticStyledString, MultiSpan};
use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@ -49,7 +49,7 @@ use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, InnerSpan, MultiSpan, Span};
use rustc_span::{BytePos, InnerSpan, Span};
use rustc_target::abi::VariantIdx;
use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
@ -1571,7 +1571,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
lint.build("bounds on generic parameters are not enforced in type aliases");
let msg = "the bound will not be checked when the type alias is used, \
and should be removed";
err.multipart_suggestion(&msg, suggestion, Applicability::MachineApplicable);
err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);
if !suggested_changing_assoc_types {
TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
suggested_changing_assoc_types = true;

View file

@ -21,7 +21,7 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject};
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync;
use rustc_errors::{struct_span_err, Applicability, SuggestionStyle};
use rustc_errors::{struct_span_err, Applicability, MultiSpan, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId};
@ -38,7 +38,7 @@ use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintI
use rustc_session::Session;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_span::{BytePos, Span, DUMMY_SP};
use rustc_target::abi;
use tracing::debug;

View file

@ -37,7 +37,7 @@ fn emit_unfulfilled_expectation_lint(
|diag| {
let mut diag = diag.build("this lint expectation is unfulfilled");
if let Some(rationale) = expectation.reason {
diag.note(&rationale.as_str());
diag.note(rationale.as_str());
}
if expectation.is_unfulfilled_lint_expectations {

View file

@ -3,7 +3,7 @@ use crate::late::unerased_lint_store;
use rustc_ast as ast;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, Diagnostic};
use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::{intravisit, HirId};
use rustc_middle::hir::nested_filter;
@ -20,7 +20,7 @@ use rustc_session::lint::{
use rustc_session::parse::{add_feature_diagnostics, feature_err};
use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
use rustc_span::{Span, DUMMY_SP};
use tracing::debug;
fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap {

View file

@ -154,7 +154,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
err.span_suggestion(
parent_expr.span,
&"use an inclusive range instead",
"use an inclusive range instead",
suggestion,
Applicability::MachineApplicable,
);
@ -399,7 +399,7 @@ fn lint_uint_literal<'tcx>(
lint.build("only `u8` can be cast into `char`")
.span_suggestion(
par_e.span,
&"use a `char` literal instead",
"use a `char` literal instead",
format!("'\\u{{{:X}}}'", lit_val),
Applicability::MachineApplicable,
)

View file

@ -3,7 +3,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
use rustc_ast as ast;
use rustc_ast::util::{classify, parser};
use rustc_ast::{ExprKind, StmtKind};
use rustc_errors::{pluralize, Applicability};
use rustc_errors::{pluralize, Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
@ -11,7 +11,7 @@ use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_span::{BytePos, Span, DUMMY_SP};
declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as

View file

@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_error_messages = { path = "../rustc_error_messages" }
rustc_span = { path = "../rustc_span" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_macros = { path = "../rustc_macros" }

View file

@ -7,10 +7,11 @@ pub use self::Level::*;
use rustc_ast::node_id::{NodeId, NodeMap};
use rustc_ast::{AttrId, Attribute};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_error_messages::MultiSpan;
use rustc_hir::HirId;
use rustc_serialize::json::Json;
use rustc_span::edition::Edition;
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
use rustc_span::{sym, symbol::Ident, Span, Symbol};
use rustc_target::spec::abi::Abi;
pub mod builtin;

View file

@ -63,9 +63,14 @@ decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_fo
decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
decl_derive!(
[SessionDiagnostic, attributes(
message,
lint,
// struct attributes
warning,
error,
note,
help,
// field attributes
skip_arg,
primary_span,
label,
suggestion,
suggestion_short,

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@ use std::cmp;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{
Diagnostic, DiagnosticBuilder, DiagnosticId, EmissionGuarantee, ErrorGuaranteed,
Diagnostic, DiagnosticBuilder, DiagnosticId, EmissionGuarantee, ErrorGuaranteed, MultiSpan,
};
use rustc_hir::HirId;
use rustc_index::vec::IndexVec;
@ -14,7 +14,7 @@ use rustc_session::lint::{
};
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::source_map::{DesugaringKind, ExpnKind};
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
/// How a lint level was set.

View file

@ -34,7 +34,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorGuaranteed;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
@ -54,7 +54,7 @@ use rustc_session::lint::{Level, Lint};
use rustc_session::Limit;
use rustc_session::Session;
use rustc_span::def_id::{DefPathHash, StableCrateId};
use rustc_span::source_map::{MultiSpan, SourceMap};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};

View file

@ -8,12 +8,18 @@ use crate::ty::{
};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic};
use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
use rustc_span::Span;
impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
format!("{}", self).into_diagnostic_arg()
}
}
impl<'tcx> Ty<'tcx> {
/// Similar to `Ty::is_primitive`, but also considers inferred numeric values to be primitive.
pub fn is_primitive_ty(self) -> bool {

View file

@ -3,11 +3,11 @@ use crate::ty::diagnostics::suggest_constraining_type_param;
use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, Diagnostic};
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{BytePos, MultiSpan, Span};
use rustc_span::{BytePos, Span};
use rustc_target::spec::abi;
use std::borrow::Cow;

View file

@ -1,7 +1,8 @@
// These functions are used by macro expansion for bug! and span_bug!
use crate::ty::{tls, TyCtxt};
use rustc_span::{MultiSpan, Span};
use rustc_errors::MultiSpan;
use rustc_span::Span;
use std::fmt;
use std::panic::{panic_any, Location};

View file

@ -8,7 +8,7 @@ use rustc_arena::TypedArena;
use rustc_ast::Mutability;
use rustc_errors::{
error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed,
ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::*;
@ -21,7 +21,7 @@ use rustc_session::lint::builtin::{
};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span};
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
let body_id = match def_id.as_local() {

View file

@ -18,10 +18,12 @@ use rustc_ast::{
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed};
use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult};
use rustc_errors::{
Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
use std::ops::{Deref, DerefMut};
use std::mem::take;
@ -273,12 +275,12 @@ impl<'a> Parser<'a> {
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
m: &str,
m: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
self.sess.span_diagnostic.struct_span_err(sp, m)
}
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: impl Into<DiagnosticMessage>) -> ! {
self.sess.span_diagnostic.span_bug(sp, m)
}
@ -584,16 +586,22 @@ impl<'a> Parser<'a> {
// field: value,
// } }
err.delay_as_bug();
self.struct_span_err(expr.span, "struct literal body without path")
.multipart_suggestion(
"you might have forgotten to add the struct literal inside the block",
vec![
(expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()),
(expr.span.shrink_to_hi(), " }".to_string()),
],
Applicability::MaybeIncorrect,
)
.emit();
self.struct_span_err(
expr.span,
DiagnosticMessage::fluent("parser-struct-literal-body-without-path"),
)
.multipart_suggestion(
DiagnosticMessage::fluent_attr(
"parser-struct-literal-body-without-path",
"suggestion",
),
vec![
(expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()),
(expr.span.shrink_to_hi(), " }".to_string()),
],
Applicability::MaybeIncorrect,
)
.emit();
self.restore_snapshot(snapshot);
let mut tail = self.mk_block(
vec![self.mk_stmt_err(expr.span)],

View file

@ -1703,7 +1703,7 @@ impl<'a> Parser<'a> {
if matches!(expr.kind, ExprKind::Err) {
let mut err = self
.diagnostic()
.struct_span_err(self.token.span, &"invalid interpolated expression");
.struct_span_err(self.token.span, "invalid interpolated expression");
err.downgrade_to_delayed_bug();
return err;
}
@ -1820,7 +1820,7 @@ impl<'a> Parser<'a> {
} else if let Some(fixed) = fix_base_capitalisation(suf) {
let msg = "invalid base prefix for number literal";
self.struct_span_err(span, &msg)
self.struct_span_err(span, msg)
.note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase")
.span_suggestion(
span,

View file

@ -1010,7 +1010,8 @@ impl<'a> Parser<'a> {
let current_qual_sp = self.prev_token.span;
let current_qual_sp = current_qual_sp.to(sp_start);
if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
if err.message() == "expected `{`, found keyword `unsafe`" {
// FIXME(davidtwco): avoid depending on the error message text
if err.message[0].0.expect_str() == "expected `{`, found keyword `unsafe`" {
let invalid_qual_sp = self.token.uninterpolated_span();
let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap();

View file

@ -33,10 +33,10 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_errors::PResult;
use rustc_errors::{
struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError,
struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{MultiSpan, Span, DUMMY_SP};
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use tracing::debug;

View file

@ -6,7 +6,7 @@
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@ -21,7 +21,7 @@ use rustc_session::lint::builtin::{
};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_span::{Span, DUMMY_SP};
use std::collections::hash_map::Entry;
pub(crate) fn target_from_impl_item<'tcx>(

View file

@ -620,8 +620,8 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D
} else {
sess.struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
.help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd))
.note(&"Please follow the instructions below to create a bug report with the provided information")
.note(&"See <https://github.com/rust-lang/rust/issues/84970> for more information")
.note("Please follow the instructions below to create a bug report with the provided information")
.note("See <https://github.com/rust-lang/rust/issues/84970> for more information")
.emit();
panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
}

View file

@ -32,10 +32,10 @@ use rustc_ast::node_id::NodeMap;
use rustc_ast::visit::{self, Visitor};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::pluralize;
use rustc_errors::{pluralize, MultiSpan};
use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_span::{Span, DUMMY_SP};
struct UnusedImport<'a> {
use_tree: &'a ast::UseTree,

View file

@ -4,7 +4,7 @@ use rustc_ast::{self as ast, Path};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::def::Namespace::{self, *};
@ -18,7 +18,7 @@ use rustc_span::hygiene::MacroKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span};
use rustc_span::{BytePos, Span};
use tracing::debug;
use crate::imports::{Import, ImportKind, ImportResolver};
@ -1341,7 +1341,7 @@ impl<'a> Resolver<'a> {
let def_span = self.session.source_map().guess_head_span(binding.span);
let mut note_span = MultiSpan::from_span(def_span);
if !first && binding.vis.is_public() {
note_span.push_span_label(def_span, "consider importing it directly".into());
note_span.push_span_label(def_span, "consider importing it directly");
}
err.span_note(note_span, &msg);
}

View file

@ -12,7 +12,7 @@ use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBindin
use rustc_ast::NodeId;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::intern::Interned;
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_hir::def::{self, PartialRes};
use rustc_hir::def_id::DefId;
use rustc_middle::metadata::ModChild;
@ -23,7 +23,7 @@ use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::hygiene::LocalExpnId;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{MultiSpan, Span};
use rustc_span::Span;
use tracing::*;
@ -739,7 +739,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
if let Some((_, UnresolvedImportError { note, .. })) = errors.iter().last() {
for message in note {
diag.note(&message);
diag.note(message);
}
}

View file

@ -14,6 +14,7 @@ use rustc_ast_pretty::pprust::path_segment_to_string;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
@ -25,7 +26,7 @@ use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_span::{BytePos, Span, DUMMY_SP};
use std::iter;
use std::ops::Deref;
@ -1106,7 +1107,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
.collect();
if non_visible_spans.len() > 0 {
let mut m: rustc_span::MultiSpan = non_visible_spans.clone().into();
let mut m: MultiSpan = non_visible_spans.clone().into();
non_visible_spans
.into_iter()
.for_each(|s| m.push_span_label(s, "private field".to_string()));
@ -1139,7 +1140,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
err.span_suggestion(
span,
&"use this syntax instead",
"use this syntax instead",
path_str.to_string(),
Applicability::MaybeIncorrect,
);

View file

@ -431,6 +431,20 @@ where
}
}
impl<'a, S: Encoder> Encodable<S> for Cow<'a, str> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
let val: &str = self;
val.encode(s)
}
}
impl<'a, D: Decoder> Decodable<D> for Cow<'a, str> {
fn decode(d: &mut D) -> Cow<'static, str> {
let v: String = Decodable::decode(d);
Cow::Owned(v)
}
}
impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_option(|s| match *self {

View file

@ -2856,6 +2856,7 @@ crate mod dep_tracking {
use crate::lint;
use crate::options::WasiExecModel;
use crate::utils::{NativeLib, NativeLibKind};
use rustc_errors::LanguageIdentifier;
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_span::RealFileName;
@ -2948,6 +2949,7 @@ crate mod dep_tracking {
LocationDetail,
BranchProtection,
OomStrategy,
LanguageIdentifier,
);
impl<T1, T2> DepTrackingHash for (T1, T2)

View file

@ -4,6 +4,7 @@ use crate::early_error;
use crate::lint;
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
use rustc_errors::LanguageIdentifier;
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
use rustc_target::spec::{
RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
@ -365,6 +366,7 @@ mod desc {
pub const parse_string: &str = "a string";
pub const parse_opt_string: &str = parse_string;
pub const parse_string_push: &str = parse_string;
pub const parse_opt_langid: &str = "a language identifier";
pub const parse_opt_pathbuf: &str = "a path";
pub const parse_list: &str = "a space-separated list of strings";
pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
@ -487,6 +489,17 @@ mod parse {
}
}
/// Parse an optional language identifier, e.g. `en-US` or `zh-CN`.
crate fn parse_opt_langid(slot: &mut Option<LanguageIdentifier>, v: Option<&str>) -> bool {
match v {
Some(s) => {
*slot = rustc_errors::LanguageIdentifier::from_str(s).ok();
true
}
None => false,
}
}
crate fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
match v {
Some(s) => {
@ -1462,6 +1475,15 @@ options! {
"the directory the intermediate files are written to"),
terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"set the current terminal width"),
// Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
// alongside query results and changes to translation options can affect diagnostics - so
// translation options should be tracked.
translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
"language identifier for diagnostic output"),
translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"additional fluent translation to preferentially use (for testing translation)"),
translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
"emit directionality isolation markers in translated diagnostics"),
tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
"select processor to schedule for (`rustc --print target-cpus` for details)"),
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],

View file

@ -7,12 +7,15 @@ use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{
error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed, MultiSpan,
};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{MultiSpan, Span, Symbol};
use rustc_span::{Span, Symbol};
use std::str;
@ -171,8 +174,17 @@ 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 sm = Lrc::new(SourceMap::new(file_path_mapping));
let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, None, Some(sm.clone()));
let handler = Handler::with_tty_emitter(
ColorConfig::Auto,
true,
None,
Some(sm.clone()),
None,
fallback_bundle,
);
ParseSess::with_span_handler(handler, sm)
}
@ -201,8 +213,11 @@ 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 sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let fatal_handler = Handler::with_tty_emitter(ColorConfig::Auto, false, None, None);
let fatal_handler =
Handler::with_tty_emitter(ColorConfig::Auto, false, None, None, None, fallback_bundle);
let handler = Handler::with_emitter(
false,
None,

View file

@ -19,11 +19,14 @@ use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter;
use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry;
use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
use rustc_errors::{
fallback_fluent_bundle, fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
EmissionGuarantee, ErrorGuaranteed, FluentBundle, MultiSpan,
};
use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
use rustc_span::edition::Edition;
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span};
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
@ -206,10 +209,10 @@ pub struct PerfStats {
/// Trait implemented by error types. This should not be implemented manually. Instead, use
/// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic].
pub trait SessionDiagnostic<'a> {
pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> {
/// Write out as a diagnostic out of `sess`.
#[must_use]
fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, ErrorGuaranteed>;
fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, T>;
}
impl Session {
@ -279,34 +282,34 @@ impl Session {
pub fn struct_span_warn<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_span_warn(sp, msg)
}
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
}
pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_warn(msg)
}
pub fn struct_span_allow<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_span_allow(sp, msg)
}
pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_allow(msg)
}
pub fn struct_expect(
&self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
id: lint::LintExpectationId,
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_expect(msg, id)
@ -314,81 +317,108 @@ impl Session {
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.diagnostic().struct_span_err(sp, msg)
}
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.diagnostic().struct_span_err_with_code(sp, msg, code)
}
// FIXME: This method should be removed (every error should have an associated error code).
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
pub fn struct_err(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.diagnostic().struct_err(msg)
}
pub fn struct_err_with_code(
&self,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.diagnostic().struct_err_with_code(msg, code)
}
pub fn struct_warn_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_warn_with_code(msg, code)
}
pub fn struct_span_fatal<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_span_fatal(sp, msg)
}
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
}
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, !> {
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_fatal(msg)
}
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().span_fatal(sp, msg)
}
pub fn span_fatal_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> ! {
self.diagnostic().span_fatal_with_code(sp, msg, code)
}
pub fn fatal(&self, msg: &str) -> ! {
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().fatal(msg).raise()
}
pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg: &str) {
pub fn span_err_or_warn<S: Into<MultiSpan>>(
&self,
is_warning: bool,
sp: S,
msg: impl Into<DiagnosticMessage>,
) {
if is_warning {
self.span_warn(sp, msg);
} else {
self.span_err(sp, msg);
}
}
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ErrorGuaranteed {
pub fn span_err<S: Into<MultiSpan>>(
&self,
sp: S,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
self.diagnostic().span_err(sp, msg)
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.diagnostic().span_err_with_code(sp, &msg, code)
pub fn span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) {
self.diagnostic().span_err_with_code(sp, msg, code)
}
pub fn err(&self, msg: &str) -> ErrorGuaranteed {
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.diagnostic().err(msg)
}
pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
err.into_diagnostic(self).emit()
}
pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
warning.into_diagnostic(self).emit()
}
#[inline]
pub fn err_count(&self) -> usize {
self.diagnostic().err_count()
@ -423,25 +453,34 @@ impl Session {
Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
}
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().span_warn(sp, msg)
}
pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
pub fn span_warn_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) {
self.diagnostic().span_warn_with_code(sp, msg, code)
}
pub fn warn(&self, msg: &str) {
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().warn(msg)
}
/// Delay a span_bug() call until abort_if_errors()
#[track_caller]
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ErrorGuaranteed {
pub fn delay_span_bug<S: Into<MultiSpan>>(
&self,
sp: S,
msg: impl Into<DiagnosticMessage>,
) -> ErrorGuaranteed {
self.diagnostic().delay_span_bug(sp, msg)
}
/// Used for code paths of expensive computations that should only take place when
/// warnings or errors are emitted. If no messages are emitted ("good path"), then
/// it's likely a bug.
pub fn delay_good_path_bug(&self, msg: &str) {
pub fn delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>) {
if self.opts.debugging_opts.print_type_sizes
|| self.opts.debugging_opts.query_dep_graph
|| self.opts.debugging_opts.dump_mir.is_some()
@ -455,13 +494,20 @@ impl Session {
self.diagnostic().delay_good_path_bug(msg)
}
pub fn note_without_error(&self, msg: &str) {
pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().note_without_error(msg)
}
pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
pub fn span_note_without_error<S: Into<MultiSpan>>(
&self,
sp: S,
msg: impl Into<DiagnosticMessage>,
) {
self.diagnostic().span_note_without_error(sp, msg)
}
pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
pub fn struct_note_without_error(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_note_without_error(msg)
}
@ -1033,6 +1079,8 @@ fn default_emitter(
sopts: &config::Options,
registry: rustc_errors::registry::Registry,
source_map: Lrc<SourceMap>,
bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: Lrc<FluentBundle>,
emitter_dest: Option<Box<dyn Write + Send>>,
) -> Box<dyn Emitter + sync::Send> {
let macro_backtrace = sopts.debugging_opts.macro_backtrace;
@ -1041,14 +1089,21 @@ fn default_emitter(
let (short, color_config) = kind.unzip();
if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
let emitter =
AnnotateSnippetEmitterWriter::new(Some(source_map), short, macro_backtrace);
let emitter = AnnotateSnippetEmitterWriter::new(
Some(source_map),
bundle,
fallback_bundle,
short,
macro_backtrace,
);
Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing))
} else {
let emitter = match dst {
None => EmitterWriter::stderr(
color_config,
Some(source_map),
bundle,
fallback_bundle,
short,
sopts.debugging_opts.teach,
sopts.debugging_opts.terminal_width,
@ -1057,6 +1112,8 @@ fn default_emitter(
Some(dst) => EmitterWriter::new(
dst,
Some(source_map),
bundle,
fallback_bundle,
short,
false, // no teach messages when writing to a buffer
false, // no colors when writing to a buffer
@ -1071,6 +1128,8 @@ fn default_emitter(
JsonEmitter::stderr(
Some(registry),
source_map,
bundle,
fallback_bundle,
pretty,
json_rendered,
sopts.debugging_opts.terminal_width,
@ -1083,6 +1142,8 @@ fn default_emitter(
dst,
Some(registry),
source_map,
bundle,
fallback_bundle,
pretty,
json_rendered,
sopts.debugging_opts.terminal_width,
@ -1152,7 +1213,19 @@ pub fn build_session(
sopts.file_path_mapping(),
hash_kind,
));
let emitter = default_emitter(&sopts, registry, source_map.clone(), write_dest);
let bundle = fluent_bundle(
&sysroot,
sopts.debugging_opts.translate_lang.clone(),
sopts.debugging_opts.translate_additional_ftl.as_deref(),
sopts.debugging_opts.translate_directionality_markers,
)
.expect("failed to load fluent bundle");
let fallback_bundle =
fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers)
.expect("failed to load fallback fluent bundle");
let emitter =
default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest);
let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags(
emitter,
@ -1385,13 +1458,24 @@ 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 emitter: Box<dyn Emitter + sync::Send> = match output {
config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
Box::new(EmitterWriter::stderr(
color_config,
None,
None,
fallback_bundle,
short,
false,
None,
false,
))
}
config::ErrorOutputType::Json { pretty, json_rendered } => {
Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
Box::new(JsonEmitter::basic(pretty, json_rendered, None, fallback_bundle, None, false))
}
};
rustc_errors::Handler::with_emitter(true, None, emitter)

View file

@ -520,20 +520,6 @@ impl Ord for Span {
}
}
/// A collection of `Span`s.
///
/// Spans have two orthogonal attributes:
///
/// - They can be *primary spans*. In this case they are the locus of
/// the error, and would be rendered with `^^^`.
/// - They can have a *label*. In this case, the label is written next
/// to the mark in the snippet when we render.
#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)]
pub struct MultiSpan {
primary_spans: Vec<Span>,
span_labels: Vec<(Span, String)>,
}
impl Span {
#[inline]
pub fn lo(self) -> BytePos {
@ -949,20 +935,6 @@ impl Span {
}
}
/// A span together with some additional data.
#[derive(Clone, Debug)]
pub struct SpanLabel {
/// The span we are going to include in the final snippet.
pub span: Span,
/// Is this a primary span? This is the "locus" of the message,
/// and is indicated with a `^^^^` underline, versus `----`.
pub is_primary: bool,
/// What label should we attach to this span (if any)?
pub label: Option<String>,
}
impl Default for Span {
fn default() -> Self {
DUMMY_SP
@ -1035,115 +1007,6 @@ impl fmt::Debug for SpanData {
}
}
impl MultiSpan {
#[inline]
pub fn new() -> MultiSpan {
MultiSpan { primary_spans: vec![], span_labels: vec![] }
}
pub fn from_span(primary_span: Span) -> MultiSpan {
MultiSpan { primary_spans: vec![primary_span], span_labels: vec![] }
}
pub fn from_spans(mut vec: Vec<Span>) -> MultiSpan {
vec.sort();
MultiSpan { primary_spans: vec, span_labels: vec![] }
}
pub fn push_span_label(&mut self, span: Span, label: String) {
self.span_labels.push((span, label));
}
/// Selects the first primary span (if any).
pub fn primary_span(&self) -> Option<Span> {
self.primary_spans.first().cloned()
}
/// Returns all primary spans.
pub fn primary_spans(&self) -> &[Span] {
&self.primary_spans
}
/// Returns `true` if any of the primary spans are displayable.
pub fn has_primary_spans(&self) -> bool {
self.primary_spans.iter().any(|sp| !sp.is_dummy())
}
/// Returns `true` if this contains only a dummy primary span with any hygienic context.
pub fn is_dummy(&self) -> bool {
let mut is_dummy = true;
for span in &self.primary_spans {
if !span.is_dummy() {
is_dummy = false;
}
}
is_dummy
}
/// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
/// display well (like std macros). Returns whether replacements occurred.
pub fn replace(&mut self, before: Span, after: Span) -> bool {
let mut replacements_occurred = false;
for primary_span in &mut self.primary_spans {
if *primary_span == before {
*primary_span = after;
replacements_occurred = true;
}
}
for span_label in &mut self.span_labels {
if span_label.0 == before {
span_label.0 = after;
replacements_occurred = true;
}
}
replacements_occurred
}
/// Returns the strings to highlight. We always ensure that there
/// is an entry for each of the primary spans -- for each primary
/// span `P`, if there is at least one label with span `P`, we return
/// those labels (marked as primary). But otherwise we return
/// `SpanLabel` instances with empty labels.
pub fn span_labels(&self) -> Vec<SpanLabel> {
let is_primary = |span| self.primary_spans.contains(&span);
let mut span_labels = self
.span_labels
.iter()
.map(|&(span, ref label)| SpanLabel {
span,
is_primary: is_primary(span),
label: Some(label.clone()),
})
.collect::<Vec<_>>();
for &span in &self.primary_spans {
if !span_labels.iter().any(|sl| sl.span == span) {
span_labels.push(SpanLabel { span, is_primary: true, label: None });
}
}
span_labels
}
/// Returns `true` if any of the span labels is displayable.
pub fn has_span_labels(&self) -> bool {
self.span_labels.iter().any(|(sp, _)| !sp.is_dummy())
}
}
impl From<Span> for MultiSpan {
fn from(span: Span) -> MultiSpan {
MultiSpan::from_span(span)
}
}
impl From<Vec<Span>> for MultiSpan {
fn from(spans: Vec<Span>) -> MultiSpan {
MultiSpan::from_spans(spans)
}
}
/// Identifies an offset of a multi-byte character in a `SourceFile`.
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
pub struct MultiByteChar {

View file

@ -15,7 +15,7 @@ use crate::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
Style,
MultiSpan, Style,
};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@ -33,7 +33,7 @@ use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::symbol::{kw, sym};
use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
use rustc_span::{ExpnKind, Span, DUMMY_SP};
use std::fmt;
use std::iter;

View file

@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed, Style,
ErrorGuaranteed, MultiSpan, Style,
};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
@ -27,7 +27,7 @@ use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span, DUMMY_SP};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
use std::fmt;
@ -597,7 +597,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
Some(format!("{}", name))
}
_ => {
err.note(&msg);
err.note(msg);
None
}
}
@ -780,7 +780,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
if has_custom_message {
err.note(&msg);
} else {
err.message = vec![(msg, Style::NoStyle)];
err.message =
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
}
if snippet.starts_with('&') {
// This is already a literal borrow and the obligation is failing
@ -2480,7 +2481,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
.opt_associated_item(trait_item_def_id)
.and_then(|i| self.tcx.opt_item_name(i.container.id()))
{
assoc_span.push_span_label(ident.span, "in this trait".into());
assoc_span.push_span_label(ident.span, "in this trait");
}
err.span_note(assoc_span, &msg);
}
@ -2505,7 +2506,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
.opt_associated_item(trait_item_def_id)
.and_then(|i| self.tcx.opt_item_name(i.container.id()))
{
assoc_span.push_span_label(ident.span, "in this trait".into());
assoc_span.push_span_label(ident.span, "in this trait");
}
err.span_note(assoc_span, &msg);
}

View file

@ -14,7 +14,7 @@ use crate::infer::TyCtxtInferExt;
use crate::traits::const_evaluatable::{self, AbstractConst};
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause};
use rustc_errors::FatalError;
use rustc_errors::{FatalError, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
@ -22,7 +22,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_middle::ty::{Predicate, ToPredicate};
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
use rustc_span::{MultiSpan, Span};
use rustc_span::Span;
use smallvec::SmallVec;
use std::iter;
@ -169,10 +169,7 @@ fn lint_object_unsafe_trait(
let node = tcx.hir().get_if_local(trait_def_id);
let mut spans = MultiSpan::from_span(span);
if let Some(hir::Node::Item(item)) = node {
spans.push_span_label(
item.ident.span,
"this trait cannot be made into an object...".into(),
);
spans.push_span_label(item.ident.span, "this trait cannot be made into an object...");
spans.push_span_label(span, format!("...because {}", violation.error_msg()));
} else {
spans.push_span_label(

View file

@ -6,7 +6,7 @@ use crate::astconv::{
use crate::errors::AssocTypeBindingNotAllowed;
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
use rustc_ast::ast::ParamKindOrd;
use rustc_errors::{struct_span_err, Applicability, Diagnostic};
use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
@ -16,7 +16,7 @@ use rustc_middle::ty::{
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
};
use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
use rustc_span::{symbol::kw, MultiSpan, Span};
use rustc_span::{symbol::kw, Span};
use smallvec::SmallVec;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {

View file

@ -1,11 +1,11 @@
use crate::check::coercion::{AsCoercionSite, CoerceMany};
use crate::check::{Diverges, Expectation, FnCtxt, Needs};
use rustc_errors::{Applicability, Diagnostic};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
use rustc_span::{MultiSpan, Span};
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,

View file

@ -4,7 +4,7 @@ use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_
use super::*;
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed};
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
@ -20,7 +20,7 @@ use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
use rustc_span::{self, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;

View file

@ -8,7 +8,7 @@ use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed};
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
@ -30,7 +30,7 @@ use rustc_session::lint;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{original_sp, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{self, BytePos, MultiSpan, Span};
use rustc_span::{self, BytePos, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{

View file

@ -11,7 +11,7 @@ use crate::check::{
use rustc_ast as ast;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic, DiagnosticId};
use rustc_errors::{Applicability, Diagnostic, DiagnosticId, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
@ -21,7 +21,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, Ty};
use rustc_session::Session;
use rustc_span::symbol::Ident;
use rustc_span::{self, MultiSpan, Span};
use rustc_span::{self, Span};
use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
use crate::structured_errors::StructuredDiagnostic;

View file

@ -2,9 +2,9 @@ use super::FnCtxt;
use crate::astconv::AstConv;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_span::{self, MultiSpan, Span};
use rustc_span::{self, Span};
use rustc_errors::{Applicability, Diagnostic};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
use rustc_hir::lang_items::LangItem;

View file

@ -7,7 +7,7 @@ use crate::errors::{
};
use crate::require_same_types;
use rustc_errors::{pluralize, struct_span_err};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::subst::Subst;
@ -43,7 +43,6 @@ fn equate_intrinsic_type<'tcx>(
span,
found,
expected,
expected_pluralize: pluralize!(expected),
descr,
});
false

View file

@ -5,6 +5,7 @@ use crate::check::FnCtxt;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@ -17,7 +18,7 @@ use rustc_middle::ty::print::with_crate_prefix;
use rustc_middle::ty::ToPolyTraitRef;
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, MultiSpan, Span};
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{

View file

@ -103,7 +103,7 @@ pub use inherited::{Inherited, InheritedBuilder};
use crate::astconv::AstConv;
use crate::check::gather_locals::GatherLocalsVisitor;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
@ -121,7 +121,7 @@ use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, BytePos, MultiSpan, Span};
use rustc_span::{self, BytePos, Span};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;

View file

@ -4,6 +4,7 @@ use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
@ -18,7 +19,7 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, MultiSpan, DUMMY_SP};
use rustc_span::{BytePos, DUMMY_SP};
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::{ObligationCause, Pattern};
use ty::VariantDef;

View file

@ -33,7 +33,7 @@
use super::FnCtxt;
use crate::expr_use_visitor as euv;
use rustc_errors::Applicability;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
@ -46,7 +46,7 @@ use rustc_middle::ty::{
};
use rustc_session::lint;
use rustc_span::sym;
use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol};
use rustc_span::{BytePos, Pos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_data_structures::stable_map::FxHashMap;

View file

@ -3,188 +3,185 @@ use rustc_macros::SessionDiagnostic;
use rustc_span::{symbol::Ident, Span, Symbol};
#[derive(SessionDiagnostic)]
#[error = "E0062"]
#[error(code = "E0062", slug = "typeck-field-multiply-specified-in-initializer")]
pub struct FieldMultiplySpecifiedInInitializer {
#[message = "field `{ident}` specified more than once"]
#[label = "used more than once"]
#[primary_span]
#[label]
pub span: Span,
#[label = "first use of `{ident}`"]
#[label = "previous-use-label"]
pub prev_span: Span,
pub ident: Ident,
}
#[derive(SessionDiagnostic)]
#[error = "E0092"]
#[error(code = "E0092", slug = "typeck-unrecognized-atomic-operation")]
pub struct UnrecognizedAtomicOperation<'a> {
#[message = "unrecognized atomic operation function: `{op}`"]
#[label = "unrecognized atomic operation"]
#[primary_span]
#[label]
pub span: Span,
pub op: &'a str,
}
#[derive(SessionDiagnostic)]
#[error = "E0094"]
#[error(code = "E0094", slug = "typeck-wrong-number-of-generic-arguments-to-intrinsic")]
pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
#[message = "intrinsic has wrong number of {descr} \
parameters: found {found}, expected {expected}"]
#[label = "expected {expected} {descr} parameter{expected_pluralize}"]
#[primary_span]
#[label]
pub span: Span,
pub found: usize,
pub expected: usize,
pub expected_pluralize: &'a str,
pub descr: &'a str,
}
#[derive(SessionDiagnostic)]
#[error = "E0093"]
#[error(code = "E0093", slug = "typeck-unrecognized-intrinsic-function")]
pub struct UnrecognizedIntrinsicFunction {
#[message = "unrecognized intrinsic function: `{name}`"]
#[label = "unrecognized intrinsic"]
#[primary_span]
#[label]
pub span: Span,
pub name: Symbol,
}
#[derive(SessionDiagnostic)]
#[error = "E0195"]
#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")]
pub struct LifetimesOrBoundsMismatchOnTrait {
#[message = "lifetime parameters or bounds on {item_kind} `{ident}` do not match the trait declaration"]
#[label = "lifetimes do not match {item_kind} in trait"]
#[primary_span]
#[label]
pub span: Span,
#[label = "lifetimes in impl do not match this {item_kind} in trait"]
#[label = "generics-label"]
pub generics_span: Option<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
#[derive(SessionDiagnostic)]
#[error = "E0120"]
#[error(code = "E0120", slug = "typeck-drop-impl-on-wrong-item")]
pub struct DropImplOnWrongItem {
#[message = "the `Drop` trait may only be implemented for structs, enums, and unions"]
#[label = "must be a struct, enum, or union"]
#[primary_span]
#[label]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0124"]
#[error(code = "E0124", slug = "typeck-field-already-declared")]
pub struct FieldAlreadyDeclared {
pub field_name: Ident,
#[message = "field `{field_name}` is already declared"]
#[label = "field already declared"]
#[primary_span]
#[label]
pub span: Span,
#[label = "`{field_name}` first declared here"]
#[label = "previous-decl-label"]
pub prev_span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0184"]
#[error(code = "E0184", slug = "typeck-copy-impl-on-type-with-dtor")]
pub struct CopyImplOnTypeWithDtor {
#[message = "the trait `Copy` may not be implemented for this type; the \
type has a destructor"]
#[label = "Copy not allowed on types with destructors"]
#[primary_span]
#[label]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0203"]
#[error(code = "E0203", slug = "typeck-multiple-relaxed-default-bounds")]
pub struct MultipleRelaxedDefaultBounds {
#[message = "type parameter has more than one relaxed default bound, only one is supported"]
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0206"]
#[error(code = "E0206", slug = "typeck-copy-impl-on-non-adt")]
pub struct CopyImplOnNonAdt {
#[message = "the trait `Copy` may not be implemented for this type"]
#[label = "type is not a structure or enumeration"]
#[primary_span]
#[label]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0224"]
#[error(code = "E0224", slug = "typeck-trait-object-declared-with-no-traits")]
pub struct TraitObjectDeclaredWithNoTraits {
#[message = "at least one trait is required for an object type"]
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0227"]
#[error(code = "E0227", slug = "typeck-ambiguous-lifetime-bound")]
pub struct AmbiguousLifetimeBound {
#[message = "ambiguous lifetime bound, explicit lifetime bound required"]
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0229"]
#[error(code = "E0229", slug = "typeck-assoc-type-binding-not-allowed")]
pub struct AssocTypeBindingNotAllowed {
#[message = "associated type bindings are not allowed here"]
#[label = "associated type not allowed here"]
#[primary_span]
#[label]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0436"]
#[error(code = "E0436", slug = "typeck-functional-record-update-on-non-struct")]
pub struct FunctionalRecordUpdateOnNonStruct {
#[message = "functional record update syntax requires a struct"]
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0516"]
#[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")]
pub struct TypeofReservedKeywordUsed {
#[message = "`typeof` is a reserved keyword but unimplemented"]
#[label = "reserved keyword"]
#[primary_span]
#[label]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0572"]
#[error(code = "E0572", slug = "typeck-return-stmt-outside-of-fn-body")]
pub struct ReturnStmtOutsideOfFnBody {
#[message = "return statement outside of function body"]
#[primary_span]
pub span: Span,
#[label = "the return is part of this body..."]
#[label = "encl-body-label"]
pub encl_body_span: Option<Span>,
#[label = "...not the enclosing function body"]
#[label = "encl-fn-label"]
pub encl_fn_span: Option<Span>,
}
#[derive(SessionDiagnostic)]
#[error = "E0627"]
#[error(code = "E0627", slug = "typeck-yield-expr-outside-of-generator")]
pub struct YieldExprOutsideOfGenerator {
#[message = "yield expression outside of generator literal"]
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0639"]
#[error(code = "E0639", slug = "typeck-struct-expr-non-exhaustive")]
pub struct StructExprNonExhaustive {
#[message = "cannot create non-exhaustive {what} using struct expression"]
#[primary_span]
pub span: Span,
pub what: &'static str,
}
#[derive(SessionDiagnostic)]
#[error = "E0699"]
#[error(code = "E0699", slug = "typeck-method-call-on-unknown-type")]
pub struct MethodCallOnUnknownType {
#[message = "the type of this value must be known to call a method on a raw pointer on it"]
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic)]
#[error = "E0719"]
#[error(code = "E0719", slug = "typeck-value-of-associated-struct-already-specified")]
pub struct ValueOfAssociatedStructAlreadySpecified {
#[message = "the value of the associated type `{item_name}` (from trait `{def_path}`) is already specified"]
#[label = "re-bound here"]
#[primary_span]
#[label]
pub span: Span,
#[label = "`{item_name}` bound here first"]
#[label = "previous-bound-label"]
pub prev_span: Span,
pub item_name: Ident,
pub def_path: String,
}
#[derive(SessionDiagnostic)]
#[error = "E0745"]
#[error(code = "E0745", slug = "typeck-address-of-temporary-taken")]
pub struct AddressOfTemporaryTaken {
#[message = "cannot take address of a temporary"]
#[label = "temporary value"]
#[primary_span]
#[label]
pub span: Span,
}

View file

@ -1,13 +1,14 @@
use crate::structured_errors::StructuredDiagnostic;
use rustc_errors::{
pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed,
MultiSpan,
};
use rustc_hir as hir;
use rustc_middle::hir::map::fn_sig;
use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
use rustc_middle::ty::{self as ty, TyCtxt};
use rustc_session::Session;
use rustc_span::{def_id::DefId, MultiSpan};
use rustc_span::def_id::DefId;
use GenericArgsInfo::*;