fe_mir/ir/
value.rs

1use id_arena::Id;
2use num_bigint::BigInt;
3use smol_str::SmolStr;
4
5use crate::db::MirDb;
6
7use super::{
8    constant::ConstantId,
9    function::BodyDataStore,
10    inst::InstId,
11    types::{TypeId, TypeKind},
12    SourceInfo,
13};
14
15pub type ValueId = Id<Value>;
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub enum Value {
19    /// A value resulted from an instruction.
20    Temporary { inst: InstId, ty: TypeId },
21
22    /// A local variable declared in a function body.
23    Local(Local),
24
25    /// An immediate value.
26    Immediate { imm: BigInt, ty: TypeId },
27
28    /// A constant value.
29    Constant { constant: ConstantId, ty: TypeId },
30
31    /// A singleton value representing `Unit` type.
32    Unit { ty: TypeId },
33}
34
35impl Value {
36    pub fn ty(&self) -> TypeId {
37        match self {
38            Self::Local(val) => val.ty,
39            Self::Immediate { ty, .. }
40            | Self::Temporary { ty, .. }
41            | Self::Unit { ty }
42            | Self::Constant { ty, .. } => *ty,
43        }
44    }
45
46    pub fn is_imm(&self) -> bool {
47        matches!(self, Self::Immediate { .. })
48    }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Hash)]
52pub enum AssignableValue {
53    Value(ValueId),
54    Aggregate {
55        lhs: Box<AssignableValue>,
56        idx: ValueId,
57    },
58    Map {
59        lhs: Box<AssignableValue>,
60        key: ValueId,
61    },
62}
63
64impl From<ValueId> for AssignableValue {
65    fn from(value: ValueId) -> Self {
66        Self::Value(value)
67    }
68}
69
70impl AssignableValue {
71    pub fn ty(&self, db: &dyn MirDb, store: &BodyDataStore) -> TypeId {
72        match self {
73            Self::Value(value) => store.value_ty(*value),
74            Self::Aggregate { lhs, idx } => {
75                let lhs_ty = lhs.ty(db, store);
76                lhs_ty.projection_ty(db, store.value_data(*idx))
77            }
78            Self::Map { lhs, .. } => {
79                let lhs_ty = lhs.ty(db, store).deref(db);
80                match lhs_ty.data(db).kind {
81                    TypeKind::Map(def) => def.value_ty.make_sptr(db),
82                    _ => unreachable!(),
83                }
84            }
85        }
86    }
87
88    pub fn value_id(&self) -> Option<ValueId> {
89        match self {
90            Self::Value(value) => Some(*value),
91            _ => None,
92        }
93    }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Hash)]
97pub struct Local {
98    /// An original name of a local variable.
99    pub name: SmolStr,
100
101    pub ty: TypeId,
102
103    /// `true` if a local is a function argument.
104    pub is_arg: bool,
105
106    /// `true` if a local is introduced in MIR.
107    pub is_tmp: bool,
108
109    pub source: SourceInfo,
110}
111
112impl Local {
113    pub fn user_local(name: SmolStr, ty: TypeId, source: SourceInfo) -> Local {
114        Self {
115            name,
116            ty,
117            is_arg: false,
118            is_tmp: false,
119            source,
120        }
121    }
122
123    pub fn arg_local(name: SmolStr, ty: TypeId, source: SourceInfo) -> Local {
124        Self {
125            name,
126            ty,
127            is_arg: true,
128            is_tmp: false,
129            source,
130        }
131    }
132
133    pub fn tmp_local(name: SmolStr, ty: TypeId) -> Local {
134        Self {
135            name,
136            ty,
137            is_arg: false,
138            is_tmp: true,
139            source: SourceInfo::dummy(),
140        }
141    }
142}