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 |
nrc
left a comment
There was a problem hiding this comment.
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
| 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.
Can we spawn a thread to do this, rather than doing it on the main thread?
There was a problem hiding this comment.
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.
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 |
nrc
left a comment
There was a problem hiding this comment.
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.
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.
Should probably expect here so we get a useful message
There was a problem hiding this comment.
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.
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.
| } | ||
| } | ||
|
|
||
| fn infer_config_defaults(project_dir: &Path, config: &mut Config) -> CargoResult<()> { |
There was a problem hiding this comment.
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.
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_defaultswhich creates aWorkspaceand queries appropriate package's targets to see which crate targets are available (including inferredlibandbinones). Then, these are set as follows: prioritizeliboverbin, and prefer defaultbinover a firstbinon 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.