diff options
| author | bors <bors@rust-lang.org> | 2025-02-14 17:17:45 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-02-14 17:17:45 +0000 |
| commit | d8810e3e2dab96778d20dd6d746ff95465515509 (patch) | |
| tree | 0cc9afbd626766ccdfe6cc4be82e010930db05f8 /compiler/rustc_errors/src | |
| parent | bdc97d104696f6abccea657f76401e282fc6ca85 (diff) | |
| parent | bd094fb57322f66c8f4400e4a22e11cd5d622bd6 (diff) | |
| download | rust-d8810e3e2dab96778d20dd6d746ff95465515509.tar.gz rust-d8810e3e2dab96778d20dd6d746ff95465515509.zip | |
Auto merge of #137030 - matthiaskrgr:rollup-267aumr, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #135778 (account for `c_enum_min_bits` in `multiple-reprs` UI test) - #136052 (Correct comment for FreeBSD and DragonFly BSD in unix/thread) - #136886 (Remove the common prelude module) - #136956 (add vendor directory to .gitignore) - #136958 (Fix presentation of purely "additive" replacement suggestion parts) - #136967 (Use `slice::fill` in `io::Repeat` implementation) - #136976 (alloc boxed: docs: use MaybeUninit::write instead of as_mut_ptr) - #137007 (Emit MIR for each bit with on `dont_reset_cast_kind_without_updating_operand`) - #137008 (Move code into `rustc_mir_transform`) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_errors/src')
| -rw-r--r-- | compiler/rustc_errors/src/emitter.rs | 25 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/lib.rs | 30 |
2 files changed, 48 insertions, 7 deletions
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4824dc098ad..634afacf539 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) || p.is_replacement(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, @@ -2213,7 +2216,12 @@ impl HumanEmitter { if let DisplaySuggestion::Diff | DisplaySuggestion::Underline | DisplaySuggestion::Add = show_code_change { - for part in parts { + for mut part in 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); + let snippet = if let Ok(snippet) = sm.span_to_snippet(part.span) { snippet } else { @@ -2376,9 +2384,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..8ff5dc12596 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -230,10 +230,40 @@ 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| { + self.snippet.trim_start().starts_with(snippet.trim_start()) + || self.snippet.trim_end().ends_with(snippet.trim_end()) + }) + } + 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 self.snippet.starts_with(&snippet) { + self.span = self.span.shrink_to_hi(); + self.snippet = self.snippet[snippet.len()..].to_string(); + } else if self.snippet.ends_with(&snippet) { + self.span = self.span.shrink_to_lo(); + self.snippet = self.snippet[..self.snippet.len() - snippet.len()].to_string(); + } + } } impl CodeSuggestion { |
