From 376bca919ea6a2b33ed0f232e357df5ce0f645c4 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 27 Nov 2025 18:56:47 +0530 Subject: [PATCH 01/15] Add bidirectional messaging proc-macro-srv --- Cargo.lock | 3 + .../hir-def/src/macro_expansion_tests/mod.rs | 3 +- crates/hir-expand/src/proc_macro.rs | 4 +- crates/load-cargo/src/lib.rs | 6 +- crates/proc-macro-api/Cargo.toml | 1 + .../src/bidirectional_protocol.rs | 296 +++++++++++++++++ .../src/bidirectional_protocol/msg.rs | 114 +++++++ crates/proc-macro-api/src/legacy_protocol.rs | 23 +- .../proc-macro-api/src/legacy_protocol/msg.rs | 2 +- crates/proc-macro-api/src/lib.rs | 11 +- crates/proc-macro-api/src/process.rs | 173 +++++++--- crates/proc-macro-api/src/transport.rs | 3 + .../src/{ => transport}/codec.rs | 5 +- .../codec}/json.rs | 6 +- .../codec}/postcard.rs | 6 +- .../src/{ => transport}/framing.rs | 4 +- crates/proc-macro-srv-cli/Cargo.toml | 1 + crates/proc-macro-srv-cli/src/main.rs | 6 + crates/proc-macro-srv-cli/src/main_loop.rs | 309 +++++++++++++++++- crates/proc-macro-srv/Cargo.toml | 1 + crates/proc-macro-srv/src/dylib.rs | 26 ++ .../proc-macro-srv/src/dylib/proc_macros.rs | 77 ++++- crates/proc-macro-srv/src/lib.rs | 86 ++++- .../src/server_impl/rust_analyzer_span.rs | 24 +- .../src/server_impl/token_id.rs | 4 + crates/test-fixture/src/lib.rs | 10 + 26 files changed, 1112 insertions(+), 92 deletions(-) create mode 100644 crates/proc-macro-api/src/bidirectional_protocol.rs create mode 100644 crates/proc-macro-api/src/bidirectional_protocol/msg.rs create mode 100644 crates/proc-macro-api/src/transport.rs rename crates/proc-macro-api/src/{ => transport}/codec.rs (76%) rename crates/proc-macro-api/src/{legacy_protocol => transport/codec}/json.rs (89%) rename crates/proc-macro-api/src/{legacy_protocol => transport/codec}/postcard.rs (84%) rename crates/proc-macro-api/src/{ => transport}/framing.rs (63%) diff --git a/Cargo.lock b/Cargo.lock index efe56cb7f61c..060a62b112b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1836,6 +1836,7 @@ dependencies = [ name = "proc-macro-api" version = "0.0.0" dependencies = [ + "base-db", "indexmap", "intern", "paths", @@ -1856,6 +1857,7 @@ dependencies = [ name = "proc-macro-srv" version = "0.0.0" dependencies = [ + "crossbeam-channel", "expect-test", "intern", "libc", @@ -1874,6 +1876,7 @@ name = "proc-macro-srv-cli" version = "0.0.0" dependencies = [ "clap", + "crossbeam-channel", "postcard", "proc-macro-api", "proc-macro-srv", diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index 78af976e1b13..07cad9695b61 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -16,7 +16,7 @@ mod proc_macros; use std::{any::TypeId, iter, ops::Range, sync}; -use base_db::RootQueryDb; +use base_db::{RootQueryDb, SourceDatabase}; use expect_test::Expect; use hir_expand::{ AstId, InFile, MacroCallId, MacroCallKind, MacroKind, @@ -374,6 +374,7 @@ struct IdentityWhenValidProcMacroExpander; impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &base_db::Env, diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index f97d721dfa88..d2614aa5f149 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -4,7 +4,7 @@ use core::fmt; use std::any::Any; use std::{panic::RefUnwindSafe, sync}; -use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError}; +use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError, SourceDatabase}; use intern::Symbol; use rustc_hash::FxHashMap; use span::Span; @@ -25,6 +25,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any { /// [`ProcMacroKind::Attr`]), environment variables, and span information. fn expand( &self, + db: &dyn SourceDatabase, subtree: &tt::TopSubtree, attrs: Option<&tt::TopSubtree>, env: &Env, @@ -309,6 +310,7 @@ impl CustomProcMacroExpander { let current_dir = calling_crate.data(db).proc_macro_cwd.to_string(); match proc_macro.expander.expand( + db, tt, attr_arg, env, diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 28fbfecfde80..e043e4ac7634 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -17,7 +17,9 @@ use hir_expand::proc_macro::{ }; use ide_db::{ ChangeWithProcMacros, FxHashMap, RootDatabase, - base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId}, + base_db::{ + CrateGraphBuilder, Env, ProcMacroLoadingError, SourceDatabase, SourceRoot, SourceRootId, + }, prime_caches, }; use itertools::Itertools; @@ -522,6 +524,7 @@ struct Expander(proc_macro_api::ProcMacro); impl ProcMacroExpander for Expander { fn expand( &self, + db: &dyn SourceDatabase, subtree: &tt::TopSubtree, attrs: Option<&tt::TopSubtree>, env: &Env, @@ -531,6 +534,7 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result, ProcMacroExpansionError> { match self.0.expand( + db, subtree.view(), attrs.map(|attrs| attrs.view()), env.clone().into(), diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 4de1a3e5dd7d..7e56d68964ce 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -19,6 +19,7 @@ serde_json = { workspace = true, features = ["unbounded_depth"] } tracing.workspace = true rustc-hash.workspace = true indexmap.workspace = true +base-db.workspace = true # local deps paths = { workspace = true, features = ["serde1"] } diff --git a/crates/proc-macro-api/src/bidirectional_protocol.rs b/crates/proc-macro-api/src/bidirectional_protocol.rs new file mode 100644 index 000000000000..246f70a10196 --- /dev/null +++ b/crates/proc-macro-api/src/bidirectional_protocol.rs @@ -0,0 +1,296 @@ +//! Bidirectional protocol methods + +use std::{ + io::{self, BufRead, Write}, + sync::Arc, +}; + +use base_db::SourceDatabase; +use paths::AbsPath; +use span::{FileId, Span}; + +use crate::{ + Codec, ProcMacro, ProcMacroKind, ServerError, + bidirectional_protocol::msg::{ + Envelope, ExpandMacro, ExpandMacroData, ExpnGlobals, Kind, Payload, Request, RequestId, + Response, SubRequest, SubResponse, + }, + legacy_protocol::{ + SpanMode, + msg::{ + FlatTree, ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map, + serialize_span_data_index_map, + }, + }, + process::ProcMacroServerProcess, + transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, + version, +}; + +pub mod msg; + +pub trait ClientCallbacks { + fn handle_sub_request(&mut self, id: u64, req: SubRequest) -> Result; +} + +pub fn run_conversation( + writer: &mut dyn Write, + reader: &mut dyn BufRead, + buf: &mut C::Buf, + id: RequestId, + initial: Payload, + callbacks: &mut dyn ClientCallbacks, +) -> Result { + let msg = Envelope { id, kind: Kind::Request, payload: initial }; + let encoded = C::encode(&msg).map_err(wrap_encode)?; + C::write(writer, &encoded).map_err(wrap_io("failed to write initial request"))?; + + loop { + let maybe_buf = C::read(reader, buf).map_err(wrap_io("failed to read message"))?; + let Some(b) = maybe_buf else { + return Err(ServerError { + message: "proc-macro server closed the stream".into(), + io: Some(Arc::new(io::Error::new(io::ErrorKind::UnexpectedEof, "closed"))), + }); + }; + + let msg: Envelope = C::decode(b).map_err(wrap_decode)?; + + if msg.id != id { + return Err(ServerError { + message: format!("unexpected message id {}, expected {}", msg.id, id), + io: None, + }); + } + + match (msg.kind, msg.payload) { + (Kind::SubRequest, Payload::SubRequest(sr)) => { + let resp = callbacks.handle_sub_request(id, sr)?; + let reply = + Envelope { id, kind: Kind::SubResponse, payload: Payload::SubResponse(resp) }; + let encoded = C::encode(&reply).map_err(wrap_encode)?; + C::write(writer, &encoded).map_err(wrap_io("failed to write sub-response"))?; + } + (Kind::Response, payload) => { + return Ok(payload); + } + (kind, payload) => { + return Err(ServerError { + message: format!( + "unexpected message kind {:?} with payload {:?}", + kind, payload + ), + io: None, + }); + } + } + } +} + +fn wrap_io(msg: &'static str) -> impl Fn(io::Error) -> ServerError { + move |err| ServerError { message: msg.into(), io: Some(Arc::new(err)) } +} + +fn wrap_encode(err: io::Error) -> ServerError { + ServerError { message: "failed to encode message".into(), io: Some(Arc::new(err)) } +} + +fn wrap_decode(err: io::Error) -> ServerError { + ServerError { message: "failed to decode message".into(), io: Some(Arc::new(err)) } +} + +pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result { + let request = Payload::Request(Request::ApiVersionCheck {}); + + struct NoCallbacks; + impl ClientCallbacks for NoCallbacks { + fn handle_sub_request( + &mut self, + _id: u64, + _req: SubRequest, + ) -> Result { + Err(ServerError { message: "sub-request not supported here".into(), io: None }) + } + } + + let mut callbacks = NoCallbacks; + + let response_payload = + run_bidirectional(srv, (0, Kind::Request, request).into(), &mut callbacks)?; + + match response_payload { + Payload::Response(Response::ApiVersionCheck(version)) => Ok(version), + other => { + Err(ServerError { message: format!("unexpected response: {:?}", other), io: None }) + } + } +} + +/// Enable support for rust-analyzer span mode if the server supports it. +pub(crate) fn enable_rust_analyzer_spans( + srv: &ProcMacroServerProcess, +) -> Result { + let request = + Payload::Request(Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer })); + + struct NoCallbacks; + impl ClientCallbacks for NoCallbacks { + fn handle_sub_request( + &mut self, + _id: u64, + _req: SubRequest, + ) -> Result { + Err(ServerError { message: "sub-request not supported here".into(), io: None }) + } + } + + let mut callbacks = NoCallbacks; + + let response_payload = + run_bidirectional(srv, (0, Kind::Request, request).into(), &mut callbacks)?; + + match response_payload { + Payload::Response(Response::SetConfig(ServerConfig { span_mode })) => Ok(span_mode), + _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + } +} + +/// Finds proc-macros in a given dynamic library. +pub(crate) fn find_proc_macros( + srv: &ProcMacroServerProcess, + dylib_path: &AbsPath, +) -> Result, String>, ServerError> { + let request = + Payload::Request(Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() }); + + struct NoCallbacks; + impl ClientCallbacks for NoCallbacks { + fn handle_sub_request( + &mut self, + _id: u64, + _req: SubRequest, + ) -> Result { + Err(ServerError { message: "sub-request not supported here".into(), io: None }) + } + } + + let mut callbacks = NoCallbacks; + + let response_payload = + run_bidirectional(srv, (0, Kind::Request, request).into(), &mut callbacks)?; + + match response_payload { + Payload::Response(Response::ListMacros(it)) => Ok(it), + _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + } +} + +pub(crate) fn expand( + proc_macro: &ProcMacro, + db: &dyn SourceDatabase, + subtree: tt::SubtreeView<'_, Span>, + attr: Option>, + env: Vec<(String, String)>, + def_site: Span, + call_site: Span, + mixed_site: Span, + current_dir: String, +) -> Result>, String>, crate::ServerError> +{ + let version = proc_macro.process.version(); + let mut span_data_table = SpanDataIndexMap::default(); + let def_site = span_data_table.insert_full(def_site).0; + let call_site = span_data_table.insert_full(call_site).0; + let mixed_site = span_data_table.insert_full(mixed_site).0; + let task = Payload::Request(Request::ExpandMacro(Box::new(ExpandMacro { + data: ExpandMacroData { + macro_body: FlatTree::from_subtree(subtree, version, &mut span_data_table), + macro_name: proc_macro.name.to_string(), + attributes: attr + .map(|subtree| FlatTree::from_subtree(subtree, version, &mut span_data_table)), + has_global_spans: ExpnGlobals { + serialize: version >= version::HAS_GLOBAL_SPANS, + def_site, + call_site, + mixed_site, + }, + span_data_table: if proc_macro.process.rust_analyzer_spans() { + serialize_span_data_index_map(&span_data_table) + } else { + Vec::new() + }, + }, + lib: proc_macro.dylib_path.to_path_buf().into(), + env, + current_dir: Some(current_dir), + }))); + + struct Callbacks<'de> { + db: &'de dyn SourceDatabase, + } + impl<'db> ClientCallbacks for Callbacks<'db> { + fn handle_sub_request( + &mut self, + _id: u64, + req: SubRequest, + ) -> Result { + match req { + SubRequest::SourceText { file_id, start, end } => { + let file = FileId::from_raw(file_id); + let text = self.db.file_text(file).text(self.db); + + let slice = text.get(start as usize..end as usize).map(|s| s.to_owned()); + + Ok(SubResponse::SourceTextResult { text: slice }) + } + } + } + } + + let mut callbacks = Callbacks { db }; + + let response_payload = + run_bidirectional(&proc_macro.process, (0, Kind::Request, task).into(), &mut callbacks)?; + + match response_payload { + Payload::Response(Response::ExpandMacro(it)) => Ok(it + .map(|tree| { + let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table); + if proc_macro.needs_fixup_change() { + proc_macro.change_fixup_to_match_old_server(&mut expanded); + } + expanded + }) + .map_err(|msg| msg.0)), + Payload::Response(Response::ExpandMacroExtended(it)) => Ok(it + .map(|resp| { + let mut expanded = FlatTree::to_subtree_resolved( + resp.tree, + version, + &deserialize_span_data_index_map(&resp.span_data_table), + ); + if proc_macro.needs_fixup_change() { + proc_macro.change_fixup_to_match_old_server(&mut expanded); + } + expanded + }) + .map_err(|msg| msg.0)), + _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + } +} + +fn run_bidirectional( + srv: &ProcMacroServerProcess, + msg: Envelope, + callbacks: &mut dyn ClientCallbacks, +) -> Result { + if let Some(server_error) = srv.exited() { + return Err(server_error.clone()); + } + + if srv.use_postcard() { + srv.run_bidirectional::(msg.id, msg.payload, callbacks) + } else { + srv.run_bidirectional::(msg.id, msg.payload, callbacks) + } +} diff --git a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs new file mode 100644 index 000000000000..7aed3ae1e607 --- /dev/null +++ b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -0,0 +1,114 @@ +//! Bidirectional protocol messages + +use paths::Utf8PathBuf; +use serde::{Deserialize, Serialize}; + +use crate::{ + ProcMacroKind, + legacy_protocol::msg::{FlatTree, Message, PanicMessage, ServerConfig}, +}; + +pub type RequestId = u64; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Envelope { + pub id: RequestId, + pub kind: Kind, + pub payload: Payload, +} + +impl From<(RequestId, Kind, Payload)> for Envelope { + fn from(value: (RequestId, Kind, Payload)) -> Self { + Envelope { id: value.0, kind: value.1, payload: value.2 } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +pub enum Kind { + Request, + Response, + SubRequest, + SubResponse, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum SubRequest { + SourceText { file_id: u32, start: u32, end: u32 }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum SubResponse { + SourceTextResult { text: Option }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Payload { + Request(Request), + Response(Response), + SubRequest(SubRequest), + SubResponse(SubResponse), +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Request { + ListMacros { dylib_path: Utf8PathBuf }, + ExpandMacro(Box), + ApiVersionCheck {}, + SetConfig(ServerConfig), +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Response { + ListMacros(Result, String>), + ExpandMacro(Result), + ApiVersionCheck(u32), + SetConfig(ServerConfig), + ExpandMacroExtended(Result), +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ExpandMacro { + pub lib: Utf8PathBuf, + pub env: Vec<(String, String)>, + pub current_dir: Option, + #[serde(flatten)] + pub data: ExpandMacroData, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ExpandMacroExtended { + pub tree: FlatTree, + pub span_data_table: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ExpandMacroData { + pub macro_body: FlatTree, + pub macro_name: String, + pub attributes: Option, + #[serde(skip_serializing_if = "ExpnGlobals::skip_serializing_if")] + #[serde(default)] + pub has_global_spans: ExpnGlobals, + + #[serde(skip_serializing_if = "Vec::is_empty")] + #[serde(default)] + pub span_data_table: Vec, +} + +#[derive(Clone, Copy, Default, Debug, Serialize, Deserialize)] +pub struct ExpnGlobals { + #[serde(skip_serializing)] + #[serde(default)] + pub serialize: bool, + pub def_site: usize, + pub call_site: usize, + pub mixed_site: usize, +} + +impl ExpnGlobals { + fn skip_serializing_if(&self) -> bool { + !self.serialize + } +} + +impl Message for Envelope {} diff --git a/crates/proc-macro-api/src/legacy_protocol.rs b/crates/proc-macro-api/src/legacy_protocol.rs index c2b132ddcc1d..81a9f391812c 100644 --- a/crates/proc-macro-api/src/legacy_protocol.rs +++ b/crates/proc-macro-api/src/legacy_protocol.rs @@ -1,30 +1,26 @@ //! The initial proc-macro-srv protocol, soon to be deprecated. -pub mod json; pub mod msg; -pub mod postcard; use std::{ io::{BufRead, Write}, sync::Arc, }; +use base_db::SourceDatabase; use paths::AbsPath; use span::Span; use crate::{ ProcMacro, ProcMacroKind, ServerError, - codec::Codec, - legacy_protocol::{ - json::JsonProtocol, - msg::{ - ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, Message, Request, Response, - ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map, - flat::serialize_span_data_index_map, - }, - postcard::PostcardProtocol, + legacy_protocol::msg::{ + ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, Message, Request, Response, + ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map, + flat::serialize_span_data_index_map, }, process::ProcMacroServerProcess, + transport::codec::Codec, + transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, version, }; @@ -82,6 +78,7 @@ pub(crate) fn find_proc_macros( pub(crate) fn expand( proc_macro: &ProcMacro, + _db: &dyn SourceDatabase, subtree: tt::SubtreeView<'_, Span>, attr: Option>, env: Vec<(String, String)>, @@ -155,9 +152,9 @@ fn send_task(srv: &ProcMacroServerProcess, req: Request) -> Result, req) + srv.send_task::<_, _, PostcardProtocol>(send_request::, req) } else { - srv.send_task(send_request::, req) + srv.send_task::<_, _, JsonProtocol>(send_request::, req) } } diff --git a/crates/proc-macro-api/src/legacy_protocol/msg.rs b/crates/proc-macro-api/src/legacy_protocol/msg.rs index a6e228d977db..0ebb0e9f93d5 100644 --- a/crates/proc-macro-api/src/legacy_protocol/msg.rs +++ b/crates/proc-macro-api/src/legacy_protocol/msg.rs @@ -8,7 +8,7 @@ use paths::Utf8PathBuf; use serde::de::DeserializeOwned; use serde_derive::{Deserialize, Serialize}; -use crate::{ProcMacroKind, codec::Codec}; +use crate::{Codec, ProcMacroKind}; /// Represents requests sent from the client to the proc-macro-srv. #[derive(Debug, Serialize, Deserialize)] diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 85b250eddfd4..7b9b5b39ab1c 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -16,18 +16,19 @@ #[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; -mod codec; -mod framing; +pub mod bidirectional_protocol; pub mod legacy_protocol; mod process; +pub mod transport; +use base_db::SourceDatabase; use paths::{AbsPath, AbsPathBuf}; use semver::Version; use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; use std::{fmt, io, sync::Arc, time::SystemTime}; -pub use crate::codec::Codec; use crate::process::ProcMacroServerProcess; +pub use crate::transport::codec::Codec; /// The versions of the server protocol pub mod version { @@ -218,6 +219,7 @@ impl ProcMacro { /// This includes span information and environmental context. pub fn expand( &self, + db: &dyn SourceDatabase, subtree: tt::SubtreeView<'_, Span>, attr: Option>, env: Vec<(String, String)>, @@ -240,7 +242,8 @@ impl ProcMacro { } } - legacy_protocol::expand( + self.process.expand( + db, self, subtree, attr, diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index d6a8d27bfc42..39d954855187 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -7,12 +7,18 @@ use std::{ sync::{Arc, Mutex, OnceLock}, }; +use base_db::SourceDatabase; use paths::AbsPath; use semver::Version; +use span::Span; use stdx::JodChild; use crate::{ - ProcMacroKind, ServerError, + Codec, ProcMacro, ProcMacroKind, ServerError, + bidirectional_protocol::{ + self, ClientCallbacks, + msg::{Payload, RequestId}, + }, legacy_protocol::{self, SpanMode}, version, }; @@ -33,6 +39,8 @@ pub(crate) struct ProcMacroServerProcess { pub(crate) enum Protocol { LegacyJson { mode: SpanMode }, LegacyPostcard { mode: SpanMode }, + NewPostcard { mode: SpanMode }, + NewJson { mode: SpanMode }, } /// Maintains the state of the proc-macro server process. @@ -62,6 +70,8 @@ impl ProcMacroServerProcess { && has_working_format_flag { &[ + (Some("postcard-new"), Protocol::NewPostcard { mode: SpanMode::Id }), + (Some("json-new"), Protocol::NewJson { mode: SpanMode::Id }), (Some("postcard-legacy"), Protocol::LegacyPostcard { mode: SpanMode::Id }), (Some("json-legacy"), Protocol::LegacyJson { mode: SpanMode::Id }), ] @@ -105,9 +115,10 @@ impl ProcMacroServerProcess { && let Ok(new_mode) = srv.enable_rust_analyzer_spans() { match &mut srv.protocol { - Protocol::LegacyJson { mode } | Protocol::LegacyPostcard { mode } => { - *mode = new_mode - } + Protocol::LegacyJson { mode } + | Protocol::LegacyPostcard { mode } + | Protocol::NewJson { mode } + | Protocol::NewPostcard { mode } => *mode = new_mode, } } tracing::info!("Proc-macro server protocol: {:?}", srv.protocol); @@ -143,22 +154,32 @@ impl ProcMacroServerProcess { match self.protocol { Protocol::LegacyJson { mode } => mode == SpanMode::RustAnalyzer, Protocol::LegacyPostcard { mode } => mode == SpanMode::RustAnalyzer, + Protocol::NewJson { mode } => mode == SpanMode::RustAnalyzer, + Protocol::NewPostcard { mode } => mode == SpanMode::RustAnalyzer, } } /// Checks the API version of the running proc-macro server. fn version_check(&self) -> Result { match self.protocol { - Protocol::LegacyJson { .. } => legacy_protocol::version_check(self), - Protocol::LegacyPostcard { .. } => legacy_protocol::version_check(self), + Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { + legacy_protocol::version_check(self) + } + Protocol::NewJson { .. } | Protocol::NewPostcard { .. } => { + bidirectional_protocol::version_check(self) + } } } /// Enable support for rust-analyzer span mode if the server supports it. fn enable_rust_analyzer_spans(&self) -> Result { match self.protocol { - Protocol::LegacyJson { .. } => legacy_protocol::enable_rust_analyzer_spans(self), - Protocol::LegacyPostcard { .. } => legacy_protocol::enable_rust_analyzer_spans(self), + Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { + legacy_protocol::enable_rust_analyzer_spans(self) + } + Protocol::NewJson { .. } | Protocol::NewPostcard { .. } => { + bidirectional_protocol::enable_rust_analyzer_spans(self) + } } } @@ -168,28 +189,69 @@ impl ProcMacroServerProcess { dylib_path: &AbsPath, ) -> Result, String>, ServerError> { match self.protocol { - Protocol::LegacyJson { .. } => legacy_protocol::find_proc_macros(self, dylib_path), - Protocol::LegacyPostcard { .. } => legacy_protocol::find_proc_macros(self, dylib_path), + Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { + legacy_protocol::find_proc_macros(self, dylib_path) + } + Protocol::NewJson { .. } | Protocol::NewPostcard { .. } => { + bidirectional_protocol::find_proc_macros(self, dylib_path) + } + } + } + + pub(crate) fn expand( + &self, + db: &dyn SourceDatabase, + proc_macro: &ProcMacro, + subtree: tt::SubtreeView<'_, Span>, + attr: Option>, + env: Vec<(String, String)>, + def_site: Span, + call_site: Span, + mixed_site: Span, + current_dir: String, + ) -> Result, String>, ServerError> { + match self.protocol { + Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { + legacy_protocol::expand( + proc_macro, + db, + subtree, + attr, + env, + def_site, + call_site, + mixed_site, + current_dir, + ) + } + Protocol::NewJson { .. } | Protocol::NewPostcard { .. } => { + bidirectional_protocol::expand( + proc_macro, + db, + subtree, + attr, + env, + def_site, + call_site, + mixed_site, + current_dir, + ) + } } } - pub(crate) fn send_task( + pub(crate) fn send_task( &self, - serialize_req: impl FnOnce( + send: impl FnOnce( &mut dyn Write, &mut dyn BufRead, Request, - &mut Buf, + &mut C::Buf, ) -> Result, ServerError>, req: Request, - ) -> Result - where - Buf: Default, - { - let state = &mut *self.state.lock().unwrap(); - let mut buf = Buf::default(); - serialize_req(&mut state.stdin, &mut state.stdout, req, &mut buf) - .and_then(|res| { + ) -> Result { + self.with_locked_io::(|writer, reader, buf| { + send(writer, reader, req, buf).and_then(|res| { res.ok_or_else(|| { let message = "proc-macro server did not respond with data".to_owned(); ServerError { @@ -201,33 +263,54 @@ impl ProcMacroServerProcess { } }) }) - .map_err(|e| { - if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) { - match state.process.child.try_wait() { - Ok(None) | Err(_) => e, - Ok(Some(status)) => { - let mut msg = String::new(); - if !status.success() - && let Some(stderr) = state.process.child.stderr.as_mut() - { - _ = stderr.read_to_string(&mut msg); - } - let server_error = ServerError { - message: format!( - "proc-macro server exited with {status}{}{msg}", - if msg.is_empty() { "" } else { ": " } - ), - io: None, - }; - // `AssertUnwindSafe` is fine here, we already correct initialized - // server_error at this point. - self.exited.get_or_init(|| AssertUnwindSafe(server_error)).0.clone() + }) + } + + pub(crate) fn with_locked_io( + &self, + f: impl FnOnce(&mut dyn Write, &mut dyn BufRead, &mut C::Buf) -> Result, + ) -> Result { + let state = &mut *self.state.lock().unwrap(); + let mut buf = C::Buf::default(); + + f(&mut state.stdin, &mut state.stdout, &mut buf).map_err(|e| { + if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) { + match state.process.child.try_wait() { + Ok(None) | Err(_) => e, + Ok(Some(status)) => { + let mut msg = String::new(); + if !status.success() + && let Some(stderr) = state.process.child.stderr.as_mut() + { + _ = stderr.read_to_string(&mut msg); } + let server_error = ServerError { + message: format!( + "proc-macro server exited with {status}{}{msg}", + if msg.is_empty() { "" } else { ": " } + ), + io: None, + }; + self.exited.get_or_init(|| AssertUnwindSafe(server_error)).0.clone() } - } else { - e } - }) + } else { + e + } + }) + } + + pub(crate) fn run_bidirectional( + &self, + id: RequestId, + initial: Payload, + callbacks: &mut dyn ClientCallbacks, + ) -> Result { + self.with_locked_io::(|writer, reader, buf| { + bidirectional_protocol::run_conversation::( + writer, reader, buf, id, initial, callbacks, + ) + }) } } diff --git a/crates/proc-macro-api/src/transport.rs b/crates/proc-macro-api/src/transport.rs new file mode 100644 index 000000000000..b7a1d8f7322c --- /dev/null +++ b/crates/proc-macro-api/src/transport.rs @@ -0,0 +1,3 @@ +//! Contains construct for transport of messages. +pub mod codec; +pub mod framing; diff --git a/crates/proc-macro-api/src/codec.rs b/crates/proc-macro-api/src/transport/codec.rs similarity index 76% rename from crates/proc-macro-api/src/codec.rs rename to crates/proc-macro-api/src/transport/codec.rs index baccaa6be4c2..c9afad260a56 100644 --- a/crates/proc-macro-api/src/codec.rs +++ b/crates/proc-macro-api/src/transport/codec.rs @@ -4,7 +4,10 @@ use std::io; use serde::de::DeserializeOwned; -use crate::framing::Framing; +use crate::transport::framing::Framing; + +pub mod json; +pub mod postcard; pub trait Codec: Framing { fn encode(msg: &T) -> io::Result; diff --git a/crates/proc-macro-api/src/legacy_protocol/json.rs b/crates/proc-macro-api/src/transport/codec/json.rs similarity index 89% rename from crates/proc-macro-api/src/legacy_protocol/json.rs rename to crates/proc-macro-api/src/transport/codec/json.rs index 1359c0568402..96db802e0bfd 100644 --- a/crates/proc-macro-api/src/legacy_protocol/json.rs +++ b/crates/proc-macro-api/src/transport/codec/json.rs @@ -3,14 +3,14 @@ use std::io::{self, BufRead, Write}; use serde::{Serialize, de::DeserializeOwned}; -use crate::{codec::Codec, framing::Framing}; +use crate::{Codec, transport::framing::Framing}; pub struct JsonProtocol; impl Framing for JsonProtocol { type Buf = String; - fn read<'a, R: BufRead>( + fn read<'a, R: BufRead + ?Sized>( inp: &mut R, buf: &'a mut String, ) -> io::Result> { @@ -35,7 +35,7 @@ impl Framing for JsonProtocol { } } - fn write(out: &mut W, buf: &String) -> io::Result<()> { + fn write(out: &mut W, buf: &String) -> io::Result<()> { tracing::debug!("> {}", buf); out.write_all(buf.as_bytes())?; out.write_all(b"\n")?; diff --git a/crates/proc-macro-api/src/legacy_protocol/postcard.rs b/crates/proc-macro-api/src/transport/codec/postcard.rs similarity index 84% rename from crates/proc-macro-api/src/legacy_protocol/postcard.rs rename to crates/proc-macro-api/src/transport/codec/postcard.rs index c28a9bfe3a1a..6f5319e75b37 100644 --- a/crates/proc-macro-api/src/legacy_protocol/postcard.rs +++ b/crates/proc-macro-api/src/transport/codec/postcard.rs @@ -4,14 +4,14 @@ use std::io::{self, BufRead, Write}; use serde::{Serialize, de::DeserializeOwned}; -use crate::{codec::Codec, framing::Framing}; +use crate::{Codec, transport::framing::Framing}; pub struct PostcardProtocol; impl Framing for PostcardProtocol { type Buf = Vec; - fn read<'a, R: BufRead>( + fn read<'a, R: BufRead + ?Sized>( inp: &mut R, buf: &'a mut Vec, ) -> io::Result>> { @@ -23,7 +23,7 @@ impl Framing for PostcardProtocol { Ok(Some(buf)) } - fn write(out: &mut W, buf: &Vec) -> io::Result<()> { + fn write(out: &mut W, buf: &Vec) -> io::Result<()> { out.write_all(buf)?; out.flush() } diff --git a/crates/proc-macro-api/src/framing.rs b/crates/proc-macro-api/src/transport/framing.rs similarity index 63% rename from crates/proc-macro-api/src/framing.rs rename to crates/proc-macro-api/src/transport/framing.rs index a1e6fc05ca11..2a11eb19c365 100644 --- a/crates/proc-macro-api/src/framing.rs +++ b/crates/proc-macro-api/src/transport/framing.rs @@ -5,10 +5,10 @@ use std::io::{self, BufRead, Write}; pub trait Framing { type Buf: Default; - fn read<'a, R: BufRead>( + fn read<'a, R: BufRead + ?Sized>( inp: &mut R, buf: &'a mut Self::Buf, ) -> io::Result>; - fn write(out: &mut W, buf: &Self::Buf) -> io::Result<()>; + fn write(out: &mut W, buf: &Self::Buf) -> io::Result<()>; } diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml index aa153897fa96..298592ee4763 100644 --- a/crates/proc-macro-srv-cli/Cargo.toml +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -15,6 +15,7 @@ proc-macro-srv.workspace = true proc-macro-api.workspace = true tt.workspace = true postcard.workspace = true +crossbeam-channel.workspace = true clap = {version = "4.5.42", default-features = false, features = ["std"]} [features] diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 813ac339a91d..d3dae0494fe4 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -52,6 +52,8 @@ fn main() -> std::io::Result<()> { enum ProtocolFormat { JsonLegacy, PostcardLegacy, + JsonNew, + PostcardNew, } impl ValueEnum for ProtocolFormat { @@ -65,12 +67,16 @@ impl ValueEnum for ProtocolFormat { ProtocolFormat::PostcardLegacy => { Some(clap::builder::PossibleValue::new("postcard-legacy")) } + ProtocolFormat::JsonNew => Some(clap::builder::PossibleValue::new("json-new")), + ProtocolFormat::PostcardNew => Some(clap::builder::PossibleValue::new("postcard-new")), } } fn from_str(input: &str, _ignore_case: bool) -> Result { match input { "json-legacy" => Ok(ProtocolFormat::JsonLegacy), "postcard-legacy" => Ok(ProtocolFormat::PostcardLegacy), + "postcard-new" => Ok(ProtocolFormat::PostcardNew), + "json-new" => Ok(ProtocolFormat::JsonNew), _ => Err(format!("unknown protocol format: {input}")), } } diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index df54f38cbccb..e543260964fb 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -1,16 +1,16 @@ //! The main loop of the proc-macro server. use std::io; +use crossbeam_channel::unbounded; +use proc_macro_api::bidirectional_protocol::msg::Request; use proc_macro_api::{ Codec, - legacy_protocol::{ - json::JsonProtocol, - msg::{ - self, ExpandMacroData, ExpnGlobals, Message, SpanMode, SpanTransformer, - deserialize_span_data_index_map, serialize_span_data_index_map, - }, - postcard::PostcardProtocol, + bidirectional_protocol::msg::{Envelope, Kind, Payload}, + legacy_protocol::msg::{ + self, ExpandMacroData, ExpnGlobals, Message, SpanMode, SpanTransformer, + deserialize_span_data_index_map, serialize_span_data_index_map, }, + transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, version::CURRENT_API_VERSION, }; use proc_macro_srv::{EnvSnapshot, SpanId}; @@ -39,9 +39,280 @@ pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> { match format { ProtocolFormat::JsonLegacy => run_::(), ProtocolFormat::PostcardLegacy => run_::(), + ProtocolFormat::JsonNew => run_new::(), + ProtocolFormat::PostcardNew => run_new::(), } } +fn run_new() -> io::Result<()> { + fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::ProcMacroKind { + match kind { + proc_macro_srv::ProcMacroKind::CustomDerive => { + proc_macro_api::ProcMacroKind::CustomDerive + } + proc_macro_srv::ProcMacroKind::Bang => proc_macro_api::ProcMacroKind::Bang, + proc_macro_srv::ProcMacroKind::Attr => proc_macro_api::ProcMacroKind::Attr, + } + } + + let mut buf = C::Buf::default(); + let mut stdin = io::stdin().lock(); + let mut stdout = io::stdout().lock(); + + let env_snapshot = EnvSnapshot::default(); + let srv = proc_macro_srv::ProcMacroSrv::new(&env_snapshot); + + let mut span_mode = SpanMode::Id; + + 'outer: loop { + let req_opt = Envelope::read::<_, C>(&mut stdin, &mut buf)?; + let Some(req) = req_opt else { + break 'outer; + }; + + match (req.kind, req.payload) { + (Kind::Request, Payload::Request(request)) => match request { + Request::ListMacros { dylib_path } => { + let res = srv.list_macros(&dylib_path).map(|macros| { + macros + .into_iter() + .map(|(name, kind)| (name, macro_kind_to_api(kind))) + .collect() + }); + + let resp_env = Envelope { + id: req.id, + kind: Kind::Response, + payload: Payload::Response( + proc_macro_api::bidirectional_protocol::msg::Response::ListMacros(res), + ), + }; + + resp_env.write::<_, C>(&mut stdout)?; + } + + Request::ApiVersionCheck {} => { + let resp_env = Envelope { + id: req.id, + kind: Kind::Response, + payload: Payload::Response( + proc_macro_api::bidirectional_protocol::msg::Response::ApiVersionCheck( + CURRENT_API_VERSION, + ), + ), + }; + resp_env.write::<_, C>(&mut stdout)?; + } + + Request::SetConfig(config) => { + span_mode = config.span_mode; + let resp_env = Envelope { + id: req.id, + kind: Kind::Response, + payload: Payload::Response( + proc_macro_api::bidirectional_protocol::msg::Response::SetConfig( + config, + ), + ), + }; + resp_env.write::<_, C>(&mut stdout)?; + } + + Request::ExpandMacro(task) => { + let proc_macro_api::bidirectional_protocol::msg::ExpandMacro { + lib, + env, + current_dir, + data: + proc_macro_api::bidirectional_protocol::msg::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: + proc_macro_api::bidirectional_protocol::msg::ExpnGlobals { + serialize: _, + def_site, + call_site, + mixed_site, + }, + span_data_table, + }, + } = *task; + + match span_mode { + SpanMode::Id => { + let def_site = SpanId(def_site as u32); + let call_site = SpanId(call_site as u32); + let mixed_site = SpanId(mixed_site as u32); + + let macro_body = macro_body.to_tokenstream_unresolved::( + CURRENT_API_VERSION, + |_, b| b, + ); + let attributes = attributes.map(|it| { + it.to_tokenstream_unresolved::( + CURRENT_API_VERSION, + |_, b| b, + ) + }); + + let res = srv + .expand( + lib, + &env, + current_dir, + ¯o_name, + macro_body, + attributes, + def_site, + call_site, + mixed_site, + ) + .map(|it| { + msg::FlatTree::from_tokenstream_raw::( + it, + call_site, + CURRENT_API_VERSION, + ) + }) + .map_err(|e| e.into_string().unwrap_or_default()) + .map_err(msg::PanicMessage); + + let resp_env = Envelope { + id: req.id, + kind: Kind::Response, + payload: Payload::Response(proc_macro_api::bidirectional_protocol::msg::Response::ExpandMacro(res)), + }; + + resp_env.write::<_, C>(&mut stdout)?; + } + + SpanMode::RustAnalyzer => { + let mut span_data_table = + deserialize_span_data_index_map(&span_data_table); + + let def_site_span = span_data_table[def_site]; + let call_site_span = span_data_table[call_site]; + let mixed_site_span = span_data_table[mixed_site]; + + let macro_body_ts = macro_body.to_tokenstream_resolved( + CURRENT_API_VERSION, + &span_data_table, + |a, b| srv.join_spans(a, b).unwrap_or(b), + ); + let attributes_ts = attributes.map(|it| { + it.to_tokenstream_resolved( + CURRENT_API_VERSION, + &span_data_table, + |a, b| srv.join_spans(a, b).unwrap_or(b), + ) + }); + + let (subreq_tx, subreq_rx) = unbounded::(); + let (subresp_tx, subresp_rx) = + unbounded::(); + let (result_tx, result_rx) = crossbeam_channel::bounded(1); + + std::thread::scope(|scope| { + let srv_ref = &srv; + + scope.spawn({ + let lib = lib.clone(); + let env = env.clone(); + let current_dir = current_dir.clone(); + let macro_name = macro_name.clone(); + move || { + let res = srv_ref + .expand_with_channels( + lib, + &env, + current_dir, + ¯o_name, + macro_body_ts, + attributes_ts, + def_site_span, + call_site_span, + mixed_site_span, + subresp_rx, + subreq_tx, + ) + .map(|it| { + ( + msg::FlatTree::from_tokenstream( + it, + CURRENT_API_VERSION, + call_site_span, + &mut span_data_table, + ), + serialize_span_data_index_map(&span_data_table), + ) + }) + .map(|(tree, span_data_table)| { + proc_macro_api::bidirectional_protocol::msg::ExpandMacroExtended { tree, span_data_table } + }) + .map_err(|e| e.into_string().unwrap_or_default()) + .map_err(msg::PanicMessage); + let _ = result_tx.send(res); + } + }); + + loop { + if let Ok(res) = result_rx.try_recv() { + let resp_env = Envelope { + id: req.id, + kind: Kind::Response, + payload: Payload::Response( + proc_macro_api::bidirectional_protocol::msg::Response::ExpandMacroExtended(res), + ), + }; + resp_env.write::<_, C>(&mut stdout).unwrap(); + break; + } + + let subreq = match subreq_rx.recv() { + Ok(r) => r, + Err(_) => { + break; + } + }; + + let sub_env = Envelope { + id: req.id, + kind: Kind::SubRequest, + payload: Payload::SubRequest(from_srv_req(subreq)), + }; + sub_env.write::<_, C>(&mut stdout).unwrap(); + + let resp_opt = + Envelope::read::<_, C>(&mut stdin, &mut buf).unwrap(); + let resp = match resp_opt { + Some(env) => env, + None => { + break; + } + }; + + match (resp.kind, resp.payload) { + (Kind::SubResponse, Payload::SubResponse(subresp)) => { + let _ = subresp_tx.send(from_client_res(subresp)); + } + _ => { + break; + } + } + } + }); + } + } + } + }, + _ => {} + } + } + + Ok(()) +} + fn run_() -> io::Result<()> { fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::ProcMacroKind { match kind { @@ -178,3 +449,27 @@ fn run_() -> io::Result<()> { Ok(()) } + +fn from_srv_req( + value: proc_macro_srv::SubRequest, +) -> proc_macro_api::bidirectional_protocol::msg::SubRequest { + match value { + proc_macro_srv::SubRequest::SourceText { file_id, start, end } => { + proc_macro_api::bidirectional_protocol::msg::SubRequest::SourceText { + file_id: file_id.file_id().index(), + start, + end, + } + } + } +} + +fn from_client_res( + value: proc_macro_api::bidirectional_protocol::msg::SubResponse, +) -> proc_macro_srv::SubResponse { + match value { + proc_macro_api::bidirectional_protocol::msg::SubResponse::SourceTextResult { text } => { + proc_macro_srv::SubResponse::SourceTextResult { text } + } + } +} diff --git a/crates/proc-macro-srv/Cargo.toml b/crates/proc-macro-srv/Cargo.toml index 361017178409..b2abda0bfd7f 100644 --- a/crates/proc-macro-srv/Cargo.toml +++ b/crates/proc-macro-srv/Cargo.toml @@ -22,6 +22,7 @@ paths.workspace = true # span = {workspace = true, default-features = false} does not work span = { path = "../span", version = "0.0.0", default-features = false} intern.workspace = true +crossbeam-channel.workspace = true ra-ap-rustc_lexer.workspace = true diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index 03433197b779..ba089c9549d3 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -54,6 +54,32 @@ impl Expander { .expand(macro_name, macro_body, attribute, def_site, call_site, mixed_site) } + pub(crate) fn expand_with_channels( + &self, + macro_name: &str, + macro_body: crate::token_stream::TokenStream, + attribute: Option>, + def_site: S, + call_site: S, + mixed_site: S, + cli_to_server: crossbeam_channel::Receiver, + server_to_cli: crossbeam_channel::Sender, + ) -> Result, crate::PanicMessage> + where + ::TokenStream: Default, + { + self.inner.proc_macros.expand_with_channels( + macro_name, + macro_body, + attribute, + def_site, + call_site, + mixed_site, + cli_to_server, + server_to_cli, + ) + } + pub(crate) fn list_macros(&self) -> impl Iterator { self.inner.proc_macros.list_macros() } diff --git a/crates/proc-macro-srv/src/dylib/proc_macros.rs b/crates/proc-macro-srv/src/dylib/proc_macros.rs index c879c7609d91..5b6f1cf2f332 100644 --- a/crates/proc-macro-srv/src/dylib/proc_macros.rs +++ b/crates/proc-macro-srv/src/dylib/proc_macros.rs @@ -1,5 +1,4 @@ //! Proc macro ABI - use proc_macro::bridge; use crate::{ProcMacroKind, ProcMacroSrvSpan, token_stream::TokenStream}; @@ -32,7 +31,65 @@ impl ProcMacros { { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site), + S::make_server(call_site, def_site, mixed_site, None, None), + macro_body, + cfg!(debug_assertions), + ); + return res.map_err(crate::PanicMessage::from); + } + bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { + let res = client.run( + &bridge::server::SameThread, + S::make_server(call_site, def_site, mixed_site, None, None), + macro_body, + cfg!(debug_assertions), + ); + return res.map_err(crate::PanicMessage::from); + } + bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { + let res = client.run( + &bridge::server::SameThread, + S::make_server(call_site, def_site, mixed_site, None, None), + parsed_attributes, + macro_body, + cfg!(debug_assertions), + ); + return res.map_err(crate::PanicMessage::from); + } + _ => continue, + } + } + + Err(bridge::PanicMessage::String(format!("proc-macro `{macro_name}` is missing")).into()) + } + + pub(crate) fn expand_with_channels( + &self, + macro_name: &str, + macro_body: TokenStream, + attribute: Option>, + def_site: S, + call_site: S, + mixed_site: S, + cli_to_server: crossbeam_channel::Receiver, + server_to_cli: crossbeam_channel::Sender, + ) -> Result, crate::PanicMessage> { + let parsed_attributes = attribute.unwrap_or_default(); + + for proc_macro in &self.0 { + match proc_macro { + bridge::client::ProcMacro::CustomDerive { trait_name, client, .. } + if *trait_name == macro_name => + { + let res = client.run( + &bridge::server::SameThread, + S::make_server( + call_site, + def_site, + mixed_site, + Some(cli_to_server), + Some(server_to_cli), + ), macro_body, cfg!(debug_assertions), ); @@ -41,7 +98,13 @@ impl ProcMacros { bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site), + S::make_server( + call_site, + def_site, + mixed_site, + Some(cli_to_server), + Some(server_to_cli), + ), macro_body, cfg!(debug_assertions), ); @@ -50,7 +113,13 @@ impl ProcMacros { bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site), + S::make_server( + call_site, + def_site, + mixed_site, + Some(cli_to_server), + Some(server_to_cli), + ), parsed_attributes, macro_body, cfg!(debug_assertions), diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 93319df824c0..f369ab93a2a3 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -47,7 +47,7 @@ use std::{ }; use paths::{Utf8Path, Utf8PathBuf}; -use span::Span; +use span::{EditionedFileId, Span}; use temp_dir::TempDir; pub use crate::server_impl::token_id::SpanId; @@ -91,6 +91,14 @@ impl<'env> ProcMacroSrv<'env> { } } +pub enum SubRequest { + SourceText { file_id: EditionedFileId, start: u32, end: u32 }, +} + +pub enum SubResponse { + SourceTextResult { text: Option }, +} + const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; impl ProcMacroSrv<'_> { @@ -133,6 +141,53 @@ impl ProcMacroSrv<'_> { result } + pub fn expand_with_channels( + &self, + lib: impl AsRef, + env: &[(String, String)], + current_dir: Option>, + macro_name: &str, + macro_body: token_stream::TokenStream, + attribute: Option>, + def_site: S, + call_site: S, + mixed_site: S, + cli_to_server: crossbeam_channel::Receiver, + server_to_cli: crossbeam_channel::Sender, + ) -> Result, PanicMessage> { + let snapped_env = self.env; + let expander = self.expander(lib.as_ref()).map_err(|err| PanicMessage { + message: Some(format!("failed to load macro: {err}")), + })?; + + let prev_env = EnvChange::apply(snapped_env, env, current_dir.as_ref().map(<_>::as_ref)); + + let result = thread::scope(|s| { + let thread = thread::Builder::new() + .stack_size(EXPANDER_STACK_SIZE) + .name(macro_name.to_owned()) + .spawn_scoped(s, move || { + expander.expand_with_channels( + macro_name, + macro_body, + attribute, + def_site, + call_site, + mixed_site, + cli_to_server, + server_to_cli, + ) + }); + match thread.unwrap().join() { + Ok(res) => res, + Err(e) => std::panic::resume_unwind(e), + } + }); + prev_env.rollback(); + + result + } + pub fn list_macros( &self, dylib_path: &Utf8Path, @@ -170,31 +225,54 @@ impl ProcMacroSrv<'_> { pub trait ProcMacroSrvSpan: Copy + Send + Sync { type Server: proc_macro::bridge::server::Server>; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server; + fn make_server( + call_site: Self, + def_site: Self, + mixed_site: Self, + cli_to_server: Option>, + server_to_cli: Option>, + ) -> Self::Server; } impl ProcMacroSrvSpan for SpanId { type Server = server_impl::token_id::SpanIdServer; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { + fn make_server( + call_site: Self, + def_site: Self, + mixed_site: Self, + cli_to_server: Option>, + server_to_cli: Option>, + ) -> Self::Server { Self::Server { call_site, def_site, mixed_site, + cli_to_server, + server_to_cli, tracked_env_vars: Default::default(), tracked_paths: Default::default(), } } } + impl ProcMacroSrvSpan for Span { type Server = server_impl::rust_analyzer_span::RaSpanServer; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { + fn make_server( + call_site: Self, + def_site: Self, + mixed_site: Self, + cli_to_server: Option>, + server_to_cli: Option>, + ) -> Self::Server { Self::Server { call_site, def_site, mixed_site, tracked_env_vars: Default::default(), tracked_paths: Default::default(), + cli_to_server, + server_to_cli, } } } diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 7c685c2da734..1a8f6d6730f7 100644 --- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -14,6 +14,7 @@ use proc_macro::bridge::server; use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span, TextRange, TextSize}; use crate::{ + SubRequest, SubResponse, bridge::{Diagnostic, ExpnGlobals, Literal, TokenTree}, server_impl::literal_from_str, }; @@ -28,6 +29,8 @@ pub struct RaSpanServer { pub call_site: Span, pub def_site: Span, pub mixed_site: Span, + pub cli_to_server: Option>, + pub server_to_cli: Option>, } impl server::Types for RaSpanServer { @@ -149,9 +152,26 @@ impl server::Span for RaSpanServer { /// /// See PR: /// https://github.com/rust-lang/rust/pull/55780 - fn source_text(&mut self, _span: Self::Span) -> Option { + fn source_text(&mut self, span: Self::Span) -> Option { // FIXME requires db, needs special handling wrt fixup spans - None + if self.server_to_cli.is_some() && self.cli_to_server.is_some() { + let file_id = span.anchor.file_id; + let start: u32 = span.range.start().into(); + let end: u32 = span.range.end().into(); + let _ = self.server_to_cli.clone().unwrap().send(SubRequest::SourceText { + file_id, + start, + end, + }); + self.cli_to_server + .clone() + .unwrap() + .recv() + .and_then(|SubResponse::SourceTextResult { text }| Ok(text)) + .expect("REASON") + } else { + None + } } fn parent(&mut self, _span: Self::Span) -> Option { diff --git a/crates/proc-macro-srv/src/server_impl/token_id.rs b/crates/proc-macro-srv/src/server_impl/token_id.rs index 5ac263b9d5f6..268042b3bc07 100644 --- a/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -9,6 +9,7 @@ use intern::Symbol; use proc_macro::bridge::server; use crate::{ + SubRequest, SubResponse, bridge::{Diagnostic, ExpnGlobals, Literal, TokenTree}, server_impl::literal_from_str, }; @@ -34,6 +35,8 @@ pub struct SpanIdServer { pub call_site: Span, pub def_site: Span, pub mixed_site: Span, + pub cli_to_server: Option>, + pub server_to_cli: Option>, } impl server::Types for SpanIdServer { @@ -139,6 +142,7 @@ impl server::Span for SpanIdServer { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, _span: Self::Span) -> Option { + // FIXME requires db, needs special handling wrt fixup spans None } diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs index 5e8b250c24a0..e08a65c39204 100644 --- a/crates/test-fixture/src/lib.rs +++ b/crates/test-fixture/src/lib.rs @@ -732,6 +732,7 @@ struct IdentityProcMacroExpander; impl ProcMacroExpander for IdentityProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -754,6 +755,7 @@ struct Issue18089ProcMacroExpander; impl ProcMacroExpander for Issue18089ProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -789,6 +791,7 @@ struct AttributeInputReplaceProcMacroExpander; impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, _: &TopSubtree, attrs: Option<&TopSubtree>, _: &Env, @@ -812,6 +815,7 @@ struct Issue18840ProcMacroExpander; impl ProcMacroExpander for Issue18840ProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, fn_: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -847,6 +851,7 @@ struct MirrorProcMacroExpander; impl ProcMacroExpander for MirrorProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, input: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -885,6 +890,7 @@ struct ShortenProcMacroExpander; impl ProcMacroExpander for ShortenProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, input: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -927,6 +933,7 @@ struct Issue17479ProcMacroExpander; impl ProcMacroExpander for Issue17479ProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -956,6 +963,7 @@ struct Issue18898ProcMacroExpander; impl ProcMacroExpander for Issue18898ProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1011,6 +1019,7 @@ struct DisallowCfgProcMacroExpander; impl ProcMacroExpander for DisallowCfgProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1042,6 +1051,7 @@ struct GenerateSuffixedTypeProcMacroExpander; impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander { fn expand( &self, + _: &dyn SourceDatabase, subtree: &TopSubtree, _attrs: Option<&TopSubtree>, _env: &Env, From 80705fb3907fe29111d11f1f37fa52b181745387 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 15 Dec 2025 20:02:26 +0530 Subject: [PATCH 02/15] remove salsa dependency check on proc_macro_srv_cli --- .github/workflows/ci.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5975272d871a..623200aea032 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -71,9 +71,6 @@ jobs: - name: Test run: cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api -- --quiet - - name: Check salsa dependency - run: "! (cargo tree -p proc-macro-srv-cli | grep -q salsa)" - rust: if: github.repository == 'rust-lang/rust-analyzer' name: Rust From 178d6ce761ebff096d18eb45f0e3d67550d8945c Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 15 Dec 2025 20:16:51 +0530 Subject: [PATCH 03/15] make json-new as default protocol choice for proc-macro-srv-cli --- crates/proc-macro-srv-cli/src/main.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index d3dae0494fe4..c9134b402dfa 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -31,7 +31,7 @@ fn main() -> std::io::Result<()> { clap::Arg::new("format") .long("format") .action(clap::ArgAction::Set) - .default_value("json-legacy") + .default_value("json-new") .value_parser(clap::builder::EnumValueParser::::new()), clap::Arg::new("version") .long("version") @@ -58,7 +58,12 @@ enum ProtocolFormat { impl ValueEnum for ProtocolFormat { fn value_variants<'a>() -> &'a [Self] { - &[ProtocolFormat::JsonLegacy, ProtocolFormat::PostcardLegacy] + &[ + ProtocolFormat::JsonLegacy, + ProtocolFormat::PostcardLegacy, + ProtocolFormat::JsonNew, + ProtocolFormat::PostcardNew, + ] } fn to_possible_value(&self) -> Option { From 28a3b808c4af775ce97611e2cb9c5b73f5eaf034 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 18 Dec 2025 10:10:23 +0530 Subject: [PATCH 04/15] add request id to requests --- .../src/bidirectional_protocol.rs | 50 ++++++------------- crates/proc-macro-api/src/process.rs | 11 +++- .../src/server_impl/rust_analyzer_span.rs | 9 ++-- 3 files changed, 29 insertions(+), 41 deletions(-) diff --git a/crates/proc-macro-api/src/bidirectional_protocol.rs b/crates/proc-macro-api/src/bidirectional_protocol.rs index 246f70a10196..728f0f707d71 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol.rs @@ -30,7 +30,7 @@ use crate::{ pub mod msg; pub trait ClientCallbacks { - fn handle_sub_request(&mut self, id: u64, req: SubRequest) -> Result; + fn handle_sub_request(&mut self, req: SubRequest) -> Result; } pub fn run_conversation( @@ -65,7 +65,7 @@ pub fn run_conversation( match (msg.kind, msg.payload) { (Kind::SubRequest, Payload::SubRequest(sr)) => { - let resp = callbacks.handle_sub_request(id, sr)?; + let resp = callbacks.handle_sub_request(sr)?; let reply = Envelope { id, kind: Kind::SubResponse, payload: Payload::SubResponse(resp) }; let encoded = C::encode(&reply).map_err(wrap_encode)?; @@ -104,19 +104,14 @@ pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result Result { + fn handle_sub_request(&mut self, _req: SubRequest) -> Result { Err(ServerError { message: "sub-request not supported here".into(), io: None }) } } let mut callbacks = NoCallbacks; - let response_payload = - run_bidirectional(srv, (0, Kind::Request, request).into(), &mut callbacks)?; + let response_payload = run_request(srv, request, &mut callbacks)?; match response_payload { Payload::Response(Response::ApiVersionCheck(version)) => Ok(version), @@ -135,19 +130,14 @@ pub(crate) fn enable_rust_analyzer_spans( struct NoCallbacks; impl ClientCallbacks for NoCallbacks { - fn handle_sub_request( - &mut self, - _id: u64, - _req: SubRequest, - ) -> Result { + fn handle_sub_request(&mut self, _req: SubRequest) -> Result { Err(ServerError { message: "sub-request not supported here".into(), io: None }) } } let mut callbacks = NoCallbacks; - let response_payload = - run_bidirectional(srv, (0, Kind::Request, request).into(), &mut callbacks)?; + let response_payload = run_request(srv, request, &mut callbacks)?; match response_payload { Payload::Response(Response::SetConfig(ServerConfig { span_mode })) => Ok(span_mode), @@ -165,19 +155,14 @@ pub(crate) fn find_proc_macros( struct NoCallbacks; impl ClientCallbacks for NoCallbacks { - fn handle_sub_request( - &mut self, - _id: u64, - _req: SubRequest, - ) -> Result { + fn handle_sub_request(&mut self, _req: SubRequest) -> Result { Err(ServerError { message: "sub-request not supported here".into(), io: None }) } } let mut callbacks = NoCallbacks; - let response_payload = - run_bidirectional(srv, (0, Kind::Request, request).into(), &mut callbacks)?; + let response_payload = run_request(srv, request, &mut callbacks)?; match response_payload { Payload::Response(Response::ListMacros(it)) => Ok(it), @@ -229,11 +214,7 @@ pub(crate) fn expand( db: &'de dyn SourceDatabase, } impl<'db> ClientCallbacks for Callbacks<'db> { - fn handle_sub_request( - &mut self, - _id: u64, - req: SubRequest, - ) -> Result { + fn handle_sub_request(&mut self, req: SubRequest) -> Result { match req { SubRequest::SourceText { file_id, start, end } => { let file = FileId::from_raw(file_id); @@ -249,8 +230,7 @@ pub(crate) fn expand( let mut callbacks = Callbacks { db }; - let response_payload = - run_bidirectional(&proc_macro.process, (0, Kind::Request, task).into(), &mut callbacks)?; + let response_payload = run_request(&proc_macro.process, task, &mut callbacks)?; match response_payload { Payload::Response(Response::ExpandMacro(it)) => Ok(it @@ -279,18 +259,20 @@ pub(crate) fn expand( } } -fn run_bidirectional( +fn run_request( srv: &ProcMacroServerProcess, - msg: Envelope, + msg: Payload, callbacks: &mut dyn ClientCallbacks, ) -> Result { if let Some(server_error) = srv.exited() { return Err(server_error.clone()); } + let id = srv.request_id(); + if srv.use_postcard() { - srv.run_bidirectional::(msg.id, msg.payload, callbacks) + srv.run_bidirectional::(id, msg, callbacks) } else { - srv.run_bidirectional::(msg.id, msg.payload, callbacks) + srv.run_bidirectional::(id, msg, callbacks) } } diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 39d954855187..723fc928ff66 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -4,7 +4,10 @@ use std::{ io::{self, BufRead, BufReader, Read, Write}, panic::AssertUnwindSafe, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, - sync::{Arc, Mutex, OnceLock}, + sync::{ + Arc, Mutex, OnceLock, + atomic::{AtomicU64, Ordering}, + }, }; use base_db::SourceDatabase; @@ -33,6 +36,7 @@ pub(crate) struct ProcMacroServerProcess { protocol: Protocol, /// Populated when the server exits. exited: OnceLock>, + next_request_id: AtomicU64, } #[derive(Debug, Clone)] @@ -90,6 +94,7 @@ impl ProcMacroServerProcess { version: 0, protocol: protocol.clone(), exited: OnceLock::new(), + next_request_id: AtomicU64::new(1), }) }; let mut srv = create_srv()?; @@ -312,6 +317,10 @@ impl ProcMacroServerProcess { ) }) } + + pub(crate) fn request_id(&self) -> RequestId { + self.next_request_id.fetch_add(1, Ordering::Relaxed) + } } /// Manages the execution of the proc-macro server process. diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 1a8f6d6730f7..cccb74429dd6 100644 --- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -163,12 +163,9 @@ impl server::Span for RaSpanServer { start, end, }); - self.cli_to_server - .clone() - .unwrap() - .recv() - .and_then(|SubResponse::SourceTextResult { text }| Ok(text)) - .expect("REASON") + match self.cli_to_server.as_ref()?.recv().ok()? { + SubResponse::SourceTextResult { text } => text, + } } else { None } From 57fdf52eccf00fe95f79251b8fe6fbf5817c7ea3 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 18 Dec 2025 14:05:45 +0530 Subject: [PATCH 05/15] refactor the main loop in proc_macro-srv-cli --- crates/proc-macro-srv-cli/src/main_loop.rs | 458 +++++++++++---------- 1 file changed, 247 insertions(+), 211 deletions(-) diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index e543260964fb..aec971c776e2 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -80,236 +80,254 @@ fn run_new() -> io::Result<()> { .collect() }); - let resp_env = Envelope { - id: req.id, - kind: Kind::Response, - payload: Payload::Response( - proc_macro_api::bidirectional_protocol::msg::Response::ListMacros(res), - ), - }; - - resp_env.write::<_, C>(&mut stdout)?; + send_response::<_, C>( + &mut stdout, + req.id, + proc_macro_api::bidirectional_protocol::msg::Response::ListMacros(res), + )?; } Request::ApiVersionCheck {} => { - let resp_env = Envelope { - id: req.id, - kind: Kind::Response, - payload: Payload::Response( - proc_macro_api::bidirectional_protocol::msg::Response::ApiVersionCheck( - CURRENT_API_VERSION, - ), + send_response::<_, C>( + &mut stdout, + req.id, + proc_macro_api::bidirectional_protocol::msg::Response::ApiVersionCheck( + CURRENT_API_VERSION, ), - }; - resp_env.write::<_, C>(&mut stdout)?; + )?; } Request::SetConfig(config) => { span_mode = config.span_mode; - let resp_env = Envelope { - id: req.id, - kind: Kind::Response, - payload: Payload::Response( - proc_macro_api::bidirectional_protocol::msg::Response::SetConfig( - config, - ), - ), - }; - resp_env.write::<_, C>(&mut stdout)?; + send_response::<_, C>( + &mut stdout, + req.id, + proc_macro_api::bidirectional_protocol::msg::Response::SetConfig(config), + )?; } - Request::ExpandMacro(task) => { - let proc_macro_api::bidirectional_protocol::msg::ExpandMacro { + handle_expand::<_, _, C>( + &srv, + &mut stdin, + &mut stdout, + &mut buf, + req.id, + span_mode, + *task, + )?; + } + }, + _ => continue, + } + } + + Ok(()) +} + +fn handle_expand( + srv: &proc_macro_srv::ProcMacroSrv<'_>, + stdin: &mut R, + stdout: &mut W, + buf: &mut C::Buf, + req_id: u64, + span_mode: SpanMode, + task: proc_macro_api::bidirectional_protocol::msg::ExpandMacro, +) -> io::Result<()> { + match span_mode { + SpanMode::Id => handle_expand_id::<_, C>(srv, stdout, req_id, task), + SpanMode::RustAnalyzer => { + handle_expand_ra::<_, _, C>(srv, stdin, stdout, buf, req_id, task) + } + } +} + +fn handle_expand_id( + srv: &proc_macro_srv::ProcMacroSrv<'_>, + stdout: &mut W, + req_id: u64, + task: proc_macro_api::bidirectional_protocol::msg::ExpandMacro, +) -> io::Result<()> { + let proc_macro_api::bidirectional_protocol::msg::ExpandMacro { lib, env, current_dir, data } = + task; + let proc_macro_api::bidirectional_protocol::msg::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: + proc_macro_api::bidirectional_protocol::msg::ExpnGlobals { + def_site, + call_site, + mixed_site, + .. + }, + .. + } = data; + + let def_site = SpanId(def_site as u32); + let call_site = SpanId(call_site as u32); + let mixed_site = SpanId(mixed_site as u32); + + let macro_body = + macro_body.to_tokenstream_unresolved::(CURRENT_API_VERSION, |_, b| b); + let attributes = attributes + .map(|it| it.to_tokenstream_unresolved::(CURRENT_API_VERSION, |_, b| b)); + + let res = srv + .expand( + lib, + &env, + current_dir, + ¯o_name, + macro_body, + attributes, + def_site, + call_site, + mixed_site, + ) + .map(|it| { + msg::FlatTree::from_tokenstream_raw::(it, call_site, CURRENT_API_VERSION) + }) + .map_err(|e| msg::PanicMessage(e.into_string().unwrap_or_default())); + + send_response::<_, C>( + stdout, + req_id, + proc_macro_api::bidirectional_protocol::msg::Response::ExpandMacro(res), + ) +} + +fn handle_expand_ra( + srv: &proc_macro_srv::ProcMacroSrv<'_>, + stdin: &mut R, + stdout: &mut W, + buf: &mut C::Buf, + req_id: u64, + task: proc_macro_api::bidirectional_protocol::msg::ExpandMacro, +) -> io::Result<()> { + let proc_macro_api::bidirectional_protocol::msg::ExpandMacro { + lib, + env, + current_dir, + data: + proc_macro_api::bidirectional_protocol::msg::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: + proc_macro_api::bidirectional_protocol::msg::ExpnGlobals { + serialize: _, + def_site, + call_site, + mixed_site, + }, + span_data_table, + }, + } = task; + + let mut span_data_table = deserialize_span_data_index_map(&span_data_table); + + let def_site_span = span_data_table[def_site]; + let call_site_span = span_data_table[call_site]; + let mixed_site_span = span_data_table[mixed_site]; + + let macro_body_ts = + macro_body.to_tokenstream_resolved(CURRENT_API_VERSION, &span_data_table, |a, b| { + srv.join_spans(a, b).unwrap_or(b) + }); + let attributes_ts = attributes.map(|it| { + it.to_tokenstream_resolved(CURRENT_API_VERSION, &span_data_table, |a, b| { + srv.join_spans(a, b).unwrap_or(b) + }) + }); + + let (subreq_tx, subreq_rx) = unbounded::(); + let (subresp_tx, subresp_rx) = unbounded::(); + let (result_tx, result_rx) = crossbeam_channel::bounded(1); + + std::thread::scope(|scope| { + let srv_ref = &srv; + + scope.spawn({ + let lib = lib.clone(); + let env = env.clone(); + let current_dir = current_dir.clone(); + let macro_name = macro_name.clone(); + move || { + let res = srv_ref + .expand_with_channels( lib, - env, + &env, current_dir, - data: - proc_macro_api::bidirectional_protocol::msg::ExpandMacroData { - macro_body, - macro_name, - attributes, - has_global_spans: - proc_macro_api::bidirectional_protocol::msg::ExpnGlobals { - serialize: _, - def_site, - call_site, - mixed_site, - }, - span_data_table, - }, - } = *task; - - match span_mode { - SpanMode::Id => { - let def_site = SpanId(def_site as u32); - let call_site = SpanId(call_site as u32); - let mixed_site = SpanId(mixed_site as u32); - - let macro_body = macro_body.to_tokenstream_unresolved::( + ¯o_name, + macro_body_ts, + attributes_ts, + def_site_span, + call_site_span, + mixed_site_span, + subresp_rx, + subreq_tx, + ) + .map(|it| { + ( + msg::FlatTree::from_tokenstream( + it, CURRENT_API_VERSION, - |_, b| b, - ); - let attributes = attributes.map(|it| { - it.to_tokenstream_unresolved::( - CURRENT_API_VERSION, - |_, b| b, - ) - }); - - let res = srv - .expand( - lib, - &env, - current_dir, - ¯o_name, - macro_body, - attributes, - def_site, - call_site, - mixed_site, - ) - .map(|it| { - msg::FlatTree::from_tokenstream_raw::( - it, - call_site, - CURRENT_API_VERSION, - ) - }) - .map_err(|e| e.into_string().unwrap_or_default()) - .map_err(msg::PanicMessage); - - let resp_env = Envelope { - id: req.id, - kind: Kind::Response, - payload: Payload::Response(proc_macro_api::bidirectional_protocol::msg::Response::ExpandMacro(res)), - }; - - resp_env.write::<_, C>(&mut stdout)?; + call_site_span, + &mut span_data_table, + ), + serialize_span_data_index_map(&span_data_table), + ) + }) + .map(|(tree, span_data_table)| { + proc_macro_api::bidirectional_protocol::msg::ExpandMacroExtended { + tree, + span_data_table, } + }) + .map_err(|e| e.into_string().unwrap_or_default()) + .map_err(msg::PanicMessage); + let _ = result_tx.send(res); + } + }); + + loop { + if let Ok(res) = result_rx.try_recv() { + send_response::<_, C>( + stdout, + req_id, + proc_macro_api::bidirectional_protocol::msg::Response::ExpandMacroExtended(res), + ) + .unwrap(); + break; + } - SpanMode::RustAnalyzer => { - let mut span_data_table = - deserialize_span_data_index_map(&span_data_table); + let subreq = match subreq_rx.recv() { + Ok(r) => r, + Err(_) => { + break; + } + }; - let def_site_span = span_data_table[def_site]; - let call_site_span = span_data_table[call_site]; - let mixed_site_span = span_data_table[mixed_site]; + send_subrequest::<_, C>(stdout, req_id, from_srv_req(subreq)).unwrap(); - let macro_body_ts = macro_body.to_tokenstream_resolved( - CURRENT_API_VERSION, - &span_data_table, - |a, b| srv.join_spans(a, b).unwrap_or(b), - ); - let attributes_ts = attributes.map(|it| { - it.to_tokenstream_resolved( - CURRENT_API_VERSION, - &span_data_table, - |a, b| srv.join_spans(a, b).unwrap_or(b), - ) - }); - - let (subreq_tx, subreq_rx) = unbounded::(); - let (subresp_tx, subresp_rx) = - unbounded::(); - let (result_tx, result_rx) = crossbeam_channel::bounded(1); - - std::thread::scope(|scope| { - let srv_ref = &srv; - - scope.spawn({ - let lib = lib.clone(); - let env = env.clone(); - let current_dir = current_dir.clone(); - let macro_name = macro_name.clone(); - move || { - let res = srv_ref - .expand_with_channels( - lib, - &env, - current_dir, - ¯o_name, - macro_body_ts, - attributes_ts, - def_site_span, - call_site_span, - mixed_site_span, - subresp_rx, - subreq_tx, - ) - .map(|it| { - ( - msg::FlatTree::from_tokenstream( - it, - CURRENT_API_VERSION, - call_site_span, - &mut span_data_table, - ), - serialize_span_data_index_map(&span_data_table), - ) - }) - .map(|(tree, span_data_table)| { - proc_macro_api::bidirectional_protocol::msg::ExpandMacroExtended { tree, span_data_table } - }) - .map_err(|e| e.into_string().unwrap_or_default()) - .map_err(msg::PanicMessage); - let _ = result_tx.send(res); - } - }); - - loop { - if let Ok(res) = result_rx.try_recv() { - let resp_env = Envelope { - id: req.id, - kind: Kind::Response, - payload: Payload::Response( - proc_macro_api::bidirectional_protocol::msg::Response::ExpandMacroExtended(res), - ), - }; - resp_env.write::<_, C>(&mut stdout).unwrap(); - break; - } - - let subreq = match subreq_rx.recv() { - Ok(r) => r, - Err(_) => { - break; - } - }; - - let sub_env = Envelope { - id: req.id, - kind: Kind::SubRequest, - payload: Payload::SubRequest(from_srv_req(subreq)), - }; - sub_env.write::<_, C>(&mut stdout).unwrap(); - - let resp_opt = - Envelope::read::<_, C>(&mut stdin, &mut buf).unwrap(); - let resp = match resp_opt { - Some(env) => env, - None => { - break; - } - }; - - match (resp.kind, resp.payload) { - (Kind::SubResponse, Payload::SubResponse(subresp)) => { - let _ = subresp_tx.send(from_client_res(subresp)); - } - _ => { - break; - } - } - } - }); - } - } + let resp_opt = Envelope::read::<_, C>(stdin, buf).unwrap(); + let resp = match resp_opt { + Some(env) => env, + None => { + break; } - }, - _ => {} - } - } + }; + match (resp.kind, resp.payload) { + (Kind::SubResponse, Payload::SubResponse(subresp)) => { + let _ = subresp_tx.send(from_client_res(subresp)); + } + _ => { + break; + } + } + } + }); Ok(()) } @@ -473,3 +491,21 @@ fn from_client_res( } } } + +fn send_response( + stdout: &mut W, + id: u64, + resp: proc_macro_api::bidirectional_protocol::msg::Response, +) -> io::Result<()> { + let resp = Envelope { id, kind: Kind::Response, payload: Payload::Response(resp) }; + resp.write::(stdout) +} + +fn send_subrequest( + stdout: &mut W, + id: u64, + resp: proc_macro_api::bidirectional_protocol::msg::SubRequest, +) -> io::Result<()> { + let resp = Envelope { id, kind: Kind::SubRequest, payload: Payload::SubRequest(resp) }; + resp.write::(stdout) +} From 58f2e178661863be683ea79d27c1c387d67b8c24 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 18 Dec 2025 14:25:15 +0530 Subject: [PATCH 06/15] make imports proper --- crates/proc-macro-srv-cli/src/main_loop.rs | 253 ++++++++++----------- 1 file changed, 120 insertions(+), 133 deletions(-) diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index aec971c776e2..1ad73d4daac2 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -2,23 +2,22 @@ use std::io; use crossbeam_channel::unbounded; -use proc_macro_api::bidirectional_protocol::msg::Request; use proc_macro_api::{ Codec, - bidirectional_protocol::msg::{Envelope, Kind, Payload}, - legacy_protocol::msg::{ - self, ExpandMacroData, ExpnGlobals, Message, SpanMode, SpanTransformer, - deserialize_span_data_index_map, serialize_span_data_index_map, - }, + bidirectional_protocol::msg as bidirectional, + legacy_protocol::msg as legacy, transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, version::CURRENT_API_VERSION, }; + +use legacy::Message; + use proc_macro_srv::{EnvSnapshot, SpanId}; use crate::ProtocolFormat; struct SpanTrans; -impl SpanTransformer for SpanTrans { +impl legacy::SpanTransformer for SpanTrans { type Table = (); type Span = SpanId; fn token_id_of( @@ -62,61 +61,61 @@ fn run_new() -> io::Result<()> { let env_snapshot = EnvSnapshot::default(); let srv = proc_macro_srv::ProcMacroSrv::new(&env_snapshot); - let mut span_mode = SpanMode::Id; + let mut span_mode = legacy::SpanMode::Id; 'outer: loop { - let req_opt = Envelope::read::<_, C>(&mut stdin, &mut buf)?; + let req_opt = bidirectional::Envelope::read::<_, C>(&mut stdin, &mut buf)?; let Some(req) = req_opt else { break 'outer; }; match (req.kind, req.payload) { - (Kind::Request, Payload::Request(request)) => match request { - Request::ListMacros { dylib_path } => { - let res = srv.list_macros(&dylib_path).map(|macros| { - macros - .into_iter() - .map(|(name, kind)| (name, macro_kind_to_api(kind))) - .collect() - }); - - send_response::<_, C>( - &mut stdout, - req.id, - proc_macro_api::bidirectional_protocol::msg::Response::ListMacros(res), - )?; - } - - Request::ApiVersionCheck {} => { - send_response::<_, C>( - &mut stdout, - req.id, - proc_macro_api::bidirectional_protocol::msg::Response::ApiVersionCheck( - CURRENT_API_VERSION, - ), - )?; - } + (bidirectional::Kind::Request, bidirectional::Payload::Request(request)) => { + match request { + bidirectional::Request::ListMacros { dylib_path } => { + let res = srv.list_macros(&dylib_path).map(|macros| { + macros + .into_iter() + .map(|(name, kind)| (name, macro_kind_to_api(kind))) + .collect() + }); - Request::SetConfig(config) => { - span_mode = config.span_mode; - send_response::<_, C>( - &mut stdout, - req.id, - proc_macro_api::bidirectional_protocol::msg::Response::SetConfig(config), - )?; - } - Request::ExpandMacro(task) => { - handle_expand::<_, _, C>( - &srv, - &mut stdin, - &mut stdout, - &mut buf, - req.id, - span_mode, - *task, - )?; + send_response::<_, C>( + &mut stdout, + req.id, + bidirectional::Response::ListMacros(res), + )?; + } + + bidirectional::Request::ApiVersionCheck {} => { + send_response::<_, C>( + &mut stdout, + req.id, + bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION), + )?; + } + + bidirectional::Request::SetConfig(config) => { + span_mode = config.span_mode; + send_response::<_, C>( + &mut stdout, + req.id, + bidirectional::Response::SetConfig(config), + )?; + } + bidirectional::Request::ExpandMacro(task) => { + handle_expand::<_, _, C>( + &srv, + &mut stdin, + &mut stdout, + &mut buf, + req.id, + span_mode, + *task, + )?; + } } - }, + } _ => continue, } } @@ -130,12 +129,12 @@ fn handle_expand( stdout: &mut W, buf: &mut C::Buf, req_id: u64, - span_mode: SpanMode, - task: proc_macro_api::bidirectional_protocol::msg::ExpandMacro, + span_mode: legacy::SpanMode, + task: bidirectional::ExpandMacro, ) -> io::Result<()> { match span_mode { - SpanMode::Id => handle_expand_id::<_, C>(srv, stdout, req_id, task), - SpanMode::RustAnalyzer => { + legacy::SpanMode::Id => handle_expand_id::<_, C>(srv, stdout, req_id, task), + legacy::SpanMode::RustAnalyzer => { handle_expand_ra::<_, _, C>(srv, stdin, stdout, buf, req_id, task) } } @@ -145,21 +144,14 @@ fn handle_expand_id( srv: &proc_macro_srv::ProcMacroSrv<'_>, stdout: &mut W, req_id: u64, - task: proc_macro_api::bidirectional_protocol::msg::ExpandMacro, + task: bidirectional::ExpandMacro, ) -> io::Result<()> { - let proc_macro_api::bidirectional_protocol::msg::ExpandMacro { lib, env, current_dir, data } = - task; - let proc_macro_api::bidirectional_protocol::msg::ExpandMacroData { + let bidirectional::ExpandMacro { lib, env, current_dir, data } = task; + let bidirectional::ExpandMacroData { macro_body, macro_name, attributes, - has_global_spans: - proc_macro_api::bidirectional_protocol::msg::ExpnGlobals { - def_site, - call_site, - mixed_site, - .. - }, + has_global_spans: bidirectional::ExpnGlobals { def_site, call_site, mixed_site, .. }, .. } = data; @@ -185,15 +177,11 @@ fn handle_expand_id( mixed_site, ) .map(|it| { - msg::FlatTree::from_tokenstream_raw::(it, call_site, CURRENT_API_VERSION) + legacy::FlatTree::from_tokenstream_raw::(it, call_site, CURRENT_API_VERSION) }) - .map_err(|e| msg::PanicMessage(e.into_string().unwrap_or_default())); + .map_err(|e| legacy::PanicMessage(e.into_string().unwrap_or_default())); - send_response::<_, C>( - stdout, - req_id, - proc_macro_api::bidirectional_protocol::msg::Response::ExpandMacro(res), - ) + send_response::<_, C>(stdout, req_id, bidirectional::Response::ExpandMacro(res)) } fn handle_expand_ra( @@ -202,29 +190,24 @@ fn handle_expand_ra( stdout: &mut W, buf: &mut C::Buf, req_id: u64, - task: proc_macro_api::bidirectional_protocol::msg::ExpandMacro, + task: bidirectional::ExpandMacro, ) -> io::Result<()> { - let proc_macro_api::bidirectional_protocol::msg::ExpandMacro { + let bidirectional::ExpandMacro { lib, env, current_dir, data: - proc_macro_api::bidirectional_protocol::msg::ExpandMacroData { + bidirectional::ExpandMacroData { macro_body, macro_name, attributes, has_global_spans: - proc_macro_api::bidirectional_protocol::msg::ExpnGlobals { - serialize: _, - def_site, - call_site, - mixed_site, - }, + bidirectional::ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, span_data_table, }, } = task; - let mut span_data_table = deserialize_span_data_index_map(&span_data_table); + let mut span_data_table = legacy::deserialize_span_data_index_map(&span_data_table); let def_site_span = span_data_table[def_site]; let call_site_span = span_data_table[call_site]; @@ -269,23 +252,21 @@ fn handle_expand_ra( ) .map(|it| { ( - msg::FlatTree::from_tokenstream( + legacy::FlatTree::from_tokenstream( it, CURRENT_API_VERSION, call_site_span, &mut span_data_table, ), - serialize_span_data_index_map(&span_data_table), + legacy::serialize_span_data_index_map(&span_data_table), ) }) - .map(|(tree, span_data_table)| { - proc_macro_api::bidirectional_protocol::msg::ExpandMacroExtended { - tree, - span_data_table, - } + .map(|(tree, span_data_table)| bidirectional::ExpandMacroExtended { + tree, + span_data_table, }) .map_err(|e| e.into_string().unwrap_or_default()) - .map_err(msg::PanicMessage); + .map_err(legacy::PanicMessage); let _ = result_tx.send(res); } }); @@ -295,7 +276,7 @@ fn handle_expand_ra( send_response::<_, C>( stdout, req_id, - proc_macro_api::bidirectional_protocol::msg::Response::ExpandMacroExtended(res), + bidirectional::Response::ExpandMacroExtended(res), ) .unwrap(); break; @@ -310,7 +291,7 @@ fn handle_expand_ra( send_subrequest::<_, C>(stdout, req_id, from_srv_req(subreq)).unwrap(); - let resp_opt = Envelope::read::<_, C>(stdin, buf).unwrap(); + let resp_opt = bidirectional::Envelope::read::<_, C>(stdin, buf).unwrap(); let resp = match resp_opt { Some(env) => env, None => { @@ -319,7 +300,10 @@ fn handle_expand_ra( }; match (resp.kind, resp.payload) { - (Kind::SubResponse, Payload::SubResponse(subresp)) => { + ( + bidirectional::Kind::SubResponse, + bidirectional::Payload::SubResponse(subresp), + ) => { let _ = subresp_tx.send(from_client_res(subresp)); } _ => { @@ -343,38 +327,38 @@ fn run_() -> io::Result<()> { } let mut buf = C::Buf::default(); - let mut read_request = || msg::Request::read::<_, C>(&mut io::stdin().lock(), &mut buf); - let write_response = |msg: msg::Response| msg.write::<_, C>(&mut io::stdout().lock()); + let mut read_request = || legacy::Request::read::<_, C>(&mut io::stdin().lock(), &mut buf); + let write_response = |msg: legacy::Response| msg.write::<_, C>(&mut io::stdout().lock()); let env = EnvSnapshot::default(); let srv = proc_macro_srv::ProcMacroSrv::new(&env); - let mut span_mode = SpanMode::Id; + let mut span_mode = legacy::SpanMode::Id; while let Some(req) = read_request()? { let res = match req { - msg::Request::ListMacros { dylib_path } => { - msg::Response::ListMacros(srv.list_macros(&dylib_path).map(|macros| { + legacy::Request::ListMacros { dylib_path } => { + legacy::Response::ListMacros(srv.list_macros(&dylib_path).map(|macros| { macros.into_iter().map(|(name, kind)| (name, macro_kind_to_api(kind))).collect() })) } - msg::Request::ExpandMacro(task) => { - let msg::ExpandMacro { + legacy::Request::ExpandMacro(task) => { + let legacy::ExpandMacro { lib, env, current_dir, data: - ExpandMacroData { + legacy::ExpandMacroData { macro_body, macro_name, attributes, has_global_spans: - ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, + legacy::ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, span_data_table, }, } = *task; match span_mode { - SpanMode::Id => msg::Response::ExpandMacro({ + legacy::SpanMode::Id => legacy::Response::ExpandMacro({ let def_site = SpanId(def_site as u32); let call_site = SpanId(call_site as u32); let mixed_site = SpanId(mixed_site as u32); @@ -397,17 +381,18 @@ fn run_() -> io::Result<()> { mixed_site, ) .map(|it| { - msg::FlatTree::from_tokenstream_raw::( + legacy::FlatTree::from_tokenstream_raw::( it, call_site, CURRENT_API_VERSION, ) }) .map_err(|e| e.into_string().unwrap_or_default()) - .map_err(msg::PanicMessage) + .map_err(legacy::PanicMessage) }), - SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended({ - let mut span_data_table = deserialize_span_data_index_map(&span_data_table); + legacy::SpanMode::RustAnalyzer => legacy::Response::ExpandMacroExtended({ + let mut span_data_table = + legacy::deserialize_span_data_index_map(&span_data_table); let def_site = span_data_table[def_site]; let call_site = span_data_table[call_site]; @@ -438,28 +423,30 @@ fn run_() -> io::Result<()> { ) .map(|it| { ( - msg::FlatTree::from_tokenstream( + legacy::FlatTree::from_tokenstream( it, CURRENT_API_VERSION, call_site, &mut span_data_table, ), - serialize_span_data_index_map(&span_data_table), + legacy::serialize_span_data_index_map(&span_data_table), ) }) - .map(|(tree, span_data_table)| msg::ExpandMacroExtended { + .map(|(tree, span_data_table)| legacy::ExpandMacroExtended { tree, span_data_table, }) .map_err(|e| e.into_string().unwrap_or_default()) - .map_err(msg::PanicMessage) + .map_err(legacy::PanicMessage) }), } } - msg::Request::ApiVersionCheck {} => msg::Response::ApiVersionCheck(CURRENT_API_VERSION), - msg::Request::SetConfig(config) => { + legacy::Request::ApiVersionCheck {} => { + legacy::Response::ApiVersionCheck(CURRENT_API_VERSION) + } + legacy::Request::SetConfig(config) => { span_mode = config.span_mode; - msg::Response::SetConfig(config) + legacy::Response::SetConfig(config) } }; write_response(res)? @@ -468,25 +455,17 @@ fn run_() -> io::Result<()> { Ok(()) } -fn from_srv_req( - value: proc_macro_srv::SubRequest, -) -> proc_macro_api::bidirectional_protocol::msg::SubRequest { +fn from_srv_req(value: proc_macro_srv::SubRequest) -> bidirectional::SubRequest { match value { proc_macro_srv::SubRequest::SourceText { file_id, start, end } => { - proc_macro_api::bidirectional_protocol::msg::SubRequest::SourceText { - file_id: file_id.file_id().index(), - start, - end, - } + bidirectional::SubRequest::SourceText { file_id: file_id.file_id().index(), start, end } } } } -fn from_client_res( - value: proc_macro_api::bidirectional_protocol::msg::SubResponse, -) -> proc_macro_srv::SubResponse { +fn from_client_res(value: bidirectional::SubResponse) -> proc_macro_srv::SubResponse { match value { - proc_macro_api::bidirectional_protocol::msg::SubResponse::SourceTextResult { text } => { + bidirectional::SubResponse::SourceTextResult { text } => { proc_macro_srv::SubResponse::SourceTextResult { text } } } @@ -495,17 +474,25 @@ fn from_client_res( fn send_response( stdout: &mut W, id: u64, - resp: proc_macro_api::bidirectional_protocol::msg::Response, + resp: bidirectional::Response, ) -> io::Result<()> { - let resp = Envelope { id, kind: Kind::Response, payload: Payload::Response(resp) }; + let resp = bidirectional::Envelope { + id, + kind: bidirectional::Kind::Response, + payload: bidirectional::Payload::Response(resp), + }; resp.write::(stdout) } fn send_subrequest( stdout: &mut W, id: u64, - resp: proc_macro_api::bidirectional_protocol::msg::SubRequest, + resp: bidirectional::SubRequest, ) -> io::Result<()> { - let resp = Envelope { id, kind: Kind::SubRequest, payload: Payload::SubRequest(resp) }; + let resp = bidirectional::Envelope { + id, + kind: bidirectional::Kind::SubRequest, + payload: bidirectional::Payload::SubRequest(resp), + }; resp.write::(stdout) } From 19e816d3bf945e0dbfd8b5db9032c0b291d4e890 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 18 Dec 2025 14:34:57 +0530 Subject: [PATCH 07/15] change request id to u32 to make powerpc happy --- .../proc-macro-api/src/bidirectional_protocol/msg.rs | 2 +- crates/proc-macro-api/src/process.rs | 6 +++--- crates/proc-macro-srv-cli/src/main_loop.rs | 11 ++++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 7aed3ae1e607..796573385c3c 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -8,7 +8,7 @@ use crate::{ legacy_protocol::msg::{FlatTree, Message, PanicMessage, ServerConfig}, }; -pub type RequestId = u64; +pub type RequestId = u32; #[derive(Debug, Serialize, Deserialize)] pub struct Envelope { diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 723fc928ff66..bb4599c53272 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -6,7 +6,7 @@ use std::{ process::{Child, ChildStdin, ChildStdout, Command, Stdio}, sync::{ Arc, Mutex, OnceLock, - atomic::{AtomicU64, Ordering}, + atomic::{AtomicU32, Ordering}, }, }; @@ -36,7 +36,7 @@ pub(crate) struct ProcMacroServerProcess { protocol: Protocol, /// Populated when the server exits. exited: OnceLock>, - next_request_id: AtomicU64, + next_request_id: AtomicU32, } #[derive(Debug, Clone)] @@ -94,7 +94,7 @@ impl ProcMacroServerProcess { version: 0, protocol: protocol.clone(), exited: OnceLock::new(), - next_request_id: AtomicU64::new(1), + next_request_id: AtomicU32::new(1), }) }; let mut srv = create_srv()?; diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index 1ad73d4daac2..dc828a87de13 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -10,6 +10,7 @@ use proc_macro_api::{ version::CURRENT_API_VERSION, }; +use bidirectional::RequestId; use legacy::Message; use proc_macro_srv::{EnvSnapshot, SpanId}; @@ -128,7 +129,7 @@ fn handle_expand( stdin: &mut R, stdout: &mut W, buf: &mut C::Buf, - req_id: u64, + req_id: RequestId, span_mode: legacy::SpanMode, task: bidirectional::ExpandMacro, ) -> io::Result<()> { @@ -143,7 +144,7 @@ fn handle_expand( fn handle_expand_id( srv: &proc_macro_srv::ProcMacroSrv<'_>, stdout: &mut W, - req_id: u64, + req_id: RequestId, task: bidirectional::ExpandMacro, ) -> io::Result<()> { let bidirectional::ExpandMacro { lib, env, current_dir, data } = task; @@ -189,7 +190,7 @@ fn handle_expand_ra( stdin: &mut R, stdout: &mut W, buf: &mut C::Buf, - req_id: u64, + req_id: RequestId, task: bidirectional::ExpandMacro, ) -> io::Result<()> { let bidirectional::ExpandMacro { @@ -473,7 +474,7 @@ fn from_client_res(value: bidirectional::SubResponse) -> proc_macro_srv::SubResp fn send_response( stdout: &mut W, - id: u64, + id: u32, resp: bidirectional::Response, ) -> io::Result<()> { let resp = bidirectional::Envelope { @@ -486,7 +487,7 @@ fn send_response( fn send_subrequest( stdout: &mut W, - id: u64, + id: u32, resp: bidirectional::SubRequest, ) -> io::Result<()> { let resp = bidirectional::Envelope { From f010e2868947e26729ad99b46e66f11eb476ca78 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Dec 2025 19:21:05 +0530 Subject: [PATCH 08/15] remove request_id, rename postcardNew to BidirectionalPostcardPrototype and remove JsonNew --- .../src/bidirectional_protocol.rs | 20 +++--------- .../src/bidirectional_protocol/msg.rs | 9 ------ crates/proc-macro-api/src/process.rs | 32 ++++++------------- crates/proc-macro-srv-cli/src/main.rs | 6 +--- crates/proc-macro-srv-cli/src/main_loop.rs | 22 +++---------- 5 files changed, 20 insertions(+), 69 deletions(-) diff --git a/crates/proc-macro-api/src/bidirectional_protocol.rs b/crates/proc-macro-api/src/bidirectional_protocol.rs index 728f0f707d71..c7caccb96ff1 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol.rs @@ -12,7 +12,7 @@ use span::{FileId, Span}; use crate::{ Codec, ProcMacro, ProcMacroKind, ServerError, bidirectional_protocol::msg::{ - Envelope, ExpandMacro, ExpandMacroData, ExpnGlobals, Kind, Payload, Request, RequestId, + Envelope, ExpandMacro, ExpandMacroData, ExpnGlobals, Kind, Payload, Request, Response, SubRequest, SubResponse, }, legacy_protocol::{ @@ -37,11 +37,10 @@ pub fn run_conversation( writer: &mut dyn Write, reader: &mut dyn BufRead, buf: &mut C::Buf, - id: RequestId, initial: Payload, callbacks: &mut dyn ClientCallbacks, ) -> Result { - let msg = Envelope { id, kind: Kind::Request, payload: initial }; + let msg = Envelope { kind: Kind::Request, payload: initial }; let encoded = C::encode(&msg).map_err(wrap_encode)?; C::write(writer, &encoded).map_err(wrap_io("failed to write initial request"))?; @@ -56,18 +55,11 @@ pub fn run_conversation( let msg: Envelope = C::decode(b).map_err(wrap_decode)?; - if msg.id != id { - return Err(ServerError { - message: format!("unexpected message id {}, expected {}", msg.id, id), - io: None, - }); - } - match (msg.kind, msg.payload) { (Kind::SubRequest, Payload::SubRequest(sr)) => { let resp = callbacks.handle_sub_request(sr)?; let reply = - Envelope { id, kind: Kind::SubResponse, payload: Payload::SubResponse(resp) }; + Envelope { kind: Kind::SubResponse, payload: Payload::SubResponse(resp) }; let encoded = C::encode(&reply).map_err(wrap_encode)?; C::write(writer, &encoded).map_err(wrap_io("failed to write sub-response"))?; } @@ -268,11 +260,9 @@ fn run_request( return Err(server_error.clone()); } - let id = srv.request_id(); - if srv.use_postcard() { - srv.run_bidirectional::(id, msg, callbacks) + srv.run_bidirectional::(msg, callbacks) } else { - srv.run_bidirectional::(id, msg, callbacks) + srv.run_bidirectional::(msg, callbacks) } } diff --git a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 796573385c3c..4f81ef4ae6bd 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -8,21 +8,12 @@ use crate::{ legacy_protocol::msg::{FlatTree, Message, PanicMessage, ServerConfig}, }; -pub type RequestId = u32; - #[derive(Debug, Serialize, Deserialize)] pub struct Envelope { - pub id: RequestId, pub kind: Kind, pub payload: Payload, } -impl From<(RequestId, Kind, Payload)> for Envelope { - fn from(value: (RequestId, Kind, Payload)) -> Self { - Envelope { id: value.0, kind: value.1, payload: value.2 } - } -} - #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] pub enum Kind { Request, diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index bb4599c53272..1c1709e5fa64 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -6,7 +6,6 @@ use std::{ process::{Child, ChildStdin, ChildStdout, Command, Stdio}, sync::{ Arc, Mutex, OnceLock, - atomic::{AtomicU32, Ordering}, }, }; @@ -20,7 +19,7 @@ use crate::{ Codec, ProcMacro, ProcMacroKind, ServerError, bidirectional_protocol::{ self, ClientCallbacks, - msg::{Payload, RequestId}, + msg::Payload, }, legacy_protocol::{self, SpanMode}, version, @@ -36,15 +35,13 @@ pub(crate) struct ProcMacroServerProcess { protocol: Protocol, /// Populated when the server exits. exited: OnceLock>, - next_request_id: AtomicU32, } #[derive(Debug, Clone)] pub(crate) enum Protocol { LegacyJson { mode: SpanMode }, LegacyPostcard { mode: SpanMode }, - NewPostcard { mode: SpanMode }, - NewJson { mode: SpanMode }, + BidirectionalPostcardPrototype { mode: SpanMode }, } /// Maintains the state of the proc-macro server process. @@ -74,8 +71,7 @@ impl ProcMacroServerProcess { && has_working_format_flag { &[ - (Some("postcard-new"), Protocol::NewPostcard { mode: SpanMode::Id }), - (Some("json-new"), Protocol::NewJson { mode: SpanMode::Id }), + (Some("postcard-new"), Protocol::BidirectionalPostcardPrototype { mode: SpanMode::Id }), (Some("postcard-legacy"), Protocol::LegacyPostcard { mode: SpanMode::Id }), (Some("json-legacy"), Protocol::LegacyJson { mode: SpanMode::Id }), ] @@ -94,7 +90,6 @@ impl ProcMacroServerProcess { version: 0, protocol: protocol.clone(), exited: OnceLock::new(), - next_request_id: AtomicU32::new(1), }) }; let mut srv = create_srv()?; @@ -122,8 +117,7 @@ impl ProcMacroServerProcess { match &mut srv.protocol { Protocol::LegacyJson { mode } | Protocol::LegacyPostcard { mode } - | Protocol::NewJson { mode } - | Protocol::NewPostcard { mode } => *mode = new_mode, + | Protocol::BidirectionalPostcardPrototype { mode } => *mode = new_mode, } } tracing::info!("Proc-macro server protocol: {:?}", srv.protocol); @@ -159,8 +153,7 @@ impl ProcMacroServerProcess { match self.protocol { Protocol::LegacyJson { mode } => mode == SpanMode::RustAnalyzer, Protocol::LegacyPostcard { mode } => mode == SpanMode::RustAnalyzer, - Protocol::NewJson { mode } => mode == SpanMode::RustAnalyzer, - Protocol::NewPostcard { mode } => mode == SpanMode::RustAnalyzer, + Protocol::BidirectionalPostcardPrototype { mode } => mode == SpanMode::RustAnalyzer, } } @@ -170,7 +163,7 @@ impl ProcMacroServerProcess { Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { legacy_protocol::version_check(self) } - Protocol::NewJson { .. } | Protocol::NewPostcard { .. } => { + Protocol::BidirectionalPostcardPrototype { .. } => { bidirectional_protocol::version_check(self) } } @@ -182,7 +175,7 @@ impl ProcMacroServerProcess { Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { legacy_protocol::enable_rust_analyzer_spans(self) } - Protocol::NewJson { .. } | Protocol::NewPostcard { .. } => { + Protocol::BidirectionalPostcardPrototype { .. } => { bidirectional_protocol::enable_rust_analyzer_spans(self) } } @@ -197,7 +190,7 @@ impl ProcMacroServerProcess { Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { legacy_protocol::find_proc_macros(self, dylib_path) } - Protocol::NewJson { .. } | Protocol::NewPostcard { .. } => { + Protocol::BidirectionalPostcardPrototype { .. } => { bidirectional_protocol::find_proc_macros(self, dylib_path) } } @@ -229,7 +222,7 @@ impl ProcMacroServerProcess { current_dir, ) } - Protocol::NewJson { .. } | Protocol::NewPostcard { .. } => { + Protocol::BidirectionalPostcardPrototype { .. } => { bidirectional_protocol::expand( proc_macro, db, @@ -307,20 +300,15 @@ impl ProcMacroServerProcess { pub(crate) fn run_bidirectional( &self, - id: RequestId, initial: Payload, callbacks: &mut dyn ClientCallbacks, ) -> Result { self.with_locked_io::(|writer, reader, buf| { bidirectional_protocol::run_conversation::( - writer, reader, buf, id, initial, callbacks, + writer, reader, buf, initial, callbacks, ) }) } - - pub(crate) fn request_id(&self) -> RequestId { - self.next_request_id.fetch_add(1, Ordering::Relaxed) - } } /// Manages the execution of the proc-macro server process. diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index c9134b402dfa..53302dd5798c 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -31,7 +31,7 @@ fn main() -> std::io::Result<()> { clap::Arg::new("format") .long("format") .action(clap::ArgAction::Set) - .default_value("json-new") + .default_value("postcard-new") .value_parser(clap::builder::EnumValueParser::::new()), clap::Arg::new("version") .long("version") @@ -52,7 +52,6 @@ fn main() -> std::io::Result<()> { enum ProtocolFormat { JsonLegacy, PostcardLegacy, - JsonNew, PostcardNew, } @@ -61,7 +60,6 @@ impl ValueEnum for ProtocolFormat { &[ ProtocolFormat::JsonLegacy, ProtocolFormat::PostcardLegacy, - ProtocolFormat::JsonNew, ProtocolFormat::PostcardNew, ] } @@ -72,7 +70,6 @@ impl ValueEnum for ProtocolFormat { ProtocolFormat::PostcardLegacy => { Some(clap::builder::PossibleValue::new("postcard-legacy")) } - ProtocolFormat::JsonNew => Some(clap::builder::PossibleValue::new("json-new")), ProtocolFormat::PostcardNew => Some(clap::builder::PossibleValue::new("postcard-new")), } } @@ -81,7 +78,6 @@ impl ValueEnum for ProtocolFormat { "json-legacy" => Ok(ProtocolFormat::JsonLegacy), "postcard-legacy" => Ok(ProtocolFormat::PostcardLegacy), "postcard-new" => Ok(ProtocolFormat::PostcardNew), - "json-new" => Ok(ProtocolFormat::JsonNew), _ => Err(format!("unknown protocol format: {input}")), } } diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index dc828a87de13..ee9b2088117d 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -10,7 +10,6 @@ use proc_macro_api::{ version::CURRENT_API_VERSION, }; -use bidirectional::RequestId; use legacy::Message; use proc_macro_srv::{EnvSnapshot, SpanId}; @@ -39,7 +38,6 @@ pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> { match format { ProtocolFormat::JsonLegacy => run_::(), ProtocolFormat::PostcardLegacy => run_::(), - ProtocolFormat::JsonNew => run_new::(), ProtocolFormat::PostcardNew => run_new::(), } } @@ -83,7 +81,6 @@ fn run_new() -> io::Result<()> { send_response::<_, C>( &mut stdout, - req.id, bidirectional::Response::ListMacros(res), )?; } @@ -91,7 +88,6 @@ fn run_new() -> io::Result<()> { bidirectional::Request::ApiVersionCheck {} => { send_response::<_, C>( &mut stdout, - req.id, bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION), )?; } @@ -100,7 +96,6 @@ fn run_new() -> io::Result<()> { span_mode = config.span_mode; send_response::<_, C>( &mut stdout, - req.id, bidirectional::Response::SetConfig(config), )?; } @@ -110,7 +105,6 @@ fn run_new() -> io::Result<()> { &mut stdin, &mut stdout, &mut buf, - req.id, span_mode, *task, )?; @@ -129,14 +123,13 @@ fn handle_expand( stdin: &mut R, stdout: &mut W, buf: &mut C::Buf, - req_id: RequestId, span_mode: legacy::SpanMode, task: bidirectional::ExpandMacro, ) -> io::Result<()> { match span_mode { - legacy::SpanMode::Id => handle_expand_id::<_, C>(srv, stdout, req_id, task), + legacy::SpanMode::Id => handle_expand_id::<_, C>(srv, stdout, task), legacy::SpanMode::RustAnalyzer => { - handle_expand_ra::<_, _, C>(srv, stdin, stdout, buf, req_id, task) + handle_expand_ra::<_, _, C>(srv, stdin, stdout, buf, task) } } } @@ -144,7 +137,6 @@ fn handle_expand( fn handle_expand_id( srv: &proc_macro_srv::ProcMacroSrv<'_>, stdout: &mut W, - req_id: RequestId, task: bidirectional::ExpandMacro, ) -> io::Result<()> { let bidirectional::ExpandMacro { lib, env, current_dir, data } = task; @@ -182,7 +174,7 @@ fn handle_expand_id( }) .map_err(|e| legacy::PanicMessage(e.into_string().unwrap_or_default())); - send_response::<_, C>(stdout, req_id, bidirectional::Response::ExpandMacro(res)) + send_response::<_, C>(stdout, bidirectional::Response::ExpandMacro(res)) } fn handle_expand_ra( @@ -190,7 +182,6 @@ fn handle_expand_ra( stdin: &mut R, stdout: &mut W, buf: &mut C::Buf, - req_id: RequestId, task: bidirectional::ExpandMacro, ) -> io::Result<()> { let bidirectional::ExpandMacro { @@ -276,7 +267,6 @@ fn handle_expand_ra( if let Ok(res) = result_rx.try_recv() { send_response::<_, C>( stdout, - req_id, bidirectional::Response::ExpandMacroExtended(res), ) .unwrap(); @@ -290,7 +280,7 @@ fn handle_expand_ra( } }; - send_subrequest::<_, C>(stdout, req_id, from_srv_req(subreq)).unwrap(); + send_subrequest::<_, C>(stdout, from_srv_req(subreq)).unwrap(); let resp_opt = bidirectional::Envelope::read::<_, C>(stdin, buf).unwrap(); let resp = match resp_opt { @@ -474,11 +464,9 @@ fn from_client_res(value: bidirectional::SubResponse) -> proc_macro_srv::SubResp fn send_response( stdout: &mut W, - id: u32, resp: bidirectional::Response, ) -> io::Result<()> { let resp = bidirectional::Envelope { - id, kind: bidirectional::Kind::Response, payload: bidirectional::Payload::Response(resp), }; @@ -487,11 +475,9 @@ fn send_response( fn send_subrequest( stdout: &mut W, - id: u32, resp: bidirectional::SubRequest, ) -> io::Result<()> { let resp = bidirectional::Envelope { - id, kind: bidirectional::Kind::SubRequest, payload: bidirectional::Payload::SubRequest(resp), }; From 2a6cc5c9fcc99ef9dbcb873f678c25fb2b20f368 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Dec 2025 19:21:22 +0530 Subject: [PATCH 09/15] comment out disabled workflow --- .github/workflows/ci.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 623200aea032..81ca0254982d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -70,6 +70,10 @@ jobs: - name: Test run: cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api -- --quiet + + # FIXME: This is temporarily disable, more info: https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Non-generic.20spans/with/564604549 + # - name: Check salsa dependency + # run: "! (cargo tree -p proc-macro-srv-cli | grep -q salsa)" rust: if: github.repository == 'rust-lang/rust-analyzer' From a79fa074fee2c7b935ce3187a8465d343dbd9467 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Dec 2025 20:04:35 +0530 Subject: [PATCH 10/15] remove envelop and keep it simple --- .../src/bidirectional_protocol.rs | 61 ++++++----- .../src/bidirectional_protocol/msg.rs | 18 +--- crates/proc-macro-api/src/process.rs | 46 ++++---- crates/proc-macro-srv-cli/src/main.rs | 6 +- crates/proc-macro-srv-cli/src/main_loop.rs | 102 +++++++----------- 5 files changed, 94 insertions(+), 139 deletions(-) diff --git a/crates/proc-macro-api/src/bidirectional_protocol.rs b/crates/proc-macro-api/src/bidirectional_protocol.rs index c7caccb96ff1..4cb6a1d90f19 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol.rs @@ -12,8 +12,8 @@ use span::{FileId, Span}; use crate::{ Codec, ProcMacro, ProcMacroKind, ServerError, bidirectional_protocol::msg::{ - Envelope, ExpandMacro, ExpandMacroData, ExpnGlobals, Kind, Payload, Request, - Response, SubRequest, SubResponse, + BidirectionalMessage, ExpandMacro, ExpandMacroData, ExpnGlobals, Request, Response, + SubRequest, SubResponse, }, legacy_protocol::{ SpanMode, @@ -37,10 +37,9 @@ pub fn run_conversation( writer: &mut dyn Write, reader: &mut dyn BufRead, buf: &mut C::Buf, - initial: Payload, + msg: BidirectionalMessage, callbacks: &mut dyn ClientCallbacks, -) -> Result { - let msg = Envelope { kind: Kind::Request, payload: initial }; +) -> Result { let encoded = C::encode(&msg).map_err(wrap_encode)?; C::write(writer, &encoded).map_err(wrap_io("failed to write initial request"))?; @@ -53,25 +52,21 @@ pub fn run_conversation( }); }; - let msg: Envelope = C::decode(b).map_err(wrap_decode)?; + let msg: BidirectionalMessage = C::decode(b).map_err(wrap_decode)?; - match (msg.kind, msg.payload) { - (Kind::SubRequest, Payload::SubRequest(sr)) => { + match msg { + BidirectionalMessage::Response(response) => { + return Ok(BidirectionalMessage::Response(response)); + } + BidirectionalMessage::SubRequest(sr) => { let resp = callbacks.handle_sub_request(sr)?; - let reply = - Envelope { kind: Kind::SubResponse, payload: Payload::SubResponse(resp) }; + let reply = BidirectionalMessage::SubResponse(resp); let encoded = C::encode(&reply).map_err(wrap_encode)?; C::write(writer, &encoded).map_err(wrap_io("failed to write sub-response"))?; } - (Kind::Response, payload) => { - return Ok(payload); - } - (kind, payload) => { + _ => { return Err(ServerError { - message: format!( - "unexpected message kind {:?} with payload {:?}", - kind, payload - ), + message: format!("unexpected message {:?}", msg), io: None, }); } @@ -92,7 +87,7 @@ fn wrap_decode(err: io::Error) -> ServerError { } pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result { - let request = Payload::Request(Request::ApiVersionCheck {}); + let request = BidirectionalMessage::Request(Request::ApiVersionCheck {}); struct NoCallbacks; impl ClientCallbacks for NoCallbacks { @@ -106,7 +101,7 @@ pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result Ok(version), + BidirectionalMessage::Response(Response::ApiVersionCheck(version)) => Ok(version), other => { Err(ServerError { message: format!("unexpected response: {:?}", other), io: None }) } @@ -117,8 +112,9 @@ pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result Result { - let request = - Payload::Request(Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer })); + let request = BidirectionalMessage::Request(Request::SetConfig(ServerConfig { + span_mode: SpanMode::RustAnalyzer, + })); struct NoCallbacks; impl ClientCallbacks for NoCallbacks { @@ -132,7 +128,9 @@ pub(crate) fn enable_rust_analyzer_spans( let response_payload = run_request(srv, request, &mut callbacks)?; match response_payload { - Payload::Response(Response::SetConfig(ServerConfig { span_mode })) => Ok(span_mode), + BidirectionalMessage::Response(Response::SetConfig(ServerConfig { span_mode })) => { + Ok(span_mode) + } _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), } } @@ -142,8 +140,9 @@ pub(crate) fn find_proc_macros( srv: &ProcMacroServerProcess, dylib_path: &AbsPath, ) -> Result, String>, ServerError> { - let request = - Payload::Request(Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() }); + let request = BidirectionalMessage::Request(Request::ListMacros { + dylib_path: dylib_path.to_path_buf().into(), + }); struct NoCallbacks; impl ClientCallbacks for NoCallbacks { @@ -157,7 +156,7 @@ pub(crate) fn find_proc_macros( let response_payload = run_request(srv, request, &mut callbacks)?; match response_payload { - Payload::Response(Response::ListMacros(it)) => Ok(it), + BidirectionalMessage::Response(Response::ListMacros(it)) => Ok(it), _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), } } @@ -179,7 +178,7 @@ pub(crate) fn expand( let def_site = span_data_table.insert_full(def_site).0; let call_site = span_data_table.insert_full(call_site).0; let mixed_site = span_data_table.insert_full(mixed_site).0; - let task = Payload::Request(Request::ExpandMacro(Box::new(ExpandMacro { + let task = BidirectionalMessage::Request(Request::ExpandMacro(Box::new(ExpandMacro { data: ExpandMacroData { macro_body: FlatTree::from_subtree(subtree, version, &mut span_data_table), macro_name: proc_macro.name.to_string(), @@ -225,7 +224,7 @@ pub(crate) fn expand( let response_payload = run_request(&proc_macro.process, task, &mut callbacks)?; match response_payload { - Payload::Response(Response::ExpandMacro(it)) => Ok(it + BidirectionalMessage::Response(Response::ExpandMacro(it)) => Ok(it .map(|tree| { let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table); if proc_macro.needs_fixup_change() { @@ -234,7 +233,7 @@ pub(crate) fn expand( expanded }) .map_err(|msg| msg.0)), - Payload::Response(Response::ExpandMacroExtended(it)) => Ok(it + BidirectionalMessage::Response(Response::ExpandMacroExtended(it)) => Ok(it .map(|resp| { let mut expanded = FlatTree::to_subtree_resolved( resp.tree, @@ -253,9 +252,9 @@ pub(crate) fn expand( fn run_request( srv: &ProcMacroServerProcess, - msg: Payload, + msg: BidirectionalMessage, callbacks: &mut dyn ClientCallbacks, -) -> Result { +) -> Result { if let Some(server_error) = srv.exited() { return Err(server_error.clone()); } diff --git a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 4f81ef4ae6bd..cf8becd922de 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -8,20 +8,6 @@ use crate::{ legacy_protocol::msg::{FlatTree, Message, PanicMessage, ServerConfig}, }; -#[derive(Debug, Serialize, Deserialize)] -pub struct Envelope { - pub kind: Kind, - pub payload: Payload, -} - -#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] -pub enum Kind { - Request, - Response, - SubRequest, - SubResponse, -} - #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { SourceText { file_id: u32, start: u32, end: u32 }, @@ -33,7 +19,7 @@ pub enum SubResponse { } #[derive(Debug, Serialize, Deserialize)] -pub enum Payload { +pub enum BidirectionalMessage { Request(Request), Response(Response), SubRequest(SubRequest), @@ -102,4 +88,4 @@ impl ExpnGlobals { } } -impl Message for Envelope {} +impl Message for BidirectionalMessage {} diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 1c1709e5fa64..6d4025001212 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -4,9 +4,7 @@ use std::{ io::{self, BufRead, BufReader, Read, Write}, panic::AssertUnwindSafe, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, - sync::{ - Arc, Mutex, OnceLock, - }, + sync::{Arc, Mutex, OnceLock}, }; use base_db::SourceDatabase; @@ -17,10 +15,7 @@ use stdx::JodChild; use crate::{ Codec, ProcMacro, ProcMacroKind, ServerError, - bidirectional_protocol::{ - self, ClientCallbacks, - msg::Payload, - }, + bidirectional_protocol::{self, ClientCallbacks, msg::BidirectionalMessage}, legacy_protocol::{self, SpanMode}, version, }; @@ -71,7 +66,10 @@ impl ProcMacroServerProcess { && has_working_format_flag { &[ - (Some("postcard-new"), Protocol::BidirectionalPostcardPrototype { mode: SpanMode::Id }), + ( + Some("postcard-new"), + Protocol::BidirectionalPostcardPrototype { mode: SpanMode::Id }, + ), (Some("postcard-legacy"), Protocol::LegacyPostcard { mode: SpanMode::Id }), (Some("json-legacy"), Protocol::LegacyJson { mode: SpanMode::Id }), ] @@ -222,19 +220,17 @@ impl ProcMacroServerProcess { current_dir, ) } - Protocol::BidirectionalPostcardPrototype { .. } => { - bidirectional_protocol::expand( - proc_macro, - db, - subtree, - attr, - env, - def_site, - call_site, - mixed_site, - current_dir, - ) - } + Protocol::BidirectionalPostcardPrototype { .. } => bidirectional_protocol::expand( + proc_macro, + db, + subtree, + attr, + env, + def_site, + call_site, + mixed_site, + current_dir, + ), } } @@ -300,13 +296,11 @@ impl ProcMacroServerProcess { pub(crate) fn run_bidirectional( &self, - initial: Payload, + initial: BidirectionalMessage, callbacks: &mut dyn ClientCallbacks, - ) -> Result { + ) -> Result { self.with_locked_io::(|writer, reader, buf| { - bidirectional_protocol::run_conversation::( - writer, reader, buf, initial, callbacks, - ) + bidirectional_protocol::run_conversation::(writer, reader, buf, initial, callbacks) }) } } diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 53302dd5798c..01b261dab748 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -57,11 +57,7 @@ enum ProtocolFormat { impl ValueEnum for ProtocolFormat { fn value_variants<'a>() -> &'a [Self] { - &[ - ProtocolFormat::JsonLegacy, - ProtocolFormat::PostcardLegacy, - ProtocolFormat::PostcardNew, - ] + &[ProtocolFormat::JsonLegacy, ProtocolFormat::PostcardLegacy, ProtocolFormat::PostcardNew] } fn to_possible_value(&self) -> Option { diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index ee9b2088117d..9c66a308b18e 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -63,54 +63,46 @@ fn run_new() -> io::Result<()> { let mut span_mode = legacy::SpanMode::Id; 'outer: loop { - let req_opt = bidirectional::Envelope::read::<_, C>(&mut stdin, &mut buf)?; + let req_opt = bidirectional::BidirectionalMessage::read::<_, C>(&mut stdin, &mut buf)?; let Some(req) = req_opt else { break 'outer; }; - match (req.kind, req.payload) { - (bidirectional::Kind::Request, bidirectional::Payload::Request(request)) => { - match request { - bidirectional::Request::ListMacros { dylib_path } => { - let res = srv.list_macros(&dylib_path).map(|macros| { - macros - .into_iter() - .map(|(name, kind)| (name, macro_kind_to_api(kind))) - .collect() - }); + match req { + bidirectional::BidirectionalMessage::Request(request) => match request { + bidirectional::Request::ListMacros { dylib_path } => { + let res = srv.list_macros(&dylib_path).map(|macros| { + macros + .into_iter() + .map(|(name, kind)| (name, macro_kind_to_api(kind))) + .collect() + }); + + send_response::<_, C>(&mut stdout, bidirectional::Response::ListMacros(res))?; + } - send_response::<_, C>( - &mut stdout, - bidirectional::Response::ListMacros(res), - )?; - } - - bidirectional::Request::ApiVersionCheck {} => { - send_response::<_, C>( - &mut stdout, - bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION), - )?; - } - - bidirectional::Request::SetConfig(config) => { - span_mode = config.span_mode; - send_response::<_, C>( - &mut stdout, - bidirectional::Response::SetConfig(config), - )?; - } - bidirectional::Request::ExpandMacro(task) => { - handle_expand::<_, _, C>( - &srv, - &mut stdin, - &mut stdout, - &mut buf, - span_mode, - *task, - )?; - } + bidirectional::Request::ApiVersionCheck {} => { + send_response::<_, C>( + &mut stdout, + bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION), + )?; } - } + + bidirectional::Request::SetConfig(config) => { + span_mode = config.span_mode; + send_response::<_, C>(&mut stdout, bidirectional::Response::SetConfig(config))?; + } + bidirectional::Request::ExpandMacro(task) => { + handle_expand::<_, _, C>( + &srv, + &mut stdin, + &mut stdout, + &mut buf, + span_mode, + *task, + )?; + } + }, _ => continue, } } @@ -265,11 +257,8 @@ fn handle_expand_ra( loop { if let Ok(res) = result_rx.try_recv() { - send_response::<_, C>( - stdout, - bidirectional::Response::ExpandMacroExtended(res), - ) - .unwrap(); + send_response::<_, C>(stdout, bidirectional::Response::ExpandMacroExtended(res)) + .unwrap(); break; } @@ -282,7 +271,7 @@ fn handle_expand_ra( send_subrequest::<_, C>(stdout, from_srv_req(subreq)).unwrap(); - let resp_opt = bidirectional::Envelope::read::<_, C>(stdin, buf).unwrap(); + let resp_opt = bidirectional::BidirectionalMessage::read::<_, C>(stdin, buf).unwrap(); let resp = match resp_opt { Some(env) => env, None => { @@ -290,11 +279,8 @@ fn handle_expand_ra( } }; - match (resp.kind, resp.payload) { - ( - bidirectional::Kind::SubResponse, - bidirectional::Payload::SubResponse(subresp), - ) => { + match resp { + bidirectional::BidirectionalMessage::SubResponse(subresp) => { let _ = subresp_tx.send(from_client_res(subresp)); } _ => { @@ -466,10 +452,7 @@ fn send_response( stdout: &mut W, resp: bidirectional::Response, ) -> io::Result<()> { - let resp = bidirectional::Envelope { - kind: bidirectional::Kind::Response, - payload: bidirectional::Payload::Response(resp), - }; + let resp = bidirectional::BidirectionalMessage::Response(resp); resp.write::(stdout) } @@ -477,9 +460,6 @@ fn send_subrequest( stdout: &mut W, resp: bidirectional::SubRequest, ) -> io::Result<()> { - let resp = bidirectional::Envelope { - kind: bidirectional::Kind::SubRequest, - payload: bidirectional::Payload::SubRequest(resp), - }; + let resp = bidirectional::BidirectionalMessage::SubRequest(resp); resp.write::(stdout) } From 2c71fa8cd4ad1a31ac153b821219e567482a0259 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 22 Dec 2025 20:56:16 +0530 Subject: [PATCH 11/15] rename PostcardNew to bidirectional-postcard-prototype --- crates/proc-macro-srv-cli/src/main.rs | 10 +++++----- crates/proc-macro-srv-cli/src/main_loop.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 01b261dab748..7e50888114ba 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -31,7 +31,7 @@ fn main() -> std::io::Result<()> { clap::Arg::new("format") .long("format") .action(clap::ArgAction::Set) - .default_value("postcard-new") + .default_value("bidirectional-postcard-prototype") .value_parser(clap::builder::EnumValueParser::::new()), clap::Arg::new("version") .long("version") @@ -52,12 +52,12 @@ fn main() -> std::io::Result<()> { enum ProtocolFormat { JsonLegacy, PostcardLegacy, - PostcardNew, + BidirectionalPostcardPrototype, } impl ValueEnum for ProtocolFormat { fn value_variants<'a>() -> &'a [Self] { - &[ProtocolFormat::JsonLegacy, ProtocolFormat::PostcardLegacy, ProtocolFormat::PostcardNew] + &[ProtocolFormat::JsonLegacy, ProtocolFormat::PostcardLegacy, ProtocolFormat::BidirectionalPostcardPrototype] } fn to_possible_value(&self) -> Option { @@ -66,14 +66,14 @@ impl ValueEnum for ProtocolFormat { ProtocolFormat::PostcardLegacy => { Some(clap::builder::PossibleValue::new("postcard-legacy")) } - ProtocolFormat::PostcardNew => Some(clap::builder::PossibleValue::new("postcard-new")), + ProtocolFormat::BidirectionalPostcardPrototype => Some(clap::builder::PossibleValue::new("postcard-new")), } } fn from_str(input: &str, _ignore_case: bool) -> Result { match input { "json-legacy" => Ok(ProtocolFormat::JsonLegacy), "postcard-legacy" => Ok(ProtocolFormat::PostcardLegacy), - "postcard-new" => Ok(ProtocolFormat::PostcardNew), + "bidirectional-postcard-prototype" => Ok(ProtocolFormat::BidirectionalPostcardPrototype), _ => Err(format!("unknown protocol format: {input}")), } } diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index 9c66a308b18e..8666c1367717 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -38,7 +38,7 @@ pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> { match format { ProtocolFormat::JsonLegacy => run_::(), ProtocolFormat::PostcardLegacy => run_::(), - ProtocolFormat::PostcardNew => run_new::(), + ProtocolFormat::BidirectionalPostcardPrototype => run_new::(), } } From 336f025424c76ba3dee71b3f039d5f9ce6418897 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 23 Dec 2025 06:03:06 +0530 Subject: [PATCH 12/15] remove internal callbacks, and move callback to rust-analyzer level --- .github/workflows/ci.yaml | 5 +- Cargo.lock | 1 - crates/load-cargo/src/lib.rs | 22 ++++- crates/proc-macro-api/Cargo.toml | 1 - .../src/bidirectional_protocol.rs | 85 +++++-------------- crates/proc-macro-api/src/legacy_protocol.rs | 2 - crates/proc-macro-api/src/lib.rs | 15 ++-- crates/proc-macro-api/src/process.rs | 36 ++++---- crates/proc-macro-srv-cli/src/main.rs | 14 ++- 9 files changed, 83 insertions(+), 98 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 81ca0254982d..e817f770a417 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -71,9 +71,8 @@ jobs: - name: Test run: cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api -- --quiet - # FIXME: This is temporarily disable, more info: https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Non-generic.20spans/with/564604549 - # - name: Check salsa dependency - # run: "! (cargo tree -p proc-macro-srv-cli | grep -q salsa)" + - name: Check salsa dependency + run: "! (cargo tree -p proc-macro-srv-cli | grep -q salsa)" rust: if: github.repository == 'rust-lang/rust-analyzer' diff --git a/Cargo.lock b/Cargo.lock index 060a62b112b7..7d133f99498b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1836,7 +1836,6 @@ dependencies = [ name = "proc-macro-api" version = "0.0.0" dependencies = [ - "base-db", "indexmap", "intern", "paths", diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index e043e4ac7634..a7b22b0d6a04 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -23,11 +23,17 @@ use ide_db::{ prime_caches, }; use itertools::Itertools; -use proc_macro_api::{MacroDylib, ProcMacroClient}; +use proc_macro_api::{ + MacroDylib, ProcMacroClient, + bidirectional_protocol::{ + msg::{SubRequest, SubResponse}, + reject_subrequests, + }, +}; use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use span::Span; use vfs::{ - AbsPath, AbsPathBuf, VfsPath, + AbsPath, AbsPathBuf, FileId, VfsPath, file_set::FileSetConfig, loader::{Handle, LoadingProgress}, }; @@ -427,7 +433,7 @@ pub fn load_proc_macro( ) -> ProcMacroLoadResult { let res: Result, _> = (|| { let dylib = MacroDylib::new(path.to_path_buf()); - let vec = server.load_dylib(dylib).map_err(|e| { + let vec = server.load_dylib(dylib, Some(&mut reject_subrequests)).map_err(|e| { ProcMacroLoadingError::ProcMacroSrvError(format!("{e}").into_boxed_str()) })?; if vec.is_empty() { @@ -533,8 +539,15 @@ impl ProcMacroExpander for Expander { mixed_site: Span, current_dir: String, ) -> Result, ProcMacroExpansionError> { + let mut cb = |req| match req { + SubRequest::SourceText { file_id, start, end } => { + let file = FileId::from_raw(file_id); + let text = db.file_text(file).text(db); + let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned); + Ok(SubResponse::SourceTextResult { text: slice }) + } + }; match self.0.expand( - db, subtree.view(), attrs.map(|attrs| attrs.view()), env.clone().into(), @@ -542,6 +555,7 @@ impl ProcMacroExpander for Expander { call_site, mixed_site, current_dir, + Some(&mut cb), ) { Ok(Ok(subtree)) => Ok(subtree), Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err)), diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 7e56d68964ce..4de1a3e5dd7d 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -19,7 +19,6 @@ serde_json = { workspace = true, features = ["unbounded_depth"] } tracing.workspace = true rustc-hash.workspace = true indexmap.workspace = true -base-db.workspace = true # local deps paths = { workspace = true, features = ["serde1"] } diff --git a/crates/proc-macro-api/src/bidirectional_protocol.rs b/crates/proc-macro-api/src/bidirectional_protocol.rs index 4cb6a1d90f19..bd74738bbdf5 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol.rs @@ -5,9 +5,8 @@ use std::{ sync::Arc, }; -use base_db::SourceDatabase; use paths::AbsPath; -use span::{FileId, Span}; +use span::Span; use crate::{ Codec, ProcMacro, ProcMacroKind, ServerError, @@ -29,16 +28,14 @@ use crate::{ pub mod msg; -pub trait ClientCallbacks { - fn handle_sub_request(&mut self, req: SubRequest) -> Result; -} +pub type SubCallback<'a> = &'a mut dyn FnMut(SubRequest) -> Result; pub fn run_conversation( writer: &mut dyn Write, reader: &mut dyn BufRead, buf: &mut C::Buf, msg: BidirectionalMessage, - callbacks: &mut dyn ClientCallbacks, + callback: SubCallback<'_>, ) -> Result { let encoded = C::encode(&msg).map_err(wrap_encode)?; C::write(writer, &encoded).map_err(wrap_io("failed to write initial request"))?; @@ -59,7 +56,7 @@ pub fn run_conversation( return Ok(BidirectionalMessage::Response(response)); } BidirectionalMessage::SubRequest(sr) => { - let resp = callbacks.handle_sub_request(sr)?; + let resp = callback(sr)?; let reply = BidirectionalMessage::SubResponse(resp); let encoded = C::encode(&reply).map_err(wrap_encode)?; C::write(writer, &encoded).map_err(wrap_io("failed to write sub-response"))?; @@ -86,19 +83,13 @@ fn wrap_decode(err: io::Error) -> ServerError { ServerError { message: "failed to decode message".into(), io: Some(Arc::new(err)) } } -pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result { +pub(crate) fn version_check( + srv: &ProcMacroServerProcess, + callback: SubCallback<'_>, +) -> Result { let request = BidirectionalMessage::Request(Request::ApiVersionCheck {}); - struct NoCallbacks; - impl ClientCallbacks for NoCallbacks { - fn handle_sub_request(&mut self, _req: SubRequest) -> Result { - Err(ServerError { message: "sub-request not supported here".into(), io: None }) - } - } - - let mut callbacks = NoCallbacks; - - let response_payload = run_request(srv, request, &mut callbacks)?; + let response_payload = run_request(srv, request, callback)?; match response_payload { BidirectionalMessage::Response(Response::ApiVersionCheck(version)) => Ok(version), @@ -111,21 +102,13 @@ pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result, ) -> Result { let request = BidirectionalMessage::Request(Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer, })); - struct NoCallbacks; - impl ClientCallbacks for NoCallbacks { - fn handle_sub_request(&mut self, _req: SubRequest) -> Result { - Err(ServerError { message: "sub-request not supported here".into(), io: None }) - } - } - - let mut callbacks = NoCallbacks; - - let response_payload = run_request(srv, request, &mut callbacks)?; + let response_payload = run_request(srv, request, callback)?; match response_payload { BidirectionalMessage::Response(Response::SetConfig(ServerConfig { span_mode })) => { @@ -139,21 +122,13 @@ pub(crate) fn enable_rust_analyzer_spans( pub(crate) fn find_proc_macros( srv: &ProcMacroServerProcess, dylib_path: &AbsPath, + callback: SubCallback<'_>, ) -> Result, String>, ServerError> { let request = BidirectionalMessage::Request(Request::ListMacros { dylib_path: dylib_path.to_path_buf().into(), }); - struct NoCallbacks; - impl ClientCallbacks for NoCallbacks { - fn handle_sub_request(&mut self, _req: SubRequest) -> Result { - Err(ServerError { message: "sub-request not supported here".into(), io: None }) - } - } - - let mut callbacks = NoCallbacks; - - let response_payload = run_request(srv, request, &mut callbacks)?; + let response_payload = run_request(srv, request, callback)?; match response_payload { BidirectionalMessage::Response(Response::ListMacros(it)) => Ok(it), @@ -163,7 +138,6 @@ pub(crate) fn find_proc_macros( pub(crate) fn expand( proc_macro: &ProcMacro, - db: &dyn SourceDatabase, subtree: tt::SubtreeView<'_, Span>, attr: Option>, env: Vec<(String, String)>, @@ -171,6 +145,7 @@ pub(crate) fn expand( call_site: Span, mixed_site: Span, current_dir: String, + callback: SubCallback<'_>, ) -> Result>, String>, crate::ServerError> { let version = proc_macro.process.version(); @@ -201,27 +176,7 @@ pub(crate) fn expand( current_dir: Some(current_dir), }))); - struct Callbacks<'de> { - db: &'de dyn SourceDatabase, - } - impl<'db> ClientCallbacks for Callbacks<'db> { - fn handle_sub_request(&mut self, req: SubRequest) -> Result { - match req { - SubRequest::SourceText { file_id, start, end } => { - let file = FileId::from_raw(file_id); - let text = self.db.file_text(file).text(self.db); - - let slice = text.get(start as usize..end as usize).map(|s| s.to_owned()); - - Ok(SubResponse::SourceTextResult { text: slice }) - } - } - } - } - - let mut callbacks = Callbacks { db }; - - let response_payload = run_request(&proc_macro.process, task, &mut callbacks)?; + let response_payload = run_request(&proc_macro.process, task, callback)?; match response_payload { BidirectionalMessage::Response(Response::ExpandMacro(it)) => Ok(it @@ -253,15 +208,19 @@ pub(crate) fn expand( fn run_request( srv: &ProcMacroServerProcess, msg: BidirectionalMessage, - callbacks: &mut dyn ClientCallbacks, + callback: SubCallback<'_>, ) -> Result { if let Some(server_error) = srv.exited() { return Err(server_error.clone()); } if srv.use_postcard() { - srv.run_bidirectional::(msg, callbacks) + srv.run_bidirectional::(msg, callback) } else { - srv.run_bidirectional::(msg, callbacks) + srv.run_bidirectional::(msg, callback) } } + +pub fn reject_subrequests(req: SubRequest) -> Result { + Err(ServerError { message: format!("{req:?} sub-request not supported here"), io: None }) +} diff --git a/crates/proc-macro-api/src/legacy_protocol.rs b/crates/proc-macro-api/src/legacy_protocol.rs index 81a9f391812c..0d16b60025d2 100644 --- a/crates/proc-macro-api/src/legacy_protocol.rs +++ b/crates/proc-macro-api/src/legacy_protocol.rs @@ -7,7 +7,6 @@ use std::{ sync::Arc, }; -use base_db::SourceDatabase; use paths::AbsPath; use span::Span; @@ -78,7 +77,6 @@ pub(crate) fn find_proc_macros( pub(crate) fn expand( proc_macro: &ProcMacro, - _db: &dyn SourceDatabase, subtree: tt::SubtreeView<'_, Span>, attr: Option>, env: Vec<(String, String)>, diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 7b9b5b39ab1c..0ee0c3afb584 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -21,14 +21,13 @@ pub mod legacy_protocol; mod process; pub mod transport; -use base_db::SourceDatabase; use paths::{AbsPath, AbsPathBuf}; use semver::Version; use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; use std::{fmt, io, sync::Arc, time::SystemTime}; -use crate::process::ProcMacroServerProcess; pub use crate::transport::codec::Codec; +use crate::{bidirectional_protocol::SubCallback, process::ProcMacroServerProcess}; /// The versions of the server protocol pub mod version { @@ -143,9 +142,13 @@ impl ProcMacroClient { } /// Loads a proc-macro dylib into the server process returning a list of `ProcMacro`s loaded. - pub fn load_dylib(&self, dylib: MacroDylib) -> Result, ServerError> { + pub fn load_dylib( + &self, + dylib: MacroDylib, + callback: Option>, + ) -> Result, ServerError> { let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered(); - let macros = self.process.find_proc_macros(&dylib.path)?; + let macros = self.process.find_proc_macros(&dylib.path, callback)?; let dylib_path = Arc::new(dylib.path); let dylib_last_modified = std::fs::metadata(dylib_path.as_path()) @@ -219,7 +222,6 @@ impl ProcMacro { /// This includes span information and environmental context. pub fn expand( &self, - db: &dyn SourceDatabase, subtree: tt::SubtreeView<'_, Span>, attr: Option>, env: Vec<(String, String)>, @@ -227,6 +229,7 @@ impl ProcMacro { call_site: Span, mixed_site: Span, current_dir: String, + callback: Option>, ) -> Result, String>, ServerError> { let (mut subtree, mut attr) = (subtree, attr); let (mut subtree_changed, mut attr_changed); @@ -243,7 +246,6 @@ impl ProcMacro { } self.process.expand( - db, self, subtree, attr, @@ -252,6 +254,7 @@ impl ProcMacro { call_site, mixed_site, current_dir, + callback, ) } } diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 6d4025001212..01de8e98ff56 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -7,7 +7,6 @@ use std::{ sync::{Arc, Mutex, OnceLock}, }; -use base_db::SourceDatabase; use paths::AbsPath; use semver::Version; use span::Span; @@ -15,7 +14,7 @@ use stdx::JodChild; use crate::{ Codec, ProcMacro, ProcMacroKind, ServerError, - bidirectional_protocol::{self, ClientCallbacks, msg::BidirectionalMessage}, + bidirectional_protocol::{self, SubCallback, msg::BidirectionalMessage, reject_subrequests}, legacy_protocol::{self, SpanMode}, version, }; @@ -67,7 +66,7 @@ impl ProcMacroServerProcess { { &[ ( - Some("postcard-new"), + Some("bidirectional-postcard-prototype"), Protocol::BidirectionalPostcardPrototype { mode: SpanMode::Id }, ), (Some("postcard-legacy"), Protocol::LegacyPostcard { mode: SpanMode::Id }), @@ -92,7 +91,7 @@ impl ProcMacroServerProcess { }; let mut srv = create_srv()?; tracing::info!("sending proc-macro server version check"); - match srv.version_check() { + match srv.version_check(Some(&mut reject_subrequests)) { Ok(v) if v > version::CURRENT_API_VERSION => { #[allow(clippy::disallowed_methods)] let process_version = Command::new(process_path) @@ -110,7 +109,8 @@ impl ProcMacroServerProcess { tracing::info!("Proc-macro server version: {v}"); srv.version = v; if srv.version >= version::RUST_ANALYZER_SPAN_SUPPORT - && let Ok(new_mode) = srv.enable_rust_analyzer_spans() + && let Ok(new_mode) = + srv.enable_rust_analyzer_spans(Some(&mut reject_subrequests)) { match &mut srv.protocol { Protocol::LegacyJson { mode } @@ -156,25 +156,30 @@ impl ProcMacroServerProcess { } /// Checks the API version of the running proc-macro server. - fn version_check(&self) -> Result { + fn version_check(&self, callback: Option>) -> Result { match self.protocol { Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { legacy_protocol::version_check(self) } Protocol::BidirectionalPostcardPrototype { .. } => { - bidirectional_protocol::version_check(self) + let cb = callback.expect("callback required for bidirectional protocol"); + bidirectional_protocol::version_check(self, cb) } } } /// Enable support for rust-analyzer span mode if the server supports it. - fn enable_rust_analyzer_spans(&self) -> Result { + fn enable_rust_analyzer_spans( + &self, + callback: Option>, + ) -> Result { match self.protocol { Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { legacy_protocol::enable_rust_analyzer_spans(self) } Protocol::BidirectionalPostcardPrototype { .. } => { - bidirectional_protocol::enable_rust_analyzer_spans(self) + let cb = callback.expect("callback required for bidirectional protocol"); + bidirectional_protocol::enable_rust_analyzer_spans(self, cb) } } } @@ -183,20 +188,21 @@ impl ProcMacroServerProcess { pub(crate) fn find_proc_macros( &self, dylib_path: &AbsPath, + callback: Option>, ) -> Result, String>, ServerError> { match self.protocol { Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { legacy_protocol::find_proc_macros(self, dylib_path) } Protocol::BidirectionalPostcardPrototype { .. } => { - bidirectional_protocol::find_proc_macros(self, dylib_path) + let cb = callback.expect("callback required for bidirectional protocol"); + bidirectional_protocol::find_proc_macros(self, dylib_path, cb) } } } pub(crate) fn expand( &self, - db: &dyn SourceDatabase, proc_macro: &ProcMacro, subtree: tt::SubtreeView<'_, Span>, attr: Option>, @@ -205,12 +211,12 @@ impl ProcMacroServerProcess { call_site: Span, mixed_site: Span, current_dir: String, + callback: Option>, ) -> Result, String>, ServerError> { match self.protocol { Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => { legacy_protocol::expand( proc_macro, - db, subtree, attr, env, @@ -222,7 +228,6 @@ impl ProcMacroServerProcess { } Protocol::BidirectionalPostcardPrototype { .. } => bidirectional_protocol::expand( proc_macro, - db, subtree, attr, env, @@ -230,6 +235,7 @@ impl ProcMacroServerProcess { call_site, mixed_site, current_dir, + callback.expect("callback required for bidirectional protocol"), ), } } @@ -297,10 +303,10 @@ impl ProcMacroServerProcess { pub(crate) fn run_bidirectional( &self, initial: BidirectionalMessage, - callbacks: &mut dyn ClientCallbacks, + callback: SubCallback<'_>, ) -> Result { self.with_locked_io::(|writer, reader, buf| { - bidirectional_protocol::run_conversation::(writer, reader, buf, initial, callbacks) + bidirectional_protocol::run_conversation::(writer, reader, buf, initial, callback) }) } } diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index 7e50888114ba..d73d20b58422 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -57,7 +57,11 @@ enum ProtocolFormat { impl ValueEnum for ProtocolFormat { fn value_variants<'a>() -> &'a [Self] { - &[ProtocolFormat::JsonLegacy, ProtocolFormat::PostcardLegacy, ProtocolFormat::BidirectionalPostcardPrototype] + &[ + ProtocolFormat::JsonLegacy, + ProtocolFormat::PostcardLegacy, + ProtocolFormat::BidirectionalPostcardPrototype, + ] } fn to_possible_value(&self) -> Option { @@ -66,14 +70,18 @@ impl ValueEnum for ProtocolFormat { ProtocolFormat::PostcardLegacy => { Some(clap::builder::PossibleValue::new("postcard-legacy")) } - ProtocolFormat::BidirectionalPostcardPrototype => Some(clap::builder::PossibleValue::new("postcard-new")), + ProtocolFormat::BidirectionalPostcardPrototype => { + Some(clap::builder::PossibleValue::new("postcard-new")) + } } } fn from_str(input: &str, _ignore_case: bool) -> Result { match input { "json-legacy" => Ok(ProtocolFormat::JsonLegacy), "postcard-legacy" => Ok(ProtocolFormat::PostcardLegacy), - "bidirectional-postcard-prototype" => Ok(ProtocolFormat::BidirectionalPostcardPrototype), + "bidirectional-postcard-prototype" => { + Ok(ProtocolFormat::BidirectionalPostcardPrototype) + } _ => Err(format!("unknown protocol format: {input}")), } } From 1f64a69249af2f5075203d50f735fa1784bcbc6c Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 23 Dec 2025 11:59:56 +0530 Subject: [PATCH 13/15] remove channels with callbacks in proc-macro-srv --- crates/proc-macro-srv-cli/src/main_loop.rs | 135 ++++++++---------- crates/proc-macro-srv/src/dylib.rs | 31 +--- .../proc-macro-srv/src/dylib/proc_macros.rs | 80 +---------- crates/proc-macro-srv/src/lib.rs | 69 ++------- .../src/server_impl/rust_analyzer_span.rs | 31 ++-- .../src/server_impl/token_id.rs | 5 +- crates/proc-macro-srv/src/tests/utils.rs | 8 +- 7 files changed, 99 insertions(+), 260 deletions(-) diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index 8666c1367717..99e3d79ef29a 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -1,7 +1,6 @@ //! The main loop of the proc-macro server. use std::io; -use crossbeam_channel::unbounded; use proc_macro_api::{ Codec, bidirectional_protocol::msg as bidirectional, @@ -82,6 +81,7 @@ fn run_new() -> io::Result<()> { } bidirectional::Request::ApiVersionCheck {} => { + // bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION).write::<_, C>(stdout) send_response::<_, C>( &mut stdout, bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION), @@ -160,6 +160,7 @@ fn handle_expand_id( def_site, call_site, mixed_site, + None, ) .map(|it| { legacy::FlatTree::from_tokenstream_raw::(it, call_site, CURRENT_API_VERSION) @@ -169,7 +170,7 @@ fn handle_expand_id( send_response::<_, C>(stdout, bidirectional::Response::ExpandMacro(res)) } -fn handle_expand_ra( +fn handle_expand_ra( srv: &proc_macro_srv::ProcMacroSrv<'_>, stdin: &mut R, stdout: &mut W, @@ -185,74 +186,69 @@ fn handle_expand_ra( macro_body, macro_name, attributes, - has_global_spans: - bidirectional::ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, + has_global_spans: bidirectional::ExpnGlobals { def_site, call_site, mixed_site, .. }, span_data_table, }, } = task; let mut span_data_table = legacy::deserialize_span_data_index_map(&span_data_table); - let def_site_span = span_data_table[def_site]; - let call_site_span = span_data_table[call_site]; - let mixed_site_span = span_data_table[mixed_site]; + let def_site = span_data_table[def_site]; + let call_site = span_data_table[call_site]; + let mixed_site = span_data_table[mixed_site]; - let macro_body_ts = + let macro_body = macro_body.to_tokenstream_resolved(CURRENT_API_VERSION, &span_data_table, |a, b| { srv.join_spans(a, b).unwrap_or(b) }); - let attributes_ts = attributes.map(|it| { + let attributes = attributes.map(|it| { it.to_tokenstream_resolved(CURRENT_API_VERSION, &span_data_table, |a, b| { srv.join_spans(a, b).unwrap_or(b) }) }); - let (subreq_tx, subreq_rx) = unbounded::(); - let (subresp_tx, subresp_rx) = unbounded::(); + let (subreq_tx, subreq_rx) = crossbeam_channel::unbounded(); + let (subresp_tx, subresp_rx) = crossbeam_channel::unbounded(); let (result_tx, result_rx) = crossbeam_channel::bounded(1); std::thread::scope(|scope| { - let srv_ref = &srv; - - scope.spawn({ - let lib = lib.clone(); - let env = env.clone(); - let current_dir = current_dir.clone(); - let macro_name = macro_name.clone(); - move || { - let res = srv_ref - .expand_with_channels( - lib, - &env, - current_dir, - ¯o_name, - macro_body_ts, - attributes_ts, - def_site_span, - call_site_span, - mixed_site_span, - subresp_rx, - subreq_tx, + scope.spawn(|| { + let callback = Box::new(move |req: proc_macro_srv::SubRequest| { + subreq_tx.send(req).unwrap(); + subresp_rx.recv().unwrap() + }); + + let res = srv + .expand( + lib, + &env, + current_dir, + ¯o_name, + macro_body, + attributes, + def_site, + call_site, + mixed_site, + Some(callback), + ) + .map(|it| { + ( + legacy::FlatTree::from_tokenstream( + it, + CURRENT_API_VERSION, + call_site, + &mut span_data_table, + ), + legacy::serialize_span_data_index_map(&span_data_table), ) - .map(|it| { - ( - legacy::FlatTree::from_tokenstream( - it, - CURRENT_API_VERSION, - call_site_span, - &mut span_data_table, - ), - legacy::serialize_span_data_index_map(&span_data_table), - ) - }) - .map(|(tree, span_data_table)| bidirectional::ExpandMacroExtended { - tree, - span_data_table, - }) - .map_err(|e| e.into_string().unwrap_or_default()) - .map_err(legacy::PanicMessage); - let _ = result_tx.send(res); - } + }) + .map(|(tree, span_data_table)| bidirectional::ExpandMacroExtended { + tree, + span_data_table, + }) + .map_err(|e| legacy::PanicMessage(e.into_string().unwrap_or_default())); + + let _ = result_tx.send(res); }); loop { @@ -264,31 +260,26 @@ fn handle_expand_ra( let subreq = match subreq_rx.recv() { Ok(r) => r, - Err(_) => { - break; - } + Err(_) => break, }; - send_subrequest::<_, C>(stdout, from_srv_req(subreq)).unwrap(); + let api_req = from_srv_req(subreq); + bidirectional::BidirectionalMessage::SubRequest(api_req).write::<_, C>(stdout).unwrap(); - let resp_opt = bidirectional::BidirectionalMessage::read::<_, C>(stdin, buf).unwrap(); - let resp = match resp_opt { - Some(env) => env, - None => { - break; - } - }; + let resp = bidirectional::BidirectionalMessage::read::<_, C>(stdin, buf) + .unwrap() + .expect("client closed connection"); match resp { - bidirectional::BidirectionalMessage::SubResponse(subresp) => { - let _ = subresp_tx.send(from_client_res(subresp)); - } - _ => { - break; + bidirectional::BidirectionalMessage::SubResponse(api_resp) => { + let srv_resp = from_client_res(api_resp); + subresp_tx.send(srv_resp).unwrap(); } + other => panic!("expected SubResponse, got {other:?}"), } } }); + Ok(()) } @@ -356,6 +347,7 @@ fn run_() -> io::Result<()> { def_site, call_site, mixed_site, + None, ) .map(|it| { legacy::FlatTree::from_tokenstream_raw::( @@ -397,6 +389,7 @@ fn run_() -> io::Result<()> { def_site, call_site, mixed_site, + None, ) .map(|it| { ( @@ -455,11 +448,3 @@ fn send_response( let resp = bidirectional::BidirectionalMessage::Response(resp); resp.write::(stdout) } - -fn send_subrequest( - stdout: &mut W, - resp: bidirectional::SubRequest, -) -> io::Result<()> { - let resp = bidirectional::BidirectionalMessage::SubRequest(resp); - resp.write::(stdout) -} diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index ba089c9549d3..082a1d77b5aa 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -12,7 +12,7 @@ use object::Object; use paths::{Utf8Path, Utf8PathBuf}; use crate::{ - PanicMessage, ProcMacroKind, ProcMacroSrvSpan, dylib::proc_macros::ProcMacros, + PanicMessage, ProcMacroKind, ProcMacroSrvSpan, SubCallback, dylib::proc_macros::ProcMacros, token_stream::TokenStream, }; @@ -45,39 +45,14 @@ impl Expander { def_site: S, call_site: S, mixed_site: S, + callback: Option, ) -> Result, PanicMessage> where ::TokenStream: Default, { self.inner .proc_macros - .expand(macro_name, macro_body, attribute, def_site, call_site, mixed_site) - } - - pub(crate) fn expand_with_channels( - &self, - macro_name: &str, - macro_body: crate::token_stream::TokenStream, - attribute: Option>, - def_site: S, - call_site: S, - mixed_site: S, - cli_to_server: crossbeam_channel::Receiver, - server_to_cli: crossbeam_channel::Sender, - ) -> Result, crate::PanicMessage> - where - ::TokenStream: Default, - { - self.inner.proc_macros.expand_with_channels( - macro_name, - macro_body, - attribute, - def_site, - call_site, - mixed_site, - cli_to_server, - server_to_cli, - ) + .expand(macro_name, macro_body, attribute, def_site, call_site, mixed_site, callback) } pub(crate) fn list_macros(&self) -> impl Iterator { diff --git a/crates/proc-macro-srv/src/dylib/proc_macros.rs b/crates/proc-macro-srv/src/dylib/proc_macros.rs index 5b6f1cf2f332..6f6bd086de64 100644 --- a/crates/proc-macro-srv/src/dylib/proc_macros.rs +++ b/crates/proc-macro-srv/src/dylib/proc_macros.rs @@ -1,8 +1,7 @@ //! Proc macro ABI +use crate::{ProcMacroKind, ProcMacroSrvSpan, SubCallback, token_stream::TokenStream}; use proc_macro::bridge; -use crate::{ProcMacroKind, ProcMacroSrvSpan, token_stream::TokenStream}; - #[repr(transparent)] pub(crate) struct ProcMacros([bridge::client::ProcMacro]); @@ -21,6 +20,7 @@ impl ProcMacros { def_site: S, call_site: S, mixed_site: S, + callback: Option, ) -> Result, crate::PanicMessage> { let parsed_attributes = attribute.unwrap_or_default(); @@ -31,65 +31,7 @@ impl ProcMacros { { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site, None, None), - macro_body, - cfg!(debug_assertions), - ); - return res.map_err(crate::PanicMessage::from); - } - bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { - let res = client.run( - &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site, None, None), - macro_body, - cfg!(debug_assertions), - ); - return res.map_err(crate::PanicMessage::from); - } - bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { - let res = client.run( - &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site, None, None), - parsed_attributes, - macro_body, - cfg!(debug_assertions), - ); - return res.map_err(crate::PanicMessage::from); - } - _ => continue, - } - } - - Err(bridge::PanicMessage::String(format!("proc-macro `{macro_name}` is missing")).into()) - } - - pub(crate) fn expand_with_channels( - &self, - macro_name: &str, - macro_body: TokenStream, - attribute: Option>, - def_site: S, - call_site: S, - mixed_site: S, - cli_to_server: crossbeam_channel::Receiver, - server_to_cli: crossbeam_channel::Sender, - ) -> Result, crate::PanicMessage> { - let parsed_attributes = attribute.unwrap_or_default(); - - for proc_macro in &self.0 { - match proc_macro { - bridge::client::ProcMacro::CustomDerive { trait_name, client, .. } - if *trait_name == macro_name => - { - let res = client.run( - &bridge::server::SameThread, - S::make_server( - call_site, - def_site, - mixed_site, - Some(cli_to_server), - Some(server_to_cli), - ), + S::make_server(call_site, def_site, mixed_site, callback), macro_body, cfg!(debug_assertions), ); @@ -98,13 +40,7 @@ impl ProcMacros { bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { let res = client.run( &bridge::server::SameThread, - S::make_server( - call_site, - def_site, - mixed_site, - Some(cli_to_server), - Some(server_to_cli), - ), + S::make_server(call_site, def_site, mixed_site, callback), macro_body, cfg!(debug_assertions), ); @@ -113,13 +49,7 @@ impl ProcMacros { bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { let res = client.run( &bridge::server::SameThread, - S::make_server( - call_site, - def_site, - mixed_site, - Some(cli_to_server), - Some(server_to_cli), - ), + S::make_server(call_site, def_site, mixed_site, callback), parsed_attributes, macro_body, cfg!(debug_assertions), diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index f369ab93a2a3..705ac930ed9c 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -91,6 +91,8 @@ impl<'env> ProcMacroSrv<'env> { } } +pub type SubCallback = Box SubResponse + Send + Sync + 'static>; + pub enum SubRequest { SourceText { file_id: EditionedFileId, start: u32, end: u32 }, } @@ -113,6 +115,7 @@ impl ProcMacroSrv<'_> { def_site: S, call_site: S, mixed_site: S, + callback: Option, ) -> Result, PanicMessage> { let snapped_env = self.env; let expander = self.expander(lib.as_ref()).map_err(|err| PanicMessage { @@ -128,54 +131,9 @@ impl ProcMacroSrv<'_> { .stack_size(EXPANDER_STACK_SIZE) .name(macro_name.to_owned()) .spawn_scoped(s, move || { - expander - .expand(macro_name, macro_body, attribute, def_site, call_site, mixed_site) - }); - match thread.unwrap().join() { - Ok(res) => res, - Err(e) => std::panic::resume_unwind(e), - } - }); - prev_env.rollback(); - - result - } - - pub fn expand_with_channels( - &self, - lib: impl AsRef, - env: &[(String, String)], - current_dir: Option>, - macro_name: &str, - macro_body: token_stream::TokenStream, - attribute: Option>, - def_site: S, - call_site: S, - mixed_site: S, - cli_to_server: crossbeam_channel::Receiver, - server_to_cli: crossbeam_channel::Sender, - ) -> Result, PanicMessage> { - let snapped_env = self.env; - let expander = self.expander(lib.as_ref()).map_err(|err| PanicMessage { - message: Some(format!("failed to load macro: {err}")), - })?; - - let prev_env = EnvChange::apply(snapped_env, env, current_dir.as_ref().map(<_>::as_ref)); - - let result = thread::scope(|s| { - let thread = thread::Builder::new() - .stack_size(EXPANDER_STACK_SIZE) - .name(macro_name.to_owned()) - .spawn_scoped(s, move || { - expander.expand_with_channels( - macro_name, - macro_body, - attribute, - def_site, - call_site, - mixed_site, - cli_to_server, - server_to_cli, + expander.expand( + macro_name, macro_body, attribute, def_site, call_site, mixed_site, + callback, ) }); match thread.unwrap().join() { @@ -229,8 +187,7 @@ pub trait ProcMacroSrvSpan: Copy + Send + Sync { call_site: Self, def_site: Self, mixed_site: Self, - cli_to_server: Option>, - server_to_cli: Option>, + callback: Option, ) -> Self::Server; } @@ -241,15 +198,13 @@ impl ProcMacroSrvSpan for SpanId { call_site: Self, def_site: Self, mixed_site: Self, - cli_to_server: Option>, - server_to_cli: Option>, + callback: Option, ) -> Self::Server { Self::Server { call_site, def_site, mixed_site, - cli_to_server, - server_to_cli, + callback, tracked_env_vars: Default::default(), tracked_paths: Default::default(), } @@ -262,17 +217,15 @@ impl ProcMacroSrvSpan for Span { call_site: Self, def_site: Self, mixed_site: Self, - cli_to_server: Option>, - server_to_cli: Option>, + callback: Option, ) -> Self::Server { Self::Server { call_site, def_site, mixed_site, + callback, tracked_env_vars: Default::default(), tracked_paths: Default::default(), - cli_to_server, - server_to_cli, } } } diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index cccb74429dd6..0bce67fcd9fe 100644 --- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -14,7 +14,7 @@ use proc_macro::bridge::server; use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span, TextRange, TextSize}; use crate::{ - SubRequest, SubResponse, + SubCallback, SubRequest, SubResponse, bridge::{Diagnostic, ExpnGlobals, Literal, TokenTree}, server_impl::literal_from_str, }; @@ -29,8 +29,7 @@ pub struct RaSpanServer { pub call_site: Span, pub def_site: Span, pub mixed_site: Span, - pub cli_to_server: Option>, - pub server_to_cli: Option>, + pub callback: Option, } impl server::Types for RaSpanServer { @@ -153,21 +152,17 @@ impl server::Span for RaSpanServer { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, span: Self::Span) -> Option { - // FIXME requires db, needs special handling wrt fixup spans - if self.server_to_cli.is_some() && self.cli_to_server.is_some() { - let file_id = span.anchor.file_id; - let start: u32 = span.range.start().into(); - let end: u32 = span.range.end().into(); - let _ = self.server_to_cli.clone().unwrap().send(SubRequest::SourceText { - file_id, - start, - end, - }); - match self.cli_to_server.as_ref()?.recv().ok()? { - SubResponse::SourceTextResult { text } => text, - } - } else { - None + let file_id = span.anchor.file_id; + let start: u32 = span.range.start().into(); + let end: u32 = span.range.end().into(); + + let req = SubRequest::SourceText { file_id, start, end }; + + let cb = self.callback.as_mut()?; + let response = cb(req); + + match response { + SubResponse::SourceTextResult { text } => text, } } diff --git a/crates/proc-macro-srv/src/server_impl/token_id.rs b/crates/proc-macro-srv/src/server_impl/token_id.rs index 268042b3bc07..3b12644ec34a 100644 --- a/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -9,7 +9,7 @@ use intern::Symbol; use proc_macro::bridge::server; use crate::{ - SubRequest, SubResponse, + SubCallback, bridge::{Diagnostic, ExpnGlobals, Literal, TokenTree}, server_impl::literal_from_str, }; @@ -35,8 +35,7 @@ pub struct SpanIdServer { pub call_site: Span, pub def_site: Span, pub mixed_site: Span, - pub cli_to_server: Option>, - pub server_to_cli: Option>, + pub callback: Option, } impl server::Types for SpanIdServer { diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs index 1b12308ad6c5..61fcd810b1d9 100644 --- a/crates/proc-macro-srv/src/tests/utils.rs +++ b/crates/proc-macro-srv/src/tests/utils.rs @@ -59,8 +59,9 @@ fn assert_expand_impl( let input_ts_string = format!("{input_ts:?}"); let attr_ts_string = attr_ts.as_ref().map(|it| format!("{it:?}")); - let res = - expander.expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site).unwrap(); + let res = expander + .expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site, None) + .unwrap(); expect.assert_eq(&format!( "{input_ts_string}{}{}{}", if attr_ts_string.is_some() { "\n\n" } else { "" }, @@ -91,7 +92,8 @@ fn assert_expand_impl( let fixture_string = format!("{fixture:?}"); let attr_string = attr.as_ref().map(|it| format!("{it:?}")); - let res = expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site).unwrap(); + let res = + expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site, None).unwrap(); expect_spanned.assert_eq(&format!( "{fixture_string}{}{}{}", if attr_string.is_some() { "\n\n" } else { "" }, From 9b03499a3bdf3eb248c0a822403e6a78516de297 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 23 Dec 2025 18:25:21 +0530 Subject: [PATCH 14/15] chore: remove unwanted comments, extra lines and putting cli srv on default --- .github/workflows/ci.yaml | 2 +- Cargo.lock | 1 - crates/proc-macro-srv-cli/src/main.rs | 4 ++-- crates/proc-macro-srv/Cargo.toml | 1 - crates/proc-macro-srv/src/server_impl/token_id.rs | 1 - 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e817f770a417..5975272d871a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -70,7 +70,7 @@ jobs: - name: Test run: cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api -- --quiet - + - name: Check salsa dependency run: "! (cargo tree -p proc-macro-srv-cli | grep -q salsa)" diff --git a/Cargo.lock b/Cargo.lock index 7d133f99498b..10cd6cd43c20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1856,7 +1856,6 @@ dependencies = [ name = "proc-macro-srv" version = "0.0.0" dependencies = [ - "crossbeam-channel", "expect-test", "intern", "libc", diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs index d73d20b58422..bdfdb50002e1 100644 --- a/crates/proc-macro-srv-cli/src/main.rs +++ b/crates/proc-macro-srv-cli/src/main.rs @@ -31,7 +31,7 @@ fn main() -> std::io::Result<()> { clap::Arg::new("format") .long("format") .action(clap::ArgAction::Set) - .default_value("bidirectional-postcard-prototype") + .default_value("json-legacy") .value_parser(clap::builder::EnumValueParser::::new()), clap::Arg::new("version") .long("version") @@ -71,7 +71,7 @@ impl ValueEnum for ProtocolFormat { Some(clap::builder::PossibleValue::new("postcard-legacy")) } ProtocolFormat::BidirectionalPostcardPrototype => { - Some(clap::builder::PossibleValue::new("postcard-new")) + Some(clap::builder::PossibleValue::new("bidirectional-postcard-prototype")) } } } diff --git a/crates/proc-macro-srv/Cargo.toml b/crates/proc-macro-srv/Cargo.toml index b2abda0bfd7f..361017178409 100644 --- a/crates/proc-macro-srv/Cargo.toml +++ b/crates/proc-macro-srv/Cargo.toml @@ -22,7 +22,6 @@ paths.workspace = true # span = {workspace = true, default-features = false} does not work span = { path = "../span", version = "0.0.0", default-features = false} intern.workspace = true -crossbeam-channel.workspace = true ra-ap-rustc_lexer.workspace = true diff --git a/crates/proc-macro-srv/src/server_impl/token_id.rs b/crates/proc-macro-srv/src/server_impl/token_id.rs index 3b12644ec34a..9db7597d849f 100644 --- a/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -141,7 +141,6 @@ impl server::Span for SpanIdServer { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, _span: Self::Span) -> Option { - // FIXME requires db, needs special handling wrt fixup spans None } From 41dade9006cd213fe105c762148bdd05710f4a81 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 23 Dec 2025 22:30:00 +0530 Subject: [PATCH 15/15] return error on combination of bidirectional message and json framing --- .../proc-macro-api/src/bidirectional_protocol.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/crates/proc-macro-api/src/bidirectional_protocol.rs b/crates/proc-macro-api/src/bidirectional_protocol.rs index bd74738bbdf5..e919ff48fe4c 100644 --- a/crates/proc-macro-api/src/bidirectional_protocol.rs +++ b/crates/proc-macro-api/src/bidirectional_protocol.rs @@ -22,7 +22,7 @@ use crate::{ }, }, process::ProcMacroServerProcess, - transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, + transport::codec::postcard::PostcardProtocol, version, }; @@ -210,14 +210,16 @@ fn run_request( msg: BidirectionalMessage, callback: SubCallback<'_>, ) -> Result { - if let Some(server_error) = srv.exited() { - return Err(server_error.clone()); + if let Some(err) = srv.exited() { + return Err(err.clone()); } - if srv.use_postcard() { - srv.run_bidirectional::(msg, callback) - } else { - srv.run_bidirectional::(msg, callback) + match srv.use_postcard() { + true => srv.run_bidirectional::(msg, callback), + false => Err(ServerError { + message: "bidirectional messaging does not support JSON".to_owned(), + io: None, + }), } }