bevy_reflect: Update on_unimplemented attributes (#15110)

# Objective

Some of the new compile error messages are a little unclear (at least to
me). For example:

```
error[E0277]: `tests::foo::Bar` can not be created through reflection
   --> crates/bevy_reflect/src/lib.rs:679:18
    |
679 |         #[derive(Reflect)]
    |                  ^^^^^^^ the trait `from_reflect::FromReflect` is not implemented for `tests::foo::Bar`
    |
    = note: consider annotating `tests::foo::Bar` with `#[derive(Reflect)]` or `#[derive(FromReflect)]`
```

While the annotation makes it clear that `FromReflect` is missing, it's
not very clear from the main error message.

My IDE lists errors with only their message immediately present:

<p align="center">
<img width="700" alt="Image of said IDE listing errors with only their
message immediately present. These errors are as follows:
\"`tests::foo::Bar` can not be created through reflection\", \"The trait
bound `tests::foo::Bar: RegisterForReflection` is not satisfied\", and
\"The trait bound `tests::foo::Bar: type_info::MaybeTyped` is not
satisfied\""
src="https://github.com/user-attachments/assets/42c24051-9e8e-4555-8477-51a9407446aa">
</p>

This makes it hard to tell at a glance why my code isn't compiling.

## Solution

Updated all `on_unimplemented` attributes in `bevy_reflect` to mention
the relevant trait—either the actual trait or the one users actually
need to implement—as well as a small snippet of what not implementing
them means.

For example, failing to implement `TypePath` now mentions missing a
`TypePath` implementation. And failing to implement `DynamicTypePath`
now also mentions missing a `TypePath` implementation, since that's the
actual trait users need to implement (i.e. they shouldn't implement
`DynamicTypePath` directly).

Lastly, I also added some missing `on_unimplemented` attributes for
`MaybeTyped` and `RegisterForReflection` (which you can see in the image
above).

Here's how this looks in my IDE now:

<p align="center">
<img width="700" alt="Similar image as before showing the errors listed
by the IDE. This time the errors read as follows: \"`tests::foo::Bar`
does not implement `FromReflect` so cannot be reified through
reflection\", \"`tests::foo::Bar` does not implement
`GetTypeRegistration` so cannot be registered for reflection\", and
\"`tests::foo::Bar` does not implement `Typed` so cannot provide static
type information\""
src="https://github.com/user-attachments/assets/f6f8501f-0450-4f78-b84f-00e7a18d0533">
</p>


## Testing

You can test by adding the following code and verifying the compile
errors are correct:

```rust
#[derive(Reflect)]
struct Foo(Bar);

struct Bar;
```
This commit is contained in:
Gino Valente 2024-09-09 09:26:17 -07:00 committed by GitHub
parent 5adacf014c
commit 245d03a78a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 18 additions and 10 deletions

View file

@ -12,8 +12,8 @@ struct NoReflect(f32);
fn main() {
let mut foo: Box<dyn Struct> = Box::new(Foo::<NoReflect> { a: NoReflect(42.0) });
//~^ ERROR: `NoReflect` does not provide type registration information
//~| ERROR: `NoReflect` can not provide type information through reflection
//~^ ERROR: `NoReflect` does not implement `GetTypeRegistration` so cannot provide type registration information
//~| ERROR: `NoReflect` does not implement `Typed` so cannot provide static type information
// foo doesn't implement Reflect because NoReflect doesn't implement Reflect
foo.get_field::<NoReflect>("a").unwrap();

View file

@ -25,7 +25,7 @@ mod incorrect_inner_type {
//~^ ERROR: `TheirInner<T>` does not implement `PartialReflect` so cannot be introspected
//~| ERROR: `TheirInner<T>` does not implement `PartialReflect` so cannot be introspected
//~| ERROR: `TheirInner<T>` does not implement `PartialReflect` so cannot be introspected
//~| ERROR: `TheirInner<T>` can not be used as a dynamic type path
//~| ERROR: `TheirInner<T>` does not implement `TypePath` so cannot provide dynamic type path information
//~| ERROR: `?` operator has incompatible types
struct MyOuter<T: FromReflect + GetTypeRegistration> {
// Reason: Should not use `MyInner<T>` directly

View file

@ -22,8 +22,8 @@ use crate::{FromType, PartialReflect, Reflect};
/// [`DynamicStruct`]: crate::DynamicStruct
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` can not be created through reflection",
note = "consider annotating `{Self}` with `#[derive(FromReflect)]`"
message = "`{Self}` does not implement `FromReflect` so cannot be created through reflection",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait FromReflect: Reflect + Sized {
/// Constructs a concrete instance of `Self` from a reflected value.

View file

@ -620,6 +620,10 @@ pub mod __macro_exports {
///
/// This trait has a blanket implementation for all types that implement `GetTypeRegistration`
/// and manual implementations for all dynamic types (which simply do nothing).
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `GetTypeRegistration` so cannot be registered for reflection",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait RegisterForReflection {
#[allow(unused_variables)]
fn __register(registry: &mut TypeRegistry) {}

View file

@ -237,7 +237,7 @@ impl<'a> ReflectPath<'a> for &'a str {
/// [`Array`]: crate::Array
/// [`Enum`]: crate::Enum
#[diagnostic::on_unimplemented(
message = "`{Self}` does not provide a reflection path",
message = "`{Self}` does not implement `GetPath` so cannot be accessed by reflection path",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait GetPath: PartialReflect {

View file

@ -83,7 +83,7 @@ use thiserror::Error;
///
/// [utility]: crate::utility
#[diagnostic::on_unimplemented(
message = "`{Self}` can not provide type information through reflection",
message = "`{Self}` does not implement `Typed` so cannot provide static type information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait Typed: Reflect + TypePath {
@ -103,6 +103,10 @@ pub trait Typed: Reflect + TypePath {
/// This trait has a blanket implementation for all types that implement `Typed`
/// and manual implementations for all dynamic types (which simply return `None`).
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `Typed` so cannot provide static type information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait MaybeTyped: PartialReflect {
/// Returns the compile-time [info] for the underlying type, if it exists.
///

View file

@ -80,7 +80,7 @@ use std::fmt;
/// [`module_path`]: TypePath::module_path
/// [`type_ident`]: TypePath::type_ident
#[diagnostic::on_unimplemented(
message = "`{Self}` does not have a type path",
message = "`{Self}` does not implement `TypePath` so cannot provide static type path information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]` or `#[derive(TypePath)]`"
)]
pub trait TypePath: 'static {
@ -134,7 +134,7 @@ pub trait TypePath: 'static {
///
/// [`Reflect`]: crate::Reflect
#[diagnostic::on_unimplemented(
message = "`{Self}` can not be used as a dynamic type path",
message = "`{Self}` does not implement `TypePath` so cannot provide dynamic type path information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]` or `#[derive(TypePath)]`"
)]
pub trait DynamicTypePath {

View file

@ -57,7 +57,7 @@ impl Debug for TypeRegistryArc {
///
/// [crate-level documentation]: crate
#[diagnostic::on_unimplemented(
message = "`{Self}` does not provide type registration information",
message = "`{Self}` does not implement `GetTypeRegistration` so cannot provide type registration information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait GetTypeRegistration: 'static {