TheBevyFlock / bevy_cli

A Bevy CLI tool and linter.
https://thebevyflock.github.io/bevy_cli/
Apache License 2.0
44 stars 7 forks source link

Fix ICE when checking `bevy_reflect` #149

Closed BD103 closed 1 month ago

BD103 commented 1 month ago

Fixes #148.

The missing_reflect lint crashed when checking bevy_reflect due to incorrect assumptions about the orphan rule.

Explanation

When searching for types that implement certain traits, Reflect in this case, missing_reflect:

  1. Finds all local trait impl blocks within a specific crate.
  2. Filters them for impl Reflect for T blocks.
  3. Looks up the Node for T in the local crate, returning it in an iterator.

While that is a greatly simplified version of what TraitType::from_local_crate() does, it conveys enough to understand where things went wrong.

In order to find the final Node for T, the lint pass calls TyCtxt::hir_node(). This method requires that T be defined within the local crate (see LocalDefId).

I assumed incorrectly that this would always be the case. I assumed that Reflect would always be external, forcing T to be local to comply with Rust's orphan rule. This is why I thought I could safely call DefId::expect_local():

https://github.com/TheBevyFlock/bevy_cli/blob/e520db3fa4ea64760cd458cdb7e8ab0fe0364cf0/bevy_lint/src/lints/missing_reflect.rs#L185-L189

The only case this may not be upheld is within Bevy's own crates.

This comment was foreshadowing for this bug. When I ran bevy_lint on the bevy_reflect crate, which defines Reflect, T was no longer required to be a type declared in the local crate. (As #148 hints, where it implements Reflect for String.)

This was the source of the bug. The lint cannot call expect_local() when run on bevy_reflect, since it is not actually required to be local.

Solution

If the DefId cannot be converted into a LocalDefId, return early and do not lint that impl block. It's as simple as that :)

This means that standard library types like String will not be linted, but that's fine because they shouldn't implement Component or Resource anyways.