Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/lib.rs')
| -rw-r--r-- | crates/syntax/src/lib.rs | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index a3c19f71fb..c510b2831e 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -19,6 +19,11 @@ //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256> //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> +#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] + +#[cfg(feature = "in-rust-tree")] +extern crate rustc_driver as _; + mod parsing; mod ptr; mod syntax_error; @@ -67,7 +72,7 @@ pub use smol_str::{SmolStr, SmolStrBuilder, ToSmolStr, format_smolstr}; /// files. #[derive(Debug, PartialEq, Eq)] pub struct Parse<T> { - green: GreenNode, + green: Option<GreenNode>, errors: Option<Arc<[SyntaxError]>>, _ty: PhantomData<fn() -> T>, } @@ -81,14 +86,14 @@ impl<T> Clone for Parse<T> { impl<T> Parse<T> { fn new(green: GreenNode, errors: Vec<SyntaxError>) -> Parse<T> { Parse { - green, + green: Some(green), errors: if errors.is_empty() { None } else { Some(errors.into()) }, _ty: PhantomData, } } pub fn syntax_node(&self) -> SyntaxNode { - SyntaxNode::new_root(self.green.clone()) + SyntaxNode::new_root(self.green.as_ref().unwrap().clone()) } pub fn errors(&self) -> Vec<SyntaxError> { @@ -100,8 +105,10 @@ impl<T> Parse<T> { impl<T: AstNode> Parse<T> { /// Converts this parse result into a parse result for an untyped syntax tree. - pub fn to_syntax(self) -> Parse<SyntaxNode> { - Parse { green: self.green, errors: self.errors, _ty: PhantomData } + pub fn to_syntax(mut self) -> Parse<SyntaxNode> { + let green = self.green.take(); + let errors = self.errors.take(); + Parse { green, errors, _ty: PhantomData } } /// Gets the parsed syntax tree as a typed ast node. @@ -124,9 +131,9 @@ impl<T: AstNode> Parse<T> { } impl Parse<SyntaxNode> { - pub fn cast<N: AstNode>(self) -> Option<Parse<N>> { + pub fn cast<N: AstNode>(mut self) -> Option<Parse<N>> { if N::cast(self.syntax_node()).is_some() { - Some(Parse { green: self.green, errors: self.errors, _ty: PhantomData }) + Some(Parse { green: self.green.take(), errors: self.errors.take(), _ty: PhantomData }) } else { None } @@ -162,7 +169,7 @@ impl Parse<SourceFile> { edition, ) .map(|(green_node, errors, _reparsed_range)| Parse { - green: green_node, + green: Some(green_node), errors: if errors.is_empty() { None } else { Some(errors.into()) }, _ty: PhantomData, }) @@ -198,6 +205,39 @@ impl ast::Expr { } } +#[cfg(not(no_salsa_async_drops))] +impl<T> Drop for Parse<T> { + fn drop(&mut self) { + let Some(green) = self.green.take() else { + return; + }; + static PARSE_DROP_THREAD: std::sync::OnceLock<std::sync::mpsc::Sender<GreenNode>> = + std::sync::OnceLock::new(); + PARSE_DROP_THREAD + .get_or_init(|| { + let (sender, receiver) = std::sync::mpsc::channel::<GreenNode>(); + std::thread::Builder::new() + .name("ParseNodeDropper".to_owned()) + .spawn(move || { + loop { + // block on a receive + _ = receiver.recv(); + // then drain the entire channel + while receiver.try_recv().is_ok() {} + // and sleep for a bit + std::thread::sleep(std::time::Duration::from_millis(100)); + } + // why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock. + // otherwise this thread will constantly wake up and sleep again. + }) + .unwrap(); + sender + }) + .send(green) + .unwrap(); + } +} + /// `SourceFile` represents a parse tree for a single Rust file. pub use crate::ast::SourceFile; @@ -258,7 +298,7 @@ fn api_walkthrough() { assert!(parse.errors().is_empty()); // The `tree` method returns an owned syntax node of type `SourceFile`. - // Owned nodes are cheap: inside, they are `Rc` handles to the underling data. + // Owned nodes are cheap: inside, they are `Rc` handles to the underlying data. let file: SourceFile = parse.tree(); // `SourceFile` is the root of the syntax tree. We can iterate file's items. |