-
Notifications
You must be signed in to change notification settings - Fork 2
feat: Fixing parallel targets in the same pass #82
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| use std::hash::Hash; | ||
|
|
||
| use rustfix::diagnostics::Diagnostic; | ||
| use serde::Deserialize; | ||
|
|
||
|
|
@@ -41,22 +43,65 @@ pub struct Target { | |
| test: bool, | ||
| } | ||
|
|
||
| #[derive(Deserialize, Hash, PartialEq, Clone, Eq, Debug)] | ||
| #[derive(Deserialize, Eq, Clone, Debug)] | ||
| #[serde(rename_all(deserialize = "kebab-case"))] | ||
| pub enum Kind { | ||
| Bin, | ||
| Example, | ||
| Test, | ||
| Bench, | ||
| CustomBuild, | ||
| #[serde(untagged)] | ||
| Lib(LibKind), | ||
| #[serde(untagged)] | ||
| Bin(BinKind), | ||
| #[serde(untagged)] | ||
| Other(String), | ||
| } | ||
|
|
||
| impl PartialEq for Kind { | ||
| fn eq(&self, other: &Self) -> bool { | ||
| match (self, other) { | ||
| (Kind::Other(a), Kind::Other(b)) => a == b, | ||
| _ => std::mem::discriminant(self) == std::mem::discriminant(other), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Hash for Kind { | ||
| fn hash<H: std::hash::Hasher>(&self, state: &mut H) { | ||
| match self { | ||
| Self::CustomBuild => state.write_u8(1), | ||
| Self::Lib(l) => { | ||
| state.write_u8(2); | ||
| l.hash(state); | ||
| } | ||
| Self::Bin(b) => { | ||
| state.write_u8(3); | ||
| b.hash(state); | ||
| } | ||
| Self::Other(a) => { | ||
| state.write_u8(4); | ||
| a.hash(state); | ||
| } | ||
| }; | ||
| } | ||
| } | ||
|
Comment on lines
+58
to
+85
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be alright to do this?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Custom PartialEq, Eq, and Hash are tricky to get correct and I'd recommend re-evaluating a design to use it. |
||
|
|
||
| #[derive(Deserialize, Hash, PartialEq, Clone, Eq, Debug)] | ||
| #[serde(rename_all(deserialize = "kebab-case"))] | ||
| pub enum LibKind { | ||
| Lib, | ||
| Rlib, | ||
| Dylib, | ||
| Cdylib, | ||
| Staticlib, | ||
| ProcMacro, | ||
| #[serde(untagged)] | ||
| Other(String), | ||
| } | ||
|
|
||
| #[derive(Deserialize, Hash, PartialEq, Clone, Eq, Debug)] | ||
| #[serde(rename_all(deserialize = "kebab-case"))] | ||
| pub enum BinKind { | ||
| Bin, | ||
| Example, | ||
| Test, | ||
| Bench, | ||
| } | ||
|
|
||
| #[derive(Deserialize, Hash, PartialEq, Clone, Eq, Debug)] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,7 +69,7 @@ fn exec(args: FixitArgs) -> CargoResult<()> { | |
| let mut iteration = 0; | ||
|
|
||
| let mut last_errors = IndexMap::new(); | ||
| let mut current_target: Option<BuildUnit> = None; | ||
| let mut current_target: IndexSet<BuildUnit> = IndexSet::new(); | ||
| let mut seen = HashSet::new(); | ||
|
|
||
| loop { | ||
|
|
@@ -80,7 +80,7 @@ fn exec(args: FixitArgs) -> CargoResult<()> { | |
| if !args.broken_code && exit_code != Some(0) { | ||
| let mut out = String::new(); | ||
|
|
||
| if current_target.is_some() { | ||
| if !current_target.is_empty() { | ||
| out.push_str( | ||
| "failed to automatically apply fixes suggested by rustc\n\n\ | ||
| after fixes were automatically applied the \ | ||
|
|
@@ -150,7 +150,10 @@ fn exec(args: FixitArgs) -> CargoResult<()> { | |
| let (mut errors, build_unit_map) = collect_errors(messages, &seen); | ||
|
|
||
| if iteration >= max_iterations { | ||
| if let Some(target) = current_target { | ||
| if current_target.is_empty() { | ||
| break; | ||
| } | ||
| for target in ¤t_target { | ||
| if seen.iter().all(|b| b.package_id != target.package_id) { | ||
| shell::status("Checking", format_package_id(&target.package_id)?)?; | ||
| } | ||
|
|
@@ -160,9 +163,9 @@ fn exec(args: FixitArgs) -> CargoResult<()> { | |
| } | ||
| files = IndexMap::new(); | ||
|
|
||
| let mut errors = errors.shift_remove(&target).unwrap_or_else(IndexSet::new); | ||
| let mut errors = errors.shift_remove(target).unwrap_or_else(IndexSet::new); | ||
|
|
||
| if let Some(e) = build_unit_map.get(&target) { | ||
| if let Some(e) = build_unit_map.get(target) { | ||
| for (_, e) in e.iter().flat_map(|(_, s)| s) { | ||
| let Some(e) = e else { | ||
| continue; | ||
|
|
@@ -174,26 +177,26 @@ fn exec(args: FixitArgs) -> CargoResult<()> { | |
| shell::print_ansi_stderr(format!("{}\n\n", e.trim_end()).as_bytes())?; | ||
| } | ||
|
|
||
| seen.insert(target); | ||
| current_target = None; | ||
| iteration = 0; | ||
| } else { | ||
| break; | ||
| seen.insert(target.clone()); | ||
| } | ||
| iteration = 0; | ||
| current_target = IndexSet::new(); | ||
|
Comment on lines
-178
to
+183
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like moving |
||
| } | ||
|
|
||
| let mut made_changes = false; | ||
| let mut made_changes = HashSet::new(); | ||
|
|
||
| for (build_unit, file_map) in build_unit_map { | ||
| if seen.contains(&build_unit) { | ||
| continue; | ||
| } | ||
|
|
||
| let same = current_target.iter().any(|b| b == &build_unit); | ||
|
|
||
| let build_unit_errors = errors | ||
| .entry(build_unit.clone()) | ||
| .or_insert_with(IndexSet::new); | ||
|
|
||
| if current_target.is_none() && file_map.is_empty() { | ||
| if current_target.is_empty() && file_map.is_empty() { | ||
| if seen.iter().all(|b| b.package_id != build_unit.package_id) { | ||
| shell::status("Checking", format_package_id(&build_unit.package_id)?)?; | ||
| } | ||
|
|
@@ -204,11 +207,11 @@ fn exec(args: FixitArgs) -> CargoResult<()> { | |
|
|
||
| seen.insert(build_unit); | ||
| } else if !file_map.is_empty() | ||
| && current_target.get_or_insert(build_unit.clone()) == &build_unit | ||
| && (same || current_target.is_empty()) | ||
| && fix_errors(&mut files, file_map, build_unit_errors)? | ||
| { | ||
| made_changes = true; | ||
| break; | ||
| current_target.insert(build_unit.clone()); | ||
| made_changes.insert(build_unit); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -218,8 +221,12 @@ fn exec(args: FixitArgs) -> CargoResult<()> { | |
| last_errors = errors; | ||
| iteration += 1; | ||
|
|
||
| if !made_changes { | ||
| if let Some(pkg) = current_target { | ||
| if made_changes.is_empty() { | ||
| if current_target.is_empty() { | ||
| break; | ||
| } | ||
|
|
||
| for pkg in current_target { | ||
| if seen.iter().all(|b| b.package_id != pkg.package_id) { | ||
| shell::status("Checking", format_package_id(&pkg.package_id)?)?; | ||
| } | ||
|
|
@@ -235,11 +242,9 @@ fn exec(args: FixitArgs) -> CargoResult<()> { | |
| } | ||
|
|
||
| seen.insert(pkg); | ||
| current_target = None; | ||
| iteration = 0; | ||
| } else { | ||
| break; | ||
| } | ||
| iteration = 0; | ||
| current_target = IndexSet::new(); | ||
| } | ||
| } | ||
|
|
||
|
|
||
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'm confused by this change doesn't look the same as cargo's
TargetKindwhich is included in the json outputThere 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 tried to have the target kinds separated into the 3 groups like I mentioned here. So just the variant would be need to be checked to know whether a fix can be applied in the current pass or not
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.
Could we also get rid of
Vecfromkind: Vec<Kind>,?I think you had mentioned about it being just a single
TargetKindthan an vec in cargo.Since we would need these 3 types to be done together
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.
Oh, I had missed the
#[serde(untagged)]This is a nice idea for simplifying the categorization!
The downside is when we merge this into cargo. We'll be wanting to read json messages using cargo's definition. In doing so, we'll have to revert to the original
TargetKindand a new enum and adapt between the two. Might be good for us to skip ahead to us creating a new enum independent of the json output for use in processing, making the adoption into cargo easier.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.
Unsure about it only ever having one element. I'd have to look at notes on that or dig back into the code. However, it is only one element for all cases but
Libwhich is more of anOtherbranch, see https://github.com/rust-lang/cargo/blob/0bfd820f837d32f1704561de8caaff10fcf2b57f/src/cargo/core/manifest.rs#L226-L241There 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.
Do you have any suggestions on how I should redesign this? While comparing a
BuildUnit, I would need to compare the whole build unit exceptTargetKind(&CrateType?) and then compare the TargetKind to determine if it should run in the current passThere 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.
Sorry, I had thought it was assumed. We should have our own data structure for identifying the need for a unique Fix Pass.