Skip to content
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

allow arbitrary inherent impls for builtin types in core #94963

Merged
merged 13 commits into from
Mar 30, 2022
Prev Previous commit
Next Next commit
rework error messages for incorrect inherent impls
lcnr committed Mar 30, 2022
commit 00cf7af44aaecb5b91f58ec8f1737f6623f910d3
29 changes: 4 additions & 25 deletions compiler/rustc_error_codes/src/error_codes/E0118.md
Original file line number Diff line number Diff line change
@@ -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,32 +33,11 @@ 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 {
"Fascinating!".to_owned()
}
}
```

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) {}
}
```
24 changes: 22 additions & 2 deletions compiler/rustc_error_codes/src/error_codes/E0390.md
Original file line number Diff line number Diff line change
@@ -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) {}
}
```
45 changes: 27 additions & 18 deletions compiler/rustc_typeck/src/coherence/inherent_impls.rs
Original file line number Diff line number Diff line change
@@ -86,8 +86,7 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
| 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 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
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 @@ impl<'tcx> InherentCollect<'tcx> {
}
}
} 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;
}
}
}
3 changes: 1 addition & 2 deletions src/test/ui/error-codes/E0117.rs
Original file line number Diff line number Diff line change
@@ -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() {}
7 changes: 7 additions & 0 deletions src/test/ui/error-codes/E0118.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
impl fn(u8) { //~ ERROR E0118
fn get_state(&self) -> String {
String::new()
}
}

fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/error-codes/E0118.stderr
Original file line number Diff line number Diff line change
@@ -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`.
3 changes: 1 addition & 2 deletions src/test/ui/error-codes/E0120.rs
Original file line number Diff line number Diff line change
@@ -5,5 +5,4 @@ impl Drop for dyn MyTrait {
fn drop(&mut self) {}
}

fn main() {
}
fn main() {}
6 changes: 6 additions & 0 deletions src/test/ui/kinds-of-primitive-impl.rs
Original file line number Diff line number Diff line change
@@ -17,4 +17,10 @@ impl char {
fn bar(self) {}
}

struct MyType;
impl &MyType {
//~^ error: cannot define inherent `impl` for primitive types
pub fn for_ref(self) {}
}

fn main() {}
11 changes: 10 additions & 1 deletion src/test/ui/kinds-of-primitive-impl.stderr
Original file line number Diff line number Diff line change
@@ -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`.