Skip to content

Commit 4068baf

Browse files
committed
Auto merge of rust-lang#147913 - matthiaskrgr:rollup-lmm3dsh, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - rust-lang#147577 (Improve error message for ambiguous numeric types in closure parameters) - rust-lang#147785 (fix incorrect line number when building trimmed multi-line suggestions) - rust-lang#147814 (btree: some cleanup with less unsafe) - rust-lang#147843 (Change the tidy license checker) r? `@ghost` `@rustbot` modify labels: rollup
2 parents bd4a800 + 2a6ac46 commit 4068baf

File tree

10 files changed

+243
-144
lines changed

10 files changed

+243
-144
lines changed

compiler/rustc_errors/src/emitter.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,11 +2154,11 @@ impl HumanEmitter {
21542154

21552155
assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
21562156

2157-
let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
2157+
let line_start = sm.lookup_char_pos(parts[0].original_span.lo()).line;
21582158
let mut lines = complete.lines();
21592159
if lines.clone().next().is_none() {
21602160
// Account for a suggestion to completely remove a line(s) with whitespace (#94192).
2161-
let line_end = sm.lookup_char_pos(parts[0].span.hi()).line;
2161+
let line_end = sm.lookup_char_pos(parts[0].original_span.hi()).line;
21622162
for line in line_start..=line_end {
21632163
self.draw_line_num(
21642164
&mut buffer,

compiler/rustc_errors/src/lib.rs

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,13 @@ pub struct SubstitutionPart {
224224
pub snippet: String,
225225
}
226226

227+
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
228+
pub struct TrimmedSubstitutionPart {
229+
pub original_span: Span,
230+
pub span: Span,
231+
pub snippet: String,
232+
}
233+
227234
/// Used to translate between `Span`s and byte positions within a single output line in highlighted
228235
/// code of structured suggestions.
229236
#[derive(Debug, Clone, Copy)]
@@ -233,6 +240,35 @@ pub(crate) struct SubstitutionHighlight {
233240
}
234241

235242
impl SubstitutionPart {
243+
/// Try to turn a replacement into an addition when the span that is being
244+
/// overwritten matches either the prefix or suffix of the replacement.
245+
fn trim_trivial_replacements(self, sm: &SourceMap) -> TrimmedSubstitutionPart {
246+
let mut trimmed_part = TrimmedSubstitutionPart {
247+
original_span: self.span,
248+
span: self.span,
249+
snippet: self.snippet,
250+
};
251+
if trimmed_part.snippet.is_empty() {
252+
return trimmed_part;
253+
}
254+
let Ok(snippet) = sm.span_to_snippet(trimmed_part.span) else {
255+
return trimmed_part;
256+
};
257+
258+
if let Some((prefix, substr, suffix)) = as_substr(&snippet, &trimmed_part.snippet) {
259+
trimmed_part.span = Span::new(
260+
trimmed_part.span.lo() + BytePos(prefix as u32),
261+
trimmed_part.span.hi() - BytePos(suffix as u32),
262+
trimmed_part.span.ctxt(),
263+
trimmed_part.span.parent(),
264+
);
265+
trimmed_part.snippet = substr.to_string();
266+
}
267+
trimmed_part
268+
}
269+
}
270+
271+
impl TrimmedSubstitutionPart {
236272
pub fn is_addition(&self, sm: &SourceMap) -> bool {
237273
!self.snippet.is_empty() && !self.replaces_meaningful_content(sm)
238274
}
@@ -260,27 +296,6 @@ impl SubstitutionPart {
260296
sm.span_to_snippet(self.span)
261297
.map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
262298
}
263-
264-
/// Try to turn a replacement into an addition when the span that is being
265-
/// overwritten matches either the prefix or suffix of the replacement.
266-
fn trim_trivial_replacements(&mut self, sm: &SourceMap) {
267-
if self.snippet.is_empty() {
268-
return;
269-
}
270-
let Ok(snippet) = sm.span_to_snippet(self.span) else {
271-
return;
272-
};
273-
274-
if let Some((prefix, substr, suffix)) = as_substr(&snippet, &self.snippet) {
275-
self.span = Span::new(
276-
self.span.lo() + BytePos(prefix as u32),
277-
self.span.hi() - BytePos(suffix as u32),
278-
self.span.ctxt(),
279-
self.span.parent(),
280-
);
281-
self.snippet = substr.to_string();
282-
}
283-
}
284299
}
285300

286301
/// Given an original string like `AACC`, and a suggestion like `AABBCC`, try to detect
@@ -310,7 +325,8 @@ impl CodeSuggestion {
310325
pub(crate) fn splice_lines(
311326
&self,
312327
sm: &SourceMap,
313-
) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)> {
328+
) -> Vec<(String, Vec<TrimmedSubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)>
329+
{
314330
// For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
315331
// corresponds to the output snippet's lines, while the second level corresponds to the
316332
// substrings within that line that should be highlighted.
@@ -428,12 +444,17 @@ impl CodeSuggestion {
428444
// or deleted code in order to point at the correct column *after* substitution.
429445
let mut acc = 0;
430446
let mut confusion_type = ConfusionType::None;
431-
for part in &mut substitution.parts {
447+
448+
let trimmed_parts = substitution
449+
.parts
450+
.into_iter()
432451
// If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the
433452
// suggestion and snippet to look as if we just suggested to add
434453
// `"b"`, which is typically much easier for the user to understand.
435-
part.trim_trivial_replacements(sm);
454+
.map(|part| part.trim_trivial_replacements(sm))
455+
.collect::<Vec<_>>();
436456

457+
for part in &trimmed_parts {
437458
let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
438459
confusion_type = confusion_type.combine(part_confusion);
439460
let cur_lo = sm.lookup_char_pos(part.span.lo());
@@ -521,7 +542,7 @@ impl CodeSuggestion {
521542
if highlights.iter().all(|parts| parts.is_empty()) {
522543
None
523544
} else {
524-
Some((buf, substitution.parts, highlights, confusion_type))
545+
Some((buf, trimmed_parts, highlights, confusion_type))
525546
}
526547
})
527548
.collect()

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2547,6 +2547,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25472547
"you must specify a type for this binding, like `{concrete_type}`",
25482548
);
25492549

2550+
// FIXME: Maybe FileName::Anon should also be handled,
2551+
// otherwise there would be no suggestion if the source is STDIN for example.
25502552
match (filename, parent_node) {
25512553
(
25522554
FileName::Real(_),
@@ -2568,6 +2570,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25682570
Applicability::MaybeIncorrect,
25692571
);
25702572
}
2573+
// For closure parameters with reference patterns (e.g., |&v|), suggest the type annotation
2574+
// on the pattern itself, e.g., |&v: &i32|
2575+
(FileName::Real(_), Node::Pat(pat))
2576+
if let Node::Pat(binding_pat) = self.tcx.hir_node(hir_id)
2577+
&& let hir::PatKind::Binding(..) = binding_pat.kind
2578+
&& let Node::Pat(parent_pat) = parent_node
2579+
&& matches!(parent_pat.kind, hir::PatKind::Ref(..)) =>
2580+
{
2581+
err.span_label(span, "you must specify a type for this binding");
2582+
2583+
let mut ref_muts = Vec::new();
2584+
let mut current_node = parent_node;
2585+
2586+
while let Node::Pat(parent_pat) = current_node {
2587+
if let hir::PatKind::Ref(_, mutability) = parent_pat.kind {
2588+
ref_muts.push(mutability);
2589+
current_node = self.tcx.parent_hir_node(parent_pat.hir_id);
2590+
} else {
2591+
break;
2592+
}
2593+
}
2594+
2595+
let mut type_annotation = String::new();
2596+
for mutability in ref_muts.iter().rev() {
2597+
match mutability {
2598+
hir::Mutability::Mut => type_annotation.push_str("&mut "),
2599+
hir::Mutability::Not => type_annotation.push('&'),
2600+
}
2601+
}
2602+
type_annotation.push_str(&concrete_type);
2603+
2604+
err.span_suggestion_verbose(
2605+
pat.span.shrink_to_hi(),
2606+
"specify the type in the closure argument list",
2607+
format!(": {type_annotation}"),
2608+
Applicability::MaybeIncorrect,
2609+
);
2610+
}
25712611
_ => {
25722612
err.span_label(span, msg);
25732613
}

library/alloc/src/collections/btree/node.rs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
use core::marker::PhantomData;
3535
use core::mem::{self, MaybeUninit};
36+
use core::num::NonZero;
3637
use core::ptr::{self, NonNull};
3738
use core::slice::SliceIndex;
3839

@@ -143,7 +144,7 @@ type BoxedNode<K, V> = NonNull<LeafNode<K, V>>;
143144
///
144145
/// A reference to a node.
145146
///
146-
/// This type has a number of parameters that controls how it acts:
147+
/// This type has a number of parameters that control how it acts:
147148
/// - `BorrowType`: A dummy type that describes the kind of borrow and carries a lifetime.
148149
/// - When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`.
149150
/// - When this is `ValMut<'a>`, the `NodeRef` acts roughly like `&'a Node`
@@ -226,33 +227,27 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
226227

227228
fn from_new_leaf<A: Allocator + Clone>(leaf: Box<LeafNode<K, V>, A>) -> Self {
228229
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
229-
let (leaf, _alloc) = Box::into_raw_with_allocator(leaf);
230-
// SAFETY: the node was just allocated.
231-
let node = unsafe { NonNull::new_unchecked(leaf) };
230+
let (node, _alloc) = Box::into_non_null_with_allocator(leaf);
232231
NodeRef { height: 0, node, _marker: PhantomData }
233232
}
234233
}
235234

236235
impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
236+
/// Creates a new internal (height > 0) `NodeRef`
237237
fn new_internal<A: Allocator + Clone>(child: Root<K, V>, alloc: A) -> Self {
238238
let mut new_node = unsafe { InternalNode::new(alloc) };
239239
new_node.edges[0].write(child.node);
240-
unsafe { NodeRef::from_new_internal(new_node, child.height + 1) }
240+
NodeRef::from_new_internal(new_node, NonZero::new(child.height + 1).unwrap())
241241
}
242242

243-
/// # Safety
244-
/// `height` must not be zero.
245-
unsafe fn from_new_internal<A: Allocator + Clone>(
243+
/// Creates a new internal (height > 0) `NodeRef` from an existing internal node
244+
fn from_new_internal<A: Allocator + Clone>(
246245
internal: Box<InternalNode<K, V>, A>,
247-
height: usize,
246+
height: NonZero<usize>,
248247
) -> Self {
249-
debug_assert!(height > 0);
250248
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
251-
let (internal, _alloc) = Box::into_raw_with_allocator(internal);
252-
// SAFETY: the node was just allocated.
253-
let internal = unsafe { NonNull::new_unchecked(internal) };
254-
let node = internal.cast();
255-
let mut this = NodeRef { height, node, _marker: PhantomData };
249+
let (node, _alloc) = Box::into_non_null_with_allocator(internal);
250+
let mut this = NodeRef { height: height.into(), node: node.cast(), _marker: PhantomData };
256251
this.borrow_mut().correct_all_childrens_parent_links();
257252
this
258253
}
@@ -625,9 +620,8 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
625620
let top = self.node;
626621

627622
// SAFETY: we asserted to be internal.
628-
let internal_self = unsafe { self.borrow_mut().cast_to_internal_unchecked() };
629-
// SAFETY: we borrowed `self` exclusively and its borrow type is exclusive.
630-
let internal_node = unsafe { &mut *NodeRef::as_internal_ptr(&internal_self) };
623+
let mut internal_self = unsafe { self.borrow_mut().cast_to_internal_unchecked() };
624+
let internal_node = internal_self.as_internal_mut();
631625
// SAFETY: the first edge is always initialized.
632626
self.node = unsafe { internal_node.edges[0].assume_init_read() };
633627
self.height -= 1;
@@ -1305,7 +1299,8 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
13051299
&mut new_node.edges[..new_len + 1],
13061300
);
13071301

1308-
let height = self.node.height;
1302+
// SAFETY: self is `marker::Internal`, so `self.node.height` is positive
1303+
let height = NonZero::new_unchecked(self.node.height);
13091304
let right = NodeRef::from_new_internal(new_node, height);
13101305

13111306
SplitResult { left: self.node, kv, right }

0 commit comments

Comments
 (0)