长期运行的Web服务器中arena的生命周期

问题描述 投票:0回答:1

我正在开发编译器管道,但不确定如何使用 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 一直存在,直到程序的网络版本被解析并进行类型检查。

rust lifetime
1个回答
0
投票

你会遇到困难。您正在尝试创建一个自引用结构。

最简单的方法可能是使用现成的自引用板条箱之一。

例如,对于

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`
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.