Skip to content

Commit 0c13a9c

Browse files
committed
smarter E0390
1 parent 5957f20 commit 0c13a9c

File tree

6 files changed

+148
-7
lines changed

6 files changed

+148
-7
lines changed

compiler/rustc_error_codes/src/error_codes/E0390.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
A method was implemented on a primitive type.
1+
A method or constant was implemented on a primitive type.
22

33
Erroneous code example:
44

@@ -12,7 +12,8 @@ impl *mut Foo {}
1212
// `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive
1313
```
1414

15-
This isn't allowed, but using a trait to implement a method is a good solution.
15+
This isn't allowed, but using a trait to implement a method or constant
16+
is a good solution.
1617
Example:
1718

1819
```

compiler/rustc_typeck/src/coherence/inherent_impls.rs

+55-3
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ struct InherentCollect<'tcx> {
4444

4545
impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
4646
fn visit_item(&mut self, item: &hir::Item<'_>) {
47-
let ty = match item.kind {
48-
hir::ItemKind::Impl { of_trait: None, ref self_ty, .. } => self_ty,
47+
let (ty, assoc_items) = match item.kind {
48+
hir::ItemKind::Impl { of_trait: None, ref self_ty, items, .. } => (self_ty, items),
4949
_ => return,
5050
};
5151

@@ -70,6 +70,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
7070
"bool",
7171
"bool",
7272
item.span,
73+
assoc_items,
7374
);
7475
}
7576
ty::Char => {
@@ -80,6 +81,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
8081
"char",
8182
"char",
8283
item.span,
84+
assoc_items,
8385
);
8486
}
8587
ty::Str => {
@@ -90,6 +92,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
9092
"str",
9193
"str",
9294
item.span,
95+
assoc_items,
9396
);
9497
}
9598
ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
@@ -100,6 +103,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
100103
"slice_u8",
101104
"[u8]",
102105
item.span,
106+
assoc_items,
103107
);
104108
}
105109
ty::Slice(_) => {
@@ -110,6 +114,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
110114
"slice",
111115
"[T]",
112116
item.span,
117+
assoc_items,
113118
);
114119
}
115120
ty::Array(_, _) => {
@@ -120,6 +125,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
120125
"array",
121126
"[T; N]",
122127
item.span,
128+
assoc_items,
123129
);
124130
}
125131
ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not })
@@ -132,6 +138,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
132138
"const_slice_ptr",
133139
"*const [T]",
134140
item.span,
141+
assoc_items,
135142
);
136143
}
137144
ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut })
@@ -144,6 +151,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
144151
"mut_slice_ptr",
145152
"*mut [T]",
146153
item.span,
154+
assoc_items,
147155
);
148156
}
149157
ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => {
@@ -154,6 +162,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
154162
"const_ptr",
155163
"*const T",
156164
item.span,
165+
assoc_items,
157166
);
158167
}
159168
ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => {
@@ -164,6 +173,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
164173
"mut_ptr",
165174
"*mut T",
166175
item.span,
176+
assoc_items,
167177
);
168178
}
169179
ty::Int(ast::IntTy::I8) => {
@@ -174,6 +184,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
174184
"i8",
175185
"i8",
176186
item.span,
187+
assoc_items,
177188
);
178189
}
179190
ty::Int(ast::IntTy::I16) => {
@@ -184,6 +195,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
184195
"i16",
185196
"i16",
186197
item.span,
198+
assoc_items,
187199
);
188200
}
189201
ty::Int(ast::IntTy::I32) => {
@@ -194,6 +206,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
194206
"i32",
195207
"i32",
196208
item.span,
209+
assoc_items,
197210
);
198211
}
199212
ty::Int(ast::IntTy::I64) => {
@@ -204,6 +217,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
204217
"i64",
205218
"i64",
206219
item.span,
220+
assoc_items,
207221
);
208222
}
209223
ty::Int(ast::IntTy::I128) => {
@@ -214,6 +228,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
214228
"i128",
215229
"i128",
216230
item.span,
231+
assoc_items,
217232
);
218233
}
219234
ty::Int(ast::IntTy::Isize) => {
@@ -224,6 +239,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
224239
"isize",
225240
"isize",
226241
item.span,
242+
assoc_items,
227243
);
228244
}
229245
ty::Uint(ast::UintTy::U8) => {
@@ -234,6 +250,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
234250
"u8",
235251
"u8",
236252
item.span,
253+
assoc_items,
237254
);
238255
}
239256
ty::Uint(ast::UintTy::U16) => {
@@ -244,6 +261,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
244261
"u16",
245262
"u16",
246263
item.span,
264+
assoc_items,
247265
);
248266
}
249267
ty::Uint(ast::UintTy::U32) => {
@@ -254,6 +272,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
254272
"u32",
255273
"u32",
256274
item.span,
275+
assoc_items,
257276
);
258277
}
259278
ty::Uint(ast::UintTy::U64) => {
@@ -264,6 +283,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
264283
"u64",
265284
"u64",
266285
item.span,
286+
assoc_items,
267287
);
268288
}
269289
ty::Uint(ast::UintTy::U128) => {
@@ -274,6 +294,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
274294
"u128",
275295
"u128",
276296
item.span,
297+
assoc_items,
277298
);
278299
}
279300
ty::Uint(ast::UintTy::Usize) => {
@@ -284,6 +305,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
284305
"usize",
285306
"usize",
286307
item.span,
308+
assoc_items,
287309
);
288310
}
289311
ty::Float(ast::FloatTy::F32) => {
@@ -294,6 +316,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
294316
"f32",
295317
"f32",
296318
item.span,
319+
assoc_items,
297320
);
298321
}
299322
ty::Float(ast::FloatTy::F64) => {
@@ -304,6 +327,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
304327
"f64",
305328
"f64",
306329
item.span,
330+
assoc_items,
307331
);
308332
}
309333
ty::Error(_) => {}
@@ -369,6 +393,7 @@ impl InherentCollect<'tcx> {
369393
lang: &str,
370394
ty: &str,
371395
span: Span,
396+
assoc_items: &[hir::ImplItemRef<'_>],
372397
) {
373398
match (lang_def_id, lang_def_id2) {
374399
(Some(lang_def_id), _) if lang_def_id == impl_def_id.to_def_id() => {
@@ -387,7 +412,34 @@ impl InherentCollect<'tcx> {
387412
lang,
388413
ty
389414
)
390-
.span_help(span, "consider using a trait to implement these methods")
415+
.span_help(
416+
span,
417+
&format!("consider using a trait{}", {
418+
if assoc_items.len() == 0 {
419+
String::new()
420+
} else {
421+
let plural = assoc_items.len() > 1;
422+
format!(
423+
" to implement {} {}{}",
424+
if plural { "these" } else { "this" },
425+
{
426+
let item_types = assoc_items.iter().map(|x| x.kind);
427+
if item_types.clone().all(|x| x == hir::AssocItemKind::Const) {
428+
"constant"
429+
} else if item_types
430+
.clone()
431+
.all(|x| matches! {x, hir::AssocItemKind::Fn{ .. } })
432+
{
433+
"method"
434+
} else {
435+
"associated item"
436+
}
437+
},
438+
if plural { "s" } else { "" }
439+
)
440+
}
441+
}),
442+
)
391443
.emit();
392444
}
393445
}

src/test/ui/error-codes/E0390.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0390]: only a single inherent implementation marked with `#[lang = "mut_p
44
LL | impl *mut Foo {}
55
| ^^^^^^^^^^^^^^^^
66
|
7-
help: consider using a trait to implement these methods
7+
help: consider using a trait
88
--> $DIR/E0390.rs:5:1
99
|
1010
LL | impl *mut Foo {}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// ignore-tidy-linelength
2+
3+
4+
impl u8 {
5+
//~^ error: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive
6+
pub const B: u8 = 0;
7+
}
8+
9+
impl str {
10+
//~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive
11+
fn foo() {}
12+
fn bar(self) {}
13+
}
14+
15+
impl char {
16+
//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive
17+
pub const B: u8 = 0;
18+
pub const C: u8 = 0;
19+
fn foo() {}
20+
fn bar(self) {}
21+
}
22+
23+
fn main() {}
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
error[E0390]: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive
2+
--> $DIR/kinds-of-primitive-impl.rs:4:1
3+
|
4+
LL | / impl u8 {
5+
LL | |
6+
LL | | pub const B: u8 = 0;
7+
LL | | }
8+
| |_^
9+
|
10+
help: consider using a trait to implement this constant
11+
--> $DIR/kinds-of-primitive-impl.rs:4:1
12+
|
13+
LL | / impl u8 {
14+
LL | |
15+
LL | | pub const B: u8 = 0;
16+
LL | | }
17+
| |_^
18+
19+
error[E0390]: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive
20+
--> $DIR/kinds-of-primitive-impl.rs:9:1
21+
|
22+
LL | / impl str {
23+
LL | |
24+
LL | | fn foo() {}
25+
LL | | fn bar(self) {}
26+
LL | | }
27+
| |_^
28+
|
29+
help: consider using a trait to implement these methods
30+
--> $DIR/kinds-of-primitive-impl.rs:9:1
31+
|
32+
LL | / impl str {
33+
LL | |
34+
LL | | fn foo() {}
35+
LL | | fn bar(self) {}
36+
LL | | }
37+
| |_^
38+
39+
error[E0390]: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive
40+
--> $DIR/kinds-of-primitive-impl.rs:15:1
41+
|
42+
LL | / impl char {
43+
LL | |
44+
LL | | pub const B: u8 = 0;
45+
LL | | pub const C: u8 = 0;
46+
LL | | fn foo() {}
47+
LL | | fn bar(self) {}
48+
LL | | }
49+
| |_^
50+
|
51+
help: consider using a trait to implement these associated items
52+
--> $DIR/kinds-of-primitive-impl.rs:15:1
53+
|
54+
LL | / impl char {
55+
LL | |
56+
LL | | pub const B: u8 = 0;
57+
LL | | pub const C: u8 = 0;
58+
LL | | fn foo() {}
59+
LL | | fn bar(self) {}
60+
LL | | }
61+
| |_^
62+
63+
error: aborting due to 3 previous errors
64+
65+
For more information about this error, try `rustc --explain E0390`.

src/test/ui/single-primitive-inherent-impl.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | |
66
LL | | }
77
| |_^
88
|
9-
help: consider using a trait to implement these methods
9+
help: consider using a trait
1010
--> $DIR/single-primitive-inherent-impl.rs:11:1
1111
|
1212
LL | / impl str {

0 commit comments

Comments
 (0)