Merge diagnostic_builder.rs
into diagnostic.rs
.
Because: - `diagnostic_builder.rs` is small (282 lines), - `Diagnostic` and `DiagnosticBuilder` are closely related types, and - there's already an `impl DiagnosticBuilder` block in `diagnostic.rs`. At the same time, reorder a few of things already in `diagnostic.rs`, e.g. move `struct Diagnostic` just before `impl Diagnostic`. This commit only moves code around. There are no functional changes.
This commit is contained in:
parent
bb594538fc
commit
8f20a54c6d
@ -1,19 +1,22 @@
|
|||||||
use crate::snippet::Style;
|
use crate::snippet::Style;
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode, Level,
|
CodeSuggestion, DiagCtxt, DiagnosticMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
|
||||||
MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
|
MultiSpan, StashKey, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
|
||||||
};
|
};
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
|
use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
|
||||||
use rustc_error_messages::FluentValue;
|
use rustc_error_messages::FluentValue;
|
||||||
use rustc_lint_defs::{Applicability, LintExpectationId};
|
use rustc_lint_defs::{Applicability, LintExpectationId};
|
||||||
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::panic::Location;
|
use std::panic;
|
||||||
|
use std::thread::panicking;
|
||||||
|
|
||||||
/// Error type for `Diagnostic`'s `suggestions` field, indicating that
|
/// Error type for `Diagnostic`'s `suggestions` field, indicating that
|
||||||
/// `.disable_suggestions()` was called on the `Diagnostic`.
|
/// `.disable_suggestions()` was called on the `Diagnostic`.
|
||||||
@ -40,6 +43,86 @@ pub enum DiagnosticArgValue {
|
|||||||
StrListSepByAnd(Vec<Cow<'static, str>>),
|
StrListSepByAnd(Vec<Cow<'static, str>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee"
|
||||||
|
/// (or "proof") token that the emission happened.
|
||||||
|
pub trait EmissionGuarantee: Sized {
|
||||||
|
/// This exists so that bugs and fatal errors can both result in `!` (an
|
||||||
|
/// abort) when emitted, but have different aborting behaviour.
|
||||||
|
type EmitResult = Self;
|
||||||
|
|
||||||
|
/// Implementation of `DiagnosticBuilder::emit`, fully controlled by each
|
||||||
|
/// `impl` of `EmissionGuarantee`, to make it impossible to create a value
|
||||||
|
/// of `Self::EmitResult` without actually performing the emission.
|
||||||
|
#[track_caller]
|
||||||
|
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmissionGuarantee for ErrorGuaranteed {
|
||||||
|
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
||||||
|
db.emit_producing_error_guaranteed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmissionGuarantee for () {
|
||||||
|
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
||||||
|
db.emit_producing_nothing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
|
||||||
|
/// bug diagnostics.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct BugAbort;
|
||||||
|
|
||||||
|
impl EmissionGuarantee for BugAbort {
|
||||||
|
type EmitResult = !;
|
||||||
|
|
||||||
|
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
||||||
|
db.emit_producing_nothing();
|
||||||
|
panic::panic_any(ExplicitBug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for
|
||||||
|
/// fatal diagnostics.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct FatalAbort;
|
||||||
|
|
||||||
|
impl EmissionGuarantee for FatalAbort {
|
||||||
|
type EmitResult = !;
|
||||||
|
|
||||||
|
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
||||||
|
db.emit_producing_nothing();
|
||||||
|
crate::FatalError.raise()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
|
||||||
|
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
||||||
|
db.emit_producing_nothing();
|
||||||
|
rustc_span::fatal_error::FatalError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait implemented by error types. This is rarely implemented manually. Instead, use
|
||||||
|
/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
|
||||||
|
#[rustc_diagnostic_item = "IntoDiagnostic"]
|
||||||
|
pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
|
||||||
|
/// Write out as a diagnostic out of `DiagCtxt`.
|
||||||
|
#[must_use]
|
||||||
|
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned<T>
|
||||||
|
where
|
||||||
|
T: IntoDiagnostic<'a, G>,
|
||||||
|
G: EmissionGuarantee,
|
||||||
|
{
|
||||||
|
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
|
||||||
|
self.node.into_diagnostic(dcx, level).with_span(self.span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic`
|
/// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic`
|
||||||
/// struct). Implemented as a custom trait rather than `From` so that it is implemented on the type
|
/// 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_*`
|
/// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*`
|
||||||
@ -98,36 +181,6 @@ pub trait DecorateLint<'a, G: EmissionGuarantee> {
|
|||||||
fn msg(&self) -> DiagnosticMessage;
|
fn msg(&self) -> DiagnosticMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main part of a diagnostic. Note that `DiagnosticBuilder`, which wraps
|
|
||||||
/// this type, is used for most operations, and should be used instead whenever
|
|
||||||
/// possible. This type should only be used when `DiagnosticBuilder`'s lifetime
|
|
||||||
/// causes difficulties, e.g. when storing diagnostics within `DiagCtxt`.
|
|
||||||
#[must_use]
|
|
||||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
|
||||||
pub struct Diagnostic {
|
|
||||||
// NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
|
|
||||||
// outside of what methods in this crate themselves allow.
|
|
||||||
pub(crate) level: Level,
|
|
||||||
|
|
||||||
pub messages: Vec<(DiagnosticMessage, Style)>,
|
|
||||||
pub code: Option<ErrCode>,
|
|
||||||
pub span: MultiSpan,
|
|
||||||
pub children: Vec<SubDiagnostic>,
|
|
||||||
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
|
||||||
args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue>,
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
/// `span` if there is one. Otherwise, it is `DUMMY_SP`.
|
|
||||||
pub sort_span: Span,
|
|
||||||
|
|
||||||
pub is_lint: Option<IsLint>,
|
|
||||||
|
|
||||||
/// With `-Ztrack_diagnostics` enabled,
|
|
||||||
/// we print where in rustc this error was emitted.
|
|
||||||
pub(crate) emitted_at: DiagnosticLocation,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||||
pub struct DiagnosticLocation {
|
pub struct DiagnosticLocation {
|
||||||
file: Cow<'static, str>,
|
file: Cow<'static, str>,
|
||||||
@ -138,7 +191,7 @@ pub struct DiagnosticLocation {
|
|||||||
impl DiagnosticLocation {
|
impl DiagnosticLocation {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn caller() -> Self {
|
fn caller() -> Self {
|
||||||
let loc = Location::caller();
|
let loc = panic::Location::caller();
|
||||||
DiagnosticLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
|
DiagnosticLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,15 +210,6 @@ pub struct IsLint {
|
|||||||
has_future_breakage: bool,
|
has_future_breakage: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A "sub"-diagnostic attached to a parent diagnostic.
|
|
||||||
/// For example, a note attached to an error.
|
|
||||||
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
|
|
||||||
pub struct SubDiagnostic {
|
|
||||||
pub level: Level,
|
|
||||||
pub messages: Vec<(DiagnosticMessage, Style)>,
|
|
||||||
pub span: MultiSpan,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct DiagnosticStyledString(pub Vec<StringPart>);
|
pub struct DiagnosticStyledString(pub Vec<StringPart>);
|
||||||
|
|
||||||
@ -215,6 +259,36 @@ pub fn highlighted<S: Into<String>>(content: S) -> StringPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main part of a diagnostic. Note that `DiagnosticBuilder`, which wraps
|
||||||
|
/// this type, is used for most operations, and should be used instead whenever
|
||||||
|
/// possible. This type should only be used when `DiagnosticBuilder`'s lifetime
|
||||||
|
/// causes difficulties, e.g. when storing diagnostics within `DiagCtxt`.
|
||||||
|
#[must_use]
|
||||||
|
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||||
|
pub struct Diagnostic {
|
||||||
|
// NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
|
||||||
|
// outside of what methods in this crate themselves allow.
|
||||||
|
pub(crate) level: Level,
|
||||||
|
|
||||||
|
pub messages: Vec<(DiagnosticMessage, Style)>,
|
||||||
|
pub code: Option<ErrCode>,
|
||||||
|
pub span: MultiSpan,
|
||||||
|
pub children: Vec<SubDiagnostic>,
|
||||||
|
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
||||||
|
args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue>,
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
/// `span` if there is one. Otherwise, it is `DUMMY_SP`.
|
||||||
|
pub sort_span: Span,
|
||||||
|
|
||||||
|
pub is_lint: Option<IsLint>,
|
||||||
|
|
||||||
|
/// With `-Ztrack_diagnostics` enabled,
|
||||||
|
/// we print where in rustc this error was emitted.
|
||||||
|
pub(crate) emitted_at: DiagnosticLocation,
|
||||||
|
}
|
||||||
|
|
||||||
impl Diagnostic {
|
impl Diagnostic {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
|
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
|
||||||
@ -336,6 +410,120 @@ pub fn args(&self) -> impl Iterator<Item = DiagnosticArg<'_>> {
|
|||||||
pub fn replace_args(&mut self, args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue>) {
|
pub fn replace_args(&mut self, args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue>) {
|
||||||
self.args = args;
|
self.args = args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fields used for Hash, and PartialEq trait.
|
||||||
|
fn keys(
|
||||||
|
&self,
|
||||||
|
) -> (
|
||||||
|
&Level,
|
||||||
|
&[(DiagnosticMessage, Style)],
|
||||||
|
&Option<ErrCode>,
|
||||||
|
&MultiSpan,
|
||||||
|
&[SubDiagnostic],
|
||||||
|
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
||||||
|
Vec<(&DiagnosticArgName, &DiagnosticArgValue)>,
|
||||||
|
&Option<IsLint>,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
&self.level,
|
||||||
|
&self.messages,
|
||||||
|
&self.code,
|
||||||
|
&self.span,
|
||||||
|
&self.children,
|
||||||
|
&self.suggestions,
|
||||||
|
self.args().collect(),
|
||||||
|
// omit self.sort_span
|
||||||
|
&self.is_lint,
|
||||||
|
// omit self.emitted_at
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for Diagnostic {
|
||||||
|
fn hash<H>(&self, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
|
self.keys().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Diagnostic {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.keys() == other.keys()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A "sub"-diagnostic attached to a parent diagnostic.
|
||||||
|
/// For example, a note attached to an error.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
|
||||||
|
pub struct SubDiagnostic {
|
||||||
|
pub level: Level,
|
||||||
|
pub messages: Vec<(DiagnosticMessage, Style)>,
|
||||||
|
pub span: MultiSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used for emitting structured error messages and other diagnostic information.
|
||||||
|
/// Wraps a `Diagnostic`, adding some useful things.
|
||||||
|
/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check
|
||||||
|
/// that it has been emitted or cancelled.
|
||||||
|
/// - The `EmissionGuarantee`, which determines the type returned from `emit`.
|
||||||
|
///
|
||||||
|
/// Each constructed `DiagnosticBuilder` must be consumed by a function such as
|
||||||
|
/// `emit`, `cancel`, `delay_as_bug`, or `into_diagnostic`. A panic occurrs if a
|
||||||
|
/// `DiagnosticBuilder` is dropped without being consumed by one of these
|
||||||
|
/// functions.
|
||||||
|
///
|
||||||
|
/// If there is some state in a downstream crate you would like to
|
||||||
|
/// access in the methods of `DiagnosticBuilder` here, consider
|
||||||
|
/// extending `DiagCtxtFlags`.
|
||||||
|
#[must_use]
|
||||||
|
pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> {
|
||||||
|
pub dcx: &'a DiagCtxt,
|
||||||
|
|
||||||
|
/// Why the `Option`? It is always `Some` until the `DiagnosticBuilder` is
|
||||||
|
/// consumed via `emit`, `cancel`, etc. At that point it is consumed and
|
||||||
|
/// replaced with `None`. Then `drop` checks that it is `None`; if not, it
|
||||||
|
/// panics because a diagnostic was built but not used.
|
||||||
|
///
|
||||||
|
/// Why the Box? `Diagnostic` is a large type, and `DiagnosticBuilder` is
|
||||||
|
/// often used as a return value, especially within the frequently-used
|
||||||
|
/// `PResult` type. In theory, return value optimization (RVO) should avoid
|
||||||
|
/// unnecessary copying. In practice, it does not (at the time of writing).
|
||||||
|
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
||||||
|
pub(crate) diag: Option<Box<Diagnostic>>,
|
||||||
|
|
||||||
|
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
||||||
|
pub(crate) _marker: PhantomData<G>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted
|
||||||
|
// twice, which would be bad.
|
||||||
|
impl<G> !Clone for DiagnosticBuilder<'_, G> {}
|
||||||
|
|
||||||
|
rustc_data_structures::static_assert_size!(
|
||||||
|
DiagnosticBuilder<'_, ()>,
|
||||||
|
2 * std::mem::size_of::<usize>()
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<G: EmissionGuarantee> Deref for DiagnosticBuilder<'_, G> {
|
||||||
|
type Target = Diagnostic;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Diagnostic {
|
||||||
|
self.diag.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Diagnostic {
|
||||||
|
self.diag.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.diag.fmt(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DiagnosticBuilder` impls many `&mut self -> &mut Self` methods. Each one
|
/// `DiagnosticBuilder` impls many `&mut self -> &mut Self` methods. Each one
|
||||||
@ -382,6 +570,20 @@ pub fn $with_f(mut $self, $($name: $ty),*) -> Self {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
||||||
|
#[rustc_lint_diagnostics]
|
||||||
|
#[track_caller]
|
||||||
|
pub fn new<M: Into<DiagnosticMessage>>(dcx: &'a DiagCtxt, level: Level, message: M) -> Self {
|
||||||
|
Self::new_diagnostic(dcx, Diagnostic::new(level, message))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `DiagnosticBuilder` with an already constructed
|
||||||
|
/// diagnostic.
|
||||||
|
#[track_caller]
|
||||||
|
pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: Diagnostic) -> Self {
|
||||||
|
debug!("Created new diagnostic");
|
||||||
|
Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
/// Delay emission of this diagnostic as a bug.
|
/// Delay emission of this diagnostic as a bug.
|
||||||
///
|
///
|
||||||
/// This can be useful in contexts where an error indicates a bug but
|
/// This can be useful in contexts where an error indicates a bug but
|
||||||
@ -1040,48 +1242,115 @@ fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span:
|
|||||||
let sub = SubDiagnostic { level, messages, span };
|
let sub = SubDiagnostic { level, messages, span };
|
||||||
self.children.push(sub);
|
self.children.push(sub);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Diagnostic {
|
/// Takes the diagnostic. For use by methods that consume the
|
||||||
/// Fields used for Hash, and PartialEq trait
|
/// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the
|
||||||
fn keys(
|
/// only code that will be run on `self`.
|
||||||
&self,
|
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
||||||
) -> (
|
pub(crate) fn take_diag(&mut self) -> Diagnostic {
|
||||||
&Level,
|
Box::into_inner(self.diag.take().unwrap())
|
||||||
&[(DiagnosticMessage, Style)],
|
}
|
||||||
&Option<ErrCode>,
|
|
||||||
&MultiSpan,
|
/// Most `emit_producing_guarantee` functions use this as a starting point.
|
||||||
&[SubDiagnostic],
|
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
||||||
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
|
pub(crate) fn emit_producing_nothing(mut self) {
|
||||||
Vec<(&DiagnosticArgName, &DiagnosticArgValue)>,
|
let diag = self.take_diag();
|
||||||
&Option<IsLint>,
|
self.dcx.emit_diagnostic(diag);
|
||||||
) {
|
}
|
||||||
(
|
|
||||||
&self.level,
|
/// `ErrorGuaranteed::emit_producing_guarantee` uses this.
|
||||||
&self.messages,
|
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
||||||
&self.code,
|
pub(crate) fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
|
||||||
&self.span,
|
let diag = self.take_diag();
|
||||||
&self.children,
|
|
||||||
&self.suggestions,
|
// The only error levels that produce `ErrorGuaranteed` are
|
||||||
self.args().collect(),
|
// `Error` and `DelayedBug`. But `DelayedBug` should never occur here
|
||||||
// omit self.sort_span
|
// because delayed bugs have their level changed to `Bug` when they are
|
||||||
&self.is_lint,
|
// actually printed, so they produce an ICE.
|
||||||
// omit self.emitted_at
|
//
|
||||||
)
|
// (Also, even though `level` isn't `pub`, the whole `Diagnostic` could
|
||||||
|
// be overwritten with a new one thanks to `DerefMut`. So this assert
|
||||||
|
// protects against that, too.)
|
||||||
|
assert!(
|
||||||
|
matches!(diag.level, Level::Error | Level::DelayedBug),
|
||||||
|
"invalid diagnostic level ({:?})",
|
||||||
|
diag.level,
|
||||||
|
);
|
||||||
|
|
||||||
|
let guar = self.dcx.emit_diagnostic(diag);
|
||||||
|
guar.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit and consume the diagnostic.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn emit(self) -> G::EmitResult {
|
||||||
|
G::emit_producing_guarantee(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit the diagnostic unless `delay` is true,
|
||||||
|
/// in which case the emission will be delayed as a bug.
|
||||||
|
///
|
||||||
|
/// See `emit` and `delay_as_bug` for details.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn emit_unless(mut self, delay: bool) -> G::EmitResult {
|
||||||
|
if delay {
|
||||||
|
self.downgrade_to_delayed_bug();
|
||||||
|
}
|
||||||
|
self.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel and consume the diagnostic. (A diagnostic must either be emitted or
|
||||||
|
/// cancelled or it will panic when dropped).
|
||||||
|
pub fn cancel(mut self) {
|
||||||
|
self.diag = None;
|
||||||
|
drop(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stashes diagnostic for possible later improvement in a different,
|
||||||
|
/// later stage of the compiler. The diagnostic can be accessed with
|
||||||
|
/// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
|
||||||
|
pub fn stash(mut self, span: Span, key: StashKey) {
|
||||||
|
self.dcx.stash_diagnostic(span, key, self.take_diag());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delay emission of this diagnostic as a bug.
|
||||||
|
///
|
||||||
|
/// This can be useful in contexts where an error indicates a bug but
|
||||||
|
/// typically this only happens when other compilation errors have already
|
||||||
|
/// happened. In those cases this can be used to defer emission of this
|
||||||
|
/// diagnostic as a bug in the compiler only if no other errors have been
|
||||||
|
/// emitted.
|
||||||
|
///
|
||||||
|
/// In the meantime, though, callsites are required to deal with the "bug"
|
||||||
|
/// locally in whichever way makes the most sense.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn delay_as_bug(mut self) -> G::EmitResult {
|
||||||
|
self.downgrade_to_delayed_bug();
|
||||||
|
self.emit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Diagnostic {
|
/// Destructor bomb: every `DiagnosticBuilder` must be consumed (emitted,
|
||||||
fn hash<H>(&self, state: &mut H)
|
/// cancelled, etc.) or we emit a bug.
|
||||||
where
|
impl<G: EmissionGuarantee> Drop for DiagnosticBuilder<'_, G> {
|
||||||
H: Hasher,
|
fn drop(&mut self) {
|
||||||
{
|
match self.diag.take() {
|
||||||
self.keys().hash(state);
|
Some(diag) if !panicking() => {
|
||||||
|
self.dcx.emit_diagnostic(Diagnostic::new(
|
||||||
|
Level::Bug,
|
||||||
|
DiagnosticMessage::from("the following error was constructed but not emitted"),
|
||||||
|
));
|
||||||
|
self.dcx.emit_diagnostic(*diag);
|
||||||
|
panic!("error was constructed but not emitted");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Diagnostic {
|
#[macro_export]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
macro_rules! struct_span_code_err {
|
||||||
self.keys() == other.keys()
|
($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
|
||||||
}
|
$dcx.struct_span_err($span, format!($($message)*)).with_code($code)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,282 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
DiagCtxt, Diagnostic, DiagnosticMessage, ErrorGuaranteed, ExplicitBug, Level, StashKey,
|
|
||||||
};
|
|
||||||
use rustc_span::source_map::Spanned;
|
|
||||||
use rustc_span::Span;
|
|
||||||
use std::fmt::{self, Debug};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
use std::panic;
|
|
||||||
use std::thread::panicking;
|
|
||||||
|
|
||||||
/// Trait implemented by error types. This is rarely implemented manually. Instead, use
|
|
||||||
/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
|
|
||||||
#[rustc_diagnostic_item = "IntoDiagnostic"]
|
|
||||||
pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
|
|
||||||
/// Write out as a diagnostic out of `DiagCtxt`.
|
|
||||||
#[must_use]
|
|
||||||
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned<T>
|
|
||||||
where
|
|
||||||
T: IntoDiagnostic<'a, G>,
|
|
||||||
G: EmissionGuarantee,
|
|
||||||
{
|
|
||||||
fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
|
|
||||||
self.node.into_diagnostic(dcx, level).with_span(self.span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used for emitting structured error messages and other diagnostic information.
|
|
||||||
/// Wraps a `Diagnostic`, adding some useful things.
|
|
||||||
/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check
|
|
||||||
/// that it has been emitted or cancelled.
|
|
||||||
/// - The `EmissionGuarantee`, which determines the type returned from `emit`.
|
|
||||||
///
|
|
||||||
/// Each constructed `DiagnosticBuilder` must be consumed by a function such as
|
|
||||||
/// `emit`, `cancel`, `delay_as_bug`, or `into_diagnostic`. A panic occurrs if a
|
|
||||||
/// `DiagnosticBuilder` is dropped without being consumed by one of these
|
|
||||||
/// functions.
|
|
||||||
///
|
|
||||||
/// If there is some state in a downstream crate you would like to
|
|
||||||
/// access in the methods of `DiagnosticBuilder` here, consider
|
|
||||||
/// extending `DiagCtxtFlags`.
|
|
||||||
#[must_use]
|
|
||||||
pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> {
|
|
||||||
pub dcx: &'a DiagCtxt,
|
|
||||||
|
|
||||||
/// Why the `Option`? It is always `Some` until the `DiagnosticBuilder` is
|
|
||||||
/// consumed via `emit`, `cancel`, etc. At that point it is consumed and
|
|
||||||
/// replaced with `None`. Then `drop` checks that it is `None`; if not, it
|
|
||||||
/// panics because a diagnostic was built but not used.
|
|
||||||
///
|
|
||||||
/// Why the Box? `Diagnostic` is a large type, and `DiagnosticBuilder` is
|
|
||||||
/// often used as a return value, especially within the frequently-used
|
|
||||||
/// `PResult` type. In theory, return value optimization (RVO) should avoid
|
|
||||||
/// unnecessary copying. In practice, it does not (at the time of writing).
|
|
||||||
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
|
||||||
pub(crate) diag: Option<Box<Diagnostic>>,
|
|
||||||
|
|
||||||
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
|
||||||
pub(crate) _marker: PhantomData<G>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted
|
|
||||||
// twice, which would be bad.
|
|
||||||
impl<G> !Clone for DiagnosticBuilder<'_, G> {}
|
|
||||||
|
|
||||||
rustc_data_structures::static_assert_size!(
|
|
||||||
DiagnosticBuilder<'_, ()>,
|
|
||||||
2 * std::mem::size_of::<usize>()
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee"
|
|
||||||
/// (or "proof") token that the emission happened.
|
|
||||||
pub trait EmissionGuarantee: Sized {
|
|
||||||
/// This exists so that bugs and fatal errors can both result in `!` (an
|
|
||||||
/// abort) when emitted, but have different aborting behaviour.
|
|
||||||
type EmitResult = Self;
|
|
||||||
|
|
||||||
/// Implementation of `DiagnosticBuilder::emit`, fully controlled by each
|
|
||||||
/// `impl` of `EmissionGuarantee`, to make it impossible to create a value
|
|
||||||
/// of `Self::EmitResult` without actually performing the emission.
|
|
||||||
#[track_caller]
|
|
||||||
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|
||||||
/// Takes the diagnostic. For use by methods that consume the
|
|
||||||
/// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the
|
|
||||||
/// only code that will be run on `self`.
|
|
||||||
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
|
||||||
pub(crate) fn take_diag(&mut self) -> Diagnostic {
|
|
||||||
Box::into_inner(self.diag.take().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Most `emit_producing_guarantee` functions use this as a starting point.
|
|
||||||
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
|
||||||
pub(crate) fn emit_producing_nothing(mut self) {
|
|
||||||
let diag = self.take_diag();
|
|
||||||
self.dcx.emit_diagnostic(diag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `ErrorGuaranteed::emit_producing_guarantee` uses this.
|
|
||||||
// FIXME(nnethercote) Make private once this moves to diagnostic.rs.
|
|
||||||
pub(crate) fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
|
|
||||||
let diag = self.take_diag();
|
|
||||||
|
|
||||||
// The only error levels that produce `ErrorGuaranteed` are
|
|
||||||
// `Error` and `DelayedBug`. But `DelayedBug` should never occur here
|
|
||||||
// because delayed bugs have their level changed to `Bug` when they are
|
|
||||||
// actually printed, so they produce an ICE.
|
|
||||||
//
|
|
||||||
// (Also, even though `level` isn't `pub`, the whole `Diagnostic` could
|
|
||||||
// be overwritten with a new one thanks to `DerefMut`. So this assert
|
|
||||||
// protects against that, too.)
|
|
||||||
assert!(
|
|
||||||
matches!(diag.level, Level::Error | Level::DelayedBug),
|
|
||||||
"invalid diagnostic level ({:?})",
|
|
||||||
diag.level,
|
|
||||||
);
|
|
||||||
|
|
||||||
let guar = self.dcx.emit_diagnostic(diag);
|
|
||||||
guar.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EmissionGuarantee for ErrorGuaranteed {
|
|
||||||
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
|
||||||
db.emit_producing_error_guaranteed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EmissionGuarantee for () {
|
|
||||||
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
|
||||||
db.emit_producing_nothing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
|
|
||||||
/// bug diagnostics.
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct BugAbort;
|
|
||||||
|
|
||||||
impl EmissionGuarantee for BugAbort {
|
|
||||||
type EmitResult = !;
|
|
||||||
|
|
||||||
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
|
||||||
db.emit_producing_nothing();
|
|
||||||
panic::panic_any(ExplicitBug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for
|
|
||||||
/// fatal diagnostics.
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct FatalAbort;
|
|
||||||
|
|
||||||
impl EmissionGuarantee for FatalAbort {
|
|
||||||
type EmitResult = !;
|
|
||||||
|
|
||||||
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
|
||||||
db.emit_producing_nothing();
|
|
||||||
crate::FatalError.raise()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
|
|
||||||
fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult {
|
|
||||||
db.emit_producing_nothing();
|
|
||||||
rustc_span::fatal_error::FatalError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<G: EmissionGuarantee> Deref for DiagnosticBuilder<'_, G> {
|
|
||||||
type Target = Diagnostic;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Diagnostic {
|
|
||||||
self.diag.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Diagnostic {
|
|
||||||
self.diag.as_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|
||||||
#[rustc_lint_diagnostics]
|
|
||||||
#[track_caller]
|
|
||||||
pub fn new<M: Into<DiagnosticMessage>>(dcx: &'a DiagCtxt, level: Level, message: M) -> Self {
|
|
||||||
Self::new_diagnostic(dcx, Diagnostic::new(level, message))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `DiagnosticBuilder` with an already constructed
|
|
||||||
/// diagnostic.
|
|
||||||
#[track_caller]
|
|
||||||
pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: Diagnostic) -> Self {
|
|
||||||
debug!("Created new diagnostic");
|
|
||||||
Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Emit and consume the diagnostic.
|
|
||||||
#[track_caller]
|
|
||||||
pub fn emit(self) -> G::EmitResult {
|
|
||||||
G::emit_producing_guarantee(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Emit the diagnostic unless `delay` is true,
|
|
||||||
/// in which case the emission will be delayed as a bug.
|
|
||||||
///
|
|
||||||
/// See `emit` and `delay_as_bug` for details.
|
|
||||||
#[track_caller]
|
|
||||||
pub fn emit_unless(mut self, delay: bool) -> G::EmitResult {
|
|
||||||
if delay {
|
|
||||||
self.downgrade_to_delayed_bug();
|
|
||||||
}
|
|
||||||
self.emit()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cancel and consume the diagnostic. (A diagnostic must either be emitted or
|
|
||||||
/// cancelled or it will panic when dropped).
|
|
||||||
pub fn cancel(mut self) {
|
|
||||||
self.diag = None;
|
|
||||||
drop(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stashes diagnostic for possible later improvement in a different,
|
|
||||||
/// later stage of the compiler. The diagnostic can be accessed with
|
|
||||||
/// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
|
|
||||||
pub fn stash(mut self, span: Span, key: StashKey) {
|
|
||||||
self.dcx.stash_diagnostic(span, key, self.take_diag());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delay emission of this diagnostic as a bug.
|
|
||||||
///
|
|
||||||
/// This can be useful in contexts where an error indicates a bug but
|
|
||||||
/// typically this only happens when other compilation errors have already
|
|
||||||
/// happened. In those cases this can be used to defer emission of this
|
|
||||||
/// diagnostic as a bug in the compiler only if no other errors have been
|
|
||||||
/// emitted.
|
|
||||||
///
|
|
||||||
/// In the meantime, though, callsites are required to deal with the "bug"
|
|
||||||
/// locally in whichever way makes the most sense.
|
|
||||||
#[track_caller]
|
|
||||||
pub fn delay_as_bug(mut self) -> G::EmitResult {
|
|
||||||
self.downgrade_to_delayed_bug();
|
|
||||||
self.emit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
self.diag.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Destructor bomb: every `DiagnosticBuilder` must be consumed (emitted,
|
|
||||||
/// cancelled, etc.) or we emit a bug.
|
|
||||||
impl<G: EmissionGuarantee> Drop for DiagnosticBuilder<'_, G> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
match self.diag.take() {
|
|
||||||
Some(diag) if !panicking() => {
|
|
||||||
self.dcx.emit_diagnostic(Diagnostic::new(
|
|
||||||
Level::Bug,
|
|
||||||
DiagnosticMessage::from("the following error was constructed but not emitted"),
|
|
||||||
));
|
|
||||||
self.dcx.emit_diagnostic(*diag);
|
|
||||||
panic!("error was constructed but not emitted");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! struct_span_code_err {
|
|
||||||
($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
|
|
||||||
$dcx.struct_span_err($span, format!($($message)*)).with_code($code)
|
|
||||||
})
|
|
||||||
}
|
|
@ -37,12 +37,9 @@
|
|||||||
|
|
||||||
pub use codes::*;
|
pub use codes::*;
|
||||||
pub use diagnostic::{
|
pub use diagnostic::{
|
||||||
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName,
|
AddToDiagnostic, BugAbort, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName,
|
||||||
DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, StringPart, SubDiagnostic,
|
DiagnosticArgValue, DiagnosticBuilder, DiagnosticStyledString, EmissionGuarantee, FatalAbort,
|
||||||
SubdiagnosticMessageOp,
|
IntoDiagnostic, IntoDiagnosticArg, StringPart, SubDiagnostic, SubdiagnosticMessageOp,
|
||||||
};
|
|
||||||
pub use diagnostic_builder::{
|
|
||||||
BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort, IntoDiagnostic,
|
|
||||||
};
|
};
|
||||||
pub use diagnostic_impls::{
|
pub use diagnostic_impls::{
|
||||||
DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter,
|
DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter,
|
||||||
@ -87,7 +84,6 @@
|
|||||||
pub mod annotate_snippet_emitter_writer;
|
pub mod annotate_snippet_emitter_writer;
|
||||||
pub mod codes;
|
pub mod codes;
|
||||||
mod diagnostic;
|
mod diagnostic;
|
||||||
mod diagnostic_builder;
|
|
||||||
mod diagnostic_impls;
|
mod diagnostic_impls;
|
||||||
pub mod emitter;
|
pub mod emitter;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
@ -8,7 +8,7 @@ LL | arg: NotIntoDiagnosticArg,
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg`
|
| ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg`
|
||||||
|
|
|
|
||||||
= help: normalized in stderr
|
= help: normalized in stderr
|
||||||
note: required by a bound in `rustc_errors::diagnostic::<impl DiagnosticBuilder<'a, G>>::arg`
|
note: required by a bound in `DiagnosticBuilder::<'a, G>::arg`
|
||||||
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
||||||
= note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ LL | arg: NotIntoDiagnosticArg,
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg`
|
| ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg`
|
||||||
|
|
|
|
||||||
= help: normalized in stderr
|
= help: normalized in stderr
|
||||||
note: required by a bound in `rustc_errors::diagnostic::<impl DiagnosticBuilder<'a, G>>::arg`
|
note: required by a bound in `DiagnosticBuilder::<'a, G>::arg`
|
||||||
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
||||||
= note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
@ -628,7 +628,7 @@ LL | other: Hello,
|
|||||||
| ^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
|
| ^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
|
||||||
|
|
|
|
||||||
= help: normalized in stderr
|
= help: normalized in stderr
|
||||||
note: required by a bound in `rustc_errors::diagnostic::<impl DiagnosticBuilder<'a, G>>::arg`
|
note: required by a bound in `DiagnosticBuilder::<'a, G>::arg`
|
||||||
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
|
||||||
= note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user