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.rs58
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.