Skip to content

smarter E0390 #79772

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions compiler/rustc_error_codes/src/error_codes/E0390.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
A method was implemented on a primitive type.
A method or constant was implemented on a primitive type.

Erroneous code example:

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

This isn't allowed, but using a trait to implement a method is a good solution.
This isn't allowed, but using a trait to implement a method or constant
is a good solution.
Example:

```
Expand Down
57 changes: 54 additions & 3 deletions compiler/rustc_typeck/src/coherence/inherent_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ struct InherentCollect<'tcx> {

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

Expand All @@ -70,6 +70,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"bool",
"bool",
item.span,
assoc_items,
);
}
ty::Char => {
Expand All @@ -80,6 +81,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"char",
"char",
item.span,
assoc_items,
);
}
ty::Str => {
Expand All @@ -90,6 +92,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"str",
"str",
item.span,
assoc_items,
);
}
ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
Expand All @@ -100,6 +103,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"slice_u8",
"[u8]",
item.span,
assoc_items,
);
}
ty::Slice(_) => {
Expand All @@ -110,6 +114,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"slice",
"[T]",
item.span,
assoc_items,
);
}
ty::Array(_, _) => {
Expand All @@ -120,6 +125,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"array",
"[T; N]",
item.span,
assoc_items,
);
}
ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not })
Expand All @@ -132,6 +138,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"const_slice_ptr",
"*const [T]",
item.span,
assoc_items,
);
}
ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut })
Expand All @@ -144,6 +151,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"mut_slice_ptr",
"*mut [T]",
item.span,
assoc_items,
);
}
ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => {
Expand All @@ -154,6 +162,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"const_ptr",
"*const T",
item.span,
assoc_items,
);
}
ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => {
Expand All @@ -164,6 +173,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"mut_ptr",
"*mut T",
item.span,
assoc_items,
);
}
ty::Int(ast::IntTy::I8) => {
Expand All @@ -174,6 +184,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"i8",
"i8",
item.span,
assoc_items,
);
}
ty::Int(ast::IntTy::I16) => {
Expand All @@ -184,6 +195,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"i16",
"i16",
item.span,
assoc_items,
);
}
ty::Int(ast::IntTy::I32) => {
Expand All @@ -194,6 +206,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"i32",
"i32",
item.span,
assoc_items,
);
}
ty::Int(ast::IntTy::I64) => {
Expand All @@ -204,6 +217,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"i64",
"i64",
item.span,
assoc_items,
);
}
ty::Int(ast::IntTy::I128) => {
Expand All @@ -214,6 +228,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"i128",
"i128",
item.span,
assoc_items,
);
}
ty::Int(ast::IntTy::Isize) => {
Expand All @@ -224,6 +239,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"isize",
"isize",
item.span,
assoc_items,
);
}
ty::Uint(ast::UintTy::U8) => {
Expand All @@ -234,6 +250,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"u8",
"u8",
item.span,
assoc_items,
);
}
ty::Uint(ast::UintTy::U16) => {
Expand All @@ -244,6 +261,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"u16",
"u16",
item.span,
assoc_items,
);
}
ty::Uint(ast::UintTy::U32) => {
Expand All @@ -254,6 +272,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"u32",
"u32",
item.span,
assoc_items,
);
}
ty::Uint(ast::UintTy::U64) => {
Expand All @@ -264,6 +283,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"u64",
"u64",
item.span,
assoc_items,
);
}
ty::Uint(ast::UintTy::U128) => {
Expand All @@ -274,6 +294,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"u128",
"u128",
item.span,
assoc_items,
);
}
ty::Uint(ast::UintTy::Usize) => {
Expand All @@ -284,6 +305,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"usize",
"usize",
item.span,
assoc_items,
);
}
ty::Float(ast::FloatTy::F32) => {
Expand All @@ -294,6 +316,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"f32",
"f32",
item.span,
assoc_items,
);
}
ty::Float(ast::FloatTy::F64) => {
Expand All @@ -304,6 +327,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
"f64",
"f64",
item.span,
assoc_items,
);
}
ty::Error(_) => {}
Expand Down Expand Up @@ -369,6 +393,7 @@ impl InherentCollect<'tcx> {
lang: &str,
ty: &str,
span: Span,
assoc_items: &[hir::ImplItemRef<'_>],
) {
match (lang_def_id, lang_def_id2) {
(Some(lang_def_id), _) if lang_def_id == impl_def_id.to_def_id() => {
Expand All @@ -378,6 +403,32 @@ impl InherentCollect<'tcx> {
// OK
}
_ => {
let to_implement = if assoc_items.len() == 0 {
String::new()
} else {
let plural = assoc_items.len() > 1;
let assoc_items_kind = {
let item_types = assoc_items.iter().map(|x| x.kind);
if item_types.clone().all(|x| x == hir::AssocItemKind::Const) {
"constant"
} else if item_types
.clone()
.all(|x| matches! {x, hir::AssocItemKind::Fn{ .. } })
{
"method"
} else {
"associated item"
}
};

format!(
" to implement {} {}{}",
if plural { "these" } else { "this" },
assoc_items_kind,
if plural { "s" } else { "" }
)
};

struct_span_err!(
self.tcx.sess,
span,
Expand All @@ -387,7 +438,7 @@ impl InherentCollect<'tcx> {
lang,
ty
)
.span_help(span, "consider using a trait to implement these methods")
.help(&format!("consider using a trait{}", to_implement))
.emit();
}
}
Expand Down
6 changes: 1 addition & 5 deletions src/test/ui/error-codes/E0390.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ error[E0390]: only a single inherent implementation marked with `#[lang = "mut_p
LL | impl *mut Foo {}
| ^^^^^^^^^^^^^^^^
|
help: consider using a trait to implement these methods
--> $DIR/E0390.rs:5:1
|
LL | impl *mut Foo {}
| ^^^^^^^^^^^^^^^^
= help: consider using a trait

error: aborting due to previous error

Expand Down
23 changes: 23 additions & 0 deletions src/test/ui/kinds-of-primitive-impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// ignore-tidy-linelength


impl u8 {
//~^ error: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive
pub const B: u8 = 0;
}

impl str {
//~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive
fn foo() {}
fn bar(self) {}
}

impl char {
//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive
pub const B: u8 = 0;
pub const C: u8 = 0;
fn foo() {}
fn bar(self) {}
}

fn main() {}
40 changes: 40 additions & 0 deletions src/test/ui/kinds-of-primitive-impl.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
error[E0390]: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive
--> $DIR/kinds-of-primitive-impl.rs:4:1
|
LL | / impl u8 {
LL | |
LL | | pub const B: u8 = 0;
LL | | }
| |_^
|
= help: consider using a trait to implement this constant

error[E0390]: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive
--> $DIR/kinds-of-primitive-impl.rs:9:1
|
LL | / impl str {
LL | |
LL | | fn foo() {}
LL | | fn bar(self) {}
LL | | }
| |_^
|
= help: consider using a trait to implement these methods

error[E0390]: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive
--> $DIR/kinds-of-primitive-impl.rs:15:1
|
LL | / impl char {
LL | |
LL | | pub const B: u8 = 0;
LL | | pub const C: u8 = 0;
LL | | fn foo() {}
LL | | fn bar(self) {}
LL | | }
| |_^
|
= help: consider using a trait to implement these associated items

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0390`.
8 changes: 1 addition & 7 deletions src/test/ui/single-primitive-inherent-impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@ LL | |
LL | | }
| |_^
|
help: consider using a trait to implement these methods
--> $DIR/single-primitive-inherent-impl.rs:11:1
|
LL | / impl str {
LL | |
LL | | }
| |_^
= help: consider using a trait

error: aborting due to previous error

Expand Down