From 00cf7af44aaecb5b91f58ec8f1737f6623f910d3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 29 Mar 2022 09:47:32 +0200 Subject: [PATCH] rework error messages for incorrect inherent impls --- .../src/error_codes/E0118.md | 29 ++---------- .../src/error_codes/E0390.md | 24 +++++++++- .../src/coherence/inherent_impls.rs | 45 +++++++++++-------- src/test/ui/error-codes/E0117.rs | 3 +- src/test/ui/error-codes/E0118.rs | 7 +++ src/test/ui/error-codes/E0118.stderr | 11 +++++ src/test/ui/error-codes/E0120.rs | 3 +- src/test/ui/kinds-of-primitive-impl.rs | 6 +++ src/test/ui/kinds-of-primitive-impl.stderr | 11 ++++- 9 files changed, 89 insertions(+), 50 deletions(-) create mode 100644 src/test/ui/error-codes/E0118.rs create mode 100644 src/test/ui/error-codes/E0118.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0118.md b/compiler/rustc_error_codes/src/error_codes/E0118.md index 345ec341c3f..8033aa8384c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0118.md +++ b/compiler/rustc_error_codes/src/error_codes/E0118.md @@ -4,7 +4,7 @@ enum, union, or trait object. Erroneous code example: ```compile_fail,E0118 -impl (u8, u8) { // error: no nominal type found for inherent implementation +impl fn(u8) { // error: no nominal type found for inherent implementation fn get_state(&self) -> String { // ... } @@ -20,8 +20,8 @@ trait LiveLongAndProsper { fn get_state(&self) -> String; } -// and now you can implement it on (u8, u8) -impl LiveLongAndProsper for (u8, u8) { +// and now you can implement it on fn(u8) +impl LiveLongAndProsper for fn(u8) { fn get_state(&self) -> String { "He's dead, Jim!".to_owned() } @@ -33,7 +33,7 @@ For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`. Example: ``` -struct TypeWrapper((u8, u8)); +struct TypeWrapper(fn(u8)); impl TypeWrapper { fn get_state(&self) -> String { @@ -41,24 +41,3 @@ impl TypeWrapper { } } ``` - -Instead of defining an inherent implementation on a reference, you could also -move the reference inside the implementation: - -```compile_fail,E0118 -struct Foo; - -impl &Foo { // error: no nominal type found for inherent implementation - fn bar(self, other: Self) {} -} -``` - -becomes - -``` -struct Foo; - -impl Foo { - fn bar(&self, other: &Self) {} -} -``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0390.md b/compiler/rustc_error_codes/src/error_codes/E0390.md index 7a13160d098..26a9dd331ce 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0390.md +++ b/compiler/rustc_error_codes/src/error_codes/E0390.md @@ -8,8 +8,7 @@ struct Foo { } impl *mut Foo {} -// error: only a single inherent implementation marked with -// `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive +// error: cannot define inherent `impl` for primitive types ``` This isn't allowed, but using a trait to implement a method or constant @@ -29,3 +28,24 @@ impl Bar for *mut Foo { fn bar() {} // ok! } ``` + +Instead of defining an inherent implementation on a reference, you could also +move the reference inside the implementation: + +```compile_fail,E0390 +struct Foo; + +impl &Foo { // error: no nominal type found for inherent implementation + fn bar(self, other: Self) {} +} +``` + +becomes + +``` +struct Foo; + +impl Foo { + fn bar(&self, other: &Self) {} +} +``` diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index e7f9ad91172..e11bd9355eb 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -86,8 +86,7 @@ fn visit_item(&mut self, item: &hir::Item<'_>) { | ty::Ref(..) | ty::Never | ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span), - ty::Error(_) => {} - _ => { + ty::FnPtr(_) | ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => { let mut err = struct_span_err!( self.tcx.sess, ty.span, @@ -98,16 +97,18 @@ fn visit_item(&mut self, item: &hir::Item<'_>) { err.span_label(ty.span, "impl requires a nominal type") .note("either implement a trait on it or create a newtype to wrap it instead"); - if let ty::Ref(_, subty, _) = self_ty.kind() { - err.note(&format!( - "you could also try moving the reference to \ - uses of `{}` (such as `self`) within the implementation", - subty - )); - } - err.emit(); } + ty::FnDef(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) => { + bug!("unexpected impl self type of impl: {:?} {:?}", item.def_id, self_ty); + } + ty::Error(_) => {} } } @@ -170,21 +171,29 @@ fn check_primitive_impl( } } } else { - struct_span_err!( + let mut err = struct_span_err!( self.tcx.sess, span, E0390, "cannot define inherent `impl` for primitive types", - ) - .help("consider using an extension trait instead") - .emit(); + ); + err.help("consider using an extension trait instead"); + if let ty::Ref(_, subty, _) = ty.kind() { + err.note(&format!( + "you could also try moving the reference to \ + uses of `{}` (such as `self`) within the implementation", + subty + )); + } + err.emit(); + return; } } - let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsPlaceholders) else { + if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsPlaceholders) { + self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); + } else { bug!("unexpected primitive type: {:?}", ty); - }; - self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); - return; + } } } diff --git a/src/test/ui/error-codes/E0117.rs b/src/test/ui/error-codes/E0117.rs index dbbac514801..22b48657385 100644 --- a/src/test/ui/error-codes/E0117.rs +++ b/src/test/ui/error-codes/E0117.rs @@ -1,5 +1,4 @@ impl Drop for u32 {} //~ ERROR E0117 //~| ERROR the `Drop` trait may only be implemented for structs, enums, and unions -fn main() { -} +fn main() {} diff --git a/src/test/ui/error-codes/E0118.rs b/src/test/ui/error-codes/E0118.rs new file mode 100644 index 00000000000..aaef8113b8a --- /dev/null +++ b/src/test/ui/error-codes/E0118.rs @@ -0,0 +1,7 @@ +impl fn(u8) { //~ ERROR E0118 + fn get_state(&self) -> String { + String::new() + } +} + +fn main() {} diff --git a/src/test/ui/error-codes/E0118.stderr b/src/test/ui/error-codes/E0118.stderr new file mode 100644 index 00000000000..296fb5d664a --- /dev/null +++ b/src/test/ui/error-codes/E0118.stderr @@ -0,0 +1,11 @@ +error[E0118]: no nominal type found for inherent implementation + --> $DIR/E0118.rs:1:6 + | +LL | impl fn(u8) { + | ^^^^^^ impl requires a nominal type + | + = note: either implement a trait on it or create a newtype to wrap it instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0118`. diff --git a/src/test/ui/error-codes/E0120.rs b/src/test/ui/error-codes/E0120.rs index 287a4088183..a0a301a06e2 100644 --- a/src/test/ui/error-codes/E0120.rs +++ b/src/test/ui/error-codes/E0120.rs @@ -5,5 +5,4 @@ impl Drop for dyn MyTrait { fn drop(&mut self) {} } -fn main() { -} +fn main() {} diff --git a/src/test/ui/kinds-of-primitive-impl.rs b/src/test/ui/kinds-of-primitive-impl.rs index 9eba72e7627..6a067a9a360 100644 --- a/src/test/ui/kinds-of-primitive-impl.rs +++ b/src/test/ui/kinds-of-primitive-impl.rs @@ -17,4 +17,10 @@ fn foo() {} fn bar(self) {} } +struct MyType; +impl &MyType { +//~^ error: cannot define inherent `impl` for primitive types + pub fn for_ref(self) {} +} + fn main() {} diff --git a/src/test/ui/kinds-of-primitive-impl.stderr b/src/test/ui/kinds-of-primitive-impl.stderr index c788317d786..f4dbd1c40e8 100644 --- a/src/test/ui/kinds-of-primitive-impl.stderr +++ b/src/test/ui/kinds-of-primitive-impl.stderr @@ -22,6 +22,15 @@ LL | impl char { | = help: consider using an extension trait instead -error: aborting due to 3 previous errors +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/kinds-of-primitive-impl.rs:21:6 + | +LL | impl &MyType { + | ^^^^^^^ + | + = help: consider using an extension trait instead + = note: you could also try moving the reference to uses of `MyType` (such as `self`) within the implementation + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0390`.