1pub mod cfg;
15pub mod dominators;
16pub mod escape;
17pub mod inspect;
18pub mod loop_analysis;
19pub mod monomorph;
20pub mod nogc_verify;
21pub mod optimize;
22pub mod reduction;
23pub mod ssa;
24pub mod ssa_loop_overlay;
25pub mod ssa_optimize;
26pub mod verify;
27
28use cjc_ast::{BinOp, UnaryOp, Visibility};
29pub use escape::AllocHint;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub struct MirFnId(pub u32);
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
39pub struct BlockId(pub u32);
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub struct TempId(pub u32);
43
44#[derive(Debug, Clone)]
50pub struct MirProgram {
51 pub functions: Vec<MirFunction>,
52 pub struct_defs: Vec<MirStructDef>,
53 pub enum_defs: Vec<MirEnumDef>,
54 pub entry: MirFnId,
57}
58
59#[derive(Debug, Clone)]
60pub struct MirStructDef {
61 pub name: String,
62 pub fields: Vec<(String, String)>, pub is_record: bool,
65 pub vis: Visibility,
66}
67
68#[derive(Debug, Clone)]
69pub struct MirEnumDef {
70 pub name: String,
71 pub variants: Vec<MirVariantDef>,
72}
73
74#[derive(Debug, Clone)]
75pub struct MirVariantDef {
76 pub name: String,
77 pub fields: Vec<String>, }
79
80#[derive(Debug, Clone)]
85pub struct MirFunction {
86 pub id: MirFnId,
87 pub name: String,
88 pub type_params: Vec<(String, Vec<String>)>, pub params: Vec<MirParam>,
90 pub return_type: Option<String>,
91 pub body: MirBody,
92 pub is_nogc: bool,
93 pub cfg_body: Option<cfg::MirCfg>,
97 pub decorators: Vec<String>,
99 pub vis: Visibility,
100}
101
102#[derive(Debug, Clone)]
103pub struct MirParam {
104 pub name: String,
105 pub ty_name: String,
106 pub default: Option<MirExpr>,
108 pub is_variadic: bool,
110}
111
112impl MirFunction {
113 pub fn build_cfg(&mut self) {
116 let cfg = cfg::CfgBuilder::build(&self.body);
117 self.cfg_body = Some(cfg);
118 }
119
120 pub fn cfg(&mut self) -> &cfg::MirCfg {
122 if self.cfg_body.is_none() {
123 self.build_cfg();
124 }
125 self.cfg_body.as_ref().unwrap()
126 }
127}
128
129impl MirProgram {
130 pub fn build_all_cfgs(&mut self) {
132 for func in &mut self.functions {
133 func.build_cfg();
134 }
135 }
136}
137
138#[derive(Debug, Clone)]
143pub struct MirBody {
144 pub stmts: Vec<MirStmt>,
145 pub result: Option<Box<MirExpr>>,
146}
147
148#[derive(Debug, Clone)]
153pub enum MirStmt {
154 Let {
155 name: String,
156 mutable: bool,
157 init: MirExpr,
158 alloc_hint: Option<AllocHint>,
160 },
161 Expr(MirExpr),
162 If {
163 cond: MirExpr,
164 then_body: MirBody,
165 else_body: Option<MirBody>,
166 },
167 While {
168 cond: MirExpr,
169 body: MirBody,
170 },
171 Return(Option<MirExpr>),
172 Break,
173 Continue,
174 NoGcBlock(MirBody),
175}
176
177#[derive(Debug, Clone)]
182pub struct MirExpr {
183 pub kind: MirExprKind,
184}
185
186#[derive(Debug, Clone)]
187pub enum MirExprKind {
188 IntLit(i64),
189 FloatLit(f64),
190 BoolLit(bool),
191 StringLit(String),
192 ByteStringLit(Vec<u8>),
193 ByteCharLit(u8),
194 RawStringLit(String),
195 RawByteStringLit(Vec<u8>),
196 RegexLit { pattern: String, flags: String },
197 TensorLit { rows: Vec<Vec<MirExpr>> },
198 Var(String),
199 Binary {
200 op: BinOp,
201 left: Box<MirExpr>,
202 right: Box<MirExpr>,
203 },
204 Unary {
205 op: UnaryOp,
206 operand: Box<MirExpr>,
207 },
208 Call {
209 callee: Box<MirExpr>,
210 args: Vec<MirExpr>,
211 },
212 Field {
213 object: Box<MirExpr>,
214 name: String,
215 },
216 Index {
217 object: Box<MirExpr>,
218 index: Box<MirExpr>,
219 },
220 MultiIndex {
221 object: Box<MirExpr>,
222 indices: Vec<MirExpr>,
223 },
224 Assign {
225 target: Box<MirExpr>,
226 value: Box<MirExpr>,
227 },
228 Block(MirBody),
229 StructLit {
230 name: String,
231 fields: Vec<(String, MirExpr)>,
232 },
233 ArrayLit(Vec<MirExpr>),
234 Col(String),
235 Lambda {
236 params: Vec<MirParam>,
237 body: Box<MirExpr>,
238 },
239 MakeClosure {
243 fn_name: String,
245 captures: Vec<MirExpr>,
249 },
250 If {
251 cond: Box<MirExpr>,
252 then_body: MirBody,
253 else_body: Option<MirBody>,
254 },
255 Match {
258 scrutinee: Box<MirExpr>,
259 arms: Vec<MirMatchArm>,
260 },
261 VariantLit {
263 enum_name: String,
264 variant: String,
265 fields: Vec<MirExpr>,
266 },
267 TupleLit(Vec<MirExpr>),
269 LinalgLU { operand: Box<MirExpr> },
271 LinalgQR { operand: Box<MirExpr> },
272 LinalgCholesky { operand: Box<MirExpr> },
273 LinalgInv { operand: Box<MirExpr> },
274 Broadcast {
276 operand: Box<MirExpr>,
277 target_shape: Vec<MirExpr>,
278 },
279 Void,
280}
281
282#[derive(Debug, Clone)]
288pub struct MirMatchArm {
289 pub pattern: MirPattern,
290 pub body: MirBody,
291}
292
293#[derive(Debug, Clone)]
295pub enum MirPattern {
296 Wildcard,
298 Binding(String),
300 LitInt(i64),
302 LitFloat(f64),
303 LitBool(bool),
304 LitString(String),
305 Tuple(Vec<MirPattern>),
307 Struct {
309 name: String,
310 fields: Vec<(String, MirPattern)>,
311 },
312 Variant {
314 enum_name: String,
315 variant: String,
316 fields: Vec<MirPattern>,
317 },
318}
319
320use cjc_hir::*;
325
326pub struct HirToMir {
328 next_fn_id: u32,
329 next_lambda_id: u32,
330 lifted_functions: Vec<MirFunction>,
333}
334
335impl HirToMir {
336 pub fn new() -> Self {
337 Self {
338 next_fn_id: 0,
339 next_lambda_id: 0,
340 lifted_functions: Vec::new(),
341 }
342 }
343
344 fn fresh_fn_id(&mut self) -> MirFnId {
345 let id = MirFnId(self.next_fn_id);
346 self.next_fn_id += 1;
347 id
348 }
349
350 fn fresh_lambda_name(&mut self) -> String {
351 let name = format!("__closure_{}", self.next_lambda_id);
352 self.next_lambda_id += 1;
353 name
354 }
355
356 pub fn lower_program(&mut self, hir: &HirProgram) -> MirProgram {
358 let mut functions = Vec::new();
359 let mut struct_defs = Vec::new();
360 let mut enum_defs = Vec::new();
361 let mut main_stmts: Vec<MirStmt> = Vec::new();
362
363 for item in &hir.items {
364 match item {
365 HirItem::Fn(f) => {
366 functions.push(self.lower_fn(f));
367 }
368 HirItem::Struct(s) => {
369 struct_defs.push(MirStructDef {
370 name: s.name.clone(),
371 fields: s.fields.clone(),
372 is_record: false,
373 vis: s.vis,
374 });
375 }
376 HirItem::Class(c) => {
377 struct_defs.push(MirStructDef {
378 name: c.name.clone(),
379 fields: c.fields.clone(),
380 is_record: false,
381 vis: c.vis,
382 });
383 }
384 HirItem::Record(r) => {
385 struct_defs.push(MirStructDef {
386 name: r.name.clone(),
387 fields: r.fields.clone(),
388 is_record: true,
389 vis: r.vis,
390 });
391 }
392 HirItem::Enum(e) => {
393 enum_defs.push(MirEnumDef {
394 name: e.name.clone(),
395 variants: e
396 .variants
397 .iter()
398 .map(|v| MirVariantDef {
399 name: v.name.clone(),
400 fields: v.fields.clone(),
401 })
402 .collect(),
403 });
404 }
405 HirItem::Let(l) => {
406 main_stmts.push(MirStmt::Let {
407 name: l.name.clone(),
408 mutable: l.mutable,
409 init: self.lower_expr(&l.init),
410 alloc_hint: None,
411 });
412 }
413 HirItem::Stmt(s) => {
414 main_stmts.push(self.lower_stmt(s));
415 }
416 HirItem::Impl(i) => {
417 for method in &i.methods {
418 let mut mir_fn = self.lower_fn(method);
420 mir_fn.name = format!("{}.{}", i.target, method.name);
421 functions.push(mir_fn);
422 }
423 }
424 HirItem::Trait(_) => {
425 }
427 }
428 }
429
430 let main_id = self.fresh_fn_id();
432 functions.push(MirFunction {
433 id: main_id,
434 name: "__main".to_string(),
435 type_params: vec![],
436 params: vec![],
437 return_type: None,
438 body: MirBody {
439 stmts: main_stmts,
440 result: None,
441 },
442 is_nogc: false,
443 cfg_body: None,
444 decorators: vec![],
445 vis: Visibility::Private,
446 });
447
448 functions.append(&mut self.lifted_functions);
450
451 MirProgram {
452 functions,
453 struct_defs,
454 enum_defs,
455 entry: main_id,
456 }
457 }
458
459 pub fn lower_fn(&mut self, f: &HirFn) -> MirFunction {
460 let id = self.fresh_fn_id();
461 let params = f
462 .params
463 .iter()
464 .map(|p| MirParam {
465 name: p.name.clone(),
466 ty_name: p.ty_name.clone(),
467 default: p.default.as_ref().map(|d| self.lower_expr(d)),
468 is_variadic: p.is_variadic,
469 })
470 .collect();
471 let body = self.lower_block(&f.body);
472 MirFunction {
473 id,
474 name: f.name.clone(),
475 type_params: f.type_params.clone(),
476 params,
477 return_type: f.return_type.clone(),
478 body,
479 is_nogc: f.is_nogc,
480 cfg_body: None,
481 decorators: f.decorators.clone(),
482 vis: f.vis,
483 }
484 }
485
486 fn lower_block(&mut self, block: &HirBlock) -> MirBody {
487 let stmts = block.stmts.iter().map(|s| self.lower_stmt(s)).collect();
488 let result = block.expr.as_ref().map(|e| Box::new(self.lower_expr(e)));
489 MirBody { stmts, result }
490 }
491
492 fn lower_stmt(&mut self, stmt: &HirStmt) -> MirStmt {
493 match &stmt.kind {
494 HirStmtKind::Let {
495 name,
496 mutable,
497 init,
498 ..
499 } => MirStmt::Let {
500 name: name.clone(),
501 mutable: *mutable,
502 init: self.lower_expr(init),
503 alloc_hint: None,
504 },
505 HirStmtKind::Expr(e) => MirStmt::Expr(self.lower_expr(e)),
506 HirStmtKind::If(if_expr) => self.lower_if_stmt(if_expr),
507 HirStmtKind::While { cond, body } => MirStmt::While {
508 cond: self.lower_expr(cond),
509 body: self.lower_block(body),
510 },
511 HirStmtKind::Return(e) => {
512 MirStmt::Return(e.as_ref().map(|ex| self.lower_expr(ex)))
513 }
514 HirStmtKind::Break => MirStmt::Break,
515 HirStmtKind::Continue => MirStmt::Continue,
516 HirStmtKind::NoGcBlock(block) => MirStmt::NoGcBlock(self.lower_block(block)),
517 }
518 }
519
520 pub fn lower_if_stmt(&mut self, if_expr: &HirIfExpr) -> MirStmt {
521 let cond = self.lower_expr(&if_expr.cond);
522 let then_body = self.lower_block(&if_expr.then_block);
523 let else_body = if_expr.else_branch.as_ref().map(|eb| match eb {
524 HirElseBranch::ElseIf(elif) => {
525 let nested = self.lower_if_stmt(elif);
527 MirBody {
528 stmts: vec![nested],
529 result: None,
530 }
531 }
532 HirElseBranch::Else(block) => self.lower_block(block),
533 });
534 MirStmt::If {
535 cond,
536 then_body,
537 else_body,
538 }
539 }
540
541 pub fn lower_expr(&mut self, expr: &HirExpr) -> MirExpr {
542 let kind = match &expr.kind {
543 HirExprKind::IntLit(v) => MirExprKind::IntLit(*v),
544 HirExprKind::FloatLit(v) => MirExprKind::FloatLit(*v),
545 HirExprKind::BoolLit(b) => MirExprKind::BoolLit(*b),
546 HirExprKind::StringLit(s) => MirExprKind::StringLit(s.clone()),
547 HirExprKind::ByteStringLit(bytes) => MirExprKind::ByteStringLit(bytes.clone()),
548 HirExprKind::ByteCharLit(b) => MirExprKind::ByteCharLit(*b),
549 HirExprKind::RawStringLit(s) => MirExprKind::RawStringLit(s.clone()),
550 HirExprKind::RawByteStringLit(bytes) => MirExprKind::RawByteStringLit(bytes.clone()),
551 HirExprKind::RegexLit { pattern, flags } => MirExprKind::RegexLit { pattern: pattern.clone(), flags: flags.clone() },
552 HirExprKind::TensorLit { rows } => {
553 let mir_rows = rows.iter().map(|row| {
554 row.iter().map(|e| self.lower_expr(e)).collect()
555 }).collect();
556 MirExprKind::TensorLit { rows: mir_rows }
557 }
558 HirExprKind::Var(name) => MirExprKind::Var(name.clone()),
559 HirExprKind::Binary { op, left, right } => MirExprKind::Binary {
560 op: *op,
561 left: Box::new(self.lower_expr(left)),
562 right: Box::new(self.lower_expr(right)),
563 },
564 HirExprKind::Unary { op, operand } => MirExprKind::Unary {
565 op: *op,
566 operand: Box::new(self.lower_expr(operand)),
567 },
568 HirExprKind::Call { callee, args } => MirExprKind::Call {
569 callee: Box::new(self.lower_expr(callee)),
570 args: args.iter().map(|a| self.lower_expr(a)).collect(),
571 },
572 HirExprKind::Field { object, name } => MirExprKind::Field {
573 object: Box::new(self.lower_expr(object)),
574 name: name.clone(),
575 },
576 HirExprKind::Index { object, index } => MirExprKind::Index {
577 object: Box::new(self.lower_expr(object)),
578 index: Box::new(self.lower_expr(index)),
579 },
580 HirExprKind::MultiIndex { object, indices } => MirExprKind::MultiIndex {
581 object: Box::new(self.lower_expr(object)),
582 indices: indices.iter().map(|i| self.lower_expr(i)).collect(),
583 },
584 HirExprKind::Assign { target, value } => MirExprKind::Assign {
585 target: Box::new(self.lower_expr(target)),
586 value: Box::new(self.lower_expr(value)),
587 },
588 HirExprKind::Block(block) => MirExprKind::Block(self.lower_block(block)),
589 HirExprKind::StructLit { name, fields } => MirExprKind::StructLit {
590 name: name.clone(),
591 fields: fields
592 .iter()
593 .map(|(n, e)| (n.clone(), self.lower_expr(e)))
594 .collect(),
595 },
596 HirExprKind::ArrayLit(elems) => {
597 MirExprKind::ArrayLit(elems.iter().map(|e| self.lower_expr(e)).collect())
598 }
599 HirExprKind::Col(name) => MirExprKind::Col(name.clone()),
600 HirExprKind::Lambda { params, body } => MirExprKind::Lambda {
601 params: params
602 .iter()
603 .map(|p| MirParam {
604 name: p.name.clone(),
605 ty_name: p.ty_name.clone(),
606 default: p.default.as_ref().map(|d| self.lower_expr(d)),
607 is_variadic: p.is_variadic,
608 })
609 .collect(),
610 body: Box::new(self.lower_expr(body)),
611 },
612 HirExprKind::Closure {
613 params,
614 body,
615 captures,
616 } => {
617 let lifted_name = self.fresh_lambda_name();
620 let lifted_id = self.fresh_fn_id();
621
622 let mut lifted_params: Vec<MirParam> = captures
624 .iter()
625 .map(|c| MirParam {
626 name: c.name.clone(),
627 ty_name: "any".to_string(), default: None,
629 is_variadic: false,
630 })
631 .collect();
632 for p in params {
633 lifted_params.push(MirParam {
634 name: p.name.clone(),
635 ty_name: p.ty_name.clone(),
636 default: p.default.as_ref().map(|d| self.lower_expr(d)),
637 is_variadic: p.is_variadic,
638 });
639 }
640
641 let lifted_body = MirBody {
642 stmts: vec![],
643 result: Some(Box::new(self.lower_expr(body))),
644 };
645
646 self.lifted_functions.push(MirFunction {
647 id: lifted_id,
648 name: lifted_name.clone(),
649 type_params: vec![],
650 params: lifted_params,
651 return_type: None,
652 body: lifted_body,
653 is_nogc: false,
654 cfg_body: None,
655 decorators: vec![],
656 vis: Visibility::Private,
657 });
658
659 let capture_exprs: Vec<MirExpr> = captures
662 .iter()
663 .map(|c| MirExpr {
664 kind: MirExprKind::Var(c.name.clone()),
665 })
666 .collect();
667
668 MirExprKind::MakeClosure {
669 fn_name: lifted_name,
670 captures: capture_exprs,
671 }
672 }
673 HirExprKind::Match { scrutinee, arms } => {
674 let mir_scrutinee = Box::new(self.lower_expr(scrutinee));
675 let mir_arms = arms
676 .iter()
677 .map(|arm| {
678 let pattern = self.lower_pattern(&arm.pattern);
679 let body = MirBody {
680 stmts: vec![],
681 result: Some(Box::new(self.lower_expr(&arm.body))),
682 };
683 MirMatchArm { pattern, body }
684 })
685 .collect();
686 MirExprKind::Match {
687 scrutinee: mir_scrutinee,
688 arms: mir_arms,
689 }
690 }
691 HirExprKind::TupleLit(elems) => {
692 MirExprKind::TupleLit(elems.iter().map(|e| self.lower_expr(e)).collect())
693 }
694 HirExprKind::VariantLit {
695 enum_name,
696 variant,
697 fields,
698 } => MirExprKind::VariantLit {
699 enum_name: enum_name.clone(),
700 variant: variant.clone(),
701 fields: fields.iter().map(|f| self.lower_expr(f)).collect(),
702 },
703 HirExprKind::If { cond, then_block, else_branch } => {
704 let mir_cond = Box::new(self.lower_expr(cond));
705 let mir_then = self.lower_block(then_block);
706 let mir_else = else_branch.as_ref().map(|eb| match eb {
707 HirElseBranch::ElseIf(elif) => {
708 let nested = self.lower_if_stmt(elif);
710 MirBody {
711 stmts: vec![nested],
712 result: None,
713 }
714 }
715 HirElseBranch::Else(block) => self.lower_block(block),
716 });
717 MirExprKind::If {
718 cond: mir_cond,
719 then_body: mir_then,
720 else_body: mir_else,
721 }
722 }
723 HirExprKind::Void => MirExprKind::Void,
724 };
725 MirExpr { kind }
726 }
727
728 fn lower_pattern(&self, pat: &HirPattern) -> MirPattern {
729 match &pat.kind {
730 HirPatternKind::Wildcard => MirPattern::Wildcard,
731 HirPatternKind::Binding(name) => MirPattern::Binding(name.clone()),
732 HirPatternKind::LitInt(v) => MirPattern::LitInt(*v),
733 HirPatternKind::LitFloat(v) => MirPattern::LitFloat(*v),
734 HirPatternKind::LitBool(b) => MirPattern::LitBool(*b),
735 HirPatternKind::LitString(s) => MirPattern::LitString(s.clone()),
736 HirPatternKind::Tuple(pats) => {
737 MirPattern::Tuple(pats.iter().map(|p| self.lower_pattern(p)).collect())
738 }
739 HirPatternKind::Struct { name, fields } => MirPattern::Struct {
740 name: name.clone(),
741 fields: fields
742 .iter()
743 .map(|f| (f.name.clone(), self.lower_pattern(&f.pattern)))
744 .collect(),
745 },
746 HirPatternKind::Variant {
747 enum_name,
748 variant,
749 fields,
750 } => MirPattern::Variant {
751 enum_name: enum_name.clone(),
752 variant: variant.clone(),
753 fields: fields.iter().map(|f| self.lower_pattern(f)).collect(),
754 },
755 }
756 }
757}
758
759impl Default for HirToMir {
760 fn default() -> Self {
761 Self::new()
762 }
763}
764
765#[cfg(test)]
770mod tests {
771 use super::*;
772 use cjc_hir::*;
773
774 fn hir_id(n: u32) -> HirId {
775 HirId(n)
776 }
777
778 fn hir_int(v: i64) -> HirExpr {
779 HirExpr {
780 kind: HirExprKind::IntLit(v),
781 hir_id: hir_id(0),
782 }
783 }
784
785 fn hir_var(name: &str) -> HirExpr {
786 HirExpr {
787 kind: HirExprKind::Var(name.to_string()),
788 hir_id: hir_id(0),
789 }
790 }
791
792 #[test]
793 fn test_lower_hir_literal() {
794 let mut lowering = HirToMir::new();
795 let hir = hir_int(42);
796 let mir = lowering.lower_expr(&hir);
797 assert!(matches!(mir.kind, MirExprKind::IntLit(42)));
798 }
799
800 #[test]
801 fn test_lower_hir_binary() {
802 let mut lowering = HirToMir::new();
803 let hir = HirExpr {
804 kind: HirExprKind::Binary {
805 op: BinOp::Add,
806 left: Box::new(hir_int(1)),
807 right: Box::new(hir_int(2)),
808 },
809 hir_id: hir_id(0),
810 };
811 let mir = lowering.lower_expr(&hir);
812 match &mir.kind {
813 MirExprKind::Binary { op, .. } => assert_eq!(*op, BinOp::Add),
814 _ => panic!("expected Binary"),
815 }
816 }
817
818 #[test]
819 fn test_lower_hir_fn() {
820 let mut lowering = HirToMir::new();
821 let hir_fn = HirFn {
822 name: "add".to_string(),
823 type_params: vec![],
824 params: vec![
825 HirParam {
826 name: "a".to_string(),
827 ty_name: "i64".to_string(),
828 default: None,
829 is_variadic: false,
830 hir_id: hir_id(1),
831 },
832 HirParam {
833 name: "b".to_string(),
834 ty_name: "i64".to_string(),
835 default: None,
836 is_variadic: false,
837 hir_id: hir_id(2),
838 },
839 ],
840 return_type: Some("i64".to_string()),
841 body: HirBlock {
842 stmts: vec![],
843 expr: Some(Box::new(HirExpr {
844 kind: HirExprKind::Binary {
845 op: BinOp::Add,
846 left: Box::new(hir_var("a")),
847 right: Box::new(hir_var("b")),
848 },
849 hir_id: hir_id(3),
850 })),
851 hir_id: hir_id(4),
852 },
853 is_nogc: false,
854 hir_id: hir_id(5),
855 decorators: vec![],
856 vis: cjc_ast::Visibility::Private,
857 };
858 let mir_fn = lowering.lower_fn(&hir_fn);
859 assert_eq!(mir_fn.name, "add");
860 assert_eq!(mir_fn.params.len(), 2);
861 assert!(mir_fn.body.result.is_some());
862 }
863
864 #[test]
865 fn test_lower_hir_program_entry() {
866 let mut lowering = HirToMir::new();
867 let hir = HirProgram {
868 items: vec![
869 HirItem::Let(HirLetDecl {
870 name: "x".to_string(),
871 mutable: false,
872 ty_name: None,
873 init: hir_int(42),
874 hir_id: hir_id(0),
875 }),
876 HirItem::Fn(HirFn {
877 name: "f".to_string(),
878 type_params: vec![],
879 params: vec![],
880 return_type: None,
881 body: HirBlock {
882 stmts: vec![],
883 expr: Some(Box::new(hir_var("x"))),
884 hir_id: hir_id(1),
885 },
886 is_nogc: false,
887 hir_id: hir_id(2),
888 decorators: vec![],
889 vis: cjc_ast::Visibility::Private,
890 }),
891 ],
892 };
893 let mir = lowering.lower_program(&hir);
894 assert_eq!(mir.functions.len(), 2);
896 let main = mir.functions.iter().find(|f| f.name == "__main").unwrap();
897 assert_eq!(main.body.stmts.len(), 1); assert_eq!(mir.entry, main.id);
899 }
900
901 #[test]
902 fn test_lower_hir_if_stmt() {
903 let mut lowering = HirToMir::new();
904 let hir_if = HirIfExpr {
905 cond: Box::new(HirExpr {
906 kind: HirExprKind::BoolLit(true),
907 hir_id: hir_id(0),
908 }),
909 then_block: HirBlock {
910 stmts: vec![],
911 expr: Some(Box::new(hir_int(1))),
912 hir_id: hir_id(1),
913 },
914 else_branch: Some(HirElseBranch::Else(HirBlock {
915 stmts: vec![],
916 expr: Some(Box::new(hir_int(2))),
917 hir_id: hir_id(2),
918 })),
919 hir_id: hir_id(3),
920 };
921 let mir_stmt = lowering.lower_if_stmt(&hir_if);
922 match &mir_stmt {
923 MirStmt::If {
924 then_body,
925 else_body,
926 ..
927 } => {
928 assert!(then_body.result.is_some());
929 assert!(else_body.is_some());
930 }
931 _ => panic!("expected If"),
932 }
933 }
934
935 #[test]
936 fn test_lower_struct_def() {
937 let mut lowering = HirToMir::new();
938 let hir = HirProgram {
939 items: vec![HirItem::Struct(HirStructDef {
940 name: "Point".to_string(),
941 fields: vec![
942 ("x".to_string(), "f64".to_string()),
943 ("y".to_string(), "f64".to_string()),
944 ],
945 hir_id: hir_id(0),
946 vis: cjc_ast::Visibility::Private,
947 })],
948 };
949 let mir = lowering.lower_program(&hir);
950 assert_eq!(mir.struct_defs.len(), 1);
951 assert_eq!(mir.struct_defs[0].name, "Point");
952 assert_eq!(mir.struct_defs[0].fields.len(), 2);
953 }
954}