ruka_mir_lower/
lib.rs

1//! Lowering from checked HIR into MIR.
2
3use std::collections::BTreeMap;
4
5use cranelift_entity::PrimaryMap;
6
7use ruka_check::{CheckedProgram, Ty};
8use ruka_hir::HirProgram;
9use ruka_mir::{
10    MirBlockId, MirEnumDecl, MirEnumVariant, MirFuncId, MirFunction, MirProgram, MirStructDecl,
11    MirStructField, MirTypeExpr,
12};
13
14mod cfg;
15mod lowerer;
16
17pub use lowerer::LowerError;
18
19use lowerer::{FunctionLowerer, lower_struct_field_type};
20
21/// Lower checked HIR into a MIR program.
22pub fn lower_program(
23    program: &HirProgram,
24    checked: &CheckedProgram,
25) -> Result<MirProgram, LowerError> {
26    let mut function_names = BTreeMap::new();
27    let mut functions: PrimaryMap<MirFuncId, MirFunction> = PrimaryMap::new();
28
29    for (_, function) in program.functions.iter() {
30        let id = functions.push(MirFunction {
31            name: function.name.clone(),
32            arity: function.params.len(),
33            return_ty: Ty::Unit,
34            locals: PrimaryMap::new(),
35            params: Vec::new(),
36            param_modes: Vec::new(),
37            entry: MirBlockId::from_u32(0),
38            blocks: PrimaryMap::new(),
39        });
40        function_names.insert(function.name.clone(), id);
41    }
42
43    for (_, source_function) in program.functions.iter() {
44        let mir_func_id = function_names
45            .get(&source_function.name)
46            .copied()
47            .expect("mir function id should exist");
48        let lowered =
49            FunctionLowerer::new(program, checked, &function_names, source_function).lower()?;
50        functions[mir_func_id] = lowered;
51    }
52
53    let mut enums = program
54        .enums
55        .iter()
56        .map(|decl| MirEnumDecl {
57            name: decl.name.clone(),
58            type_params: decl.type_params.clone(),
59            variants: decl
60                .variants
61                .iter()
62                .map(|variant| MirEnumVariant {
63                    name: variant.name.clone(),
64                    payload: variant
65                        .payload
66                        .iter()
67                        .map(lower_struct_field_type)
68                        .collect(),
69                })
70                .collect(),
71        })
72        .collect::<Vec<_>>();
73    if !enums.iter().any(|decl| decl.name == "Option") {
74        enums.push(MirEnumDecl {
75            name: "Option".to_owned(),
76            type_params: vec!["T".to_owned()],
77            variants: vec![
78                MirEnumVariant {
79                    name: "None".to_owned(),
80                    payload: Vec::new(),
81                },
82                MirEnumVariant {
83                    name: "Some".to_owned(),
84                    payload: vec![MirTypeExpr::Named("T".to_owned())],
85                },
86            ],
87        });
88    }
89
90    Ok(MirProgram {
91        functions,
92        function_names,
93        structs: program
94            .structs
95            .iter()
96            .map(|decl| MirStructDecl {
97                name: decl.name.clone(),
98                type_params: decl.type_params.clone(),
99                fields: decl
100                    .fields
101                    .iter()
102                    .map(|field| MirStructField {
103                        name: field.name.clone(),
104                        ty: lower_struct_field_type(&field.ty),
105                    })
106                    .collect(),
107            })
108            .collect(),
109        enums,
110    })
111}