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

Report missing import error #91

Merged
merged 7 commits into from
Nov 4, 2024

Conversation

IceSentry
Copy link
Contributor

@IceSentry IceSentry commented May 26, 2024

Objective

If an import is missing from the module it currently just unwraps and panics without any explanations.

Solution

Don't unwrap and bubble up the error instead.

The error reporting is a bit weird because it just points at the start of the file and I'm not sure how to improve it.

@robtfm
Copy link
Collaborator

robtfm commented May 26, 2024

Could you share a reproduction of the issue? Missing imports should be handled already.

@IceSentry
Copy link
Contributor Author

IceSentry commented May 26, 2024

I hit that bug while testing the SSR PR, but I also hit it at work and had no easy way to even diagnose it.

If you pull this commit, bevyengine/bevy@383e87e (#13418) (the commit itself isn't the issue, it's just the one right before the fix) and run the transmission example you'll see this error message:

thread 'Async Compute Task Pool (3)' panicked at C:\Users\Charles\.cargo\registry\src\index.crates.io-6f17d22bba15001f\naga_oil-0.13.0\src\compose\mod.rs:1330:59:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'Async Compute Task Pool (0)' panicked at crates\bevy_render\src\render_resource\pipeline_cache.rs:734:60:
called `Result::unwrap()` on an `Err` value: PoisonError { .. }
thread 'Async Compute Task Pool (2)' panicked at crates\bevy_render\src\render_resource\pipeline_cache.rs:734:60:
called `Result::unwrap()` on an `Err` value: PoisonError { .. }

The first error is related to an unwrap in naga_oil and this is what this PR is attempting to fix.

Essentially, the issue is that in the SSR PR (before it was fixed) when transmission is used without checking for the ENVIRONMENT_MAP shader_def, it tries to read the environment_map import that doesn't exist since it's behind the shader_def and that's when things blow up. I don't know how it reached that point, but it does and it gives a very cryptic error with no explanation as to what is going on.

@robtfm
Copy link
Collaborator

robtfm commented May 26, 2024

ok thanks, i reproduced it.

i think the problem here reduces down to

#ifdef USE_A
    #import a::b
#endif

fn main() -> u32 {
    return b::C;
}

for this, get_preprocessor_data claims that the total set of potential imports are [ImportDefinition { import: "a::b", items: ["C"] }]

but that's not true since if USE_A is not specified, we actually want a module called b.

i wonder if it is possible / desirable to make it so that this explicitly reports that b is a required dependency, but

#ifdef USE_A
    #import a::b
#endif

fn main() -> u32 {
#ifdef USE_A
    return b::C;
#else
    return 0;
#endif
}

would still report only a::b as required... i think this would probably be decently better for catching issues like this one at compile-time preprocess / asset-load time.

@robtfm
Copy link
Collaborator

robtfm commented May 27, 2024

after thinking about it a bit i think while contextually resolving the required imports would be better, it's not easy.

it would require

  • capturing the def-state of each import (i.e. what defs need to be defined/undefined/match a given comparison, for the import statement to apply)
  • capturing the def-state of each usage of an import
  • check if the usage def-state overlaps with the def-state for each import that it could refer to, and marking the import as a dependency if so
  • checking if the usage def-state is fully contained within the set of states for all the imports that it could be referring to, and adding it raw (i.e. adding b as a dependency in the above example) if not

.. which is not totally straightforward and might be pretty slow (a lot of cloning of def-states and non-trivial intersection / containment tests). so i think your approach is good for now.

ideally we'd avoid cloning the source strings on the happy path (they can be big), but i can't see a clean way to do that. we could put a dummy string in for the source, and check the path in a map_err then replace the source if it matches, or pass a closure into ensure_import or something, but these are both pretty ugly and criterion says it has no impact on the pbr_compose_test example, so maybe not worthwhile.

i also noticed that my small example above still fails with this pr, because the imports that were ensured at the top-level were based on the preprocessor metadata instead of the preprocess data (which uses the shader-defs). i fixed that by moving the preprocess step up a few lines, and added a couple of tests on a pr to your pr. it passes all the builtin tests but i will check on bevy as well since this is a slightly more invasive change (shouldn't break anything but just to be sure).

@IceSentry
Copy link
Contributor Author

ideally we'd avoid cloning the source strings on the happy path

Yeah, I don't like it either, but I wasn't sure how to handle it because of the recursive case. I'll merge your PR and see if I can figure out something better.

@IceSentry
Copy link
Contributor Author

Okay, I changed the error handling a bit to just bubble up the import name until it needs to be converted to a ComposerError. It's a bit annoying that I'm forced to create an intermediary enum for that, but now it avois the clone until it's actually needed.

One nice side effect is that now it reports at the place where that import is trying to be used which makes it much clearer. In the nested case though, it points the #import middle line in top_nested instead of pointing to the file that has the missing import. It's not ideal, but it's not too bad either I think.

Copy link
Collaborator

@robtfm robtfm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this approach is much nicer. i'll approve when the last point is addressed.

src/compose/test.rs Outdated Show resolved Hide resolved
@mockersf mockersf force-pushed the missing-import-error branch from 0effdbc to 04d4255 Compare August 3, 2024 09:42
@alice-i-cecile alice-i-cecile merged commit 7e101db into bevyengine:master Nov 4, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants