Rollup merge of #108482 - Ezrashaw:force-error-docs, r=GuillaumeGomez
statically guarantee that current error codes are documented Closes #61137 (that's right!) Pretty simple refactor (often just a change from `Result<Option<&str>>` to `Result<&str>`) r? `@GuillaumeGomez` (could you specially look at 53044158eff0d64673a6100f701c57b484232aca? I believe you wrote that in the first place, just want to make sure you're happy with the change)
This commit is contained in:
commit
edd27cf4ca
@ -1445,6 +1445,7 @@ name = "error_index_generator"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"mdbook",
|
||||
"rustc_error_codes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -485,7 +485,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
|
||||
let normalised =
|
||||
if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
|
||||
match registry.try_find_description(&normalised) {
|
||||
Ok(Some(description)) => {
|
||||
Ok(description) => {
|
||||
let mut is_in_code_block = false;
|
||||
let mut text = String::new();
|
||||
// Slice off the leading newline and print.
|
||||
@ -509,9 +509,6 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
|
||||
print!("{text}");
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
early_error(output, &format!("no extended information for {code}"));
|
||||
}
|
||||
Err(InvalidErrorCode) => {
|
||||
early_error(output, &format!("{code} is not a valid error code"));
|
||||
}
|
||||
|
@ -513,7 +513,9 @@
|
||||
E0791: include_str!("./error_codes/E0791.md"),
|
||||
E0792: include_str!("./error_codes/E0792.md"),
|
||||
E0793: include_str!("./error_codes/E0793.md"),
|
||||
;
|
||||
}
|
||||
|
||||
// Undocumented removed error codes. Note that many removed error codes are documented.
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
// E0019, // merged into E0015
|
||||
@ -570,7 +572,7 @@
|
||||
// E0246, // invalid recursive type
|
||||
// E0247,
|
||||
// E0248, // value used as a type, now reported earlier during resolution
|
||||
// as E0412
|
||||
// // as E0412
|
||||
// E0249,
|
||||
// E0257,
|
||||
// E0258,
|
||||
@ -631,14 +633,14 @@
|
||||
// E0558, // replaced with a generic attribute input check
|
||||
// E0563, // cannot determine a type for this `impl Trait` removed in 6383de15
|
||||
// E0564, // only named lifetimes are allowed in `impl Trait`,
|
||||
// but `{}` was found in the type `{}`
|
||||
// // but `{}` was found in the type `{}`
|
||||
// E0598, // lifetime of {} is too short to guarantee its contents can be...
|
||||
// E0611, // merged into E0616
|
||||
// E0612, // merged into E0609
|
||||
// E0613, // Removed (merged with E0609)
|
||||
// E0629, // missing 'feature' (rustc_const_unstable)
|
||||
// E0630, // rustc_const_unstable attribute must be paired with stable/unstable
|
||||
// attribute
|
||||
// // attribute
|
||||
// E0645, // trait aliases not finished
|
||||
// E0694, // an unknown tool name found in scoped attributes
|
||||
// E0702, // replaced with a generic attribute input check
|
||||
@ -647,4 +649,3 @@
|
||||
// E0721, // `await` keyword
|
||||
// E0723, // unstable feature in `const` context
|
||||
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
|
||||
}
|
||||
|
@ -5,10 +5,9 @@
|
||||
//! the goal being to make their maintenance easier.
|
||||
|
||||
macro_rules! register_diagnostics {
|
||||
($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
|
||||
pub static DIAGNOSTICS: &[(&str, Option<&str>)] = &[
|
||||
$( (stringify!($ecode), Some($message)), )*
|
||||
$( (stringify!($code), None), )*
|
||||
($($ecode:ident: $message:expr,)*) => (
|
||||
pub static DIAGNOSTICS: &[(&str, &str)] = &[
|
||||
$( (stringify!($ecode), $message), )*
|
||||
];
|
||||
)
|
||||
}
|
||||
|
@ -580,7 +580,7 @@ fn map_opt_string(s: Option<DiagnosticId>, je: &JsonEmitter) -> Option<Diagnosti
|
||||
let je_result =
|
||||
je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap();
|
||||
|
||||
DiagnosticCode { code: s, explanation: je_result.unwrap_or(None) }
|
||||
DiagnosticCode { code: s, explanation: je_result.ok() }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1477,9 +1477,7 @@ fn print_error_count(&mut self, registry: &Registry) {
|
||||
.emitted_diagnostic_codes
|
||||
.iter()
|
||||
.filter_map(|x| match &x {
|
||||
DiagnosticId::Error(s)
|
||||
if registry.try_find_description(s).map_or(false, |o| o.is_some()) =>
|
||||
{
|
||||
DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => {
|
||||
Some(s.clone())
|
||||
}
|
||||
_ => None,
|
||||
|
@ -5,21 +5,17 @@
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Registry {
|
||||
long_descriptions: FxHashMap<&'static str, Option<&'static str>>,
|
||||
long_descriptions: FxHashMap<&'static str, &'static str>,
|
||||
}
|
||||
|
||||
impl Registry {
|
||||
pub fn new(long_descriptions: &[(&'static str, Option<&'static str>)]) -> Registry {
|
||||
pub fn new(long_descriptions: &[(&'static str, &'static str)]) -> Registry {
|
||||
Registry { long_descriptions: long_descriptions.iter().copied().collect() }
|
||||
}
|
||||
|
||||
/// Returns `InvalidErrorCode` if the code requested does not exist in the
|
||||
/// registry. Otherwise, returns an `Option` where `None` means the error
|
||||
/// code is valid but has no extended information.
|
||||
pub fn try_find_description(
|
||||
&self,
|
||||
code: &str,
|
||||
) -> Result<Option<&'static str>, InvalidErrorCode> {
|
||||
/// registry.
|
||||
pub fn try_find_description(&self, code: &str) -> Result<&'static str, InvalidErrorCode> {
|
||||
self.long_descriptions.get(code).copied().ok_or(InvalidErrorCode)
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
mdbook = { version = "0.4", default-features = false, features = ["search"] }
|
||||
rustc_error_codes = { version = "0.0.0", path = "../../../compiler/rustc_error_codes" }
|
||||
|
||||
[[bin]]
|
||||
name = "error_index_generator"
|
||||
|
@ -2,9 +2,6 @@
|
||||
|
||||
extern crate rustc_driver;
|
||||
|
||||
// We use the function we generate from `register_diagnostics!`.
|
||||
use crate::error_codes::error_codes;
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs::{self, File};
|
||||
@ -17,22 +14,6 @@
|
||||
use mdbook::book::{parse_summary, BookItem, Chapter};
|
||||
use mdbook::{Config, MDBook};
|
||||
|
||||
macro_rules! register_diagnostics {
|
||||
($($error_code:ident: $message:expr,)+ ; $($undocumented:ident,)* ) => {
|
||||
pub fn error_codes() -> Vec<(&'static str, Option<&'static str>)> {
|
||||
let mut errors: Vec<(&str, Option<&str>)> = vec![
|
||||
$((stringify!($error_code), Some($message)),)+
|
||||
$((stringify!($undocumented), None),)*
|
||||
];
|
||||
errors.sort();
|
||||
errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[path = "../../../compiler/rustc_error_codes/src/error_codes.rs"]
|
||||
mod error_codes;
|
||||
|
||||
enum OutputFormat {
|
||||
HTML,
|
||||
Markdown,
|
||||
@ -55,11 +36,8 @@ fn render_markdown(output_path: &Path) -> Result<(), Box<dyn Error>> {
|
||||
|
||||
write!(output_file, "# Rust Compiler Error Index\n")?;
|
||||
|
||||
for (err_code, description) in error_codes().iter() {
|
||||
match description {
|
||||
Some(ref desc) => write!(output_file, "## {}\n{}\n", err_code, desc)?,
|
||||
None => {}
|
||||
}
|
||||
for (err_code, description) in rustc_error_codes::DIAGNOSTICS.iter() {
|
||||
write!(output_file, "## {}\n{}\n", err_code, description)?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -105,27 +83,23 @@ fn render_html(output_path: &Path) -> Result<(), Box<dyn Error>> {
|
||||
"
|
||||
);
|
||||
|
||||
let err_codes = error_codes();
|
||||
let err_codes = rustc_error_codes::DIAGNOSTICS;
|
||||
let mut chapters = Vec::with_capacity(err_codes.len());
|
||||
|
||||
for (err_code, explanation) in err_codes.iter() {
|
||||
if let Some(explanation) = explanation {
|
||||
introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code));
|
||||
introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code));
|
||||
|
||||
let content = add_rust_attribute_on_codeblock(explanation);
|
||||
chapters.push(BookItem::Chapter(Chapter {
|
||||
name: err_code.to_string(),
|
||||
content: format!("# Error code {}\n\n{}\n", err_code, content),
|
||||
number: None,
|
||||
sub_items: Vec::new(),
|
||||
// We generate it into the `error_codes` folder.
|
||||
path: Some(PathBuf::from(&format!("{}.html", err_code))),
|
||||
source_path: None,
|
||||
parent_names: Vec::new(),
|
||||
}));
|
||||
} else {
|
||||
introduction.push_str(&format!(" * {}\n", err_code));
|
||||
}
|
||||
let content = add_rust_attribute_on_codeblock(explanation);
|
||||
chapters.push(BookItem::Chapter(Chapter {
|
||||
name: err_code.to_string(),
|
||||
content: format!("# Error code {}\n\n{}\n", err_code, content),
|
||||
number: None,
|
||||
sub_items: Vec::new(),
|
||||
// We generate it into the `error_codes` folder.
|
||||
path: Some(PathBuf::from(&format!("{}.html", err_code))),
|
||||
source_path: None,
|
||||
parent_names: Vec::new(),
|
||||
}));
|
||||
}
|
||||
|
||||
let mut config = Config::from_str(include_str!("book_config.toml"))?;
|
||||
|
@ -45,7 +45,7 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut
|
||||
let mut errors = Vec::new();
|
||||
|
||||
// Stage 1: create list
|
||||
let error_codes = extract_error_codes(root_path, &mut errors, verbose);
|
||||
let error_codes = extract_error_codes(root_path, &mut errors);
|
||||
println!("Found {} error codes", error_codes.len());
|
||||
println!("Highest error code: `{}`", error_codes.iter().max().unwrap());
|
||||
|
||||
@ -65,18 +65,17 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut
|
||||
}
|
||||
|
||||
/// Stage 1: Parses a list of error codes from `error_codes.rs`.
|
||||
fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>, verbose: bool) -> Vec<String> {
|
||||
fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String> {
|
||||
let path = root_path.join(Path::new(ERROR_CODES_PATH));
|
||||
let file =
|
||||
fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}"));
|
||||
|
||||
let mut error_codes = Vec::new();
|
||||
let mut reached_undocumented_codes = false;
|
||||
|
||||
for line in file.lines() {
|
||||
let line = line.trim();
|
||||
|
||||
if !reached_undocumented_codes && line.starts_with('E') {
|
||||
if line.starts_with('E') {
|
||||
let split_line = line.split_once(':');
|
||||
|
||||
// Extract the error code from the line, emitting a fatal error if it is not in a correct format.
|
||||
@ -111,23 +110,6 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>, verbose: bool
|
||||
}
|
||||
|
||||
error_codes.push(err_code);
|
||||
} else if reached_undocumented_codes && line.starts_with('E') {
|
||||
let err_code = match line.split_once(',') {
|
||||
None => line,
|
||||
Some((err_code, _)) => err_code,
|
||||
}
|
||||
.to_string();
|
||||
|
||||
verbose_print!(verbose, "warning: Error code `{}` is undocumented.", err_code);
|
||||
|
||||
if error_codes.contains(&err_code) {
|
||||
errors.push(format!("Found duplicate error code: `{}`", err_code));
|
||||
}
|
||||
|
||||
error_codes.push(err_code);
|
||||
} else if line == ";" {
|
||||
// Once we reach the undocumented error codes, adapt to different syntax.
|
||||
reached_undocumented_codes = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user