rework error messages for incorrect inherent impls
This commit is contained in:
parent
ee62514b16
commit
00cf7af44a
9 changed files with 89 additions and 50 deletions
|
@ -4,7 +4,7 @@ enum, union, or trait object.
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0118
|
```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 {
|
fn get_state(&self) -> String {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ trait LiveLongAndProsper {
|
||||||
fn get_state(&self) -> String;
|
fn get_state(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
// and now you can implement it on (u8, u8)
|
// and now you can implement it on fn(u8)
|
||||||
impl LiveLongAndProsper for (u8, u8) {
|
impl LiveLongAndProsper for fn(u8) {
|
||||||
fn get_state(&self) -> String {
|
fn get_state(&self) -> String {
|
||||||
"He's dead, Jim!".to_owned()
|
"He's dead, Jim!".to_owned()
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```
|
```
|
||||||
struct TypeWrapper((u8, u8));
|
struct TypeWrapper(fn(u8));
|
||||||
|
|
||||||
impl TypeWrapper {
|
impl TypeWrapper {
|
||||||
fn get_state(&self) -> String {
|
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) {}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
|
@ -8,8 +8,7 @@ struct Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl *mut Foo {}
|
impl *mut Foo {}
|
||||||
// error: only a single inherent implementation marked with
|
// error: cannot define inherent `impl` for primitive types
|
||||||
// `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This isn't allowed, but using a trait to implement a method or constant
|
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!
|
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) {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -86,8 +86,7 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
|
||||||
| ty::Ref(..)
|
| ty::Ref(..)
|
||||||
| ty::Never
|
| ty::Never
|
||||||
| ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
|
| 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!(
|
let mut err = struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
ty.span,
|
ty.span,
|
||||||
|
@ -98,16 +97,18 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
|
||||||
err.span_label(ty.span, "impl requires a nominal type")
|
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");
|
.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();
|
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 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
span,
|
span,
|
||||||
E0390,
|
E0390,
|
||||||
"cannot define inherent `impl` for primitive types",
|
"cannot define inherent `impl` for primitive types",
|
||||||
)
|
);
|
||||||
.help("consider using an extension trait instead")
|
err.help("consider using an extension trait instead");
|
||||||
.emit();
|
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);
|
bug!("unexpected primitive type: {:?}", ty);
|
||||||
};
|
}
|
||||||
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
impl Drop for u32 {} //~ ERROR E0117
|
impl Drop for u32 {} //~ ERROR E0117
|
||||||
//~| ERROR the `Drop` trait may only be implemented for structs, enums, and unions
|
//~| ERROR the `Drop` trait may only be implemented for structs, enums, and unions
|
||||||
|
|
||||||
fn main() {
|
fn main() {}
|
||||||
}
|
|
||||||
|
|
7
src/test/ui/error-codes/E0118.rs
Normal file
7
src/test/ui/error-codes/E0118.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
impl fn(u8) { //~ ERROR E0118
|
||||||
|
fn get_state(&self) -> String {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
11
src/test/ui/error-codes/E0118.stderr
Normal file
11
src/test/ui/error-codes/E0118.stderr
Normal file
|
@ -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`.
|
|
@ -5,5 +5,4 @@ impl Drop for dyn MyTrait {
|
||||||
fn drop(&mut self) {}
|
fn drop(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {}
|
||||||
}
|
|
||||||
|
|
|
@ -17,4 +17,10 @@ impl char {
|
||||||
fn bar(self) {}
|
fn bar(self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MyType;
|
||||||
|
impl &MyType {
|
||||||
|
//~^ error: cannot define inherent `impl` for primitive types
|
||||||
|
pub fn for_ref(self) {}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -22,6 +22,15 @@ LL | impl char {
|
||||||
|
|
|
|
||||||
= help: consider using an extension trait instead
|
= 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`.
|
For more information about this error, try `rustc --explain E0390`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue