1
Fork 0

Stop using String for error codes.

Error codes are integers, but `String` is used everywhere to represent
them. Gross!

This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.

With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123)  // macro call

struct_span_code_err!(dcx, span, E0123, "msg");  // bare ident arg to macro call

\#[diag(name, code = "E0123")]  // string
struct Diag;
```

With the new code, they all use the `E0123` constant.
```
E0123  // constant

struct_span_code_err!(dcx, span, E0123, "msg");  // constant

\#[diag(name, code = E0123)]  // constant
struct Diag;
```

The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
  used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
  moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
  code constants and the `DIAGNOSTIC_TABLES`. This is in its new
  `codes.rs` file.
This commit is contained in:
Nicholas Nethercote 2024-01-14 10:57:07 +11:00
parent 0321de2778
commit 5d9dfbd08f
110 changed files with 1624 additions and 1572 deletions

View file

@ -9,8 +9,8 @@ use crate::emitter::FileWithAnnotatedLines;
use crate::snippet::Line;
use crate::translation::{to_fluent_args, Translate};
use crate::{
CodeSuggestion, Diagnostic, DiagnosticMessage, Emitter, FluentBundle, LazyFallbackBundle,
Level, MultiSpan, Style, SubDiagnostic,
CodeSuggestion, Diagnostic, DiagnosticMessage, Emitter, ErrCode, FluentBundle,
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
};
use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
use rustc_data_structures::sync::Lrc;
@ -127,7 +127,7 @@ impl AnnotateSnippetEmitter {
level: &Level,
messages: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
code: &Option<String>,
code: &Option<ErrCode>,
msp: &MultiSpan,
_children: &[SubDiagnostic],
_suggestions: &[CodeSuggestion],
@ -178,6 +178,7 @@ impl AnnotateSnippetEmitter {
.collect::<Vec<Owned>>()
})
.collect();
let code = code.map(|code| code.to_string());
let snippet = Snippet {
title: Some(Annotation {
label: Some(&message),

View file

@ -0,0 +1,39 @@
//! This module defines the following.
//! - The `ErrCode` type.
//! - A constant for every error code, with a name like `E0123`.
//! - A static table `DIAGNOSTICS` pairing every error code constant with its
//! long description text.
use std::fmt;
rustc_index::newtype_index! {
#[max = 9999] // Because all error codes have four digits.
#[orderable]
#[encodable]
#[debug_format = "ErrCode({})"]
pub struct ErrCode {}
}
impl fmt::Display for ErrCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "E{:04}", self.as_u32())
}
}
macro_rules! define_error_code_constants_and_diagnostics_table {
($($name:ident: $num:literal,)*) => (
$(
pub const $name: $crate::ErrCode = $crate::ErrCode::from_u32($num);
)*
pub static DIAGNOSTICS: &[($crate::ErrCode, &str)] = &[
$( (
$name,
include_str!(
concat!("../../rustc_error_codes/src/error_codes/", stringify!($name), ".md")
)
), )*
];
)
}
rustc_error_codes::error_codes!(define_error_code_constants_and_diagnostics_table);

View file

@ -1,7 +1,8 @@
use crate::snippet::Style;
use crate::{
CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level,
MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
CodeSuggestion, DelayedBugKind, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee,
ErrCode, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart,
SuggestionStyle,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
@ -104,7 +105,7 @@ pub struct Diagnostic {
pub(crate) level: Level,
pub messages: Vec<(DiagnosticMessage, Style)>,
pub code: Option<String>,
pub code: Option<ErrCode>,
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
@ -893,8 +894,8 @@ impl Diagnostic {
self
}
pub fn code(&mut self, s: String) -> &mut Self {
self.code = Some(s);
pub fn code(&mut self, code: ErrCode) -> &mut Self {
self.code = Some(code);
self
}
@ -903,8 +904,8 @@ impl Diagnostic {
self
}
pub fn get_code(&self) -> Option<&str> {
self.code.as_deref()
pub fn get_code(&self) -> Option<ErrCode> {
self.code
}
pub fn primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
@ -990,7 +991,7 @@ impl Diagnostic {
&Level,
&[(DiagnosticMessage, Style)],
Vec<(&Cow<'static, str>, &DiagnosticArgValue<'static>)>,
&Option<String>,
&Option<ErrCode>,
&Option<IsLint>,
&MultiSpan,
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>,

View file

@ -1,7 +1,7 @@
use crate::diagnostic::IntoDiagnosticArg;
use crate::{DiagCtxt, Level, MultiSpan, StashKey};
use crate::{
Diagnostic, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed, ExplicitBug,
Diagnostic, DiagnosticMessage, DiagnosticStyledString, ErrCode, ErrorGuaranteed, ExplicitBug,
SubdiagnosticMessage,
};
use rustc_lint_defs::Applicability;
@ -399,7 +399,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
name: String, has_future_breakage: bool,
));
forward!((code, with_code)(
s: String,
code: ErrCode,
));
forward!((arg, with_arg)(
name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg,
@ -439,12 +439,7 @@ impl<G: EmissionGuarantee> Drop for DiagnosticBuilder<'_, G> {
#[macro_export]
macro_rules! struct_span_code_err {
($dcx:expr, $span:expr, $code:ident, $($message:tt)*) => ({
$dcx.struct_span_err($span, format!($($message)*)).with_code($crate::error_code!($code))
($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({
$dcx.struct_span_err($span, format!($($message)*)).with_code($code)
})
}
#[macro_export]
macro_rules! error_code {
($code:ident) => {{ stringify!($code).to_owned() }};
}

View file

@ -1,7 +1,7 @@
use crate::diagnostic::DiagnosticLocation;
use crate::{fluent_generated as fluent, AddToDiagnostic};
use crate::{
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic,
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, ErrCode, IntoDiagnostic,
IntoDiagnosticArg, Level,
};
use rustc_ast as ast;
@ -93,6 +93,7 @@ into_diagnostic_arg_using_display!(
&TargetTriple,
SplitDebuginfo,
ExitStatus,
ErrCode,
);
into_diagnostic_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);

View file

@ -17,8 +17,8 @@ use crate::styled_buffer::StyledBuffer;
use crate::translation::{to_fluent_args, Translate};
use crate::{
diagnostic::DiagnosticLocation, CodeSuggestion, DiagCtxt, Diagnostic, DiagnosticMessage,
FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight,
SuggestionStyle, TerminalUrl,
ErrCode, FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic,
SubstitutionHighlight, SuggestionStyle, TerminalUrl,
};
use rustc_lint_defs::pluralize;
@ -1309,7 +1309,7 @@ impl HumanEmitter {
msp: &MultiSpan,
msgs: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
code: &Option<String>,
code: &Option<ErrCode>,
level: &Level,
max_line_num_len: usize,
is_secondary: bool,
@ -1340,9 +1340,9 @@ impl HumanEmitter {
buffer.append(0, "[", Style::Level(*level));
let code = if let TerminalUrl::Yes = self.terminal_url {
let path = "https://doc.rust-lang.org/error_codes";
Cow::Owned(format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07"))
format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07")
} else {
Cow::Borrowed(code)
code.to_string()
};
buffer.append(0, &code, Style::Level(*level));
buffer.append(0, "]", Style::Level(*level));
@ -2076,7 +2076,7 @@ impl HumanEmitter {
level: &Level,
messages: &[(DiagnosticMessage, Style)],
args: &FluentArgs<'_>,
code: &Option<String>,
code: &Option<ErrCode>,
span: &MultiSpan,
children: &[SubDiagnostic],
suggestions: &[CodeSuggestion],

View file

@ -400,10 +400,10 @@ impl Diagnostic {
let translated_message = je.translate_messages(&diag.messages, &args);
let code = if let Some(code) = &diag.code {
let code = if let Some(code) = diag.code {
Some(DiagnosticCode {
code: code.to_string(),
explanation: je.registry.as_ref().unwrap().try_find_description(&code).ok(),
explanation: je.registry.as_ref().unwrap().try_find_description(code).ok(),
})
} else if let Some(IsLint { name, .. }) = &diag.is_lint {
Some(DiagnosticCode { code: name.to_string(), explanation: None })

View file

@ -14,6 +14,7 @@
#![feature(error_reporter)]
#![feature(extract_if)]
#![feature(let_chains)]
#![feature(min_specialization)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(rustc_attrs)]
@ -30,6 +31,7 @@ extern crate tracing;
extern crate self as rustc_errors;
pub use codes::*;
pub use diagnostic::{
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue,
DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
@ -78,6 +80,7 @@ use std::path::{Path, PathBuf};
use Level::*;
pub mod annotate_snippet_emitter_writer;
pub mod codes;
mod diagnostic;
mod diagnostic_builder;
mod diagnostic_impls;
@ -446,10 +449,10 @@ struct DiagCtxtInner {
/// This set contains the code of all emitted diagnostics to avoid
/// emitting the same diagnostic with extended help (`--teach`) twice, which
/// would be unnecessary repetition.
taught_diagnostics: FxHashSet<String>,
taught_diagnostics: FxHashSet<ErrCode>,
/// Used to suggest rustc --explain `<error code>`
emitted_diagnostic_codes: FxIndexSet<String>,
emitted_diagnostic_codes: FxIndexSet<ErrCode>,
/// This set contains a hash of every diagnostic that has been emitted by
/// this `DiagCtxt`. These hashes is used to avoid emitting the same error
@ -1004,9 +1007,9 @@ impl DiagCtxt {
let mut error_codes = inner
.emitted_diagnostic_codes
.iter()
.filter_map(|code| {
.filter_map(|&code| {
if registry.try_find_description(code).is_ok().clone() {
Some(code.clone())
Some(code.to_string())
} else {
None
}
@ -1052,8 +1055,8 @@ impl DiagCtxt {
///
/// Used to suppress emitting the same error multiple times with extended explanation when
/// calling `-Zteach`.
pub fn must_teach(&self, code: &str) -> bool {
self.inner.borrow_mut().taught_diagnostics.insert(code.to_string())
pub fn must_teach(&self, code: ErrCode) -> bool {
self.inner.borrow_mut().taught_diagnostics.insert(code)
}
pub fn force_print_diagnostic(&self, db: Diagnostic) {
@ -1313,8 +1316,8 @@ impl DiagCtxtInner {
let mut guaranteed = None;
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| {
if let Some(ref code) = diagnostic.code {
self.emitted_diagnostic_codes.insert(code.clone());
if let Some(code) = diagnostic.code {
self.emitted_diagnostic_codes.insert(code);
}
let already_emitted = {

View file

@ -1,3 +1,4 @@
use crate::ErrCode;
use rustc_data_structures::fx::FxHashMap;
#[derive(Debug)]
@ -5,17 +6,17 @@ pub struct InvalidErrorCode;
#[derive(Clone)]
pub struct Registry {
long_descriptions: FxHashMap<&'static str, &'static str>,
long_descriptions: FxHashMap<ErrCode, &'static str>,
}
impl Registry {
pub fn new(long_descriptions: &[(&'static str, &'static str)]) -> Registry {
pub fn new(long_descriptions: &[(ErrCode, &'static str)]) -> Registry {
Registry { long_descriptions: long_descriptions.iter().copied().collect() }
}
/// Returns `InvalidErrorCode` if the code requested does not exist in the
/// registry.
pub fn try_find_description(&self, code: &str) -> Result<&'static str, InvalidErrorCode> {
self.long_descriptions.get(code).copied().ok_or(InvalidErrorCode)
pub fn try_find_description(&self, code: ErrCode) -> Result<&'static str, InvalidErrorCode> {
self.long_descriptions.get(&code).copied().ok_or(InvalidErrorCode)
}
}