-
Notifications
You must be signed in to change notification settings - Fork 256
Infer appropriate crate target from workspace #438
Conversation
So for inferred/default stuff, here are some thoughts: just to make sure, let's only do this where we need to (which is build_lib/bin for now, I think). I think then we want to split the config struct so we have a RawConfig which we can deserialise from LSP and then the Config we use internally. The raw one doesn't have the inferred/whatever thing. Then use a generic enum for build_bin, etc. - I think you need Specified/Inferred/None (where the last is used when we haven't inferred yet, or can't be inferred), then have an |
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 think all the Cargo stuff looks fine, and generally this is a good approach, I think the only thing that needs work is the Config for Inferred vs Default and merging configs.
src/actions/mod.rs
Outdated
@@ -92,6 +98,10 @@ impl ActionHandler { | |||
pub fn init<O: Output>(&self, init_options: InitializationOptions, out: O) { | |||
trace!("init: {:?}", init_options); | |||
|
|||
if let Err(err) = self.infer_config_defaults(&mut *self.config.lock().unwrap()) { |
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 spawn a thread to do this, rather than doing it on the main thread?
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've tried to catch every Err
and surface it out so we won't get a panic there (updated now, got rid of the .expect()
and .unwrap()
). Should I still spawn a new thread for that here?
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.
So my concern was that this might take a long time to run and block other main thread options, rather than about error handling. Given that we're doing a bunch of disk access, I think it is probably still too long running a task to be on the main thread.
8172909
to
86d1ab3
Compare
Updated, added new test cases for inferring crate target types. Introduced |
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.
Looks good! A couple of nits inline.
src/config.rs
Outdated
} | ||
|
||
/// Deserialize as if it's `Option<T>` and use `None` variant if it's `None`, | ||
/// otherwise use `Specified` variant for deserialized value. |
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.
nit: I think this should be a regular comment, not a doc comment
src/config.rs
Outdated
match self { | ||
&Inferrable::Inferred(ref value) | | ||
&Inferrable::Specified(ref value) => value, | ||
&Inferrable::None => unreachable!(), |
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.
Should probably expect
here so we get a useful message
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.
In fact, I wonder that we might hit this in real life - either because inference has not completed yet, or the user resets to null. In which case we should probably be able to continue without crashing - either just skip the build or build with some defaults or something
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.
Currently it's impossible to reset the config value to None
, it's only a way to not get Specified
value when deserializing. However if user desires to fall back to auto-detecting, we'd still have to run the infer_...
again after config change, which isn't done yet.
I made an assumption, that all values (including default ones, which I set to Inferred
) should not ever be None
, but I have a hard time trying to enforce that at compile-time. Splitting the config into deserialized/actually used would work, but we'd lose compile-time guarantee that we copy every value and would have to duplicate a lot of code or write less straightforward macro, that's why I went with this approach. How should I tackle this?
Yes please. |
On RLS initialize, call `infer_config_defaults` which creates a `Workspace` and queries appropriate package's targets to see which crate targets are available (including inferred `lib` and `bin` ones). Whenever received changed config has some `null` values (most probably the user wants to use inferred values again), set them to the default values and run `infer_config_defaults` later as well.
@@ -812,6 +850,76 @@ impl ActionHandler { | |||
} | |||
} | |||
|
|||
fn infer_config_defaults(project_dir: &Path, config: &mut Config) -> CargoResult<()> { |
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.
Should this be in an impl Config
? This would need more Cargo-related bits moved to config.rs
, not sure if it's good from in terms of the module split/architecture
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.
Yeah, I think I would expect this to be in the cargo module and probably a method on Config
. Taking a mut ref to Config is a bit strange, I guess I would expect to take a Config and return a new one? And that might make some of the referencing calling this easier? Anyway, I'm going to merge this now, we can refactor later if you like because I think this is polish.
I guess it'd be also good to introduce a test case to detect inference user sends a |
This is only a proof-of-concept and needs some ironing out. Most importantly it'd be good to handle properly inferred/default and explicitly stated values when updating the config via LSP message. Additionally, it'd be good not to duplicate code that creates a
Workspace
, although I'm not really sure how to do that, as Workspace needs to be created with borrows and I'm not sure how to cleanly separate a struct that would hold the data and Workspace without running into self-borrowing issues when initializing.Right now it works like this: On RLS initialize, call
infer_config_defaults
which creates aWorkspace
and queries appropriate package's targets to see which crate targets are available (including inferredlib
andbin
ones). Then, these are set as follows: prioritizelib
overbin
, and prefer defaultbin
over a firstbin
on the list. These are just mindlessly copied into current config and during config change, we just ignore those (which we shouldn't, it needs work).Everything marked with
TODO:
I'd like to resolve first before merging.