-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Better ScheduleBuildError
introspection and handling
#20256
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good cleanup. The context about the borrow checker was really helpful in understanding why this is necessary.
/// Category of warnings encountered during [`Schedule::initialize`](crate::schedule::Schedule::initialize). | ||
#[non_exhaustive] | ||
#[derive(Error, Debug)] | ||
pub enum ScheduleBuildWarning { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just alias ScheduleBuildError as ScheduleBuildWarning? It doesn't feel like it deserves it's own type as it's just the difference in how the error is reported/handled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually added it last minute expecting someone to say something along the lines of "well if only two of the variants can actually be warnings then there should be a separate enum". Happy to remove it, though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, the error enum should have an ElevatedWarning
variant that wraps these warnings. I think that would be best of both worlds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't that make the type recursive and hence unsized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added ScheduleBuildError::Elevated
and removed the duplicate variants in ScheduleBuildError
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I misunderstood what the suggestion was. I think I still prefer my solution as now you have to look in two places to see all the errors, but not going to block on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of small ideas, but looks good to me! I don't know enough about how schedules are built to do a full correctness review, but the code quality looks good to me!
I have also been annoyed with the previous state because of borrow checking when I was working on queued component registration, so I'm very glad for this to be cleaned up!
self.initialize(world) | ||
.unwrap_or_else(|e| panic!("Error when initializing schedule {:?}: {e}", self.label)); | ||
self.initialize(world).unwrap_or_else(|e| { | ||
panic!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This panic feels like it should be an error returned out, but same behavior as before, so I'm fine with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replacing panics with errors is always good, but I'll leave that for a small follow up PR.
impl ScheduleBuildError { | ||
/// Renders the error as a human-readable string with node identifiers | ||
/// replaced with their names. | ||
pub fn to_string(&self, graph: &ScheduleGraph, world: &World) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when the wrong graph or world is passed in? I don't really care as long as it doesn't panic. And documenting what would happen would be good too IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDK, but another idea would be to keep a reference to the graph and world in the error types. That way, using the wrong world and graph would be impossible. As long as the reference is only tied in at the end, I don't think it would cause any borrow checking issues while calculating the errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when the wrong graph or world is passed in? I don't really care as long as it doesn't panic. And documenting what would happen would be good too IMO.
It just leads to incorrect node names and component names; I added this as a note for the function.
IDK, but another idea would be to keep a reference to the graph and world in the error types. That way, using the wrong world and graph would be impossible. As long as the reference is only tied in at the end, I don't think it would cause any borrow checking issues while calculating the errors.
Eh, I think we've had annoyances in the past with error types that hold references.
/// Category of warnings encountered during [`Schedule::initialize`](crate::schedule::Schedule::initialize). | ||
#[non_exhaustive] | ||
#[derive(Error, Debug)] | ||
pub enum ScheduleBuildWarning { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, the error enum should have an ElevatedWarning
variant that wraps these warnings. I think that would be best of both worlds.
/// Category of errors encountered during [`Schedule::initialize`](crate::schedule::Schedule::initialize). | ||
#[non_exhaustive] | ||
#[derive(Error, Debug)] | ||
pub enum ScheduleBuildError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this needs to change since it was like this before, but It sounds like multiple of these errors could happen at once. Like there could be a cross-dependency and a dependency loop I would guess. Not returning all errors could turn fixing them into a game of wack-a-mole. It might be nice to just have a struct that could represent all possible permutations of errors, like vecs of dependency loops, a bool for uninitialized, etc. IDK if that's actually a good idea; just something to think about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to move in this direction at some point, but would rather let the larger changes surface first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the elevated warning variant. Nice!
Objective
I want to pull out the ad-hoc graph manipulation and analysis functions into generalized reusable functions, but in doing so encounter some borrow-checker issues. This is because the graphs are mutably borrowed during the build process at the points where we need to render warning and error messages (which require full access to the
ScheduleGraph
).Solution
So, lets defer message rendering until the consumer actually needs it:
String
s inScheduleBuildError
variants with just theNodeId
/SystemKey
/SystemSetKey
.ScheduleBuildError::to_string
to render the messages as they were previously.ScheduleBuildWarning
, a subset of the error enum of just the possible warnings.Vec
and returned them from the build process, caching them in theSchedule
and made accessible viaSchedule::warnings
. Additionally automaticallywarn!()
these warnings after the schedule is built.ScheduleGraph::get_node_name
so external consumers can do any special rendering themselves.ScheduleBuildError
andScheduleBuildWarning
to their own files to help incrementally minimize the largeschedule.rs
module.Testing
Reusing current tests.