mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-22 08:08:35 +00:00
syntax: Drop Parse on separate thread
Rowan's green nodes are super drop heavy and as lru eviction happens on cancellation this can block for quite some time, especially after cache priming
This commit is contained in:
parent
4bf516ee5a
commit
a3910c6f14
1 changed files with 31 additions and 8 deletions
|
|
@ -67,7 +67,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 +81,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 +100,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 +126,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 +164,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 +200,27 @@ impl ast::Expr {
|
|||
}
|
||||
}
|
||||
|
||||
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 || receiver.iter().for_each(drop))
|
||||
.unwrap();
|
||||
sender
|
||||
})
|
||||
.send(green)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// `SourceFile` represents a parse tree for a single Rust file.
|
||||
pub use crate::ast::SourceFile;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue