1use std::sync::Arc;
2
3use dada_ir_ast::{ast::PermissionOp, diagnostic::Reported};
4use dada_ir_sym::ir::exprs::{SymBinaryOp, SymExpr, SymExprKind, SymLiteral, SymMatchArm};
5use dada_ir_sym::ir::types::{SymGenericTerm, SymTy, SymTyKind};
6use dada_ir_sym::{
7 ir::primitive::SymPrimitiveKind, ir::subst::Subst, ir::types::SymTyName,
8 ir::variables::SymVariable,
9};
10use dada_util::Map;
11use wasm_encoder::{Instruction, ValType};
12use wasm_place_repr::{WasmLocal, WasmPlaceRepr};
13
14use super::wasm_repr::WasmReprCx;
15use super::{Cx, wasm_repr::WasmRepr};
16
17pub(crate) mod wasm_place_repr;
18
19pub(crate) struct ExprCodegen<'cx, 'db> {
20 cx: &'cx mut Cx<'db>,
21
22 generics: Map<SymVariable<'db>, SymGenericTerm<'db>>,
24
25 wasm_locals: Vec<wasm_encoder::ValType>,
27
28 wasm_stack_pointer: WasmLocal,
30
31 wasm_stack_frame_size: u32,
33
34 variables: Map<SymVariable<'db>, Arc<WasmPlaceRepr>>,
36
37 instructions: Vec<Instruction<'static>>,
39}
40
41impl<'cx, 'db> ExprCodegen<'cx, 'db> {
42 pub fn new(cx: &'cx mut Cx<'db>, generics: Map<SymVariable<'db>, SymGenericTerm<'db>>) -> Self {
43 Self {
45 cx,
46 generics,
47 wasm_locals: vec![ValType::I32],
48 variables: Default::default(),
49 instructions: Default::default(),
50 wasm_stack_frame_size: 0,
51 wasm_stack_pointer: WasmLocal { index: 0 },
52 }
53 }
54
55 pub fn into_function(self) -> wasm_encoder::Function {
56 let mut f = wasm_encoder::Function::new_with_locals_types(self.wasm_locals);
57 for instruction in self.instructions {
58 f.instruction(&instruction);
59 }
60 f
61 }
62
63 pub fn wasm_repr_of_type(&self, ty: SymTy<'db>) -> WasmRepr {
65 let db = self.cx.db;
66 let mut wrcx = WasmReprCx::new(db, &self.generics);
67 wrcx.wasm_repr_of_type(ty)
68 }
69
70 pub fn pop_arguments(&mut self, inputs: &[SymVariable<'db>], input_tys: &[SymTy<'db>]) {
71 assert_eq!(inputs.len(), input_tys.len());
72 for (&input, &input_ty) in inputs.iter().zip(input_tys).rev() {
73 self.insert_variable(input, input_ty);
74 self.pop_and_store(&self.place_for_local(input));
75 }
76 self.instructions
77 .push(Instruction::LocalSet(self.wasm_stack_pointer.index));
78 }
79
80 pub fn push_expr(&mut self, expr: SymExpr<'db>) {
82 let db = self.cx.db;
83 match *expr.kind(db) {
84 SymExprKind::Semi(object_expr, object_expr1) => {
85 self.push_expr(object_expr);
86 self.pop_and_drop(object_expr.ty(db));
87 self.push_expr(object_expr1);
88 }
89 SymExprKind::Tuple(ref elements) => {
90 for &element in elements {
92 self.push_expr(element);
93 }
94 }
95 SymExprKind::Primitive(literal) => self.push_literal(expr.ty(db), literal),
96 SymExprKind::LetIn {
97 lv,
98 ty,
99 initializer,
100 body,
101 } => {
102 self.insert_variable(lv, ty);
103
104 if let Some(initializer) = initializer {
105 self.push_expr(initializer);
106 self.pop_and_store(&self.variables[&lv].clone());
107 } else {
108 }
110
111 self.push_expr(body);
112 }
113 SymExprKind::Await {
114 future,
115 await_keyword: _,
116 } => {
117 self.push_expr(future);
118 }
120 SymExprKind::Assign { place, value } => {
121 let wasm_place = self.place(place);
122 self.push_expr(value);
123
124 self.pop_and_store(&wasm_place);
127 }
128 SymExprKind::PermissionOp(permission_op, object_place_expr) => {
129 let wasm_place_repr = self.place(object_place_expr);
130 match permission_op {
131 PermissionOp::Mutate => {
132 self.push_leased_from(&wasm_place_repr);
133 }
134
135 PermissionOp::Reference => {
136 self.push_shared_from(&wasm_place_repr);
137 }
138
139 PermissionOp::Give => {
140 self.push_from(&wasm_place_repr);
141 }
142
143 PermissionOp::Share => {
144 todo!()
145 }
146 }
147 }
148 SymExprKind::Call {
149 function,
150 ref substitution,
151 ref arg_temps,
152 } => {
153 let fn_args = substitution.subst_vars(db, &self.generics);
154 let fn_index = self.cx.declare_fn(function, fn_args);
155
156 self.push_pointer(self.next_stack_frame());
158
159 for arg_temp in arg_temps {
161 let place = self.variables[arg_temp].clone();
162 self.push_from(&place);
163 }
164
165 self.instructions.push(Instruction::Call(fn_index.0));
166 }
167 SymExprKind::Return(object_expr) => {
168 self.push_expr(object_expr);
169 self.instructions.push(Instruction::Return);
170 }
171 SymExprKind::Not {
172 operand,
173 op_span: _,
174 } => {
175 self.push_expr(operand);
176 self.instructions.push(Instruction::I32Const(1));
177 self.instructions.push(Instruction::I32Xor);
178 }
179 SymExprKind::BinaryOp(binary_op, object_expr, object_expr1) => {
180 self.push_expr(object_expr);
181 self.push_expr(object_expr1);
182 self.execute_binary_op(binary_op, object_expr.ty(db), object_expr.ty(db));
183 }
184 SymExprKind::Aggregate { ty, ref fields } => {
185 let wasm_repr = self.wasm_repr_of_type(ty);
186 match wasm_repr {
187 WasmRepr::Struct(field_reprs) => {
188 assert_eq!(fields.len(), field_reprs.len());
189 for &field in fields {
190 self.push_expr(field);
191 }
192 }
193 WasmRepr::Class(field_reprs) => {
194 assert_eq!(fields.len(), field_reprs.len());
195
196 self.instructions.push(Instruction::I32Const(1));
198
199 for &field in fields {
200 self.push_expr(field);
201 }
202 }
203 WasmRepr::Val(_) | WasmRepr::Nothing => {
204 panic!("not an aggregate: {ty:?}")
205 }
206 }
207 }
208 SymExprKind::Match { ref arms } => {
209 self.push_match_expr(expr.ty(db), arms);
210 }
211 SymExprKind::Error(reported) => self.push_error(reported),
212 #[expect(unused_variables)]
213 SymExprKind::ByteLiteral(sym_byte_literal) => todo!(),
214 }
215 }
216
217 fn pop_and_drop(&mut self, _of_type: SymTy<'db>) {
218 }
220
221 pub(super) fn pop_and_return(&mut self, _of_type: SymTy<'db>) {
222 self.instructions.push(Instruction::Return);
223 }
224
225 fn execute_binary_op(
227 &mut self,
228 binary_op: SymBinaryOp,
229 lhs_ty: SymTy<'db>,
230 rhs_ty: SymTy<'db>,
231 ) {
232 match self.primitive_kind(lhs_ty) {
233 Ok(prim_kind) => {
234 assert_eq!(self.primitive_kind(rhs_ty), Ok(prim_kind));
235 self.execute_binary_op_on_primitives(binary_op, prim_kind)
236 }
237 Err(e) => match e {
238 NotPrimitive::DeadCode => (),
239 NotPrimitive::OtherType => {
240 panic!("don't know how to execute a binary op on ({lhs_ty:?}, {rhs_ty:?})")
241 }
242 },
243 }
244 }
245
246 fn execute_binary_op_on_primitives(
248 &mut self,
249 binary_op: SymBinaryOp,
250 prim_kind: SymPrimitiveKind,
251 ) {
252 let instruction = match (prim_kind, binary_op) {
253 (SymPrimitiveKind::Char, SymBinaryOp::Add)
254 | (SymPrimitiveKind::Char, SymBinaryOp::Sub)
255 | (SymPrimitiveKind::Char, SymBinaryOp::Mul)
256 | (SymPrimitiveKind::Char, SymBinaryOp::Div)
257 | (SymPrimitiveKind::Bool, SymBinaryOp::Add)
258 | (SymPrimitiveKind::Bool, SymBinaryOp::Sub)
259 | (SymPrimitiveKind::Bool, SymBinaryOp::Mul)
260 | (SymPrimitiveKind::Bool, SymBinaryOp::Div) => {
261 panic!("invalid primitive binary op: {binary_op:?}, {prim_kind:?}")
262 }
263
264 (SymPrimitiveKind::Char, SymBinaryOp::GreaterThan)
265 | (SymPrimitiveKind::Bool, SymBinaryOp::GreaterThan) => Instruction::I32GtU,
266
267 (SymPrimitiveKind::Char, SymBinaryOp::LessThan)
268 | (SymPrimitiveKind::Bool, SymBinaryOp::LessThan) => Instruction::I32LtU,
269
270 (SymPrimitiveKind::Char, SymBinaryOp::GreaterEqual)
271 | (SymPrimitiveKind::Bool, SymBinaryOp::GreaterEqual) => Instruction::I32GeU,
272
273 (SymPrimitiveKind::Char, SymBinaryOp::LessEqual)
274 | (SymPrimitiveKind::Bool, SymBinaryOp::LessEqual) => Instruction::I32GeU,
275
276 (SymPrimitiveKind::Char, SymBinaryOp::EqualEqual)
277 | (SymPrimitiveKind::Bool, SymBinaryOp::EqualEqual) => Instruction::I32Eq,
278
279 (SymPrimitiveKind::Int { bits }, SymBinaryOp::Add) if bits <= 32 => Instruction::I32Add,
280 (SymPrimitiveKind::Int { bits }, SymBinaryOp::Sub) if bits <= 32 => Instruction::I32Sub,
281 (SymPrimitiveKind::Int { bits }, SymBinaryOp::Mul) if bits <= 32 => Instruction::I32Mul,
282 (SymPrimitiveKind::Int { bits }, SymBinaryOp::Div) if bits <= 32 => {
283 Instruction::I32DivS
284 }
285 (SymPrimitiveKind::Int { bits }, SymBinaryOp::GreaterThan) if bits <= 32 => {
286 Instruction::I32GtS
287 }
288 (SymPrimitiveKind::Int { bits }, SymBinaryOp::LessThan) if bits <= 32 => {
289 Instruction::I32LtS
290 }
291 (SymPrimitiveKind::Int { bits }, SymBinaryOp::GreaterEqual) if bits <= 32 => {
292 Instruction::I32GeS
293 }
294 (SymPrimitiveKind::Int { bits }, SymBinaryOp::LessEqual) if bits <= 32 => {
295 Instruction::I32LeS
296 }
297 (SymPrimitiveKind::Int { bits }, SymBinaryOp::EqualEqual) if bits <= 32 => {
298 Instruction::I32Eq
299 }
300
301 (SymPrimitiveKind::Int { bits }, SymBinaryOp::Add) if bits <= 64 => Instruction::I64Add,
302 (SymPrimitiveKind::Int { bits }, SymBinaryOp::Sub) if bits <= 64 => Instruction::I64Sub,
303 (SymPrimitiveKind::Int { bits }, SymBinaryOp::Mul) if bits <= 64 => Instruction::I64Mul,
304 (SymPrimitiveKind::Int { bits }, SymBinaryOp::Div) if bits <= 64 => {
305 Instruction::I64DivS
306 }
307 (SymPrimitiveKind::Int { bits }, SymBinaryOp::GreaterThan) if bits <= 64 => {
308 Instruction::I64GtS
309 }
310 (SymPrimitiveKind::Int { bits }, SymBinaryOp::LessThan) if bits <= 64 => {
311 Instruction::I64LtS
312 }
313 (SymPrimitiveKind::Int { bits }, SymBinaryOp::GreaterEqual) if bits <= 64 => {
314 Instruction::I64GeS
315 }
316 (SymPrimitiveKind::Int { bits }, SymBinaryOp::LessEqual) if bits <= 64 => {
317 Instruction::I64LeS
318 }
319 (SymPrimitiveKind::Int { bits }, SymBinaryOp::EqualEqual) if bits <= 64 => {
320 Instruction::I64Eq
321 }
322
323 (SymPrimitiveKind::Isize, SymBinaryOp::Add) => Instruction::I32Add,
324 (SymPrimitiveKind::Isize, SymBinaryOp::Sub) => Instruction::I32Sub,
325 (SymPrimitiveKind::Isize, SymBinaryOp::Mul) => Instruction::I32Mul,
326 (SymPrimitiveKind::Isize, SymBinaryOp::Div) => Instruction::I32DivS,
327 (SymPrimitiveKind::Isize, SymBinaryOp::GreaterThan) => Instruction::I32GtS,
328 (SymPrimitiveKind::Isize, SymBinaryOp::LessThan) => Instruction::I32LtS,
329 (SymPrimitiveKind::Isize, SymBinaryOp::GreaterEqual) => Instruction::I32GeS,
330 (SymPrimitiveKind::Isize, SymBinaryOp::LessEqual) => Instruction::I32LeS,
331 (SymPrimitiveKind::Isize, SymBinaryOp::EqualEqual) => Instruction::I32Eq,
332
333 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::Add) if bits <= 32 => {
334 Instruction::I32Add
335 }
336 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::Sub) if bits <= 32 => {
337 Instruction::I32Sub
338 }
339 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::Mul) if bits <= 32 => {
340 Instruction::I32Mul
341 }
342 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::Div) if bits <= 32 => {
343 Instruction::I32DivU
344 }
345 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::GreaterThan) if bits <= 32 => {
346 Instruction::I32GtU
347 }
348 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::LessThan) if bits <= 32 => {
349 Instruction::I32LtU
350 }
351 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::GreaterEqual) if bits <= 32 => {
352 Instruction::I32GeU
353 }
354 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::LessEqual) if bits <= 32 => {
355 Instruction::I32LeU
356 }
357 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::EqualEqual) if bits <= 32 => {
358 Instruction::I32Eq
359 }
360
361 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::Add) if bits <= 64 => {
362 Instruction::I64Add
363 }
364 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::Sub) if bits <= 64 => {
365 Instruction::I64Sub
366 }
367 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::Mul) if bits <= 64 => {
368 Instruction::I64Mul
369 }
370 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::Div) if bits <= 64 => {
371 Instruction::I64DivU
372 }
373 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::GreaterThan) if bits <= 64 => {
374 Instruction::I64GtU
375 }
376 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::LessThan) if bits <= 64 => {
377 Instruction::I64LtU
378 }
379 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::GreaterEqual) if bits <= 64 => {
380 Instruction::I64GeU
381 }
382 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::LessEqual) if bits <= 64 => {
383 Instruction::I64LeU
384 }
385 (SymPrimitiveKind::Uint { bits }, SymBinaryOp::EqualEqual) if bits <= 64 => {
386 Instruction::I64Eq
387 }
388
389 (SymPrimitiveKind::Usize, SymBinaryOp::Add) => Instruction::I32Add,
390 (SymPrimitiveKind::Usize, SymBinaryOp::Sub) => Instruction::I32Sub,
391 (SymPrimitiveKind::Usize, SymBinaryOp::Mul) => Instruction::I32Mul,
392 (SymPrimitiveKind::Usize, SymBinaryOp::Div) => Instruction::I32DivU,
393 (SymPrimitiveKind::Usize, SymBinaryOp::GreaterThan) => Instruction::I32GtU,
394 (SymPrimitiveKind::Usize, SymBinaryOp::LessThan) => Instruction::I32LtU,
395 (SymPrimitiveKind::Usize, SymBinaryOp::GreaterEqual) => Instruction::I32GeU,
396 (SymPrimitiveKind::Usize, SymBinaryOp::LessEqual) => Instruction::I32LeU,
397 (SymPrimitiveKind::Usize, SymBinaryOp::EqualEqual) => Instruction::I32Eq,
398
399 (SymPrimitiveKind::Float { bits }, SymBinaryOp::Add) if bits <= 32 => {
400 Instruction::F32Add
401 }
402 (SymPrimitiveKind::Float { bits }, SymBinaryOp::Sub) if bits <= 32 => {
403 Instruction::F32Sub
404 }
405 (SymPrimitiveKind::Float { bits }, SymBinaryOp::Mul) if bits <= 32 => {
406 Instruction::F32Mul
407 }
408 (SymPrimitiveKind::Float { bits }, SymBinaryOp::Div) if bits <= 32 => {
409 Instruction::F32Div
410 }
411 (SymPrimitiveKind::Float { bits }, SymBinaryOp::GreaterThan) if bits <= 32 => {
412 Instruction::F32Gt
413 }
414 (SymPrimitiveKind::Float { bits }, SymBinaryOp::LessThan) if bits <= 32 => {
415 Instruction::F32Lt
416 }
417 (SymPrimitiveKind::Float { bits }, SymBinaryOp::GreaterEqual) if bits <= 32 => {
418 Instruction::F32Ge
419 }
420 (SymPrimitiveKind::Float { bits }, SymBinaryOp::LessEqual) if bits <= 32 => {
421 Instruction::F32Le
422 }
423 (SymPrimitiveKind::Float { bits }, SymBinaryOp::EqualEqual) if bits <= 32 => {
424 Instruction::F32Eq
425 }
426
427 (SymPrimitiveKind::Float { bits }, SymBinaryOp::Add) if bits <= 64 => {
428 Instruction::F64Add
429 }
430 (SymPrimitiveKind::Float { bits }, SymBinaryOp::Sub) if bits <= 64 => {
431 Instruction::F64Sub
432 }
433 (SymPrimitiveKind::Float { bits }, SymBinaryOp::Mul) if bits <= 64 => {
434 Instruction::F64Mul
435 }
436 (SymPrimitiveKind::Float { bits }, SymBinaryOp::Div) if bits <= 64 => {
437 Instruction::F64Div
438 }
439 (SymPrimitiveKind::Float { bits }, SymBinaryOp::GreaterThan) if bits <= 64 => {
440 Instruction::F64Gt
441 }
442 (SymPrimitiveKind::Float { bits }, SymBinaryOp::LessThan) if bits <= 64 => {
443 Instruction::F64Lt
444 }
445 (SymPrimitiveKind::Float { bits }, SymBinaryOp::GreaterEqual) if bits <= 64 => {
446 Instruction::F64Ge
447 }
448 (SymPrimitiveKind::Float { bits }, SymBinaryOp::LessEqual) if bits <= 64 => {
449 Instruction::F64Le
450 }
451 (SymPrimitiveKind::Float { bits }, SymBinaryOp::EqualEqual) if bits <= 64 => {
452 Instruction::F64Eq
453 }
454
455 (SymPrimitiveKind::Int { bits: _ }, _)
456 | (SymPrimitiveKind::Uint { bits: _ } | SymPrimitiveKind::Float { bits: _ }, _) => {
457 panic!("invalid number of bits for scalar: {prim_kind:?}")
458 }
459 };
460
461 self.instructions.push(instruction);
462 }
463
464 fn primitive_kind(&self, ty: SymTy<'db>) -> Result<SymPrimitiveKind, NotPrimitive> {
466 let db = self.cx.db;
467 match ty.kind(db) {
468 SymTyKind::Named(ty_name, _ty_args) => match ty_name {
469 SymTyName::Primitive(sym_primitive) => Ok(sym_primitive.kind(db)),
470 SymTyName::Aggregate(_) | SymTyName::Future | SymTyName::Tuple { arity: _ } => {
471 Err(NotPrimitive::OtherType)
472 }
473 },
474 SymTyKind::Var(sym_variable) => {
475 self.primitive_kind(self.generics[sym_variable].assert_type(db))
476 }
477 SymTyKind::Never | SymTyKind::Error(_) => Err(NotPrimitive::DeadCode),
478 SymTyKind::Infer(_) => panic!("unexpected inference variable"),
479 #[expect(unused_variables)]
480 SymTyKind::Perm(sym_perm, sym_ty) => todo!(),
481 }
482 }
483
484 fn push_match_expr(&mut self, match_ty: SymTy<'db>, arms: &[SymMatchArm<'db>]) {
485 let Some((if_arm, else_arms)) = arms.split_first() else {
486 return;
487 };
488
489 if let Some(condition) = if_arm.condition {
490 self.push_expr(condition);
492
493 let block_type = self.block_type(match_ty);
496 self.instructions.push(Instruction::If(block_type));
497
498 self.push_expr(if_arm.body);
500
501 self.instructions.push(Instruction::Else);
503 self.push_match_expr(match_ty, else_arms);
504
505 self.instructions.push(Instruction::End);
507 } else {
508 self.push_expr(if_arm.body);
510
511 let _ = else_arms;
513 }
514 }
515
516 fn block_type(&mut self, match_ty: SymTy<'db>) -> wasm_encoder::BlockType {
525 let val_types = self.wasm_repr_of_type(match_ty).flatten();
526 match val_types.len() {
527 0 => wasm_encoder::BlockType::Empty,
528 1 => wasm_encoder::BlockType::Result(val_types[0]),
529 _ => wasm_encoder::BlockType::FunctionType(u32::from(
530 self.cx.declare_fn_type(vec![], val_types),
531 )),
532 }
533 }
534
535 fn push_literal(&mut self, ty: SymTy<'db>, literal: SymLiteral) {
536 let db = self.cx.db;
537 let kind = match ty.kind(db) {
538 SymTyKind::Named(sym_ty_name, _) => match sym_ty_name {
539 SymTyName::Primitive(sym_primitive) => sym_primitive.kind(db),
540 SymTyName::Aggregate(_) | SymTyName::Future | SymTyName::Tuple { arity: _ } => {
541 panic!("unexpected type for literal {literal:?}: {ty:?}")
542 }
543 },
544 SymTyKind::Var(sym_variable) => {
545 return self.push_literal(self.generics[sym_variable].assert_type(db), literal);
546 }
547 SymTyKind::Infer(_) | SymTyKind::Never => {
548 panic!("unexpected type for literal {literal:?}: {ty:?}")
549 }
550 SymTyKind::Error(reported) => {
551 return self.push_error(*reported);
552 }
553 #[expect(unused_variables)]
554 SymTyKind::Perm(sym_perm, sym_ty) => todo!(),
555 };
556 match kind {
557 SymPrimitiveKind::Bool
558 | SymPrimitiveKind::Isize
559 | SymPrimitiveKind::Usize
560 | SymPrimitiveKind::Char => {
561 let SymLiteral::Integral { bits } = literal else {
562 panic!("expected integral {literal:?}");
563 };
564 self.instructions.push(Instruction::I32Const(bits as i32));
565 }
566 SymPrimitiveKind::Int { bits } | SymPrimitiveKind::Uint { bits } if bits <= 32 => {
567 let SymLiteral::Integral { bits } = literal else {
568 panic!("expected integral {literal:?}");
569 };
570 self.instructions.push(Instruction::I32Const(bits as i32));
571 }
572 SymPrimitiveKind::Int { bits } | SymPrimitiveKind::Uint { bits } if bits <= 64 => {
573 let SymLiteral::Integral { bits } = literal else {
574 panic!("expected integral {literal:?}");
575 };
576 self.instructions.push(Instruction::I64Const(bits as i64));
577 }
578 SymPrimitiveKind::Float { bits } if bits <= 32 => {
579 let SymLiteral::Float { bits } = literal else {
580 panic!("expected float {literal:?}");
581 };
582 self.instructions.push(Instruction::F32Const(bits.0 as f32));
583 }
584 SymPrimitiveKind::Float { bits } if bits <= 32 => {
585 let SymLiteral::Float { bits } = literal else {
586 panic!("expected float {literal:?}");
587 };
588 self.instructions.push(Instruction::F64Const(bits.0));
589 }
590 SymPrimitiveKind::Int { .. }
591 | SymPrimitiveKind::Uint { .. }
592 | SymPrimitiveKind::Float { .. } => {
593 panic!("unexpected kind: {kind:?}");
594 }
595 }
596 }
597
598 fn push_error(&mut self, _reported: Reported) {
599 self.instructions.push(Instruction::Unreachable);
600 }
601}
602
603#[derive(Debug, PartialEq, Eq, Copy, Clone)]
605enum NotPrimitive {
606 DeadCode,
607 OtherType,
608}