Skip to content

Commit df986a9

Browse files
committed
Add rustc_confusables annotations to some stdlib APIs
Help with common API confusion, like asking for `push` when the data structure really has `append`. ``` error[E0599]: no method named `size` found for struct `Vec<{integer}>` in the current scope --> $DIR/rustc_confusables_std_cases.rs:17:7 | LL | x.size(); | ^^^^ | help: you might have meant to use `len` | LL | x.len(); | ~~~ help: there is a method with a similar name | LL | x.resize(); | ~~~~~~ ``` rust-lang#59450
1 parent bdc1592 commit df986a9

File tree

20 files changed

+180
-29
lines changed

20 files changed

+180
-29
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+32-27
Original file line numberDiff line numberDiff line change
@@ -1113,32 +1113,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11131113
err.note(format!(
11141114
"the {item_kind} was found for\n{type_candidates}{additional_types}"
11151115
));
1116-
} else {
1117-
'outer: for inherent_impl_did in
1118-
self.tcx.inherent_impls(adt.did()).into_iter().flatten()
1119-
{
1120-
for inherent_method in
1121-
self.tcx.associated_items(inherent_impl_did).in_definition_order()
1122-
{
1123-
if let Some(attr) = self
1124-
.tcx
1125-
.get_attr(inherent_method.def_id, sym::rustc_confusables)
1126-
&& let Some(candidates) = parse_confusables(attr)
1127-
&& candidates.contains(&item_name.name)
1128-
{
1129-
err.span_suggestion_verbose(
1130-
item_name.span,
1131-
format!(
1132-
"you might have meant to use `{}`",
1133-
inherent_method.name
1134-
),
1135-
inherent_method.name,
1136-
Applicability::MaybeIncorrect,
1137-
);
1138-
break 'outer;
1139-
}
1140-
}
1141-
}
11421116
}
11431117
}
11441118
} else {
@@ -1164,6 +1138,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11641138
label_span_not_found(&mut err);
11651139
}
11661140

1141+
let mut confusable_suggested = None;
1142+
if let ty::Adt(adt, _) = rcvr_ty.kind() {
1143+
'outer: for inherent_impl_did in
1144+
self.tcx.inherent_impls(adt.did()).into_iter().flatten()
1145+
{
1146+
for inherent_method in
1147+
self.tcx.associated_items(inherent_impl_did).in_definition_order()
1148+
{
1149+
if let Some(attr) =
1150+
self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables)
1151+
&& let Some(candidates) = parse_confusables(attr)
1152+
&& candidates.contains(&item_name.name)
1153+
{
1154+
{
1155+
err.span_suggestion_verbose(
1156+
item_name.span,
1157+
format!("you might have meant to use `{}`", inherent_method.name),
1158+
inherent_method.name,
1159+
Applicability::MaybeIncorrect,
1160+
);
1161+
confusable_suggested = Some(inherent_method.name);
1162+
break 'outer;
1163+
}
1164+
}
1165+
}
1166+
}
1167+
}
1168+
11671169
// Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
11681170
// can't be called due to `typeof(expr): Clone` not holding.
11691171
if unsatisfied_predicates.is_empty() {
@@ -1265,7 +1267,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12651267
} else if let Some(similar_candidate) = similar_candidate {
12661268
// Don't emit a suggestion if we found an actual method
12671269
// that had unsatisfied trait bounds
1268-
if unsatisfied_predicates.is_empty() {
1270+
if unsatisfied_predicates.is_empty()
1271+
// ...or if we already suggested that name because of `rustc_confusable` annotation.
1272+
&& Some(similar_candidate.name) != confusable_suggested
1273+
{
12691274
let def_kind = similar_candidate.kind.as_def_kind();
12701275
// Methods are defined within the context of a struct and their first parameter is always self,
12711276
// which represents the instance of the struct the method is being called on

library/alloc/src/collections/binary_heap/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ impl<T: Ord, A: Allocator> BinaryHeap<T, A> {
607607
/// occurs when capacity is exhausted and needs a resize. The resize cost
608608
/// has been amortized in the previous figures.
609609
#[stable(feature = "rust1", since = "1.0.0")]
610+
#[rustc_confusables("append", "put")]
610611
pub fn push(&mut self, item: T) {
611612
let old_len = self.len();
612613
self.data.push(item);
@@ -1264,6 +1265,7 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
12641265
/// ```
12651266
#[must_use]
12661267
#[stable(feature = "rust1", since = "1.0.0")]
1268+
#[rustc_confusables("length", "size")]
12671269
pub fn len(&self) -> usize {
12681270
self.data.len()
12691271
}

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

+3
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
979979
/// assert_eq!(map[&37], "c");
980980
/// ```
981981
#[stable(feature = "rust1", since = "1.0.0")]
982+
#[rustc_confusables("push", "put", "set")]
982983
pub fn insert(&mut self, key: K, value: V) -> Option<V>
983984
where
984985
K: Ord,
@@ -1041,6 +1042,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
10411042
/// assert_eq!(map.remove(&1), None);
10421043
/// ```
10431044
#[stable(feature = "rust1", since = "1.0.0")]
1045+
#[rustc_confusables("delete", "take")]
10441046
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
10451047
where
10461048
K: Borrow<Q> + Ord,
@@ -2495,6 +2497,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
24952497
issue = "71835",
24962498
implied_by = "const_btree_new"
24972499
)]
2500+
#[rustc_confusables("length", "size")]
24982501
pub const fn len(&self) -> usize {
24992502
self.length
25002503
}

library/alloc/src/collections/btree/map/entry.rs

+3
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> {
347347
/// assert_eq!(map["poneyland"], 37);
348348
/// ```
349349
#[stable(feature = "rust1", since = "1.0.0")]
350+
#[rustc_confusables("push", "put")]
350351
pub fn insert(mut self, value: V) -> &'a mut V {
351352
let out_ptr = match self.handle {
352353
None => {
@@ -524,6 +525,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> OccupiedEntry<'a, K, V, A> {
524525
/// assert_eq!(map["poneyland"], 15);
525526
/// ```
526527
#[stable(feature = "rust1", since = "1.0.0")]
528+
#[rustc_confusables("push", "put")]
527529
pub fn insert(&mut self, value: V) -> V {
528530
mem::replace(self.get_mut(), value)
529531
}
@@ -546,6 +548,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> OccupiedEntry<'a, K, V, A> {
546548
/// // println!("{}", map["poneyland"]);
547549
/// ```
548550
#[stable(feature = "rust1", since = "1.0.0")]
551+
#[rustc_confusables("delete", "take")]
549552
pub fn remove(self) -> V {
550553
self.remove_kv().1
551554
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
790790
/// ```
791791
#[must_use]
792792
#[stable(feature = "map_first_last", since = "1.66.0")]
793+
#[rustc_confusables("front")]
793794
pub fn first(&self) -> Option<&T>
794795
where
795796
T: Ord,
@@ -816,6 +817,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
816817
/// ```
817818
#[must_use]
818819
#[stable(feature = "map_first_last", since = "1.66.0")]
820+
#[rustc_confusables("back")]
819821
pub fn last(&self) -> Option<&T>
820822
where
821823
T: Ord,
@@ -896,6 +898,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
896898
/// assert_eq!(set.len(), 1);
897899
/// ```
898900
#[stable(feature = "rust1", since = "1.0.0")]
901+
#[rustc_confusables("push", "put")]
899902
pub fn insert(&mut self, value: T) -> bool
900903
where
901904
T: Ord,
@@ -919,6 +922,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
919922
/// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10);
920923
/// ```
921924
#[stable(feature = "set_recovery", since = "1.9.0")]
925+
#[rustc_confusables("swap")]
922926
pub fn replace(&mut self, value: T) -> Option<T>
923927
where
924928
T: Ord,
@@ -1152,6 +1156,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
11521156
issue = "71835",
11531157
implied_by = "const_btree_new"
11541158
)]
1159+
#[rustc_confusables("length", "size")]
11551160
pub const fn len(&self) -> usize {
11561161
self.map.len()
11571162
}

library/alloc/src/collections/linked_list.rs

+10
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
656656
#[inline]
657657
#[must_use]
658658
#[stable(feature = "rust1", since = "1.0.0")]
659+
#[rustc_confusables("length", "size")]
659660
pub fn len(&self) -> usize {
660661
self.len
661662
}
@@ -740,6 +741,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
740741
#[inline]
741742
#[must_use]
742743
#[stable(feature = "rust1", since = "1.0.0")]
744+
#[rustc_confusables("first")]
743745
pub fn front(&self) -> Option<&T> {
744746
unsafe { self.head.as_ref().map(|node| &node.as_ref().element) }
745747
}
@@ -890,6 +892,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
890892
/// assert_eq!(3, *d.back().unwrap());
891893
/// ```
892894
#[stable(feature = "rust1", since = "1.0.0")]
895+
#[rustc_confusables("push", "append")]
893896
pub fn push_back(&mut self, elt: T) {
894897
let node = Box::new_in(Node::new(elt), &self.alloc);
895898
let node_ptr = NonNull::from(Box::leak(node));
@@ -1004,6 +1007,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
10041007
/// assert_eq!(d.remove(0), 1);
10051008
/// ```
10061009
#[unstable(feature = "linked_list_remove", issue = "69210")]
1010+
#[rustc_confusables("delete", "take")]
10071011
pub fn remove(&mut self, at: usize) -> T {
10081012
let len = self.len();
10091013
assert!(at < len, "Cannot remove at an index outside of the list bounds");
@@ -1478,6 +1482,7 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> {
14781482
/// or None if the list is empty.
14791483
#[must_use]
14801484
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1485+
#[rustc_confusables("first")]
14811486
pub fn front(&self) -> Option<&'a T> {
14821487
self.list.front()
14831488
}
@@ -1486,6 +1491,7 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> {
14861491
/// or None if the list is empty.
14871492
#[must_use]
14881493
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1494+
#[rustc_confusables("last")]
14891495
pub fn back(&self) -> Option<&'a T> {
14901496
self.list.back()
14911497
}
@@ -1788,6 +1794,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
17881794
///
17891795
/// This operation should compute in *O*(1) time.
17901796
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1797+
#[rustc_confusables("push", "append")]
17911798
pub fn push_back(&mut self, elt: T) {
17921799
// Safety: We know that `push_back` does not change the position in
17931800
// memory of other nodes. This ensures that `self.current` remains
@@ -1834,6 +1841,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
18341841
///
18351842
/// This operation should compute in *O*(1) time.
18361843
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1844+
#[rustc_confusables("pop")]
18371845
pub fn pop_back(&mut self) -> Option<T> {
18381846
if self.list.is_empty() {
18391847
None
@@ -1854,6 +1862,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
18541862
/// or None if the list is empty.
18551863
#[must_use]
18561864
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1865+
#[rustc_confusables("first")]
18571866
pub fn front(&self) -> Option<&T> {
18581867
self.list.front()
18591868
}
@@ -1870,6 +1879,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
18701879
/// or None if the list is empty.
18711880
#[must_use]
18721881
#[unstable(feature = "linked_list_cursors", issue = "58533")]
1882+
#[rustc_confusables("last")]
18731883
pub fn back(&self) -> Option<&T> {
18741884
self.list.back()
18751885
}

library/alloc/src/collections/vec_deque/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
12091209
/// assert_eq!(deque.len(), 1);
12101210
/// ```
12111211
#[stable(feature = "rust1", since = "1.0.0")]
1212+
#[rustc_confusables("length", "size")]
12121213
pub fn len(&self) -> usize {
12131214
self.len
12141215
}
@@ -1491,6 +1492,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
14911492
/// assert_eq!(d.front(), Some(&1));
14921493
/// ```
14931494
#[stable(feature = "rust1", since = "1.0.0")]
1495+
#[rustc_confusables("first")]
14941496
pub fn front(&self) -> Option<&T> {
14951497
self.get(0)
14961498
}
@@ -1535,6 +1537,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
15351537
/// assert_eq!(d.back(), Some(&2));
15361538
/// ```
15371539
#[stable(feature = "rust1", since = "1.0.0")]
1540+
#[rustc_confusables("last")]
15381541
pub fn back(&self) -> Option<&T> {
15391542
self.get(self.len.wrapping_sub(1))
15401543
}
@@ -1654,6 +1657,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
16541657
/// assert_eq!(3, *buf.back().unwrap());
16551658
/// ```
16561659
#[stable(feature = "rust1", since = "1.0.0")]
1660+
#[rustc_confusables("push", "put", "append")]
16571661
pub fn push_back(&mut self, value: T) {
16581662
if self.is_full() {
16591663
self.grow();
@@ -1813,6 +1817,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
18131817
/// assert_eq!(buf, [1, 3]);
18141818
/// ```
18151819
#[stable(feature = "rust1", since = "1.0.0")]
1820+
#[rustc_confusables("delete", "take")]
18161821
pub fn remove(&mut self, index: usize) -> Option<T> {
18171822
if self.len <= index {
18181823
return None;

library/alloc/src/string.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,7 @@ impl String {
14451445
/// ```
14461446
#[inline]
14471447
#[stable(feature = "rust1", since = "1.0.0")]
1448+
#[rustc_confusables("delete", "take")]
14481449
pub fn remove(&mut self, idx: usize) -> char {
14491450
let ch = match self[idx..].chars().next() {
14501451
Some(ch) => ch,
@@ -1639,6 +1640,7 @@ impl String {
16391640
#[cfg(not(no_global_oom_handling))]
16401641
#[inline]
16411642
#[stable(feature = "rust1", since = "1.0.0")]
1643+
#[rustc_confusables("set")]
16421644
pub fn insert(&mut self, idx: usize, ch: char) {
16431645
assert!(self.is_char_boundary(idx));
16441646
let mut bits = [0; 4];
@@ -1738,6 +1740,7 @@ impl String {
17381740
#[inline]
17391741
#[must_use]
17401742
#[stable(feature = "rust1", since = "1.0.0")]
1743+
#[rustc_confusables("length", "size")]
17411744
pub fn len(&self) -> usize {
17421745
self.vec.len()
17431746
}

library/alloc/src/vec/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1554,6 +1554,7 @@ impl<T, A: Allocator> Vec<T, A> {
15541554
/// ```
15551555
#[stable(feature = "rust1", since = "1.0.0")]
15561556
#[track_caller]
1557+
#[rustc_confusables("delete", "take")]
15571558
pub fn remove(&mut self, index: usize) -> T {
15581559
#[cold]
15591560
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
@@ -1915,6 +1916,7 @@ impl<T, A: Allocator> Vec<T, A> {
19151916
#[cfg(not(no_global_oom_handling))]
19161917
#[inline]
19171918
#[stable(feature = "rust1", since = "1.0.0")]
1919+
#[rustc_confusables("push_back", "put", "append")]
19181920
pub fn push(&mut self, value: T) {
19191921
// This will panic or abort if we would allocate > isize::MAX bytes
19201922
// or if the length increment would overflow for zero-sized types.
@@ -2141,6 +2143,7 @@ impl<T, A: Allocator> Vec<T, A> {
21412143
/// ```
21422144
#[inline]
21432145
#[stable(feature = "rust1", since = "1.0.0")]
2146+
#[rustc_confusables("length", "size")]
21442147
pub fn len(&self) -> usize {
21452148
self.len
21462149
}

library/core/src/cell.rs

+2
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ impl<T> Cell<T> {
471471
/// ```
472472
#[inline]
473473
#[stable(feature = "move_cell", since = "1.17.0")]
474+
#[rustc_confusables("swap")]
474475
pub fn replace(&self, val: T) -> T {
475476
// SAFETY: This can cause data races if called from a separate thread,
476477
// but `Cell` is `!Sync` so this won't happen.
@@ -862,6 +863,7 @@ impl<T> RefCell<T> {
862863
#[inline]
863864
#[stable(feature = "refcell_replace", since = "1.24.0")]
864865
#[track_caller]
866+
#[rustc_confusables("swap")]
865867
pub fn replace(&self, t: T) -> T {
866868
mem::replace(&mut *self.borrow_mut(), t)
867869
}

library/proc_macro/src/bridge/scoped_cell.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ impl<T: LambdaL> ScopedCell<T> {
4343
/// running `f`, which gets the old value, mutably.
4444
/// The old value will be restored after `f` exits, even
4545
/// by panic, including modifications made to it by `f`.
46+
#[rustc_confusables("swap")]
4647
pub fn replace<'a, R>(
4748
&self,
4849
replacement: <T as ApplyL<'a>>::Out,

library/std/src/collections/hash/map.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,7 @@ where
11011101
/// ```
11021102
#[inline]
11031103
#[stable(feature = "rust1", since = "1.0.0")]
1104+
#[rustc_confusables("push", "append")]
11041105
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
11051106
self.base.insert(k, v)
11061107
}
@@ -1155,6 +1156,7 @@ where
11551156
/// ```
11561157
#[inline]
11571158
#[stable(feature = "rust1", since = "1.0.0")]
1159+
#[rustc_confusables("delete", "take")]
11581160
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
11591161
where
11601162
K: Borrow<Q>,

0 commit comments

Comments
 (0)