dada_codegen/cx/
wasm_repr.rs1use dada_ir_sym::{
2 ir::{
3 classes::{SymAggregate, SymAggregateStyle},
4 primitive::SymPrimitiveKind,
5 types::{SymGenericTerm, SymPerm, SymPermKind, SymPlace, SymTy, SymTyKind, SymTyName},
6 variables::SymVariable,
7 },
8 prelude::CheckedFieldTy,
9};
10use dada_util::Map;
11use wasm_encoder::ValType;
12
13#[derive(Debug)]
32pub(crate) enum WasmRepr {
33 Val(ValType),
36
37 Struct(Vec<WasmRepr>),
40
41 Class(Vec<WasmRepr>),
45
46 Nothing,
48}
49
50type Generics<'db> = Map<SymVariable<'db>, SymGenericTerm<'db>>;
51
52pub(super) struct WasmReprCx<'g, 'db> {
53 db: &'db dyn crate::Db,
54 generics: &'g Generics<'db>,
55}
56
57impl<'g, 'db> WasmReprCx<'g, 'db> {
58 pub(super) fn new(db: &'db dyn crate::Db, generics: &'g Generics<'db>) -> Self {
59 Self { db, generics }
60 }
61
62 pub(super) fn wasm_repr_of_type(&mut self, of_type: SymTy<'db>) -> WasmRepr {
64 let db = self.db;
65 match *of_type.kind(db) {
66 SymTyKind::Named(ty_name, ref ty_args) => {
67 self.wasm_repr_of_named_type(ty_name, ty_args)
68 }
69 SymTyKind::Var(sym_variable) => self.wasm_repr_of_variable(sym_variable),
70 SymTyKind::Infer(_) => panic!("unexpected inference variable"),
71 SymTyKind::Never | SymTyKind::Error(_) => WasmRepr::Nothing,
72 SymTyKind::Perm(sym_perm, sym_ty) => self.wasm_repr_of_perm_type(sym_perm, sym_ty),
73 }
74 }
75
76 fn wasm_repr_of_variable(&mut self, sym_variable: SymVariable<'db>) -> WasmRepr {
77 let result = self
78 .generics
79 .get(&sym_variable)
80 .expect("expected value for each generic type")
81 .assert_type(self.db);
82 self.wasm_repr_of_type(result)
83 }
84
85 fn wasm_repr_of_perm_type(&mut self, sym_perm: SymPerm<'db>, sym_ty: SymTy<'db>) -> WasmRepr {
86 let db = self.db;
87 match *sym_perm.kind(db) {
88 SymPermKind::Mutable(_) => self.wasm_pointer(),
89 SymPermKind::My | SymPermKind::Our | SymPermKind::Referenced(_) => {
90 self.wasm_repr_of_type(sym_ty)
91 }
92 SymPermKind::Var(sym_variable) => {
93 let result = self
94 .generics
95 .get(&sym_variable)
96 .expect("expected value for each generic type")
97 .assert_perm(db);
98 self.wasm_repr_of_perm_type(result, sym_ty)
99 }
100 SymPermKind::Error(_) => WasmRepr::Nothing,
101 SymPermKind::Apply(left, _) => self.wasm_repr_of_perm_type(left, sym_ty),
102 SymPermKind::Infer(_infer_var_index) => unreachable!(),
103 SymPermKind::Or(perm_l, _perm_r) => {
104 self.wasm_repr_of_perm_type(perm_l, sym_ty)
106 }
107 }
108 }
109
110 fn wasm_repr_of_named_type(
112 &mut self,
113 ty_name: SymTyName<'db>,
114 ty_args: &Vec<SymGenericTerm<'db>>,
115 ) -> WasmRepr {
116 let db = self.db;
117 match ty_name {
118 SymTyName::Primitive(sym_primitive) => {
119 WasmRepr::Val(self.wasm_valtype_for_primitive_kind(sym_primitive.kind(db)))
120 }
121 SymTyName::Aggregate(aggr) => match aggr.style(db) {
122 SymAggregateStyle::Struct => {
124 WasmRepr::Struct(self.wasm_repr_of_aggr_fields(aggr, ty_args))
125 }
126
127 SymAggregateStyle::Class => {
128 WasmRepr::Class(self.wasm_repr_of_aggr_fields(aggr, ty_args))
129 }
130 },
131 SymTyName::Future => {
132 assert_eq!(ty_args.len(), 1);
133 let ty_arg = ty_args[0].assert_type(db);
134 WasmRepr::Class(vec![self.wasm_repr_of_type(ty_arg)])
135 }
136 SymTyName::Tuple { arity } => {
137 assert_eq!(ty_args.len(), arity);
138 WasmRepr::Struct(
139 ty_args
140 .iter()
141 .map(|term| self.wasm_repr_of_type(term.assert_type(db)))
142 .collect(),
143 )
144 }
145 }
146 }
147
148 fn wasm_valtype_for_primitive_kind(&self, primitive: SymPrimitiveKind) -> ValType {
151 match primitive {
152 SymPrimitiveKind::Bool => ValType::I32,
153 SymPrimitiveKind::Char => ValType::I32,
154 SymPrimitiveKind::Int { bits } | SymPrimitiveKind::Uint { bits } => match bits {
155 0..=32 => ValType::I32,
156 33..=64 => ValType::I64,
157 _ => panic!("unexpectedly large number of integer bits {bits}"),
158 },
159 SymPrimitiveKind::Usize | SymPrimitiveKind::Isize => self.pointer_val_type(),
160 SymPrimitiveKind::Float { bits } => match bits {
161 32 => ValType::F32,
162 64 => ValType::F64,
163 _ => panic!("unexpected number of floating point bits {bits}"),
164 },
165 }
166 }
167
168 fn wasm_repr_of_aggr_fields(
171 &mut self,
172 aggr: SymAggregate<'db>,
173 ty_args: &Vec<SymGenericTerm<'db>>,
174 ) -> Vec<WasmRepr> {
175 self.aggr_field_tys(aggr, ty_args)
176 .iter()
177 .map(|ty| self.wasm_repr_of_type(*ty))
178 .collect()
179 }
180
181 fn aggr_field_tys<'a>(
183 &self,
184 aggr: SymAggregate<'db>,
185 ty_args: &'a Vec<SymGenericTerm<'db>>,
186 ) -> Vec<SymTy<'db>> {
187 let db = self.db;
188 aggr.fields(db)
189 .map(|f| f.checked_field_ty(db))
190 .map(|ty| {
191 let ty = ty.substitute(db, ty_args);
192 ty.substitute(db, &[SymGenericTerm::Place(SymPlace::erased(db))])
193 })
194 .collect()
195 }
196
197 fn wasm_pointer(&self) -> WasmRepr {
199 WasmRepr::Val(self.pointer_val_type())
200 }
201
202 fn pointer_val_type(&self) -> ValType {
205 ValType::I32
206 }
207}