我正在开发编译器管道,但不确定如何使用 arenas 正确建模 AST 的所有权。
我在 AST 中使用
rustc
将类型表示为对 arenas 的引用(很像 TyCtxt
自己的
typed_arena
)。作为一个虚拟示例(但很乐意提供更多详细信息):
use typed_arena::Arena;
enum Ty<'ty> {
Int,
List(&'ty Ty<'ty>),
}
enum Expr<'ty> {
Literal(isize),
List(Vec<Expr<'ty>>),
TypeAnnotated(Expr<'ty>, &'ty Ty<'ty>)
}
fn parse_and_type_check<'ty>(input: String, ty_arena: &'ty Arena<Ty<'ty>>) -> Expr<'ty> {
todo!()
}
这对于单独运行编译管道来说效果很好,但现在我想在语言服务器中使用它,我希望
Expr<'ty>
能够根据需要长期存在:
struct LanguageServerState<'ty> {
latest_program: Option<(Arena<'ty>, Expr<'ty>)>,
}
fn main() {
let mut state = LanguageServerState { latest_program: None };
// in reality, this is accepting connections and selecting receiving messages from an LSP client
loop {
// ...on a new program
let new_program = "[1, [2, 3]]".to_owned();
let fresh_arena = Arena::new();
let new_program = parse_and_type_check(new_program, &fresh_arena);
state = LanguageServerState { latest_program: Some((fresh_arena, new_program)) };
// ...on some LSP request I may need to do something using `latest_program`
}
}
这是有道理的,这不会通过借用检查器 - 正如所写的,代码将允许我将
Arena
放入 LanguageServerState
中,而不删除 Expr<'ty>
,这会留下悬空指针。
我只是不确定:在这种情况下对
LanguageServerState
进行建模的正确方法是什么?当程序本身被删除时,我确实需要能够从 arena 回收内存,但我需要整个程序 + arena 一直存在,直到程序的网络版本被解析并进行类型检查。
你会遇到困难。您正在尝试创建一个自引用结构。
最简单的方法可能是使用现成的自引用板条箱之一。
yoke
(请注意,我将类型化的 arena 切换到了非类型化的 arena,因为 yoke
在竞技场中存在生命周期问题。如果您分配需要的类型,这可能会导致问题被删除。优点是你也可以在那里分配 Expr
):
use bumpalo::Bump;
#[derive(yoke::Yokeable)]
enum Ty<'ty> {
Int,
List(&'ty [Ty<'ty>]),
}
#[derive(yoke::Yokeable)]
enum Expr<'ty> {
Literal(isize),
List(Vec<Expr<'ty>>),
TypeAnnotated(Box<Expr<'ty>>, &'ty Ty<'ty>),
}
fn parse_and_type_check<'ty>(input: String, ty_arena: &'ty Bump) -> Expr<'ty> {
todo!()
}
struct LanguageServerState {
latest_program: Option<yoke::Yoke<Expr<'static>, Box<Bump>>>,
}
fn main() {
let mut state = LanguageServerState {
latest_program: None,
};
// in reality, this is accepting connections and selecting receiving messages from an LSP client
loop {
// ...on a new program
let new_program = "[1, [2, 3]]".to_owned();
let fresh_arena = Bump::new();
state = LanguageServerState {
latest_program: Some(yoke::Yoke::attach_to_cart(
Box::new(fresh_arena),
|fresh_arena| parse_and_type_check(new_program, &fresh_arena),
)),
};
// ...on some LSP request I may need to do something using `latest_program`
}
}