dada_ir_sym/check/
statements.rs1use dada_ir_ast::{ast::AstStatement, span::Span};
2use dada_util::boxed_async_fn;
3
4use crate::{
5 check::{CheckExprInEnv, env::Env, report::InvalidInitializerType},
6 ir::{
7 exprs::{SymExpr, SymExprKind},
8 types::SymTy,
9 variables::SymVariable,
10 },
11};
12
13use super::{CheckTyInEnv, live_places::LivePlaces};
14
15#[boxed_async_fn]
16pub async fn check_block_statements<'db>(
17 env: &mut Env<'db>,
18 live_after: LivePlaces,
19 block_span: Span<'db>,
20 statements: &[AstStatement<'db>],
21) -> SymExpr<'db> {
22 let db = env.db();
23
24 let Some((first, rest)) = statements.split_first() else {
25 return SymExpr::new(db, block_span, SymTy::unit(db), SymExprKind::Tuple(vec![]));
26 };
27
28 match first {
29 AstStatement::Let(s) => {
30 let lv = SymVariable::new_local(db, s.name(db).id, s.name(db).span);
31
32 let ty = match s.ty(db) {
34 Some(ty) => ty.check_in_env(env).await,
35 None => env.fresh_ty_inference_var(s.name(db).span),
36 };
37
38 let (initializer, body) = env
39 .join(
40 async |env| match s.initializer(db) {
41 Some(initializer) => {
42 let initializer = initializer
43 .check_in_env(env, LivePlaces::fixme())
44 .await
45 .into_expr_with_enclosed_temporaries(env);
46 env.spawn_require_assignable_type(
47 LivePlaces::fixme(),
48 initializer.ty(db),
49 ty,
50 &InvalidInitializerType::new(lv, s.name(db).span, ty, initializer),
51 );
52 Some(initializer)
53 }
54
55 None => None,
56 },
57 async |env| {
58 env.push_program_variable_with_ty(lv, ty);
59 check_block_statements(env, LivePlaces::fixme(), block_span, rest).await
60 },
61 )
62 .await;
63
64 let span = s.span(db).to(db, body.span(db));
66 SymExpr::new(
67 db,
68 span,
69 body.ty(db),
70 SymExprKind::LetIn {
71 lv,
72 ty,
73 initializer,
74 body,
75 },
76 )
77 }
78
79 AstStatement::Expr(e) => {
80 let check_e = async |env: &mut Env<'db>| {
81 e.check_in_env(env, LivePlaces::fixme())
82 .await
83 .into_expr_with_enclosed_temporaries(env)
84 };
85 if rest.is_empty() {
86 check_e(env).await
89 } else {
90 let (ce, re) = env
91 .join(check_e, async |env| {
92 check_block_statements(env, live_after, block_span, rest).await
93 })
94 .await;
95 SymExpr::new(
96 db,
97 ce.span(db).to(db, re.span(db)),
98 re.ty(db),
99 SymExprKind::Semi(ce, re),
100 )
101 }
102 }
103 }
104}