Description
Code
trait Foo<T> {
fn id(me: T) -> T;
}
/* note the "missing" for ... (in this case for i64, in order for this to compile) */
impl Foo<i64> {
fn id(me: i64) -> i64 {me}
}
fn main() {
let x: i64 = <i64 as Foo<i64>>::id(10);
println!("{}",x);
}
Current output
error[E0038]: the trait `Foo` cannot be made into an object
--> <source>:5:6
|
5 | impl Foo<i64> {
| ^^^^^^^^ `Foo` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> <source>:2:8
|
1 | trait Foo<T> {
| --- this trait cannot be made into an object...
2 | fn id(me: T) -> T;
| ^^ ...because associated function `id` has no `self` parameter
help: consider turning `id` into a method by giving it a `&self` argument
|
2 | fn id(&self, me: T) -> T;
| ++++++
help: alternatively, consider constraining `id` so it does not apply to trait objects
|
2 | fn id(me: T) -> T where Self: Sized;
| +++++++++++++++++
error[E0277]: the trait bound `i64: Foo<i64>` is not satisfied
--> <source>:10:19
|
10 | let x: i64 = <i64 as Foo<i64>>::id(10);
| ^^^ the trait `Foo<i64>` is not implemented for `i64`
|
help: this trait has no implementations, consider adding one
--> <source>:1:1
|
1 | trait Foo<T> {
| ^^^^^^^^^^^^
error[E0782]: trait objects must include the `dyn` keyword
--> <source>:5:6
|
5 | impl Foo<i64> {
| ^^^^^^^^
|
help: add `dyn` keyword before this trait
|
5 | impl dyn Foo<i64> {
| +++
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0038, E0277, E0782.
For more information about an error, try `rustc --explain E0038`.
Compiler returned: 1
Desired output
- At least some suggestion that a
for
may be missing (ie to signal an implementation of a trait), instead of only a suggestion around anonymous trait objects, which is somewhat misleading in this case. - The object-safety error would ideally not appear.
Rationale and extra context
The lack of a for ...
here, to implement Foo
for some type, causes two large unrelated errors, both of which are only relevant for code not migrated from Rust 2015. While these are obviously good to keep around, I would think that a suggestion that a for ...
might be missing could also be useful, as it's a very plausible error to make.
Additionally, having the object-safety error come up in a modern rust edition, when it is known that that impl
cannot be for a trait object, seems like it may cause more confusion than it solves. That error is obviously still needed, but for it to be "blocked" behind impl ...
being changed to impl dyn ...
if the Rust edition is >=2018, ensuring the "intentional" presence of a trait object, seems to me like a good approach.
This would be a very easy mistake to make if you were attempting to use Rust traits like Haskell typeclasses because the below compiles and runs fine, due to the lack of implicit self:
class Foo t where
id' :: t -> t
instance Foo Int where
id' x = x
main = print (id' (10 :: Int))
Rust Version
rustc 1.81.0 (eeb90cd 2024-09-04)
binary: rustc
commit-hash: eeb90cd
commit-date: 2024-09-04
host: x86_64-unknown-linux-gnu
release: 1.81.0
LLVM version: 18.1.7
Compiler returned: 0