aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2020-04-04 09:04:01 +0100
committerEdwin Cheng <[email protected]>2020-04-06 16:07:48 +0100
commitb2844917ad29e967043bea4e187421a6a3f61682 (patch)
tree92e8a79dee5710bd8dc88879f4e8bffc7c650eff /crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs
parent40616fdb49252c17d8e11a4413ff861692d4cc03 (diff)
Add proc_macro mod (copy from lib_proc_macro)
Diffstat (limited to 'crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs')
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs404
1 files changed, 404 insertions, 0 deletions
diff --git a/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs b/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs
new file mode 100644
index 000000000..6ae3926b2
--- /dev/null
+++ b/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs
@@ -0,0 +1,404 @@
1//! lib-proc-macro Internal interface for communicating between a `proc_macro` client
2//!
3//! Copy from https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/mod.rs
4//! augmented with removing unstable features
5//!
6//! Internal interface for communicating between a `proc_macro` client
7//! (a proc macro crate) and a `proc_macro` server (a compiler front-end).
8//!
9//! Serialization (with C ABI buffers) and unique integer handles are employed
10//! to allow safely interfacing between two copies of `proc_macro` built
11//! (from the same source) by different compilers with potentially mismatching
12//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap).
13
14#![deny(unsafe_code)]
15
16pub use crate::proc_macro::{Delimiter, Level, LineColumn, Spacing};
17use std::fmt;
18use std::hash::Hash;
19use std::marker;
20use std::mem;
21use std::ops::Bound;
22use std::panic;
23use std::sync::atomic::AtomicUsize;
24use std::sync::Once;
25use std::thread;
26
27/// Higher-order macro describing the server RPC API, allowing automatic
28/// generation of type-safe Rust APIs, both client-side and server-side.
29///
30/// `with_api!(MySelf, my_self, my_macro)` expands to:
31/// ```rust,ignore (pseudo-code)
32/// my_macro! {
33/// // ...
34/// Literal {
35/// // ...
36/// fn character(ch: char) -> MySelf::Literal;
37/// // ...
38/// fn span(my_self: &MySelf::Literal) -> MySelf::Span;
39/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span);
40/// },
41/// // ...
42/// }
43/// ```
44///
45/// The first two arguments serve to customize the arguments names
46/// and argument/return types, to enable several different usecases:
47///
48/// If `my_self` is just `self`, then each `fn` signature can be used
49/// as-is for a method. If it's anything else (`self_` in practice),
50/// then the signatures don't have a special `self` argument, and
51/// can, therefore, have a different one introduced.
52///
53/// If `MySelf` is just `Self`, then the types are only valid inside
54/// a trait or a trait impl, where the trait has associated types
55/// for each of the API types. If non-associated types are desired,
56/// a module name (`self` in practice) can be used instead of `Self`.
57macro_rules! with_api {
58 ($S:ident, $self:ident, $m:ident) => {
59 $m! {
60 TokenStream {
61 fn drop($self: $S::TokenStream);
62 fn clone($self: &$S::TokenStream) -> $S::TokenStream;
63 fn new() -> $S::TokenStream;
64 fn is_empty($self: &$S::TokenStream) -> bool;
65 fn from_str(src: &str) -> $S::TokenStream;
66 fn to_string($self: &$S::TokenStream) -> String;
67 fn from_token_tree(
68 tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>,
69 ) -> $S::TokenStream;
70 fn into_iter($self: $S::TokenStream) -> $S::TokenStreamIter;
71 },
72 TokenStreamBuilder {
73 fn drop($self: $S::TokenStreamBuilder);
74 fn new() -> $S::TokenStreamBuilder;
75 fn push($self: &mut $S::TokenStreamBuilder, stream: $S::TokenStream);
76 fn build($self: $S::TokenStreamBuilder) -> $S::TokenStream;
77 },
78 TokenStreamIter {
79 fn drop($self: $S::TokenStreamIter);
80 fn clone($self: &$S::TokenStreamIter) -> $S::TokenStreamIter;
81 fn next(
82 $self: &mut $S::TokenStreamIter,
83 ) -> Option<TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>>;
84 },
85 Group {
86 fn drop($self: $S::Group);
87 fn clone($self: &$S::Group) -> $S::Group;
88 fn new(delimiter: Delimiter, stream: $S::TokenStream) -> $S::Group;
89 fn delimiter($self: &$S::Group) -> Delimiter;
90 fn stream($self: &$S::Group) -> $S::TokenStream;
91 fn span($self: &$S::Group) -> $S::Span;
92 fn span_open($self: &$S::Group) -> $S::Span;
93 fn span_close($self: &$S::Group) -> $S::Span;
94 fn set_span($self: &mut $S::Group, span: $S::Span);
95 },
96 Punct {
97 fn new(ch: char, spacing: Spacing) -> $S::Punct;
98 fn as_char($self: $S::Punct) -> char;
99 fn spacing($self: $S::Punct) -> Spacing;
100 fn span($self: $S::Punct) -> $S::Span;
101 fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct;
102 },
103 Ident {
104 fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident;
105 fn span($self: $S::Ident) -> $S::Span;
106 fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident;
107 },
108 Literal {
109 fn drop($self: $S::Literal);
110 fn clone($self: &$S::Literal) -> $S::Literal;
111 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
112 fn debug($self: &$S::Literal) -> String;
113 fn integer(n: &str) -> $S::Literal;
114 fn typed_integer(n: &str, kind: &str) -> $S::Literal;
115 fn float(n: &str) -> $S::Literal;
116 fn f32(n: &str) -> $S::Literal;
117 fn f64(n: &str) -> $S::Literal;
118 fn string(string: &str) -> $S::Literal;
119 fn character(ch: char) -> $S::Literal;
120 fn byte_string(bytes: &[u8]) -> $S::Literal;
121 fn span($self: &$S::Literal) -> $S::Span;
122 fn set_span($self: &mut $S::Literal, span: $S::Span);
123 fn subspan(
124 $self: &$S::Literal,
125 start: Bound<usize>,
126 end: Bound<usize>,
127 ) -> Option<$S::Span>;
128 },
129 SourceFile {
130 fn drop($self: $S::SourceFile);
131 fn clone($self: &$S::SourceFile) -> $S::SourceFile;
132 fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool;
133 fn path($self: &$S::SourceFile) -> String;
134 fn is_real($self: &$S::SourceFile) -> bool;
135 },
136 MultiSpan {
137 fn drop($self: $S::MultiSpan);
138 fn new() -> $S::MultiSpan;
139 fn push($self: &mut $S::MultiSpan, span: $S::Span);
140 },
141 Diagnostic {
142 fn drop($self: $S::Diagnostic);
143 fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic;
144 fn sub(
145 $self: &mut $S::Diagnostic,
146 level: Level,
147 msg: &str,
148 span: $S::MultiSpan,
149 );
150 fn emit($self: $S::Diagnostic);
151 },
152 Span {
153 fn debug($self: $S::Span) -> String;
154 fn def_site() -> $S::Span;
155 fn call_site() -> $S::Span;
156 fn mixed_site() -> $S::Span;
157 fn source_file($self: $S::Span) -> $S::SourceFile;
158 fn parent($self: $S::Span) -> Option<$S::Span>;
159 fn source($self: $S::Span) -> $S::Span;
160 fn start($self: $S::Span) -> LineColumn;
161 fn end($self: $S::Span) -> LineColumn;
162 fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
163 fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
164 fn source_text($self: $S::Span) -> Option<String>;
165 },
166 }
167 };
168}
169
170// FIXME(eddyb) this calls `encode` for each argument, but in reverse,
171// to avoid borrow conflicts from borrows started by `&mut` arguments.
172macro_rules! reverse_encode {
173 ($writer:ident;) => {};
174 ($writer:ident; $first:ident $(, $rest:ident)*) => {
175 reverse_encode!($writer; $($rest),*);
176 $first.encode(&mut $writer, &mut ());
177 }
178}
179
180// FIXME(eddyb) this calls `decode` for each argument, but in reverse,
181// to avoid borrow conflicts from borrows started by `&mut` arguments.
182macro_rules! reverse_decode {
183 ($reader:ident, $s:ident;) => {};
184 ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => {
185 reverse_decode!($reader, $s; $($rest: $rest_ty),*);
186 let $first = <$first_ty>::decode(&mut $reader, $s);
187 }
188}
189
190#[allow(unsafe_code)]
191mod buffer;
192#[forbid(unsafe_code)]
193pub mod client;
194#[allow(unsafe_code)]
195mod closure;
196#[forbid(unsafe_code)]
197mod handle;
198#[macro_use]
199#[forbid(unsafe_code)]
200mod rpc;
201#[allow(unsafe_code)]
202mod scoped_cell;
203#[forbid(unsafe_code)]
204pub mod server;
205
206use buffer::Buffer;
207pub use rpc::PanicMessage;
208use rpc::{Decode, DecodeMut, Encode, Reader, Writer};
209
210/// An active connection between a server and a client.
211/// The server creates the bridge (`Bridge::run_server` in `server.rs`),
212/// then passes it to the client through the function pointer in the `run`
213/// field of `client::Client`. The client holds its copy of the `Bridge`
214/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`).
215#[repr(C)]
216pub struct Bridge<'a> {
217 /// Reusable buffer (only `clear`-ed, never shrunk), primarily
218 /// used for making requests, but also for passing input to client.
219 cached_buffer: Buffer<u8>,
220
221 /// Server-side function that the client uses to make requests.
222 dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>,
223}
224
225#[forbid(unsafe_code)]
226#[allow(non_camel_case_types)]
227mod api_tags {
228 use super::rpc::{DecodeMut, Encode, Reader, Writer};
229
230 macro_rules! declare_tags {
231 ($($name:ident {
232 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
233 }),* $(,)?) => {
234 $(
235 pub(super) enum $name {
236 $($method),*
237 }
238 rpc_encode_decode!(enum $name { $($method),* });
239 )*
240
241
242 pub(super) enum Method {
243 $($name($name)),*
244 }
245 rpc_encode_decode!(enum Method { $($name(m)),* });
246 }
247 }
248 with_api!(self, self, declare_tags);
249}
250
251/// Helper to wrap associated types to allow trait impl dispatch.
252/// That is, normally a pair of impls for `T::Foo` and `T::Bar`
253/// can overlap, but if the impls are, instead, on types like
254/// `Marked<T::Foo, Foo>` and `Marked<T::Bar, Bar>`, they can't.
255trait Mark {
256 type Unmarked;
257 fn mark(unmarked: Self::Unmarked) -> Self;
258}
259
260/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details).
261trait Unmark {
262 type Unmarked;
263 fn unmark(self) -> Self::Unmarked;
264}
265
266#[derive(Copy, Clone, PartialEq, Eq, Hash)]
267struct Marked<T, M> {
268 value: T,
269 _marker: marker::PhantomData<M>,
270}
271
272impl<T, M> Mark for Marked<T, M> {
273 type Unmarked = T;
274 fn mark(unmarked: Self::Unmarked) -> Self {
275 Marked { value: unmarked, _marker: marker::PhantomData }
276 }
277}
278impl<T, M> Unmark for Marked<T, M> {
279 type Unmarked = T;
280 fn unmark(self) -> Self::Unmarked {
281 self.value
282 }
283}
284impl<'a, T, M> Unmark for &'a Marked<T, M> {
285 type Unmarked = &'a T;
286 fn unmark(self) -> Self::Unmarked {
287 &self.value
288 }
289}
290impl<'a, T, M> Unmark for &'a mut Marked<T, M> {
291 type Unmarked = &'a mut T;
292 fn unmark(self) -> Self::Unmarked {
293 &mut self.value
294 }
295}
296
297impl<T: Mark> Mark for Option<T> {
298 type Unmarked = Option<T::Unmarked>;
299 fn mark(unmarked: Self::Unmarked) -> Self {
300 unmarked.map(T::mark)
301 }
302}
303impl<T: Unmark> Unmark for Option<T> {
304 type Unmarked = Option<T::Unmarked>;
305 fn unmark(self) -> Self::Unmarked {
306 self.map(T::unmark)
307 }
308}
309
310macro_rules! mark_noop {
311 ($($ty:ty),* $(,)?) => {
312 $(
313 impl Mark for $ty {
314 type Unmarked = Self;
315 fn mark(unmarked: Self::Unmarked) -> Self {
316 unmarked
317 }
318 }
319 impl Unmark for $ty {
320 type Unmarked = Self;
321 fn unmark(self) -> Self::Unmarked {
322 self
323 }
324 }
325 )*
326 }
327}
328mark_noop! {
329 (),
330 bool,
331 char,
332 &'_ [u8],
333 &'_ str,
334 String,
335 Delimiter,
336 Level,
337 LineColumn,
338 Spacing,
339 Bound<usize>,
340}
341
342rpc_encode_decode!(
343 enum Delimiter {
344 Parenthesis,
345 Brace,
346 Bracket,
347 None,
348 }
349);
350rpc_encode_decode!(
351 enum Level {
352 Error,
353 Warning,
354 Note,
355 Help,
356 }
357);
358rpc_encode_decode!(struct LineColumn { line, column });
359rpc_encode_decode!(
360 enum Spacing {
361 Alone,
362 Joint,
363 }
364);
365
366#[derive(Clone)]
367pub enum TokenTree<G, P, I, L> {
368 Group(G),
369 Punct(P),
370 Ident(I),
371 Literal(L),
372}
373
374impl<G: Mark, P: Mark, I: Mark, L: Mark> Mark for TokenTree<G, P, I, L> {
375 type Unmarked = TokenTree<G::Unmarked, P::Unmarked, I::Unmarked, L::Unmarked>;
376 fn mark(unmarked: Self::Unmarked) -> Self {
377 match unmarked {
378 TokenTree::Group(tt) => TokenTree::Group(G::mark(tt)),
379 TokenTree::Punct(tt) => TokenTree::Punct(P::mark(tt)),
380 TokenTree::Ident(tt) => TokenTree::Ident(I::mark(tt)),
381 TokenTree::Literal(tt) => TokenTree::Literal(L::mark(tt)),
382 }
383 }
384}
385impl<G: Unmark, P: Unmark, I: Unmark, L: Unmark> Unmark for TokenTree<G, P, I, L> {
386 type Unmarked = TokenTree<G::Unmarked, P::Unmarked, I::Unmarked, L::Unmarked>;
387 fn unmark(self) -> Self::Unmarked {
388 match self {
389 TokenTree::Group(tt) => TokenTree::Group(tt.unmark()),
390 TokenTree::Punct(tt) => TokenTree::Punct(tt.unmark()),
391 TokenTree::Ident(tt) => TokenTree::Ident(tt.unmark()),
392 TokenTree::Literal(tt) => TokenTree::Literal(tt.unmark()),
393 }
394 }
395}
396
397rpc_encode_decode!(
398 enum TokenTree<G, P, I, L> {
399 Group(tt),
400 Punct(tt),
401 Ident(tt),
402 Literal(tt),
403 }
404);