Skip to content

Commit b013e69

Browse files
committed
Auto merge of rust-lang#13496 - y21:issue10619, r=Alexendoo
Show interior mutability chain in `mutable_key_type` Fixes rust-lang#10619 Just ran into this myself and I definitely agree it's not very nice to have to manually go through all the types involved to figure out why this happens and to evaluate if this is really a problem (knowing if the field of a struct is something that a hash impl relies on), so this changes the lint to emit notes for each step involved. changelog: none
2 parents 1c9e5d0 + 19d1358 commit b013e69

File tree

3 files changed

+98
-23
lines changed

3 files changed

+98
-23
lines changed

clippy_lints/src/mut_key.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use clippy_config::Conf;
2-
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::diagnostics::span_lint_and_then;
33
use clippy_utils::trait_ref_of_method;
44
use clippy_utils::ty::InteriorMut;
55
use rustc_hir as hir;
66
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_middle::ty::print::with_forced_trimmed_paths;
78
use rustc_middle::ty::{self, Ty, TyCtxt};
89
use rustc_session::impl_lint_pass;
910
use rustc_span::Span;
@@ -132,8 +133,14 @@ impl<'tcx> MutableKeyType<'tcx> {
132133
)
133134
{
134135
let subst_ty = args.type_at(0);
135-
if self.interior_mut.is_interior_mut_ty(cx, subst_ty) {
136-
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
136+
if let Some(chain) = self.interior_mut.interior_mut_ty_chain(cx, subst_ty) {
137+
span_lint_and_then(cx, MUTABLE_KEY_TYPE, span, "mutable key type", |diag| {
138+
for ty in chain.iter().rev() {
139+
diag.note(with_forced_trimmed_paths!(format!(
140+
"... because it contains `{ty}`, which has interior mutability"
141+
)));
142+
}
143+
});
137144
}
138145
}
139146
}

clippy_utils/src/ty.rs

+28-20
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ pub fn make_normalized_projection<'tcx>(
11681168
pub struct InteriorMut<'tcx> {
11691169
ignored_def_ids: FxHashSet<DefId>,
11701170
ignore_pointers: bool,
1171-
tys: FxHashMap<Ty<'tcx>, Option<bool>>,
1171+
tys: FxHashMap<Ty<'tcx>, Option<&'tcx ty::List<Ty<'tcx>>>>,
11721172
}
11731173

11741174
impl<'tcx> InteriorMut<'tcx> {
@@ -1194,25 +1194,24 @@ impl<'tcx> InteriorMut<'tcx> {
11941194
}
11951195
}
11961196

1197-
/// Check if given type has inner mutability such as [`std::cell::Cell`] or
1198-
/// [`std::cell::RefCell`] etc.
1199-
pub fn is_interior_mut_ty(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
1197+
/// Check if given type has interior mutability such as [`std::cell::Cell`] or
1198+
/// [`std::cell::RefCell`] etc. and if it does, returns a chain of types that causes
1199+
/// this type to be interior mutable
1200+
pub fn interior_mut_ty_chain(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx ty::List<Ty<'tcx>>> {
12001201
match self.tys.entry(ty) {
1201-
Entry::Occupied(o) => return *o.get() == Some(true),
1202+
Entry::Occupied(o) => return *o.get(),
12021203
// Temporarily insert a `None` to break cycles
12031204
Entry::Vacant(v) => v.insert(None),
12041205
};
12051206

1206-
let interior_mut = match *ty.kind() {
1207-
ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.is_interior_mut_ty(cx, inner_ty),
1208-
ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.is_interior_mut_ty(cx, inner_ty),
1209-
ty::Array(inner_ty, size) => {
1210-
size.try_eval_target_usize(cx.tcx, cx.param_env)
1211-
.map_or(true, |u| u != 0)
1212-
&& self.is_interior_mut_ty(cx, inner_ty)
1207+
let chain = match *ty.kind() {
1208+
ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain(cx, inner_ty),
1209+
ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain(cx, inner_ty),
1210+
ty::Array(inner_ty, size) if size.try_eval_target_usize(cx.tcx, cx.param_env) != Some(0) => {
1211+
self.interior_mut_ty_chain(cx, inner_ty)
12131212
},
1214-
ty::Tuple(fields) => fields.iter().any(|ty| self.is_interior_mut_ty(cx, ty)),
1215-
ty::Adt(def, _) if def.is_unsafe_cell() => true,
1213+
ty::Tuple(fields) => fields.iter().find_map(|ty| self.interior_mut_ty_chain(cx, ty)),
1214+
ty::Adt(def, _) if def.is_unsafe_cell() => Some(ty::List::empty()),
12161215
ty::Adt(def, args) => {
12171216
let is_std_collection = matches!(
12181217
cx.tcx.get_diagnostic_name(def.did()),
@@ -1231,19 +1230,28 @@ impl<'tcx> InteriorMut<'tcx> {
12311230

12321231
if is_std_collection || def.is_box() {
12331232
// Include the types from std collections that are behind pointers internally
1234-
args.types().any(|ty| self.is_interior_mut_ty(cx, ty))
1233+
args.types().find_map(|ty| self.interior_mut_ty_chain(cx, ty))
12351234
} else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() {
1236-
false
1235+
None
12371236
} else {
12381237
def.all_fields()
1239-
.any(|f| self.is_interior_mut_ty(cx, f.ty(cx.tcx, args)))
1238+
.find_map(|f| self.interior_mut_ty_chain(cx, f.ty(cx.tcx, args)))
12401239
}
12411240
},
1242-
_ => false,
1241+
_ => None,
12431242
};
12441243

1245-
self.tys.insert(ty, Some(interior_mut));
1246-
interior_mut
1244+
chain.map(|chain| {
1245+
let list = cx.tcx.mk_type_list_from_iter(chain.iter().chain([ty]));
1246+
self.tys.insert(ty, Some(list));
1247+
list
1248+
})
1249+
}
1250+
1251+
/// Check if given type has interior mutability such as [`std::cell::Cell`] or
1252+
/// [`std::cell::RefCell`] etc.
1253+
pub fn is_interior_mut_ty(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
1254+
self.interior_mut_ty_chain(cx, ty).is_some()
12471255
}
12481256
}
12491257

tests/ui/mut_key.stderr

+60
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ error: mutable key type
44
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7+
= note: ... because it contains `Key`, which has interior mutability
8+
= note: ... because it contains `AtomicUsize`, which has interior mutability
9+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
710
= note: `-D clippy::mutable-key-type` implied by `-D warnings`
811
= help: to override `-D warnings` add `#[allow(clippy::mutable_key_type)]`
912

@@ -12,84 +15,141 @@ error: mutable key type
1215
|
1316
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
1417
| ^^^^^^^^^^^^
18+
|
19+
= note: ... because it contains `Key`, which has interior mutability
20+
= note: ... because it contains `AtomicUsize`, which has interior mutability
21+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
1522

1623
error: mutable key type
1724
--> tests/ui/mut_key.rs:35:5
1825
|
1926
LL | let _other: HashMap<Key, bool> = HashMap::new();
2027
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28+
|
29+
= note: ... because it contains `Key`, which has interior mutability
30+
= note: ... because it contains `AtomicUsize`, which has interior mutability
31+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
2132

2233
error: mutable key type
2334
--> tests/ui/mut_key.rs:63:22
2435
|
2536
LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
2637
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
|
39+
= note: ... because it contains `(Key, U)`, which has interior mutability
40+
= note: ... because it contains `Key`, which has interior mutability
41+
= note: ... because it contains `AtomicUsize`, which has interior mutability
42+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
2743

2844
error: mutable key type
2945
--> tests/ui/mut_key.rs:76:5
3046
|
3147
LL | let _map = HashMap::<Cell<usize>, usize>::new();
3248
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
|
50+
= note: ... because it contains `Cell<usize>`, which has interior mutability
51+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
3352

3453
error: mutable key type
3554
--> tests/ui/mut_key.rs:78:5
3655
|
3756
LL | let _map = HashMap::<&mut Cell<usize>, usize>::new();
3857
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
58+
|
59+
= note: ... because it contains `&mut Cell<usize>`, which has interior mutability
60+
= note: ... because it contains `Cell<usize>`, which has interior mutability
61+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
3962

4063
error: mutable key type
4164
--> tests/ui/mut_key.rs:81:5
4265
|
4366
LL | let _map = HashMap::<Vec<Cell<usize>>, usize>::new();
4467
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68+
|
69+
= note: ... because it contains `Vec<Cell<usize>>`, which has interior mutability
70+
= note: ... because it contains `Cell<usize>`, which has interior mutability
71+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
4572

4673
error: mutable key type
4774
--> tests/ui/mut_key.rs:83:5
4875
|
4976
LL | let _map = HashMap::<BTreeMap<Cell<usize>, ()>, usize>::new();
5077
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
78+
|
79+
= note: ... because it contains `BTreeMap<Cell<usize>, ()>`, which has interior mutability
80+
= note: ... because it contains `Cell<usize>`, which has interior mutability
81+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
5182

5283
error: mutable key type
5384
--> tests/ui/mut_key.rs:85:5
5485
|
5586
LL | let _map = HashMap::<BTreeMap<(), Cell<usize>>, usize>::new();
5687
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
88+
|
89+
= note: ... because it contains `BTreeMap<(), Cell<usize>>`, which has interior mutability
90+
= note: ... because it contains `Cell<usize>`, which has interior mutability
91+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
5792

5893
error: mutable key type
5994
--> tests/ui/mut_key.rs:87:5
6095
|
6196
LL | let _map = HashMap::<BTreeSet<Cell<usize>>, usize>::new();
6297
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
98+
|
99+
= note: ... because it contains `BTreeSet<Cell<usize>>`, which has interior mutability
100+
= note: ... because it contains `Cell<usize>`, which has interior mutability
101+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
63102

64103
error: mutable key type
65104
--> tests/ui/mut_key.rs:89:5
66105
|
67106
LL | let _map = HashMap::<Option<Cell<usize>>, usize>::new();
68107
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
108+
|
109+
= note: ... because it contains `Option<Cell<usize>>`, which has interior mutability
110+
= note: ... because it contains `Cell<usize>`, which has interior mutability
111+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
69112

70113
error: mutable key type
71114
--> tests/ui/mut_key.rs:91:5
72115
|
73116
LL | let _map = HashMap::<Option<Vec<Cell<usize>>>, usize>::new();
74117
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
118+
|
119+
= note: ... because it contains `Option<Vec<Cell<usize>>>`, which has interior mutability
120+
= note: ... because it contains `Vec<Cell<usize>>`, which has interior mutability
121+
= note: ... because it contains `Cell<usize>`, which has interior mutability
122+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
75123

76124
error: mutable key type
77125
--> tests/ui/mut_key.rs:94:5
78126
|
79127
LL | let _map = HashMap::<Box<Cell<usize>>, usize>::new();
80128
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
129+
|
130+
= note: ... because it contains `Box<Cell<usize>>`, which has interior mutability
131+
= note: ... because it contains `Cell<usize>`, which has interior mutability
132+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
81133

82134
error: mutable key type
83135
--> tests/ui/mut_key.rs:96:5
84136
|
85137
LL | let _map = HashMap::<Rc<Cell<usize>>, usize>::new();
86138
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
139+
|
140+
= note: ... because it contains `Rc<Cell<usize>>`, which has interior mutability
141+
= note: ... because it contains `Cell<usize>`, which has interior mutability
142+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
87143

88144
error: mutable key type
89145
--> tests/ui/mut_key.rs:98:5
90146
|
91147
LL | let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
92148
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
149+
|
150+
= note: ... because it contains `Arc<Cell<usize>>`, which has interior mutability
151+
= note: ... because it contains `Cell<usize>`, which has interior mutability
152+
= note: ... because it contains `UnsafeCell<usize>`, which has interior mutability
93153

94154
error: aborting due to 15 previous errors
95155

0 commit comments

Comments
 (0)