Auto merge of #14070 - Veykril:proc-macro-api, r=Veykril

Implement proc-macro-api versioning

So as it stands, we can't really change the proc-macro-api protocol at all without breaking all proc-macro servers again. To somewhat alleviate this we can move the supported ABI mess over to the proc-macro-api now by supporting multiple versions there (versions defined by us at least, not by rustc). Since the proc-macro-api protocol has no versioning scheme at the moment though, the best we can do here is add a new request to query the version from a server. Due to how the server currently works though, if it encounters an unknown request it will exit, meaning we can check if it is a server without support by checking if it exited after our version check request, that way we can support the current circulating server as well.

We need this since our span type will change from `TokenId` to something else at some point, but for that to work we need to comply with that the server expects. So knowing the version the server is using we can decide whether to send our new span data, or the tokenid (assuming we keep that information with our span data as well, alternatively we send irrelevant tokenids). That way we can keep old servers working while the user installations slowly migrate to newer servers that support the new spandata.
This commit is contained in:
bors 2023-02-03 09:41:24 +00:00
commit 6133e27b83
4 changed files with 50 additions and 9 deletions

View File

@ -115,7 +115,7 @@ impl ProcMacroServer {
/// Spawns an external process as the proc macro server and returns a client connected to it.
pub fn spawn(
process_path: AbsPathBuf,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
args: impl IntoIterator<Item = impl AsRef<OsStr>> + Clone,
) -> io::Result<ProcMacroServer> {
let process = ProcMacroProcessSrv::run(process_path, args)?;
Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) })
@ -174,7 +174,7 @@ impl ProcMacro {
let response = self.process.lock().unwrap_or_else(|e| e.into_inner()).send_task(request)?;
match response {
msg::Response::ExpandMacro(it) => Ok(it.map(FlatTree::to_subtree)),
msg::Response::ListMacros { .. } => {
msg::Response::ListMacros(..) | msg::Response::ApiVersionCheck(..) => {
Err(ServerError { message: "unexpected response".to_string(), io: None })
}
}

View File

@ -12,16 +12,21 @@ use crate::ProcMacroKind;
pub use crate::msg::flat::FlatTree;
pub const NO_VERSION_CHECK_VERSION: u32 = 0;
pub const CURRENT_API_VERSION: u32 = 1;
#[derive(Debug, Serialize, Deserialize)]
pub enum Request {
ListMacros { dylib_path: PathBuf },
ExpandMacro(ExpandMacro),
ApiVersionCheck {},
}
#[derive(Debug, Serialize, Deserialize)]
pub enum Response {
ListMacros(Result<Vec<(String, ProcMacroKind)>, String>),
ExpandMacro(Result<FlatTree, PanicMessage>),
ApiVersionCheck(u32),
}
#[derive(Debug, Serialize, Deserialize)]

View File

@ -10,7 +10,7 @@ use paths::{AbsPath, AbsPathBuf};
use stdx::JodChild;
use crate::{
msg::{Message, Request, Response},
msg::{Message, Request, Response, CURRENT_API_VERSION},
ProcMacroKind, ServerError,
};
@ -19,19 +19,52 @@ pub(crate) struct ProcMacroProcessSrv {
_process: Process,
stdin: ChildStdin,
stdout: BufReader<ChildStdout>,
version: u32,
}
impl ProcMacroProcessSrv {
pub(crate) fn run(
process_path: AbsPathBuf,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
args: impl IntoIterator<Item = impl AsRef<OsStr>> + Clone,
) -> io::Result<ProcMacroProcessSrv> {
let mut process = Process::run(process_path, args)?;
let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
let create_srv = || {
let mut process = Process::run(process_path.clone(), args.clone())?;
let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
let srv = ProcMacroProcessSrv { _process: process, stdin, stdout };
io::Result::Ok(ProcMacroProcessSrv { _process: process, stdin, stdout, version: 0 })
};
let mut srv = create_srv()?;
tracing::info!("sending version check");
match srv.version_check() {
Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::new(
io::ErrorKind::Other,
format!(
"proc-macro server's api version ({}) is newer than rust-analyzer's ({})",
v, CURRENT_API_VERSION
),
)),
Ok(v) => {
tracing::info!("got version {v}");
srv.version = v;
Ok(srv)
}
Err(e) => {
tracing::info!(%e, "proc-macro version check failed, restarting and assuming version 0");
create_srv()
}
}
}
Ok(srv)
pub(crate) fn version_check(&mut self) -> Result<u32, ServerError> {
let request = Request::ApiVersionCheck {};
let response = self.send_task(request)?;
match response {
Response::ApiVersionCheck(version) => Ok(version),
Response::ExpandMacro { .. } | Response::ListMacros { .. } => {
Err(ServerError { message: "unexpected response".to_string(), io: None })
}
}
}
pub(crate) fn find_proc_macros(
@ -44,7 +77,7 @@ impl ProcMacroProcessSrv {
match response {
Response::ListMacros(it) => Ok(it),
Response::ExpandMacro { .. } => {
Response::ExpandMacro { .. } | Response::ApiVersionCheck { .. } => {
Err(ServerError { message: "unexpected response".to_string(), io: None })
}
}

View File

@ -15,6 +15,9 @@ pub fn run() -> io::Result<()> {
msg::Response::ListMacros(srv.list_macros(&dylib_path))
}
msg::Request::ExpandMacro(task) => msg::Response::ExpandMacro(srv.expand(task)),
msg::Request::ApiVersionCheck {} => {
msg::Response::ApiVersionCheck(proc_macro_api::msg::CURRENT_API_VERSION)
}
};
write_response(res)?
}