diff options
| author | Boxy <rust@boxyuwu.dev> | 2025-02-25 21:27:44 +0000 |
|---|---|---|
| committer | Boxy <rust@boxyuwu.dev> | 2025-02-25 21:27:44 +0000 |
| commit | d9683df7c2f6d4141b1321e27635d2ce3167eaa4 (patch) | |
| tree | dce0d46d1b7d624ec9b9b09b2c1854f6245a5ff4 /compiler/rustc_errors | |
| parent | 46392d1661540e256fd9573d8f06c2784a58c983 (diff) | |
| parent | 4ecd70ddd1039a3954056c1071e40278048476fa (diff) | |
| download | rust-d9683df7c2f6d4141b1321e27635d2ce3167eaa4.tar.gz rust-d9683df7c2f6d4141b1321e27635d2ce3167eaa4.zip | |
Merge from rustc
Diffstat (limited to 'compiler/rustc_errors')
| -rw-r--r-- | compiler/rustc_errors/Cargo.toml | 4 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/diagnostic_impls.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/emitter.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/lib.rs | 66 |
4 files changed, 87 insertions, 13 deletions
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index fbb6a1cc475..b11793c190a 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_errors" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -10,10 +10,12 @@ derive_setters = "0.1.6" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index d179396398f..db6532f41ea 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -8,6 +8,7 @@ use std::process::ExitStatus; use rustc_abi::TargetDataLayoutErrors; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast_pretty::pprust; +use rustc_attr_data_structures::RustcVersion; use rustc_macros::Subdiagnostic; use rustc_span::edition::Edition; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol}; @@ -93,8 +94,15 @@ into_diag_arg_using_display!( SplitDebuginfo, ExitStatus, ErrCode, + rustc_abi::ExternAbi, ); +impl IntoDiagArg for RustcVersion { + fn into_diag_arg(self) -> DiagArgValue { + DiagArgValue::Str(Cow::Owned(self.to_string())) + } +} + impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::TraitRef<I> { fn into_diag_arg(self) -> DiagArgValue { self.to_string().into_diag_arg() @@ -108,13 +116,13 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTrait } impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self) -> DiagArgValue { format!("{self:?}").into_diag_arg() } } impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self) -> DiagArgValue { format!("{self:?}").into_diag_arg() } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 15cf285e7ff..f7f84239308 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1976,13 +1976,16 @@ impl HumanEmitter { Some(Style::HeaderMsg), ); + let other_suggestions = suggestions.len().saturating_sub(MAX_SUGGESTIONS); + let mut row_num = 2; for (i, (complete, parts, highlights, _)) in - suggestions.iter().enumerate().take(MAX_SUGGESTIONS) + suggestions.into_iter().enumerate().take(MAX_SUGGESTIONS) { debug!(?complete, ?parts, ?highlights); - let has_deletion = parts.iter().any(|p| p.is_deletion(sm)); + let has_deletion = + parts.iter().any(|p| p.is_deletion(sm) || p.is_destructive_replacement(sm)); let is_multiline = complete.lines().count() > 1; if i == 0 { @@ -2167,7 +2170,7 @@ impl HumanEmitter { self.draw_code_line( &mut buffer, &mut row_num, - highlight_parts, + &highlight_parts, line_pos + line_start, line, show_code_change, @@ -2376,9 +2379,12 @@ impl HumanEmitter { row_num = row + 1; } } - if suggestions.len() > MAX_SUGGESTIONS { - let others = suggestions.len() - MAX_SUGGESTIONS; - let msg = format!("and {} other candidate{}", others, pluralize!(others)); + if other_suggestions > 0 { + let msg = format!( + "and {} other candidate{}", + other_suggestions, + pluralize!(other_suggestions) + ); buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9af17db9a6e..f2b133f5677 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -15,7 +15,6 @@ #![feature(box_into_inner)] #![feature(box_patterns)] #![feature(error_reporter)] -#![feature(extract_if)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(negative_impls)] @@ -58,19 +57,20 @@ pub use emitter::ColorConfig; use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; +use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{DynSend, Lock}; pub use rustc_error_messages::{ DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; +use rustc_hashes::Hash128; use rustc_lint_defs::LintExpectationId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; use rustc_span::source_map::SourceMap; -use rustc_span::{DUMMY_SP, Loc, Span}; +use rustc_span::{BytePos, DUMMY_SP, Loc, Span}; pub use snippet::Style; // Used by external projects such as `rust-gpu`. // See https://github.com/rust-lang/rust/pull/115393. @@ -230,10 +230,63 @@ impl SubstitutionPart { !self.snippet.is_empty() && self.replaces_meaningful_content(sm) } + /// Whether this is a replacement that overwrites source with a snippet + /// in a way that isn't a superset of the original string. For example, + /// replacing "abc" with "abcde" is not destructive, but replacing it + /// it with "abx" is, since the "c" character is lost. + pub fn is_destructive_replacement(&self, sm: &SourceMap) -> bool { + self.is_replacement(sm) + && !sm + .span_to_snippet(self.span) + .is_ok_and(|snippet| as_substr(snippet.trim(), self.snippet.trim()).is_some()) + } + fn replaces_meaningful_content(&self, sm: &SourceMap) -> bool { sm.span_to_snippet(self.span) .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty()) } + + /// Try to turn a replacement into an addition when the span that is being + /// overwritten matches either the prefix or suffix of the replacement. + fn trim_trivial_replacements(&mut self, sm: &SourceMap) { + if self.snippet.is_empty() { + return; + } + let Ok(snippet) = sm.span_to_snippet(self.span) else { + return; + }; + + if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) { + self.span = Span::new( + self.span.lo() + BytePos(prefix as u32), + self.span.hi() - BytePos(suffix as u32), + self.span.ctxt(), + self.span.parent(), + ); + self.snippet = substr.to_string(); + } + } +} + +/// Given an original string like `AACC`, and a suggestion like `AABBCC`, try to detect +/// the case where a substring of the suggestion is "sandwiched" in the original, like +/// `BB` is. Return the length of the prefix, the "trimmed" suggestion, and the length +/// of the suffix. +fn as_substr<'a>(original: &'a str, suggestion: &'a str) -> Option<(usize, &'a str, usize)> { + let common_prefix = original + .chars() + .zip(suggestion.chars()) + .take_while(|(c1, c2)| c1 == c2) + .map(|(c, _)| c.len_utf8()) + .sum(); + let original = &original[common_prefix..]; + let suggestion = &suggestion[common_prefix..]; + if suggestion.ends_with(original) { + let common_suffix = original.len(); + Some((common_prefix, &suggestion[..suggestion.len() - original.len()], common_suffix)) + } else { + None + } } impl CodeSuggestion { @@ -349,7 +402,12 @@ impl CodeSuggestion { // or deleted code in order to point at the correct column *after* substitution. let mut acc = 0; let mut only_capitalization = false; - for part in &substitution.parts { + for part in &mut substitution.parts { + // If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the + // suggestion and snippet to look as if we just suggested to add + // `"b"`, which is typically much easier for the user to understand. + part.trim_trivial_replacements(sm); + only_capitalization |= is_case_difference(sm, &part.snippet, part.span); let cur_lo = sm.lookup_char_pos(part.span.lo()); if prev_hi.line == cur_lo.line { |
