1use std::fmt;
7
8use gruel_span::Span;
9use lasso::{Key, Spur};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub struct InstRef(u32);
16
17impl InstRef {
18 #[inline]
20 pub const fn from_raw(index: u32) -> Self {
21 Self(index)
22 }
23
24 #[inline]
26 pub const fn as_u32(self) -> u32 {
27 self.0
28 }
29}
30
31#[derive(Debug, Clone)]
33pub struct RirDirective {
34 pub name: Spur,
36 pub args: Vec<Spur>,
38 pub span: Span,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
44pub enum RirParamMode {
45 #[default]
47 Normal,
48 Inout,
50 Borrow,
52 Comptime,
54}
55
56#[derive(Debug, Clone)]
58pub struct RirParam {
59 pub name: Spur,
61 pub ty: Spur,
63 pub mode: RirParamMode,
65 pub is_comptime: bool,
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
71pub enum RirArgMode {
72 #[default]
74 Normal,
75 Inout,
77 Borrow,
79}
80
81#[derive(Debug, Clone)]
83pub struct RirCallArg {
84 pub value: InstRef,
86 pub mode: RirArgMode,
88}
89
90impl RirCallArg {
91 pub fn is_inout(&self) -> bool {
94 self.mode == RirArgMode::Inout
95 }
96
97 pub fn is_borrow(&self) -> bool {
99 self.mode == RirArgMode::Borrow
100 }
101}
102
103#[derive(Debug, Clone)]
105pub enum RirPattern {
106 Wildcard(Span),
108 Int(i64, Span),
110 Bool(bool, Span),
112 Path {
114 module: Option<InstRef>,
116 type_name: Spur,
118 variant: Spur,
120 span: Span,
122 },
123 DataVariant {
125 module: Option<InstRef>,
127 type_name: Spur,
129 variant: Spur,
131 bindings: Vec<RirPatternBinding>,
133 span: Span,
135 },
136 StructVariant {
138 module: Option<InstRef>,
140 type_name: Spur,
142 variant: Spur,
144 field_bindings: Vec<RirStructPatternBinding>,
146 span: Span,
148 },
149}
150
151#[derive(Debug, Clone)]
153pub struct RirPatternBinding {
154 pub is_wildcard: bool,
156 pub is_mut: bool,
158 pub name: Option<Spur>,
160}
161
162#[derive(Debug, Clone)]
164pub struct RirStructPatternBinding {
165 pub field_name: Spur,
167 pub binding: RirPatternBinding,
169}
170
171impl RirPattern {
172 pub fn span(&self) -> Span {
174 match self {
175 RirPattern::Wildcard(span) => *span,
176 RirPattern::Int(_, span) => *span,
177 RirPattern::Bool(_, span) => *span,
178 RirPattern::Path { span, .. } => *span,
179 RirPattern::DataVariant { span, .. } => *span,
180 RirPattern::StructVariant { span, .. } => *span,
181 }
182 }
183}
184
185const CALL_ARG_SIZE: u32 = 2;
190
191const PARAM_SIZE: u32 = 4;
194
195#[repr(u32)]
200#[derive(Debug, Clone, Copy, PartialEq, Eq)]
201pub enum PatternKind {
202 Wildcard = 0,
204 Int = 1,
206 Bool = 2,
208 Path = 3,
211 DataVariant = 4,
214 StructVariant = 5,
217}
218
219const PATTERN_WILDCARD_SIZE: u32 = 4; const PATTERN_INT_SIZE: u32 = 6; const PATTERN_BOOL_SIZE: u32 = 5; const PATTERN_PATH_SIZE: u32 = 7; const DESTRUCTURE_FIELD_SIZE: u32 = 4;
229
230#[derive(Debug, Clone)]
232pub struct RirDestructureField {
233 pub field_name: Spur,
235 pub binding_name: Option<Spur>,
237 pub is_wildcard: bool,
239 pub is_mut: bool,
241}
242
243const FIELD_INIT_SIZE: u32 = 2;
246
247const FIELD_DECL_SIZE: u32 = 2;
250
251#[derive(Debug, Clone)]
259pub struct FunctionSpan {
260 pub name: Spur,
262 pub body_start: InstRef,
265 pub decl: InstRef,
268}
269
270impl FunctionSpan {
271 pub fn new(name: Spur, body_start: InstRef, decl: InstRef) -> Self {
273 Self {
274 name,
275 body_start,
276 decl,
277 }
278 }
279
280 pub fn instruction_count(&self) -> u32 {
282 self.decl.as_u32() - self.body_start.as_u32() + 1
283 }
284}
285
286#[derive(Debug)]
291pub struct RirFunctionView<'a> {
292 rir: &'a Rir,
293 body_start: InstRef,
294 decl: InstRef,
295}
296
297impl<'a> RirFunctionView<'a> {
298 #[inline]
302 pub fn get(&self, inst_ref: InstRef) -> &'a Inst {
303 debug_assert!(
304 inst_ref.as_u32() >= self.body_start.as_u32()
305 && inst_ref.as_u32() <= self.decl.as_u32(),
306 "InstRef {} is outside function range [{}, {}]",
307 inst_ref,
308 self.body_start,
309 self.decl
310 );
311 self.rir.get(inst_ref)
312 }
313
314 #[inline]
316 pub fn fn_decl(&self) -> &'a Inst {
317 self.rir.get(self.decl)
318 }
319
320 pub fn iter(&self) -> impl Iterator<Item = (InstRef, &'a Inst)> {
322 let start = self.body_start.as_u32();
323 let end = self.decl.as_u32() + 1;
324 (start..end).map(move |i| {
325 let inst_ref = InstRef::from_raw(i);
326 (inst_ref, self.rir.get(inst_ref))
327 })
328 }
329
330 pub fn len(&self) -> usize {
332 (self.decl.as_u32() - self.body_start.as_u32() + 1) as usize
333 }
334
335 pub fn is_empty(&self) -> bool {
337 self.body_start.as_u32() > self.decl.as_u32()
338 }
339
340 pub fn rir(&self) -> &'a Rir {
343 self.rir
344 }
345}
346
347#[derive(Debug, Default)]
349pub struct Rir {
350 instructions: Vec<Inst>,
352 extra: Vec<u32>,
354 function_spans: Vec<FunctionSpan>,
356}
357
358impl Rir {
359 pub fn new() -> Self {
361 Self::default()
362 }
363
364 pub fn add_inst(&mut self, inst: Inst) -> InstRef {
366 debug_assert!(
368 self.instructions.len() < u32::MAX as usize,
369 "RIR instruction count overflow: {} instructions exceeds u32::MAX - 1",
370 self.instructions.len()
371 );
372
373 let index = self.instructions.len() as u32;
374 self.instructions.push(inst);
375 InstRef::from_raw(index)
376 }
377
378 #[inline]
380 pub fn get(&self, inst_ref: InstRef) -> &Inst {
381 &self.instructions[inst_ref.0 as usize]
382 }
383
384 #[inline]
386 pub fn get_mut(&mut self, inst_ref: InstRef) -> &mut Inst {
387 &mut self.instructions[inst_ref.0 as usize]
388 }
389
390 #[inline]
392 pub fn len(&self) -> usize {
393 self.instructions.len()
394 }
395
396 #[inline]
398 pub fn is_empty(&self) -> bool {
399 self.instructions.is_empty()
400 }
401
402 pub fn iter(&self) -> impl Iterator<Item = (InstRef, &Inst)> {
404 self.instructions
405 .iter()
406 .enumerate()
407 .map(|(i, inst)| (InstRef::from_raw(i as u32), inst))
408 }
409
410 pub fn add_extra(&mut self, data: &[u32]) -> u32 {
412 debug_assert!(
414 self.extra.len() <= u32::MAX as usize,
415 "RIR extra data overflow: {} entries exceeds u32::MAX",
416 self.extra.len()
417 );
418 debug_assert!(
419 self.extra.len().saturating_add(data.len()) <= u32::MAX as usize,
420 "RIR extra data would overflow: {} + {} exceeds u32::MAX",
421 self.extra.len(),
422 data.len()
423 );
424
425 let start = self.extra.len() as u32;
426 self.extra.extend_from_slice(data);
427 start
428 }
429
430 #[inline]
432 pub fn get_extra(&self, start: u32, len: u32) -> &[u32] {
433 let start = start as usize;
434 let end = start + len as usize;
435 &self.extra[start..end]
436 }
437
438 pub fn add_inst_refs(&mut self, refs: &[InstRef]) -> (u32, u32) {
442 let data: Vec<u32> = refs.iter().map(|r| r.as_u32()).collect();
443 let start = self.add_extra(&data);
444 (start, refs.len() as u32)
445 }
446
447 pub fn get_inst_refs(&self, start: u32, len: u32) -> Vec<InstRef> {
449 self.get_extra(start, len)
450 .iter()
451 .map(|&v| InstRef::from_raw(v))
452 .collect()
453 }
454
455 pub fn add_symbols(&mut self, symbols: &[Spur]) -> (u32, u32) {
457 let data: Vec<u32> = symbols.iter().map(|s| s.into_usize() as u32).collect();
458 let start = self.add_extra(&data);
459 (start, symbols.len() as u32)
460 }
461
462 pub fn get_symbols(&self, start: u32, len: u32) -> Vec<Spur> {
464 self.get_extra(start, len)
465 .iter()
466 .map(|&v| Spur::try_from_usize(v as usize).unwrap())
467 .collect()
468 }
469
470 pub fn add_enum_variant_decls(
479 &mut self,
480 variants: &[(Spur, Vec<Spur>, Vec<Spur>)],
481 ) -> (u32, u32) {
482 let start = self.extra.len() as u32;
483 for (name, field_types, field_names) in variants {
484 self.extra.push(name.into_usize() as u32);
485 self.extra.push(field_types.len() as u32);
486 let is_struct = if field_names.is_empty() { 0u32 } else { 1u32 };
487 self.extra.push(is_struct);
488 for field_ty in field_types {
489 self.extra.push(field_ty.into_usize() as u32);
490 }
491 for field_name in field_names {
492 self.extra.push(field_name.into_usize() as u32);
493 }
494 }
495 (start, variants.len() as u32)
496 }
497
498 pub fn get_enum_variant_decls(
502 &self,
503 start: u32,
504 variant_count: u32,
505 ) -> Vec<(Spur, Vec<Spur>, Vec<Spur>)> {
506 let mut result = Vec::with_capacity(variant_count as usize);
507 let mut pos = start as usize;
508 for _ in 0..variant_count {
509 let name = Spur::try_from_usize(self.extra[pos] as usize).unwrap();
510 let field_count = self.extra[pos + 1] as usize;
511 let is_struct = self.extra[pos + 2] != 0;
512 pos += 3;
513 let field_types: Vec<Spur> = (0..field_count)
514 .map(|i| Spur::try_from_usize(self.extra[pos + i] as usize).unwrap())
515 .collect();
516 pos += field_count;
517 let field_names = if is_struct {
518 let names: Vec<Spur> = (0..field_count)
519 .map(|i| Spur::try_from_usize(self.extra[pos + i] as usize).unwrap())
520 .collect();
521 pos += field_count;
522 names
523 } else {
524 Vec::new()
525 };
526 result.push((name, field_types, field_names));
527 }
528 result
529 }
530
531 pub fn add_call_args(&mut self, args: &[RirCallArg]) -> (u32, u32) {
534 let mut data = Vec::with_capacity(args.len() * CALL_ARG_SIZE as usize);
535 for arg in args {
536 data.push(arg.value.as_u32());
537 data.push(arg.mode as u32);
538 }
539 let start = self.add_extra(&data);
540 (start, args.len() as u32)
541 }
542
543 pub fn get_call_args(&self, start: u32, len: u32) -> Vec<RirCallArg> {
545 let data = self.get_extra(start, len * CALL_ARG_SIZE);
546 let mut args = Vec::with_capacity(len as usize);
547 for chunk in data.chunks(CALL_ARG_SIZE as usize) {
548 let value = InstRef::from_raw(chunk[0]);
549 let mode = match chunk[1] {
550 0 => RirArgMode::Normal,
551 1 => RirArgMode::Inout,
552 2 => RirArgMode::Borrow,
553 _ => RirArgMode::Normal, };
555 args.push(RirCallArg { value, mode });
556 }
557 args
558 }
559
560 pub fn add_params(&mut self, params: &[RirParam]) -> (u32, u32) {
563 let mut data = Vec::with_capacity(params.len() * PARAM_SIZE as usize);
564 for param in params {
565 data.push(param.name.into_usize() as u32);
566 data.push(param.ty.into_usize() as u32);
567 data.push(param.mode as u32);
568 data.push(param.is_comptime as u32);
569 }
570 let start = self.add_extra(&data);
571 (start, params.len() as u32)
572 }
573
574 pub fn get_params(&self, start: u32, len: u32) -> Vec<RirParam> {
576 let data = self.get_extra(start, len * PARAM_SIZE);
577 let mut params = Vec::with_capacity(len as usize);
578 for chunk in data.chunks(PARAM_SIZE as usize) {
579 let name = Spur::try_from_usize(chunk[0] as usize).unwrap();
580 let ty = Spur::try_from_usize(chunk[1] as usize).unwrap();
581 let mode = match chunk[2] {
582 0 => RirParamMode::Normal,
583 1 => RirParamMode::Inout,
584 2 => RirParamMode::Borrow,
585 3 => RirParamMode::Comptime,
586 _ => RirParamMode::Normal, };
588 let is_comptime = chunk[3] != 0;
589 params.push(RirParam {
590 name,
591 ty,
592 mode,
593 is_comptime,
594 });
595 }
596 params
597 }
598
599 pub fn add_match_arms(&mut self, arms: &[(RirPattern, InstRef)]) -> (u32, u32) {
602 let start = self.extra.len() as u32;
603 for (pattern, body) in arms {
604 match pattern {
605 RirPattern::Wildcard(span) => {
606 self.extra.push(PatternKind::Wildcard as u32);
607 self.extra.push(span.start());
608 self.extra.push(span.len());
609 self.extra.push(body.as_u32());
610 }
611 RirPattern::Int(value, span) => {
612 self.extra.push(PatternKind::Int as u32);
613 self.extra.push(span.start());
614 self.extra.push(span.len());
615 self.extra.push(*value as u32);
617 self.extra.push((*value >> 32) as u32);
618 self.extra.push(body.as_u32());
619 }
620 RirPattern::Bool(value, span) => {
621 self.extra.push(PatternKind::Bool as u32);
622 self.extra.push(span.start());
623 self.extra.push(span.len());
624 self.extra.push(if *value { 1 } else { 0 });
625 self.extra.push(body.as_u32());
626 }
627 RirPattern::Path {
628 module,
629 type_name,
630 variant,
631 span,
632 } => {
633 self.extra.push(PatternKind::Path as u32);
634 self.extra.push(span.start());
635 self.extra.push(span.len());
636 self.extra.push(module.map_or(u32::MAX, |r| r.as_u32()));
638 self.extra.push(type_name.into_usize() as u32);
639 self.extra.push(variant.into_usize() as u32);
640 self.extra.push(body.as_u32());
641 }
642 RirPattern::DataVariant {
643 module,
644 type_name,
645 variant,
646 bindings,
647 span,
648 } => {
649 self.extra.push(PatternKind::DataVariant as u32);
650 self.extra.push(span.start());
651 self.extra.push(span.len());
652 self.extra.push(module.map_or(u32::MAX, |r| r.as_u32()));
653 self.extra.push(type_name.into_usize() as u32);
654 self.extra.push(variant.into_usize() as u32);
655 self.extra.push(body.as_u32());
656 self.extra.push(bindings.len() as u32);
657 for binding in bindings {
658 let flags = if binding.is_wildcard { 1u32 } else { 0 }
659 | if binding.is_mut { 2 } else { 0 };
660 self.extra.push(flags);
661 self.extra
662 .push(binding.name.map_or(u32::MAX, |s| s.into_usize() as u32));
663 }
664 }
665 RirPattern::StructVariant {
666 module,
667 type_name,
668 variant,
669 field_bindings,
670 span,
671 } => {
672 self.extra.push(PatternKind::StructVariant as u32);
673 self.extra.push(span.start());
674 self.extra.push(span.len());
675 self.extra.push(module.map_or(u32::MAX, |r| r.as_u32()));
676 self.extra.push(type_name.into_usize() as u32);
677 self.extra.push(variant.into_usize() as u32);
678 self.extra.push(body.as_u32());
679 self.extra.push(field_bindings.len() as u32);
680 for fb in field_bindings {
681 self.extra.push(fb.field_name.into_usize() as u32);
682 let flags = if fb.binding.is_wildcard { 1u32 } else { 0 }
683 | if fb.binding.is_mut { 2 } else { 0 };
684 self.extra.push(flags);
685 self.extra
686 .push(fb.binding.name.map_or(u32::MAX, |s| s.into_usize() as u32));
687 }
688 }
689 }
690 }
691 (start, arms.len() as u32)
692 }
693
694 pub fn get_match_arms(&self, start: u32, arm_count: u32) -> Vec<(RirPattern, InstRef)> {
696 let mut arms = Vec::with_capacity(arm_count as usize);
697 let mut pos = start as usize;
698
699 for _ in 0..arm_count {
700 let kind = self.extra[pos];
701 match kind {
702 k if k == PatternKind::Wildcard as u32 => {
703 let span_start = self.extra[pos + 1];
704 let span_len = self.extra[pos + 2];
705 let span = Span::new(span_start, span_start + span_len);
706 let body = InstRef::from_raw(self.extra[pos + 3]);
707 arms.push((RirPattern::Wildcard(span), body));
708 pos += PATTERN_WILDCARD_SIZE as usize;
709 }
710 k if k == PatternKind::Int as u32 => {
711 let span_start = self.extra[pos + 1];
712 let span_len = self.extra[pos + 2];
713 let span = Span::new(span_start, span_start + span_len);
714 let value_lo = self.extra[pos + 3] as i64;
715 let value_hi = self.extra[pos + 4] as i64;
716 let value = value_lo | (value_hi << 32);
717 let body = InstRef::from_raw(self.extra[pos + 5]);
718 arms.push((RirPattern::Int(value, span), body));
719 pos += PATTERN_INT_SIZE as usize;
720 }
721 k if k == PatternKind::Bool as u32 => {
722 let span_start = self.extra[pos + 1];
723 let span_len = self.extra[pos + 2];
724 let span = Span::new(span_start, span_start + span_len);
725 let value = self.extra[pos + 3] != 0;
726 let body = InstRef::from_raw(self.extra[pos + 4]);
727 arms.push((RirPattern::Bool(value, span), body));
728 pos += PATTERN_BOOL_SIZE as usize;
729 }
730 k if k == PatternKind::Path as u32 => {
731 let span_start = self.extra[pos + 1];
732 let span_len = self.extra[pos + 2];
733 let span = Span::new(span_start, span_start + span_len);
734 let module_raw = self.extra[pos + 3];
736 let module = if module_raw == u32::MAX {
737 None
738 } else {
739 Some(InstRef::from_raw(module_raw))
740 };
741 let type_name = Spur::try_from_usize(self.extra[pos + 4] as usize).unwrap();
742 let variant = Spur::try_from_usize(self.extra[pos + 5] as usize).unwrap();
743 let body = InstRef::from_raw(self.extra[pos + 6]);
744 arms.push((
745 RirPattern::Path {
746 module,
747 type_name,
748 variant,
749 span,
750 },
751 body,
752 ));
753 pos += PATTERN_PATH_SIZE as usize;
754 }
755 k if k == PatternKind::DataVariant as u32 => {
756 let span_start = self.extra[pos + 1];
757 let span_len = self.extra[pos + 2];
758 let span = Span::new(span_start, span_start + span_len);
759 let module_raw = self.extra[pos + 3];
760 let module = if module_raw == u32::MAX {
761 None
762 } else {
763 Some(InstRef::from_raw(module_raw))
764 };
765 let type_name = Spur::try_from_usize(self.extra[pos + 4] as usize).unwrap();
766 let variant = Spur::try_from_usize(self.extra[pos + 5] as usize).unwrap();
767 let body = InstRef::from_raw(self.extra[pos + 6]);
768 let bindings_len = self.extra[pos + 7] as usize;
769 let mut bindings = Vec::with_capacity(bindings_len);
770 for i in 0..bindings_len {
771 let flags = self.extra[pos + 8 + i * 2];
772 let name_raw = self.extra[pos + 9 + i * 2];
773 let is_wildcard = flags & 1 != 0;
774 let is_mut = flags & 2 != 0;
775 let name = if name_raw == u32::MAX {
776 None
777 } else {
778 Some(Spur::try_from_usize(name_raw as usize).unwrap())
779 };
780 bindings.push(RirPatternBinding {
781 is_wildcard,
782 is_mut,
783 name,
784 });
785 }
786 arms.push((
787 RirPattern::DataVariant {
788 module,
789 type_name,
790 variant,
791 bindings,
792 span,
793 },
794 body,
795 ));
796 pos += 8 + 2 * bindings_len;
797 }
798 k if k == PatternKind::StructVariant as u32 => {
799 let span_start = self.extra[pos + 1];
800 let span_len = self.extra[pos + 2];
801 let span = Span::new(span_start, span_start + span_len);
802 let module_raw = self.extra[pos + 3];
803 let module = if module_raw == u32::MAX {
804 None
805 } else {
806 Some(InstRef::from_raw(module_raw))
807 };
808 let type_name = Spur::try_from_usize(self.extra[pos + 4] as usize).unwrap();
809 let variant = Spur::try_from_usize(self.extra[pos + 5] as usize).unwrap();
810 let body = InstRef::from_raw(self.extra[pos + 6]);
811 let bindings_len = self.extra[pos + 7] as usize;
812 let mut field_bindings = Vec::with_capacity(bindings_len);
813 for i in 0..bindings_len {
814 let field_name =
815 Spur::try_from_usize(self.extra[pos + 8 + i * 3] as usize).unwrap();
816 let flags = self.extra[pos + 9 + i * 3];
817 let name_raw = self.extra[pos + 10 + i * 3];
818 let is_wildcard = flags & 1 != 0;
819 let is_mut = flags & 2 != 0;
820 let name = if name_raw == u32::MAX {
821 None
822 } else {
823 Some(Spur::try_from_usize(name_raw as usize).unwrap())
824 };
825 field_bindings.push(RirStructPatternBinding {
826 field_name,
827 binding: RirPatternBinding {
828 is_wildcard,
829 is_mut,
830 name,
831 },
832 });
833 }
834 arms.push((
835 RirPattern::StructVariant {
836 module,
837 type_name,
838 variant,
839 field_bindings,
840 span,
841 },
842 body,
843 ));
844 pos += 8 + 3 * bindings_len;
845 }
846 _ => panic!("Unknown pattern kind: {}", kind),
847 }
848 }
849 arms
850 }
851
852 pub fn add_field_inits(&mut self, fields: &[(Spur, InstRef)]) -> (u32, u32) {
855 let mut data = Vec::with_capacity(fields.len() * FIELD_INIT_SIZE as usize);
856 for (name, value) in fields {
857 data.push(name.into_usize() as u32);
858 data.push(value.as_u32());
859 }
860 let start = self.add_extra(&data);
861 (start, fields.len() as u32)
862 }
863
864 pub fn get_field_inits(&self, start: u32, len: u32) -> Vec<(Spur, InstRef)> {
866 let data = self.get_extra(start, len * FIELD_INIT_SIZE);
867 let mut fields = Vec::with_capacity(len as usize);
868 for chunk in data.chunks(FIELD_INIT_SIZE as usize) {
869 let name = Spur::try_from_usize(chunk[0] as usize).unwrap();
870 let value = InstRef::from_raw(chunk[1]);
871 fields.push((name, value));
872 }
873 fields
874 }
875
876 pub fn add_field_decls(&mut self, fields: &[(Spur, Spur)]) -> (u32, u32) {
879 let mut data = Vec::with_capacity(fields.len() * FIELD_DECL_SIZE as usize);
880 for (name, ty) in fields {
881 data.push(name.into_usize() as u32);
882 data.push(ty.into_usize() as u32);
883 }
884 let start = self.add_extra(&data);
885 (start, fields.len() as u32)
886 }
887
888 pub fn get_field_decls(&self, start: u32, len: u32) -> Vec<(Spur, Spur)> {
890 let data = self.get_extra(start, len * FIELD_DECL_SIZE);
891 let mut fields = Vec::with_capacity(len as usize);
892 for chunk in data.chunks(FIELD_DECL_SIZE as usize) {
893 let name = Spur::try_from_usize(chunk[0] as usize).unwrap();
894 let ty = Spur::try_from_usize(chunk[1] as usize).unwrap();
895 fields.push((name, ty));
896 }
897 fields
898 }
899
900 pub fn add_directives(&mut self, directives: &[RirDirective]) -> (u32, u32) {
903 let start = self.extra.len() as u32;
904 for directive in directives {
905 self.extra.push(directive.name.into_usize() as u32);
906 self.extra.push(directive.span.start());
907 self.extra.push(directive.span.len());
908 self.extra.push(directive.args.len() as u32);
909 for arg in &directive.args {
910 self.extra.push(arg.into_usize() as u32);
911 }
912 }
913 (start, directives.len() as u32)
914 }
915
916 pub fn get_directives(&self, start: u32, directive_count: u32) -> Vec<RirDirective> {
918 let mut directives = Vec::with_capacity(directive_count as usize);
919 let mut pos = start as usize;
920
921 for _ in 0..directive_count {
922 let name = Spur::try_from_usize(self.extra[pos] as usize).unwrap();
923 let span = Span::new(self.extra[pos + 1], self.extra[pos + 2]);
924 let args_len = self.extra[pos + 3] as usize;
925 pos += 4;
926
927 let args: Vec<Spur> = (0..args_len)
928 .map(|i| Spur::try_from_usize(self.extra[pos + i] as usize).unwrap())
929 .collect();
930 pos += args_len;
931
932 directives.push(RirDirective { name, args, span });
933 }
934 directives
935 }
936
937 pub fn add_destructure_fields(&mut self, fields: &[RirDestructureField]) -> (u32, u32) {
939 let start = self.extra.len() as u32;
940 for field in fields {
941 self.extra.push(field.field_name.into_usize() as u32);
942 self.extra
943 .push(field.binding_name.map_or(0, |s| s.into_usize() as u32));
944 self.extra.push(field.is_wildcard as u32);
945 self.extra.push(field.is_mut as u32);
946 }
947 (start, fields.len() as u32)
948 }
949
950 pub fn get_destructure_fields(&self, start: u32, count: u32) -> Vec<RirDestructureField> {
952 let mut fields = Vec::with_capacity(count as usize);
953 for i in 0..count {
954 let pos = (start + i * DESTRUCTURE_FIELD_SIZE) as usize;
955 let field_name = Spur::try_from_usize(self.extra[pos] as usize).unwrap();
956 let binding_raw = self.extra[pos + 1];
957 let binding_name = if binding_raw == 0 {
958 None
959 } else {
960 Some(Spur::try_from_usize(binding_raw as usize).unwrap())
961 };
962 let is_wildcard = self.extra[pos + 2] != 0;
963 let is_mut = self.extra[pos + 3] != 0;
964 fields.push(RirDestructureField {
965 field_name,
966 binding_name,
967 is_wildcard,
968 is_mut,
969 });
970 }
971 fields
972 }
973
974 pub fn add_function_span(&mut self, span: FunctionSpan) {
978 self.function_spans.push(span);
979 }
980
981 pub fn function_spans(&self) -> &[FunctionSpan] {
983 &self.function_spans
984 }
985
986 pub fn functions(&self) -> impl Iterator<Item = &FunctionSpan> {
988 self.function_spans.iter()
989 }
990
991 pub fn function_count(&self) -> usize {
993 self.function_spans.len()
994 }
995
996 pub fn function_view(&self, fn_span: &FunctionSpan) -> RirFunctionView<'_> {
998 RirFunctionView {
999 rir: self,
1000 body_start: fn_span.body_start,
1001 decl: fn_span.decl,
1002 }
1003 }
1004
1005 pub fn find_function(&self, name: Spur) -> Option<&FunctionSpan> {
1007 self.function_spans.iter().find(|span| span.name == name)
1008 }
1009
1010 pub fn current_inst_index(&self) -> u32 {
1012 self.instructions.len() as u32
1013 }
1014
1015 pub fn merge(rirs: &[Rir]) -> Rir {
1029 if rirs.is_empty() {
1030 return Rir::new();
1031 }
1032
1033 if rirs.len() == 1 {
1034 return Rir {
1036 instructions: rirs[0].instructions.clone(),
1037 extra: rirs[0].extra.clone(),
1038 function_spans: rirs[0].function_spans.clone(),
1039 };
1040 }
1041
1042 let total_instructions: usize = rirs.iter().map(|r| r.instructions.len()).sum();
1044 let total_extra: usize = rirs.iter().map(|r| r.extra.len()).sum();
1045 let total_functions: usize = rirs.iter().map(|r| r.function_spans.len()).sum();
1046
1047 let mut merged = Rir {
1048 instructions: Vec::with_capacity(total_instructions),
1049 extra: Vec::with_capacity(total_extra),
1050 function_spans: Vec::with_capacity(total_functions),
1051 };
1052
1053 let mut inst_offset: u32 = 0;
1055 let mut extra_offset: u32 = 0;
1056
1057 for rir in rirs {
1058 merged.extra.extend_from_slice(&rir.extra);
1060
1061 for inst in &rir.instructions {
1063 let renumbered = Self::renumber_instruction(inst, inst_offset, extra_offset);
1064 merged.instructions.push(renumbered);
1065 }
1066
1067 Self::renumber_extra_inst_refs(
1070 &mut merged.extra,
1071 &rir.instructions,
1072 inst_offset,
1073 extra_offset,
1074 );
1075
1076 for fn_span in &rir.function_spans {
1078 merged.function_spans.push(FunctionSpan {
1079 name: fn_span.name,
1080 body_start: InstRef::from_raw(fn_span.body_start.as_u32() + inst_offset),
1081 decl: InstRef::from_raw(fn_span.decl.as_u32() + inst_offset),
1082 });
1083 }
1084
1085 inst_offset += rir.instructions.len() as u32;
1087 extra_offset += rir.extra.len() as u32;
1088 }
1089
1090 merged
1091 }
1092
1093 fn renumber_instruction(inst: &Inst, inst_offset: u32, extra_offset: u32) -> Inst {
1095 let renumber = |r: InstRef| InstRef::from_raw(r.as_u32() + inst_offset);
1096 let renumber_opt = |r: Option<InstRef>| r.map(renumber);
1097
1098 let data = match &inst.data {
1099 InstData::IntConst(v) => InstData::IntConst(*v),
1101 InstData::FloatConst(bits) => InstData::FloatConst(*bits),
1102 InstData::BoolConst(v) => InstData::BoolConst(*v),
1103 InstData::StringConst(s) => InstData::StringConst(*s),
1104 InstData::UnitConst => InstData::UnitConst,
1105 InstData::Break => InstData::Break,
1106 InstData::Continue => InstData::Continue,
1107 InstData::VarRef { name } => InstData::VarRef { name: *name },
1108 InstData::ParamRef { index, name } => InstData::ParamRef {
1109 index: *index,
1110 name: *name,
1111 },
1112 InstData::EnumVariant {
1113 module,
1114 type_name,
1115 variant,
1116 } => InstData::EnumVariant {
1117 module: module.map(renumber),
1118 type_name: *type_name,
1119 variant: *variant,
1120 },
1121 InstData::EnumStructVariant {
1122 module,
1123 type_name,
1124 variant,
1125 fields_start,
1126 fields_len,
1127 } => InstData::EnumStructVariant {
1128 module: module.map(renumber),
1129 type_name: *type_name,
1130 variant: *variant,
1131 fields_start: *fields_start,
1132 fields_len: *fields_len,
1133 },
1134 InstData::TypeIntrinsic { name, type_arg } => InstData::TypeIntrinsic {
1135 name: *name,
1136 type_arg: *type_arg,
1137 },
1138
1139 InstData::Add { lhs, rhs } => InstData::Add {
1141 lhs: renumber(*lhs),
1142 rhs: renumber(*rhs),
1143 },
1144 InstData::Sub { lhs, rhs } => InstData::Sub {
1145 lhs: renumber(*lhs),
1146 rhs: renumber(*rhs),
1147 },
1148 InstData::Mul { lhs, rhs } => InstData::Mul {
1149 lhs: renumber(*lhs),
1150 rhs: renumber(*rhs),
1151 },
1152 InstData::Div { lhs, rhs } => InstData::Div {
1153 lhs: renumber(*lhs),
1154 rhs: renumber(*rhs),
1155 },
1156 InstData::Mod { lhs, rhs } => InstData::Mod {
1157 lhs: renumber(*lhs),
1158 rhs: renumber(*rhs),
1159 },
1160 InstData::Eq { lhs, rhs } => InstData::Eq {
1161 lhs: renumber(*lhs),
1162 rhs: renumber(*rhs),
1163 },
1164 InstData::Ne { lhs, rhs } => InstData::Ne {
1165 lhs: renumber(*lhs),
1166 rhs: renumber(*rhs),
1167 },
1168 InstData::Lt { lhs, rhs } => InstData::Lt {
1169 lhs: renumber(*lhs),
1170 rhs: renumber(*rhs),
1171 },
1172 InstData::Gt { lhs, rhs } => InstData::Gt {
1173 lhs: renumber(*lhs),
1174 rhs: renumber(*rhs),
1175 },
1176 InstData::Le { lhs, rhs } => InstData::Le {
1177 lhs: renumber(*lhs),
1178 rhs: renumber(*rhs),
1179 },
1180 InstData::Ge { lhs, rhs } => InstData::Ge {
1181 lhs: renumber(*lhs),
1182 rhs: renumber(*rhs),
1183 },
1184 InstData::And { lhs, rhs } => InstData::And {
1185 lhs: renumber(*lhs),
1186 rhs: renumber(*rhs),
1187 },
1188 InstData::Or { lhs, rhs } => InstData::Or {
1189 lhs: renumber(*lhs),
1190 rhs: renumber(*rhs),
1191 },
1192 InstData::BitAnd { lhs, rhs } => InstData::BitAnd {
1193 lhs: renumber(*lhs),
1194 rhs: renumber(*rhs),
1195 },
1196 InstData::BitOr { lhs, rhs } => InstData::BitOr {
1197 lhs: renumber(*lhs),
1198 rhs: renumber(*rhs),
1199 },
1200 InstData::BitXor { lhs, rhs } => InstData::BitXor {
1201 lhs: renumber(*lhs),
1202 rhs: renumber(*rhs),
1203 },
1204 InstData::Shl { lhs, rhs } => InstData::Shl {
1205 lhs: renumber(*lhs),
1206 rhs: renumber(*rhs),
1207 },
1208 InstData::Shr { lhs, rhs } => InstData::Shr {
1209 lhs: renumber(*lhs),
1210 rhs: renumber(*rhs),
1211 },
1212
1213 InstData::Neg { operand } => InstData::Neg {
1215 operand: renumber(*operand),
1216 },
1217 InstData::Not { operand } => InstData::Not {
1218 operand: renumber(*operand),
1219 },
1220 InstData::BitNot { operand } => InstData::BitNot {
1221 operand: renumber(*operand),
1222 },
1223
1224 InstData::Branch {
1226 cond,
1227 then_block,
1228 else_block,
1229 } => InstData::Branch {
1230 cond: renumber(*cond),
1231 then_block: renumber(*then_block),
1232 else_block: renumber_opt(*else_block),
1233 },
1234 InstData::Loop { cond, body } => InstData::Loop {
1235 cond: renumber(*cond),
1236 body: renumber(*body),
1237 },
1238 InstData::For {
1239 binding,
1240 is_mut,
1241 iterable,
1242 body,
1243 } => InstData::For {
1244 binding: *binding,
1245 is_mut: *is_mut,
1246 iterable: renumber(*iterable),
1247 body: renumber(*body),
1248 },
1249 InstData::InfiniteLoop { body } => InstData::InfiniteLoop {
1250 body: renumber(*body),
1251 },
1252 InstData::Ret(value) => InstData::Ret(renumber_opt(*value)),
1253
1254 InstData::Match {
1256 scrutinee,
1257 arms_start,
1258 arms_len,
1259 } => InstData::Match {
1260 scrutinee: renumber(*scrutinee),
1261 arms_start: *arms_start + extra_offset,
1262 arms_len: *arms_len,
1263 },
1264
1265 InstData::Block { extra_start, len } => InstData::Block {
1267 extra_start: *extra_start + extra_offset,
1268 len: *len,
1269 },
1270
1271 InstData::Alloc {
1273 directives_start,
1274 directives_len,
1275 name,
1276 is_mut,
1277 ty,
1278 init,
1279 } => InstData::Alloc {
1280 directives_start: *directives_start + extra_offset,
1281 directives_len: *directives_len,
1282 name: *name,
1283 is_mut: *is_mut,
1284 ty: *ty,
1285 init: renumber(*init),
1286 },
1287 InstData::StructDestructure {
1288 type_name,
1289 fields_start,
1290 fields_len,
1291 init,
1292 } => InstData::StructDestructure {
1293 type_name: *type_name,
1294 fields_start: *fields_start + extra_offset,
1295 fields_len: *fields_len,
1296 init: renumber(*init),
1297 },
1298 InstData::Assign { name, value } => InstData::Assign {
1299 name: *name,
1300 value: renumber(*value),
1301 },
1302
1303 InstData::FnDecl {
1305 directives_start,
1306 directives_len,
1307 is_pub,
1308 is_unchecked,
1309 name,
1310 params_start,
1311 params_len,
1312 return_type,
1313 body,
1314 has_self,
1315 } => InstData::FnDecl {
1316 directives_start: *directives_start + extra_offset,
1317 directives_len: *directives_len,
1318 is_pub: *is_pub,
1319 is_unchecked: *is_unchecked,
1320 name: *name,
1321 params_start: *params_start + extra_offset,
1322 params_len: *params_len,
1323 return_type: *return_type,
1324 body: renumber(*body),
1325 has_self: *has_self,
1326 },
1327
1328 InstData::ConstDecl {
1330 directives_start,
1331 directives_len,
1332 is_pub,
1333 name,
1334 ty,
1335 init,
1336 } => InstData::ConstDecl {
1337 directives_start: *directives_start + extra_offset,
1338 directives_len: *directives_len,
1339 is_pub: *is_pub,
1340 name: *name,
1341 ty: *ty,
1342 init: renumber(*init),
1343 },
1344
1345 InstData::Call {
1347 name,
1348 args_start,
1349 args_len,
1350 } => InstData::Call {
1351 name: *name,
1352 args_start: *args_start + extra_offset,
1353 args_len: *args_len,
1354 },
1355
1356 InstData::Intrinsic {
1358 name,
1359 args_start,
1360 args_len,
1361 } => InstData::Intrinsic {
1362 name: *name,
1363 args_start: *args_start + extra_offset,
1364 args_len: *args_len,
1365 },
1366
1367 InstData::StructDecl {
1369 directives_start,
1370 directives_len,
1371 is_pub,
1372 is_linear,
1373 name,
1374 fields_start,
1375 fields_len,
1376 methods_start,
1377 methods_len,
1378 } => InstData::StructDecl {
1379 directives_start: *directives_start + extra_offset,
1380 directives_len: *directives_len,
1381 is_pub: *is_pub,
1382 is_linear: *is_linear,
1383 name: *name,
1384 fields_start: *fields_start + extra_offset,
1385 fields_len: *fields_len,
1386 methods_start: *methods_start + extra_offset,
1387 methods_len: *methods_len,
1388 },
1389 InstData::StructInit {
1390 module,
1391 type_name,
1392 fields_start,
1393 fields_len,
1394 } => InstData::StructInit {
1395 module: module.map(renumber),
1396 type_name: *type_name,
1397 fields_start: *fields_start + extra_offset,
1398 fields_len: *fields_len,
1399 },
1400 InstData::FieldGet { base, field } => InstData::FieldGet {
1401 base: renumber(*base),
1402 field: *field,
1403 },
1404 InstData::FieldSet { base, field, value } => InstData::FieldSet {
1405 base: renumber(*base),
1406 field: *field,
1407 value: renumber(*value),
1408 },
1409
1410 InstData::EnumDecl {
1412 is_pub,
1413 name,
1414 variants_start,
1415 variants_len,
1416 } => InstData::EnumDecl {
1417 is_pub: *is_pub,
1418 name: *name,
1419 variants_start: *variants_start + extra_offset,
1420 variants_len: *variants_len,
1421 },
1422
1423 InstData::ArrayInit {
1425 elems_start,
1426 elems_len,
1427 } => InstData::ArrayInit {
1428 elems_start: *elems_start + extra_offset,
1429 elems_len: *elems_len,
1430 },
1431 InstData::IndexGet { base, index } => InstData::IndexGet {
1432 base: renumber(*base),
1433 index: renumber(*index),
1434 },
1435 InstData::IndexSet { base, index, value } => InstData::IndexSet {
1436 base: renumber(*base),
1437 index: renumber(*index),
1438 value: renumber(*value),
1439 },
1440
1441 InstData::MethodCall {
1443 receiver,
1444 method,
1445 args_start,
1446 args_len,
1447 } => InstData::MethodCall {
1448 receiver: renumber(*receiver),
1449 method: *method,
1450 args_start: *args_start + extra_offset,
1451 args_len: *args_len,
1452 },
1453 InstData::AssocFnCall {
1454 type_name,
1455 function,
1456 args_start,
1457 args_len,
1458 } => InstData::AssocFnCall {
1459 type_name: *type_name,
1460 function: *function,
1461 args_start: *args_start + extra_offset,
1462 args_len: *args_len,
1463 },
1464 InstData::DropFnDecl { type_name, body } => InstData::DropFnDecl {
1465 type_name: *type_name,
1466 body: renumber(*body),
1467 },
1468 InstData::Comptime { expr } => InstData::Comptime {
1469 expr: renumber(*expr),
1470 },
1471 InstData::ComptimeUnrollFor {
1472 binding,
1473 iterable,
1474 body,
1475 } => InstData::ComptimeUnrollFor {
1476 binding: *binding,
1477 iterable: renumber(*iterable),
1478 body: renumber(*body),
1479 },
1480 InstData::Checked { expr } => InstData::Checked {
1481 expr: renumber(*expr),
1482 },
1483 InstData::TypeConst { type_name } => InstData::TypeConst {
1484 type_name: *type_name,
1485 },
1486 InstData::AnonStructType {
1487 fields_start,
1488 fields_len,
1489 methods_start,
1490 methods_len,
1491 } => InstData::AnonStructType {
1492 fields_start: *fields_start + extra_offset,
1493 fields_len: *fields_len,
1494 methods_start: *methods_start + extra_offset,
1495 methods_len: *methods_len,
1496 },
1497 InstData::AnonEnumType {
1498 variants_start,
1499 variants_len,
1500 methods_start,
1501 methods_len,
1502 } => InstData::AnonEnumType {
1503 variants_start: *variants_start + extra_offset,
1504 variants_len: *variants_len,
1505 methods_start: *methods_start + extra_offset,
1506 methods_len: *methods_len,
1507 },
1508 };
1509
1510 Inst {
1511 data,
1512 span: inst.span,
1513 }
1514 }
1515
1516 fn renumber_extra_inst_refs(
1527 extra: &mut [u32],
1528 instructions: &[Inst],
1529 inst_offset: u32,
1530 extra_offset: u32,
1531 ) {
1532 for inst in instructions {
1533 match &inst.data {
1534 InstData::Block { extra_start, len } => {
1536 let start = (*extra_start + extra_offset) as usize;
1537 for i in 0..*len as usize {
1538 extra[start + i] += inst_offset;
1539 }
1540 }
1541
1542 InstData::ArrayInit {
1544 elems_start,
1545 elems_len,
1546 } => {
1547 let start = (*elems_start + extra_offset) as usize;
1548 for i in 0..*elems_len as usize {
1549 extra[start + i] += inst_offset;
1550 }
1551 }
1552
1553 InstData::Intrinsic {
1555 args_start,
1556 args_len,
1557 ..
1558 } => {
1559 let start = (*args_start + extra_offset) as usize;
1560 for i in 0..*args_len as usize {
1561 extra[start + i] += inst_offset;
1562 }
1563 }
1564
1565 InstData::StructDecl {
1567 methods_start,
1568 methods_len,
1569 ..
1570 } => {
1571 let start = (*methods_start + extra_offset) as usize;
1572 for i in 0..*methods_len as usize {
1573 extra[start + i] += inst_offset;
1574 }
1575 }
1576
1577 InstData::AnonStructType {
1579 methods_start,
1580 methods_len,
1581 ..
1582 } => {
1583 let start = (*methods_start + extra_offset) as usize;
1584 for i in 0..*methods_len as usize {
1585 extra[start + i] += inst_offset;
1586 }
1587 }
1588
1589 InstData::AnonEnumType {
1591 methods_start,
1592 methods_len,
1593 ..
1594 } => {
1595 let start = (*methods_start + extra_offset) as usize;
1596 for i in 0..*methods_len as usize {
1597 extra[start + i] += inst_offset;
1598 }
1599 }
1600
1601 InstData::Call {
1603 args_start,
1604 args_len,
1605 ..
1606 }
1607 | InstData::MethodCall {
1608 args_start,
1609 args_len,
1610 ..
1611 }
1612 | InstData::AssocFnCall {
1613 args_start,
1614 args_len,
1615 ..
1616 } => {
1617 let start = (*args_start + extra_offset) as usize;
1618 for i in 0..*args_len as usize {
1619 extra[start + i * 2] += inst_offset;
1621 }
1622 }
1623
1624 InstData::StructInit {
1626 fields_start,
1627 fields_len,
1628 ..
1629 }
1630 | InstData::EnumStructVariant {
1631 fields_start,
1632 fields_len,
1633 ..
1634 } => {
1635 let start = (*fields_start + extra_offset) as usize;
1636 for i in 0..*fields_len as usize {
1637 extra[start + i * 2 + 1] += inst_offset;
1639 }
1640 }
1641
1642 InstData::Match {
1644 arms_start,
1645 arms_len,
1646 ..
1647 } => {
1648 let mut pos = (*arms_start + extra_offset) as usize;
1649 for _ in 0..*arms_len {
1650 let kind = extra[pos];
1651 let pattern_size = match kind {
1652 k if k == PatternKind::Wildcard as u32 => {
1653 PATTERN_WILDCARD_SIZE as usize
1654 }
1655 k if k == PatternKind::Int as u32 => PATTERN_INT_SIZE as usize,
1656 k if k == PatternKind::Bool as u32 => PATTERN_BOOL_SIZE as usize,
1657 k if k == PatternKind::Path as u32 => PATTERN_PATH_SIZE as usize,
1658 _ => panic!("Unknown pattern kind during merge: {}", kind),
1659 };
1660 extra[pos + pattern_size - 1] += inst_offset;
1662 pos += pattern_size;
1663 }
1664 }
1665
1666 InstData::IntConst(_)
1668 | InstData::FloatConst(_)
1669 | InstData::BoolConst(_)
1670 | InstData::StringConst(_)
1671 | InstData::UnitConst
1672 | InstData::Add { .. }
1673 | InstData::Sub { .. }
1674 | InstData::Mul { .. }
1675 | InstData::Div { .. }
1676 | InstData::Mod { .. }
1677 | InstData::Eq { .. }
1678 | InstData::Ne { .. }
1679 | InstData::Lt { .. }
1680 | InstData::Gt { .. }
1681 | InstData::Le { .. }
1682 | InstData::Ge { .. }
1683 | InstData::And { .. }
1684 | InstData::Or { .. }
1685 | InstData::BitAnd { .. }
1686 | InstData::BitOr { .. }
1687 | InstData::BitXor { .. }
1688 | InstData::Shl { .. }
1689 | InstData::Shr { .. }
1690 | InstData::Neg { .. }
1691 | InstData::Not { .. }
1692 | InstData::BitNot { .. }
1693 | InstData::Branch { .. }
1694 | InstData::Loop { .. }
1695 | InstData::For { .. }
1696 | InstData::InfiniteLoop { .. }
1697 | InstData::Break
1698 | InstData::Continue
1699 | InstData::Ret(_)
1700 | InstData::VarRef { .. }
1701 | InstData::ParamRef { .. }
1702 | InstData::Alloc { .. }
1703 | InstData::Assign { .. }
1704 | InstData::FnDecl { .. }
1705 | InstData::ConstDecl { .. }
1706 | InstData::FieldGet { .. }
1707 | InstData::FieldSet { .. }
1708 | InstData::EnumDecl { .. }
1709 | InstData::EnumVariant { .. }
1710 | InstData::IndexGet { .. }
1711 | InstData::IndexSet { .. }
1712 | InstData::TypeIntrinsic { .. }
1713 | InstData::DropFnDecl { .. }
1714 | InstData::Comptime { .. }
1715 | InstData::ComptimeUnrollFor { .. }
1716 | InstData::Checked { .. }
1717 | InstData::TypeConst { .. }
1718 | InstData::StructDestructure { .. } => {}
1719 }
1720 }
1721 }
1722}
1723
1724#[derive(Debug, Clone)]
1726pub struct Inst {
1727 pub data: InstData,
1728 pub span: Span,
1729}
1730
1731#[derive(Debug, Clone)]
1733pub enum InstData {
1734 IntConst(u64),
1736
1737 FloatConst(u64),
1740
1741 BoolConst(bool),
1743
1744 StringConst(Spur),
1746
1747 UnitConst,
1749
1750 Add { lhs: InstRef, rhs: InstRef },
1753 Sub { lhs: InstRef, rhs: InstRef },
1755 Mul { lhs: InstRef, rhs: InstRef },
1757 Div { lhs: InstRef, rhs: InstRef },
1759 Mod { lhs: InstRef, rhs: InstRef },
1761
1762 Eq { lhs: InstRef, rhs: InstRef },
1765 Ne { lhs: InstRef, rhs: InstRef },
1767 Lt { lhs: InstRef, rhs: InstRef },
1769 Gt { lhs: InstRef, rhs: InstRef },
1771 Le { lhs: InstRef, rhs: InstRef },
1773 Ge { lhs: InstRef, rhs: InstRef },
1775
1776 And { lhs: InstRef, rhs: InstRef },
1779 Or { lhs: InstRef, rhs: InstRef },
1781
1782 BitAnd { lhs: InstRef, rhs: InstRef },
1785 BitOr { lhs: InstRef, rhs: InstRef },
1787 BitXor { lhs: InstRef, rhs: InstRef },
1789 Shl { lhs: InstRef, rhs: InstRef },
1791 Shr { lhs: InstRef, rhs: InstRef },
1793
1794 Neg { operand: InstRef },
1797 Not { operand: InstRef },
1799 BitNot { operand: InstRef },
1801
1802 Branch {
1805 cond: InstRef,
1806 then_block: InstRef,
1807 else_block: Option<InstRef>,
1808 },
1809
1810 Loop { cond: InstRef, body: InstRef },
1812
1813 For {
1815 binding: Spur,
1817 is_mut: bool,
1819 iterable: InstRef,
1821 body: InstRef,
1823 },
1824
1825 InfiniteLoop { body: InstRef },
1827
1828 Match {
1831 scrutinee: InstRef,
1833 arms_start: u32,
1835 arms_len: u32,
1837 },
1838
1839 Break,
1841
1842 Continue,
1844
1845 FnDecl {
1849 directives_start: u32,
1851 directives_len: u32,
1853 is_pub: bool,
1855 is_unchecked: bool,
1857 name: Spur,
1858 params_start: u32,
1860 params_len: u32,
1862 return_type: Spur,
1863 body: InstRef,
1864 has_self: bool,
1868 },
1869
1870 ConstDecl {
1875 directives_start: u32,
1877 directives_len: u32,
1879 is_pub: bool,
1881 name: Spur,
1883 ty: Option<Spur>,
1885 init: InstRef,
1887 },
1888
1889 Call {
1892 name: Spur,
1894 args_start: u32,
1896 args_len: u32,
1898 },
1899
1900 Intrinsic {
1903 name: Spur,
1905 args_start: u32,
1907 args_len: u32,
1909 },
1910
1911 TypeIntrinsic {
1913 name: Spur,
1915 type_arg: Spur,
1917 },
1918
1919 ParamRef {
1921 index: u32,
1923 name: Spur,
1925 },
1926
1927 Ret(Option<InstRef>),
1929
1930 Block {
1933 extra_start: u32,
1935 len: u32,
1937 },
1938
1939 Alloc {
1944 directives_start: u32,
1946 directives_len: u32,
1948 name: Option<Spur>,
1950 is_mut: bool,
1952 ty: Option<Spur>,
1954 init: InstRef,
1956 },
1957
1958 StructDestructure {
1962 type_name: Spur,
1964 fields_start: u32,
1966 fields_len: u32,
1968 init: InstRef,
1970 },
1971
1972 VarRef {
1974 name: Spur,
1976 },
1977
1978 Assign {
1980 name: Spur,
1982 value: InstRef,
1984 },
1985
1986 StructDecl {
1990 directives_start: u32,
1992 directives_len: u32,
1994 is_pub: bool,
1996 is_linear: bool,
1998 name: Spur,
2000 fields_start: u32,
2002 fields_len: u32,
2004 methods_start: u32,
2006 methods_len: u32,
2008 },
2009
2010 StructInit {
2013 module: Option<InstRef>,
2016 type_name: Spur,
2018 fields_start: u32,
2020 fields_len: u32,
2022 },
2023
2024 FieldGet {
2026 base: InstRef,
2028 field: Spur,
2030 },
2031
2032 FieldSet {
2034 base: InstRef,
2036 field: Spur,
2038 value: InstRef,
2040 },
2041
2042 EnumDecl {
2047 is_pub: bool,
2049 name: Spur,
2051 variants_start: u32,
2053 variants_len: u32,
2055 },
2056
2057 EnumVariant {
2059 module: Option<InstRef>,
2062 type_name: Spur,
2064 variant: Spur,
2066 },
2067
2068 EnumStructVariant {
2071 module: Option<InstRef>,
2073 type_name: Spur,
2075 variant: Spur,
2077 fields_start: u32,
2079 fields_len: u32,
2081 },
2082
2083 ArrayInit {
2087 elems_start: u32,
2089 elems_len: u32,
2091 },
2092
2093 IndexGet {
2095 base: InstRef,
2097 index: InstRef,
2099 },
2100
2101 IndexSet {
2103 base: InstRef,
2105 index: InstRef,
2107 value: InstRef,
2109 },
2110
2111 MethodCall {
2115 receiver: InstRef,
2117 method: Spur,
2119 args_start: u32,
2121 args_len: u32,
2123 },
2124
2125 AssocFnCall {
2128 type_name: Spur,
2130 function: Spur,
2132 args_start: u32,
2134 args_len: u32,
2136 },
2137
2138 DropFnDecl {
2140 type_name: Spur,
2142 body: InstRef,
2144 },
2145
2146 Comptime {
2149 expr: InstRef,
2151 },
2152
2153 ComptimeUnrollFor {
2157 binding: Spur,
2159 iterable: InstRef,
2161 body: InstRef,
2163 },
2164
2165 Checked {
2169 expr: InstRef,
2171 },
2172
2173 TypeConst {
2176 type_name: Spur,
2178 },
2179
2180 AnonStructType {
2185 fields_start: u32,
2187 fields_len: u32,
2189 methods_start: u32,
2191 methods_len: u32,
2193 },
2194
2195 AnonEnumType {
2200 variants_start: u32,
2202 variants_len: u32,
2204 methods_start: u32,
2206 methods_len: u32,
2208 },
2209}
2210
2211impl fmt::Display for InstRef {
2212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2213 write!(f, "%{}", self.0)
2214 }
2215}
2216
2217pub struct RirPrinter<'a, 'b> {
2219 rir: &'a Rir,
2220 interner: &'b lasso::ThreadedRodeo,
2221}
2222
2223impl<'a, 'b> RirPrinter<'a, 'b> {
2224 pub fn new(rir: &'a Rir, interner: &'b lasso::ThreadedRodeo) -> Self {
2226 Self { rir, interner }
2227 }
2228
2229 fn format_call_arg(arg: &RirCallArg) -> String {
2231 match arg.mode {
2232 RirArgMode::Inout => format!("inout {}", arg.value),
2233 RirArgMode::Borrow => format!("borrow {}", arg.value),
2234 RirArgMode::Normal => format!("{}", arg.value),
2235 }
2236 }
2237
2238 fn format_call_args(args: &[RirCallArg]) -> String {
2240 args.iter()
2241 .map(Self::format_call_arg)
2242 .collect::<Vec<_>>()
2243 .join(", ")
2244 }
2245
2246 fn format_pattern(&self, pat: &RirPattern) -> String {
2248 match pat {
2249 RirPattern::Wildcard(_) => "_".to_string(),
2250 RirPattern::Int(n, _) => n.to_string(),
2251 RirPattern::Bool(b, _) => b.to_string(),
2252 RirPattern::Path {
2253 module,
2254 type_name,
2255 variant,
2256 ..
2257 } => {
2258 let prefix = if let Some(module_ref) = module {
2259 format!("%{}..", module_ref.as_u32())
2260 } else {
2261 String::new()
2262 };
2263 format!(
2264 "{}{}::{}",
2265 prefix,
2266 self.interner.resolve(type_name),
2267 self.interner.resolve(variant)
2268 )
2269 }
2270 RirPattern::DataVariant {
2271 module,
2272 type_name,
2273 variant,
2274 bindings,
2275 ..
2276 } => {
2277 let prefix = if let Some(module_ref) = module {
2278 format!("%{}..", module_ref.as_u32())
2279 } else {
2280 String::new()
2281 };
2282 let binding_strs: Vec<String> = bindings
2283 .iter()
2284 .map(|b| {
2285 if b.is_wildcard {
2286 "_".to_string()
2287 } else {
2288 let name = b
2289 .name
2290 .map(|s| self.interner.resolve(&s).to_string())
2291 .unwrap_or_else(|| "_".to_string());
2292 if b.is_mut {
2293 format!("mut {}", name)
2294 } else {
2295 name
2296 }
2297 }
2298 })
2299 .collect();
2300 format!(
2301 "{}{}::{}({})",
2302 prefix,
2303 self.interner.resolve(type_name),
2304 self.interner.resolve(variant),
2305 binding_strs.join(", ")
2306 )
2307 }
2308 RirPattern::StructVariant {
2309 module,
2310 type_name,
2311 variant,
2312 field_bindings,
2313 ..
2314 } => {
2315 let prefix = if let Some(module_ref) = module {
2316 format!("%{}..", module_ref.as_u32())
2317 } else {
2318 String::new()
2319 };
2320 let field_strs: Vec<String> = field_bindings
2321 .iter()
2322 .map(|fb| {
2323 let field = self.interner.resolve(&fb.field_name);
2324 if fb.binding.is_wildcard {
2325 format!("{}: _", field)
2326 } else {
2327 let name = fb
2328 .binding
2329 .name
2330 .map(|s| self.interner.resolve(&s).to_string())
2331 .unwrap_or_else(|| "_".to_string());
2332 if fb.binding.is_mut {
2333 format!("{}: mut {}", field, name)
2334 } else if name == field {
2335 field.to_string()
2336 } else {
2337 format!("{}: {}", field, name)
2338 }
2339 }
2340 })
2341 .collect();
2342 format!(
2343 "{}{}::{} {{ {} }}",
2344 prefix,
2345 self.interner.resolve(type_name),
2346 self.interner.resolve(variant),
2347 field_strs.join(", ")
2348 )
2349 }
2350 }
2351 }
2352
2353 pub fn render(&self) -> String {
2355 use std::fmt::Write;
2356
2357 let mut out = String::new();
2358 for (inst_ref, inst) in self.rir.iter() {
2359 write!(out, "{} = ", inst_ref).unwrap();
2360 match &inst.data {
2361 InstData::IntConst(v) => writeln!(out, "const {}", v).unwrap(),
2363 InstData::FloatConst(bits) => {
2364 writeln!(out, "const {}", f64::from_bits(*bits)).unwrap()
2365 }
2366 InstData::BoolConst(v) => writeln!(out, "const {}", v).unwrap(),
2367 InstData::StringConst(s) => {
2368 writeln!(out, "const {:?}", self.interner.resolve(s)).unwrap()
2369 }
2370 InstData::UnitConst => writeln!(out, "const ()").unwrap(),
2371
2372 InstData::Add { lhs, rhs } => writeln!(out, "add {}, {}", lhs, rhs).unwrap(),
2374 InstData::Sub { lhs, rhs } => writeln!(out, "sub {}, {}", lhs, rhs).unwrap(),
2375 InstData::Mul { lhs, rhs } => writeln!(out, "mul {}, {}", lhs, rhs).unwrap(),
2376 InstData::Div { lhs, rhs } => writeln!(out, "div {}, {}", lhs, rhs).unwrap(),
2377 InstData::Mod { lhs, rhs } => writeln!(out, "mod {}, {}", lhs, rhs).unwrap(),
2378 InstData::Eq { lhs, rhs } => writeln!(out, "eq {}, {}", lhs, rhs).unwrap(),
2379 InstData::Ne { lhs, rhs } => writeln!(out, "ne {}, {}", lhs, rhs).unwrap(),
2380 InstData::Lt { lhs, rhs } => writeln!(out, "lt {}, {}", lhs, rhs).unwrap(),
2381 InstData::Gt { lhs, rhs } => writeln!(out, "gt {}, {}", lhs, rhs).unwrap(),
2382 InstData::Le { lhs, rhs } => writeln!(out, "le {}, {}", lhs, rhs).unwrap(),
2383 InstData::Ge { lhs, rhs } => writeln!(out, "ge {}, {}", lhs, rhs).unwrap(),
2384 InstData::And { lhs, rhs } => writeln!(out, "and {}, {}", lhs, rhs).unwrap(),
2385 InstData::Or { lhs, rhs } => writeln!(out, "or {}, {}", lhs, rhs).unwrap(),
2386 InstData::BitAnd { lhs, rhs } => writeln!(out, "bit_and {}, {}", lhs, rhs).unwrap(),
2387 InstData::BitOr { lhs, rhs } => writeln!(out, "bit_or {}, {}", lhs, rhs).unwrap(),
2388 InstData::BitXor { lhs, rhs } => writeln!(out, "bit_xor {}, {}", lhs, rhs).unwrap(),
2389 InstData::Shl { lhs, rhs } => writeln!(out, "shl {}, {}", lhs, rhs).unwrap(),
2390 InstData::Shr { lhs, rhs } => writeln!(out, "shr {}, {}", lhs, rhs).unwrap(),
2391
2392 InstData::Neg { operand } => writeln!(out, "neg {}", operand).unwrap(),
2394 InstData::Not { operand } => writeln!(out, "not {}", operand).unwrap(),
2395 InstData::BitNot { operand } => writeln!(out, "bit_not {}", operand).unwrap(),
2396
2397 InstData::Branch {
2399 cond,
2400 then_block,
2401 else_block,
2402 } => {
2403 if let Some(else_b) = else_block {
2404 writeln!(out, "branch {}, {}, {}", cond, then_block, else_b).unwrap();
2405 } else {
2406 writeln!(out, "branch {}, {}", cond, then_block).unwrap();
2407 }
2408 }
2409 InstData::Loop { cond, body } => writeln!(out, "loop {}, {}", cond, body).unwrap(),
2410 InstData::For {
2411 binding,
2412 is_mut,
2413 iterable,
2414 body,
2415 } => {
2416 let mut_str = if *is_mut { "mut " } else { "" };
2417 writeln!(
2418 out,
2419 "for {}{} in {}, {}",
2420 mut_str,
2421 self.interner.resolve(binding),
2422 iterable,
2423 body
2424 )
2425 .unwrap()
2426 }
2427 InstData::InfiniteLoop { body } => writeln!(out, "infinite_loop {}", body).unwrap(),
2428 InstData::Match {
2429 scrutinee,
2430 arms_start,
2431 arms_len,
2432 } => {
2433 let arms = self.rir.get_match_arms(*arms_start, *arms_len);
2434 let arms_str: Vec<String> = arms
2435 .iter()
2436 .map(|(pat, body)| format!("{} => {}", self.format_pattern(pat), body))
2437 .collect();
2438 writeln!(out, "match {} {{ {} }}", scrutinee, arms_str.join(", ")).unwrap();
2439 }
2440 InstData::Break => writeln!(out, "break").unwrap(),
2441 InstData::Continue => writeln!(out, "continue").unwrap(),
2442
2443 InstData::FnDecl {
2445 directives_start: _,
2446 directives_len: _,
2447 is_pub,
2448 is_unchecked,
2449 name,
2450 params_start,
2451 params_len,
2452 return_type,
2453 body,
2454 has_self,
2455 } => {
2456 let pub_str = if *is_pub { "pub " } else { "" };
2457 let unchecked_str = if *is_unchecked { "unchecked " } else { "" };
2458 let name_str = self.interner.resolve(name);
2459 let ret_str = self.interner.resolve(return_type);
2460 let self_str = if *has_self { "self, " } else { "" };
2461 let params = self.rir.get_params(*params_start, *params_len);
2462 let params_str: Vec<String> = params
2463 .iter()
2464 .map(|p| {
2465 let mode_prefix = match p.mode {
2466 RirParamMode::Inout => "inout ",
2467 RirParamMode::Borrow => "borrow ",
2468 RirParamMode::Comptime => "comptime ",
2469 RirParamMode::Normal => "",
2470 };
2471 format!(
2472 "{}{}: {}",
2473 mode_prefix,
2474 self.interner.resolve(&p.name),
2475 self.interner.resolve(&p.ty)
2476 )
2477 })
2478 .collect();
2479 writeln!(
2480 out,
2481 "{}{}fn {}({}{}) -> {} {{",
2482 pub_str,
2483 unchecked_str,
2484 name_str,
2485 self_str,
2486 params_str.join(", "),
2487 ret_str
2488 )
2489 .unwrap();
2490 writeln!(out, " {}", body).unwrap();
2491 writeln!(out, "}}").unwrap();
2492 }
2493 InstData::ConstDecl {
2494 directives_start: _,
2495 directives_len: _,
2496 is_pub,
2497 name,
2498 ty,
2499 init,
2500 } => {
2501 let pub_str = if *is_pub { "pub " } else { "" };
2502 let name_str = self.interner.resolve(name);
2503 let ty_str = ty
2504 .map(|t| format!(": {}", self.interner.resolve(&t)))
2505 .unwrap_or_default();
2506 writeln!(out, "{}const {}{} = {}", pub_str, name_str, ty_str, init).unwrap();
2507 }
2508 InstData::Ret(inner) => {
2509 if let Some(inner) = inner {
2510 writeln!(out, "ret {}", inner).unwrap();
2511 } else {
2512 writeln!(out, "ret").unwrap();
2513 }
2514 }
2515 InstData::Call {
2516 name,
2517 args_start,
2518 args_len,
2519 } => {
2520 let name_str = self.interner.resolve(name);
2521 let args = self.rir.get_call_args(*args_start, *args_len);
2522 writeln!(out, "call {}({})", name_str, Self::format_call_args(&args)).unwrap();
2523 }
2524 InstData::Intrinsic {
2525 name,
2526 args_start,
2527 args_len,
2528 } => {
2529 let name_str = self.interner.resolve(name);
2530 let args = self.rir.get_inst_refs(*args_start, *args_len);
2531 let args_str: Vec<String> = args.iter().map(|a| format!("{}", a)).collect();
2532 writeln!(out, "intrinsic @{}({})", name_str, args_str.join(", ")).unwrap();
2533 }
2534 InstData::TypeIntrinsic { name, type_arg } => {
2535 let name_str = self.interner.resolve(name);
2536 let type_str = self.interner.resolve(type_arg);
2537 writeln!(out, "type_intrinsic @{}({})", name_str, type_str).unwrap();
2538 }
2539 InstData::ParamRef { index, name } => {
2540 writeln!(out, "param {} ({})", index, self.interner.resolve(name)).unwrap();
2541 }
2542 InstData::Block { extra_start, len } => {
2543 writeln!(out, "block({}, {})", extra_start, len).unwrap();
2544 }
2545
2546 InstData::Alloc {
2548 directives_start: _,
2549 directives_len: _,
2550 name,
2551 is_mut,
2552 ty,
2553 init,
2554 } => {
2555 let name_str = name
2556 .map(|n| self.interner.resolve(&n).to_string())
2557 .unwrap_or_else(|| "_".to_string());
2558 let mut_str = if *is_mut { "mut " } else { "" };
2559 let ty_str = ty
2560 .map(|t| format!(": {}", self.interner.resolve(&t)))
2561 .unwrap_or_default();
2562 writeln!(out, "alloc {}{}{}= {}", mut_str, name_str, ty_str, init).unwrap();
2563 }
2564 InstData::StructDestructure {
2565 type_name,
2566 fields_start,
2567 fields_len,
2568 init,
2569 } => {
2570 let type_str = self.interner.resolve(type_name);
2571 let fields = self.rir.get_destructure_fields(*fields_start, *fields_len);
2572 let field_strs: Vec<String> = fields
2573 .iter()
2574 .map(|f| {
2575 let name = self.interner.resolve(&f.field_name);
2576 if f.is_wildcard {
2577 format!("{}: _", name)
2578 } else if let Some(binding) = f.binding_name {
2579 let binding_str = self.interner.resolve(&binding);
2580 format!("{}: {}", name, binding_str)
2581 } else {
2582 name.to_string()
2583 }
2584 })
2585 .collect();
2586 writeln!(
2587 out,
2588 "destructure {} {{ {} }} = {}",
2589 type_str,
2590 field_strs.join(", "),
2591 init
2592 )
2593 .unwrap();
2594 }
2595 InstData::VarRef { name } => {
2596 writeln!(out, "var_ref {}", self.interner.resolve(name)).unwrap();
2597 }
2598 InstData::Assign { name, value } => {
2599 writeln!(out, "assign {} = {}", self.interner.resolve(name), value).unwrap();
2600 }
2601
2602 InstData::StructDecl {
2604 directives_start,
2605 directives_len,
2606 is_pub,
2607 is_linear,
2608 name,
2609 fields_start,
2610 fields_len,
2611 methods_start,
2612 methods_len,
2613 } => {
2614 let pub_str = if *is_pub { "pub " } else { "" };
2615 let name_str = self.interner.resolve(name);
2616 let fields = self.rir.get_field_decls(*fields_start, *fields_len);
2617 let fields_str: Vec<String> = fields
2618 .iter()
2619 .map(|(fname, ftype)| {
2620 format!(
2621 "{}: {}",
2622 self.interner.resolve(fname),
2623 self.interner.resolve(ftype)
2624 )
2625 })
2626 .collect();
2627 let directives = self.rir.get_directives(*directives_start, *directives_len);
2628 let linear_str = if *is_linear { "linear " } else { "" };
2629 let directives_str = if directives.is_empty() {
2630 String::new()
2631 } else {
2632 let dir_names: Vec<String> = directives
2633 .iter()
2634 .map(|d| format!("@{}", self.interner.resolve(&d.name)))
2635 .collect();
2636 format!("{} ", dir_names.join(" "))
2637 };
2638 let methods = self.rir.get_inst_refs(*methods_start, *methods_len);
2639 let methods_str = if methods.is_empty() {
2640 String::new()
2641 } else {
2642 let method_refs: Vec<String> =
2643 methods.iter().map(|m| format!("{}", m)).collect();
2644 format!(" methods: [{}]", method_refs.join(", "))
2645 };
2646 writeln!(
2647 out,
2648 "{}{}{}struct {} {{ {} }}{}",
2649 directives_str,
2650 pub_str,
2651 linear_str,
2652 name_str,
2653 fields_str.join(", "),
2654 methods_str
2655 )
2656 .unwrap();
2657 }
2658 InstData::StructInit {
2659 module,
2660 type_name,
2661 fields_start,
2662 fields_len,
2663 } => {
2664 let module_str = module.map(|m| format!("{}.", m)).unwrap_or_default();
2665 let type_str = self.interner.resolve(type_name);
2666 let fields = self.rir.get_field_inits(*fields_start, *fields_len);
2667 let fields_str: Vec<String> = fields
2668 .iter()
2669 .map(|(fname, value)| {
2670 format!("{}: {}", self.interner.resolve(fname), value)
2671 })
2672 .collect();
2673 writeln!(
2674 out,
2675 "struct_init {}{} {{ {} }}",
2676 module_str,
2677 type_str,
2678 fields_str.join(", ")
2679 )
2680 .unwrap();
2681 }
2682 InstData::FieldGet { base, field } => {
2683 writeln!(out, "field_get {}.{}", base, self.interner.resolve(field)).unwrap();
2684 }
2685 InstData::FieldSet { base, field, value } => {
2686 writeln!(
2687 out,
2688 "field_set {}.{} = {}",
2689 base,
2690 self.interner.resolve(field),
2691 value
2692 )
2693 .unwrap();
2694 }
2695
2696 InstData::EnumDecl {
2698 is_pub,
2699 name,
2700 variants_start,
2701 variants_len,
2702 } => {
2703 let pub_str = if *is_pub { "pub " } else { "" };
2704 let name_str = self.interner.resolve(name);
2705 let variants = self
2706 .rir
2707 .get_enum_variant_decls(*variants_start, *variants_len);
2708 let variants_str: Vec<String> = variants
2709 .iter()
2710 .map(|(v, field_types, field_names)| {
2711 let vname = self.interner.resolve(v).to_string();
2712 if field_types.is_empty() {
2713 vname
2714 } else if field_names.is_empty() {
2715 let field_strs: Vec<&str> = field_types
2717 .iter()
2718 .map(|f| self.interner.resolve(f))
2719 .collect();
2720 format!("{}({})", vname, field_strs.join(", "))
2721 } else {
2722 let field_strs: Vec<String> = field_names
2724 .iter()
2725 .zip(field_types.iter())
2726 .map(|(n, t)| {
2727 format!(
2728 "{}: {}",
2729 self.interner.resolve(n),
2730 self.interner.resolve(t)
2731 )
2732 })
2733 .collect();
2734 format!("{} {{ {} }}", vname, field_strs.join(", "))
2735 }
2736 })
2737 .collect();
2738 writeln!(
2739 out,
2740 "{}enum {} {{ {} }}",
2741 pub_str,
2742 name_str,
2743 variants_str.join(", ")
2744 )
2745 .unwrap();
2746 }
2747 InstData::EnumVariant {
2748 module,
2749 type_name,
2750 variant,
2751 } => {
2752 let module_str = module.map(|m| format!("{}.", m)).unwrap_or_default();
2753 writeln!(
2754 out,
2755 "enum_variant {}{}::{}",
2756 module_str,
2757 self.interner.resolve(type_name),
2758 self.interner.resolve(variant)
2759 )
2760 .unwrap();
2761 }
2762 InstData::EnumStructVariant {
2763 module,
2764 type_name,
2765 variant,
2766 fields_start,
2767 fields_len,
2768 } => {
2769 let module_str = module.map(|m| format!("{}.", m)).unwrap_or_default();
2770 let fields = self.rir.get_field_inits(*fields_start, *fields_len);
2771 let field_strs: Vec<String> = fields
2772 .iter()
2773 .map(|(name, value)| format!("{}: {}", self.interner.resolve(name), value))
2774 .collect();
2775 writeln!(
2776 out,
2777 "enum_struct_variant {}{}::{} {{ {} }}",
2778 module_str,
2779 self.interner.resolve(type_name),
2780 self.interner.resolve(variant),
2781 field_strs.join(", ")
2782 )
2783 .unwrap();
2784 }
2785
2786 InstData::ArrayInit {
2788 elems_start,
2789 elems_len,
2790 } => {
2791 let elements = self.rir.get_inst_refs(*elems_start, *elems_len);
2792 let elems_str: Vec<String> =
2793 elements.iter().map(|e| format!("{}", e)).collect();
2794 writeln!(out, "array_init [{}]", elems_str.join(", ")).unwrap();
2795 }
2796 InstData::IndexGet { base, index } => {
2797 writeln!(out, "index_get {}[{}]", base, index).unwrap();
2798 }
2799 InstData::IndexSet { base, index, value } => {
2800 writeln!(out, "index_set {}[{}] = {}", base, index, value).unwrap();
2801 }
2802
2803 InstData::MethodCall {
2805 receiver,
2806 method,
2807 args_start,
2808 args_len,
2809 } => {
2810 let args = self.rir.get_call_args(*args_start, *args_len);
2811 writeln!(
2812 out,
2813 "method_call {}.{}({})",
2814 receiver,
2815 self.interner.resolve(method),
2816 Self::format_call_args(&args)
2817 )
2818 .unwrap();
2819 }
2820 InstData::AssocFnCall {
2821 type_name,
2822 function,
2823 args_start,
2824 args_len,
2825 } => {
2826 let args = self.rir.get_call_args(*args_start, *args_len);
2827 writeln!(
2828 out,
2829 "assoc_fn_call {}::{}({})",
2830 self.interner.resolve(type_name),
2831 self.interner.resolve(function),
2832 Self::format_call_args(&args)
2833 )
2834 .unwrap();
2835 }
2836
2837 InstData::DropFnDecl { type_name, body } => {
2839 writeln!(out, "drop fn {}(self) {{", self.interner.resolve(type_name)).unwrap();
2840 writeln!(out, " {}", body).unwrap();
2841 writeln!(out, "}}").unwrap();
2842 }
2843
2844 InstData::Comptime { expr } => {
2846 writeln!(out, "comptime {{ {} }}", expr).unwrap();
2847 }
2848
2849 InstData::ComptimeUnrollFor {
2851 binding,
2852 iterable,
2853 body,
2854 } => writeln!(
2855 out,
2856 "comptime_unroll for {} in {}, {}",
2857 self.interner.resolve(binding),
2858 iterable,
2859 body
2860 )
2861 .unwrap(),
2862
2863 InstData::Checked { expr } => {
2865 writeln!(out, "checked {{ {} }}", expr).unwrap();
2866 }
2867
2868 InstData::TypeConst { type_name } => {
2870 let name = self.interner.resolve(type_name);
2871 writeln!(out, "type {}", name).unwrap();
2872 }
2873
2874 InstData::AnonStructType {
2876 fields_start,
2877 fields_len,
2878 methods_start,
2879 methods_len,
2880 } => {
2881 write!(out, "struct {{ ").unwrap();
2882 let fields = self.rir.get_field_decls(*fields_start, *fields_len);
2883 for (i, (name, ty)) in fields.iter().enumerate() {
2884 if i > 0 {
2885 write!(out, ", ").unwrap();
2886 }
2887 let name_str = self.interner.resolve(name);
2888 let ty_str = self.interner.resolve(ty);
2889 write!(out, "{}: {}", name_str, ty_str).unwrap();
2890 }
2891 if *methods_len > 0 {
2893 let methods = self.rir.get_inst_refs(*methods_start, *methods_len);
2894 let methods_str: Vec<String> =
2895 methods.iter().map(|m| format!("{}", m)).collect();
2896 if !fields.is_empty() {
2897 write!(out, ", ").unwrap();
2898 }
2899 write!(out, "methods: [{}]", methods_str.join(", ")).unwrap();
2900 }
2901 writeln!(out, " }}").unwrap();
2902 }
2903
2904 InstData::AnonEnumType {
2906 variants_start,
2907 variants_len,
2908 methods_start,
2909 methods_len,
2910 } => {
2911 write!(out, "enum {{ ").unwrap();
2912 let variants = self
2913 .rir
2914 .get_enum_variant_decls(*variants_start, *variants_len);
2915 let variants_str: Vec<String> = variants
2916 .iter()
2917 .map(|(v, field_types, field_names)| {
2918 let vname = self.interner.resolve(v).to_string();
2919 if field_types.is_empty() {
2920 vname
2921 } else if field_names.is_empty() {
2922 let field_strs: Vec<&str> = field_types
2923 .iter()
2924 .map(|f| self.interner.resolve(f))
2925 .collect();
2926 format!("{}({})", vname, field_strs.join(", "))
2927 } else {
2928 let field_strs: Vec<String> = field_names
2929 .iter()
2930 .zip(field_types.iter())
2931 .map(|(n, t)| {
2932 format!(
2933 "{}: {}",
2934 self.interner.resolve(n),
2935 self.interner.resolve(t)
2936 )
2937 })
2938 .collect();
2939 format!("{} {{ {} }}", vname, field_strs.join(", "))
2940 }
2941 })
2942 .collect();
2943 write!(out, "{}", variants_str.join(", ")).unwrap();
2944 if *methods_len > 0 {
2945 let methods = self.rir.get_inst_refs(*methods_start, *methods_len);
2946 let methods_str: Vec<String> =
2947 methods.iter().map(|m| format!("{}", m)).collect();
2948 if !variants_str.is_empty() {
2949 write!(out, ", ").unwrap();
2950 }
2951 write!(out, "methods: [{}]", methods_str.join(", ")).unwrap();
2952 }
2953 writeln!(out, " }}").unwrap();
2954 }
2955 }
2956 }
2957 out
2958 }
2959}
2960
2961impl fmt::Display for RirPrinter<'_, '_> {
2962 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2963 write!(f, "{}", self.render())
2964 }
2965}
2966
2967#[cfg(test)]
2968mod tests {
2969 use super::*;
2970 use lasso::ThreadedRodeo;
2971
2972 #[test]
2973 fn test_inst_ref_size() {
2974 assert_eq!(std::mem::size_of::<InstRef>(), 4);
2975 }
2976
2977 #[test]
2978 fn test_add_and_get_inst() {
2979 let mut rir = Rir::new();
2980 let inst = Inst {
2981 data: InstData::IntConst(42),
2982 span: Span::new(0, 2),
2983 };
2984 let inst_ref = rir.add_inst(inst);
2985
2986 let retrieved = rir.get(inst_ref);
2987 assert!(matches!(retrieved.data, InstData::IntConst(42)));
2988 }
2989
2990 #[test]
2991 fn test_rir_is_empty() {
2992 let rir = Rir::new();
2993 assert!(rir.is_empty());
2994 assert_eq!(rir.len(), 0);
2995 }
2996
2997 #[test]
2998 fn test_rir_extra_data() {
2999 let mut rir = Rir::new();
3000 let data = [1, 2, 3, 4, 5];
3001 let start = rir.add_extra(&data);
3002 assert_eq!(start, 0);
3003
3004 let retrieved = rir.get_extra(start, 5);
3005 assert_eq!(retrieved, &data);
3006
3007 let data2 = [10, 20];
3009 let start2 = rir.add_extra(&data2);
3010 assert_eq!(start2, 5);
3011 }
3012
3013 #[test]
3014 fn test_rir_iter() {
3015 let mut rir = Rir::new();
3016 rir.add_inst(Inst {
3017 data: InstData::IntConst(1),
3018 span: Span::new(0, 1),
3019 });
3020 rir.add_inst(Inst {
3021 data: InstData::IntConst(2),
3022 span: Span::new(2, 3),
3023 });
3024
3025 let items: Vec<_> = rir.iter().collect();
3026 assert_eq!(items.len(), 2);
3027 assert_eq!(items[0].0.as_u32(), 0);
3028 assert_eq!(items[1].0.as_u32(), 1);
3029 }
3030
3031 #[test]
3032 fn test_inst_ref_display() {
3033 let inst_ref = InstRef::from_raw(42);
3034 assert_eq!(format!("{}", inst_ref), "%42");
3035 }
3036
3037 #[test]
3039 fn test_rir_pattern_wildcard_span() {
3040 let span = Span::new(10, 11);
3041 let pattern = RirPattern::Wildcard(span);
3042 assert_eq!(pattern.span(), span);
3043 }
3044
3045 #[test]
3046 fn test_rir_pattern_int_span() {
3047 let span = Span::new(20, 22);
3048 let pattern = RirPattern::Int(42, span);
3049 assert_eq!(pattern.span(), span);
3050
3051 let pattern_neg = RirPattern::Int(-100, span);
3053 assert_eq!(pattern_neg.span(), span);
3054 }
3055
3056 #[test]
3057 fn test_rir_pattern_bool_span() {
3058 let span = Span::new(30, 34);
3059 let pattern = RirPattern::Bool(true, span);
3060 assert_eq!(pattern.span(), span);
3061
3062 let pattern_false = RirPattern::Bool(false, span);
3063 assert_eq!(pattern_false.span(), span);
3064 }
3065
3066 #[test]
3067 fn test_rir_pattern_path_span() {
3068 let span = Span::new(40, 50);
3069 let interner = ThreadedRodeo::new();
3070 let type_name = interner.get_or_intern("Color");
3071 let variant = interner.get_or_intern("Red");
3072
3073 let pattern = RirPattern::Path {
3074 module: None,
3075 type_name,
3076 variant,
3077 span,
3078 };
3079 assert_eq!(pattern.span(), span);
3080 }
3081
3082 #[test]
3084 fn test_rir_call_arg_is_inout() {
3085 let arg_normal = RirCallArg {
3086 value: InstRef::from_raw(0),
3087 mode: RirArgMode::Normal,
3088 };
3089 assert!(!arg_normal.is_inout());
3090 assert!(!arg_normal.is_borrow());
3091
3092 let arg_inout = RirCallArg {
3093 value: InstRef::from_raw(0),
3094 mode: RirArgMode::Inout,
3095 };
3096 assert!(arg_inout.is_inout());
3097 assert!(!arg_inout.is_borrow());
3098
3099 let arg_borrow = RirCallArg {
3100 value: InstRef::from_raw(0),
3101 mode: RirArgMode::Borrow,
3102 };
3103 assert!(!arg_borrow.is_inout());
3104 assert!(arg_borrow.is_borrow());
3105 }
3106
3107 fn create_printer_test_rir() -> (Rir, ThreadedRodeo) {
3109 let rir = Rir::new();
3110 let interner = ThreadedRodeo::new();
3111 (rir, interner)
3112 }
3113
3114 #[test]
3115 fn test_printer_int_const() {
3116 let (mut rir, interner) = create_printer_test_rir();
3117 rir.add_inst(Inst {
3118 data: InstData::IntConst(42),
3119 span: Span::new(0, 2),
3120 });
3121
3122 let printer = RirPrinter::new(&rir, &interner);
3123 let output = printer.to_string();
3124 assert!(output.contains("%0 = const 42"));
3125 }
3126
3127 #[test]
3128 fn test_printer_bool_const() {
3129 let (mut rir, interner) = create_printer_test_rir();
3130 rir.add_inst(Inst {
3131 data: InstData::BoolConst(true),
3132 span: Span::new(0, 4),
3133 });
3134 rir.add_inst(Inst {
3135 data: InstData::BoolConst(false),
3136 span: Span::new(0, 5),
3137 });
3138
3139 let printer = RirPrinter::new(&rir, &interner);
3140 let output = printer.to_string();
3141 assert!(output.contains("%0 = const true"));
3142 assert!(output.contains("%1 = const false"));
3143 }
3144
3145 #[test]
3146 fn test_printer_string_const() {
3147 let (mut rir, interner) = create_printer_test_rir();
3148 let hello = interner.get_or_intern("hello world");
3149 rir.add_inst(Inst {
3150 data: InstData::StringConst(hello),
3151 span: Span::new(0, 13),
3152 });
3153
3154 let printer = RirPrinter::new(&rir, &interner);
3155 let output = printer.to_string();
3156 assert!(output.contains("%0 = const \"hello world\""));
3157 }
3158
3159 #[test]
3160 fn test_printer_unit_const() {
3161 let (mut rir, interner) = create_printer_test_rir();
3162 rir.add_inst(Inst {
3163 data: InstData::UnitConst,
3164 span: Span::new(0, 2),
3165 });
3166
3167 let printer = RirPrinter::new(&rir, &interner);
3168 let output = printer.to_string();
3169 assert!(output.contains("%0 = const ()"));
3170 }
3171
3172 #[test]
3173 fn test_printer_binary_ops() {
3174 let (mut rir, interner) = create_printer_test_rir();
3175 let lhs = rir.add_inst(Inst {
3176 data: InstData::IntConst(1),
3177 span: Span::new(0, 1),
3178 });
3179 let rhs = rir.add_inst(Inst {
3180 data: InstData::IntConst(2),
3181 span: Span::new(2, 3),
3182 });
3183
3184 let ops = vec![
3186 (InstData::Add { lhs, rhs }, "add"),
3187 (InstData::Sub { lhs, rhs }, "sub"),
3188 (InstData::Mul { lhs, rhs }, "mul"),
3189 (InstData::Div { lhs, rhs }, "div"),
3190 (InstData::Mod { lhs, rhs }, "mod"),
3191 (InstData::Eq { lhs, rhs }, "eq"),
3192 (InstData::Ne { lhs, rhs }, "ne"),
3193 (InstData::Lt { lhs, rhs }, "lt"),
3194 (InstData::Gt { lhs, rhs }, "gt"),
3195 (InstData::Le { lhs, rhs }, "le"),
3196 (InstData::Ge { lhs, rhs }, "ge"),
3197 (InstData::And { lhs, rhs }, "and"),
3198 (InstData::Or { lhs, rhs }, "or"),
3199 (InstData::BitAnd { lhs, rhs }, "bit_and"),
3200 (InstData::BitOr { lhs, rhs }, "bit_or"),
3201 (InstData::BitXor { lhs, rhs }, "bit_xor"),
3202 (InstData::Shl { lhs, rhs }, "shl"),
3203 (InstData::Shr { lhs, rhs }, "shr"),
3204 ];
3205
3206 for (_data, op_name) in ops {
3207 let mut test_rir = Rir::new();
3208 let lhs = test_rir.add_inst(Inst {
3209 data: InstData::IntConst(1),
3210 span: Span::new(0, 1),
3211 });
3212 let rhs = test_rir.add_inst(Inst {
3213 data: InstData::IntConst(2),
3214 span: Span::new(2, 3),
3215 });
3216 let data = match op_name {
3218 "add" => InstData::Add { lhs, rhs },
3219 "sub" => InstData::Sub { lhs, rhs },
3220 "mul" => InstData::Mul { lhs, rhs },
3221 "div" => InstData::Div { lhs, rhs },
3222 "mod" => InstData::Mod { lhs, rhs },
3223 "eq" => InstData::Eq { lhs, rhs },
3224 "ne" => InstData::Ne { lhs, rhs },
3225 "lt" => InstData::Lt { lhs, rhs },
3226 "gt" => InstData::Gt { lhs, rhs },
3227 "le" => InstData::Le { lhs, rhs },
3228 "ge" => InstData::Ge { lhs, rhs },
3229 "and" => InstData::And { lhs, rhs },
3230 "or" => InstData::Or { lhs, rhs },
3231 "bit_and" => InstData::BitAnd { lhs, rhs },
3232 "bit_or" => InstData::BitOr { lhs, rhs },
3233 "bit_xor" => InstData::BitXor { lhs, rhs },
3234 "shl" => InstData::Shl { lhs, rhs },
3235 "shr" => InstData::Shr { lhs, rhs },
3236 _ => unreachable!(),
3237 };
3238 test_rir.add_inst(Inst {
3239 data,
3240 span: Span::new(0, 5),
3241 });
3242
3243 let printer = RirPrinter::new(&test_rir, &interner);
3244 let output = printer.to_string();
3245 let expected = format!("%2 = {} %0, %1", op_name);
3246 assert!(
3247 output.contains(&expected),
3248 "Expected '{}' in output:\n{}",
3249 expected,
3250 output
3251 );
3252 }
3253 }
3254
3255 #[test]
3256 fn test_printer_unary_ops() {
3257 let (mut rir, interner) = create_printer_test_rir();
3258 let operand = rir.add_inst(Inst {
3259 data: InstData::IntConst(42),
3260 span: Span::new(0, 2),
3261 });
3262
3263 rir.add_inst(Inst {
3264 data: InstData::Neg { operand },
3265 span: Span::new(0, 3),
3266 });
3267 rir.add_inst(Inst {
3268 data: InstData::Not { operand },
3269 span: Span::new(0, 3),
3270 });
3271 rir.add_inst(Inst {
3272 data: InstData::BitNot { operand },
3273 span: Span::new(0, 3),
3274 });
3275
3276 let printer = RirPrinter::new(&rir, &interner);
3277 let output = printer.to_string();
3278 assert!(output.contains("neg %0"));
3279 assert!(output.contains("not %0"));
3280 assert!(output.contains("bit_not %0"));
3281 }
3282
3283 #[test]
3284 fn test_printer_branch() {
3285 let (mut rir, interner) = create_printer_test_rir();
3286 let cond = rir.add_inst(Inst {
3287 data: InstData::BoolConst(true),
3288 span: Span::new(0, 4),
3289 });
3290 let then_block = rir.add_inst(Inst {
3291 data: InstData::IntConst(1),
3292 span: Span::new(0, 1),
3293 });
3294 let else_block = rir.add_inst(Inst {
3295 data: InstData::IntConst(0),
3296 span: Span::new(0, 1),
3297 });
3298
3299 rir.add_inst(Inst {
3301 data: InstData::Branch {
3302 cond,
3303 then_block,
3304 else_block: Some(else_block),
3305 },
3306 span: Span::new(0, 20),
3307 });
3308
3309 let printer = RirPrinter::new(&rir, &interner);
3310 let output = printer.to_string();
3311 assert!(output.contains("branch %0, %1, %2"));
3312 }
3313
3314 #[test]
3315 fn test_printer_branch_no_else() {
3316 let (mut rir, interner) = create_printer_test_rir();
3317 let cond = rir.add_inst(Inst {
3318 data: InstData::BoolConst(true),
3319 span: Span::new(0, 4),
3320 });
3321 let then_block = rir.add_inst(Inst {
3322 data: InstData::IntConst(1),
3323 span: Span::new(0, 1),
3324 });
3325
3326 rir.add_inst(Inst {
3327 data: InstData::Branch {
3328 cond,
3329 then_block,
3330 else_block: None,
3331 },
3332 span: Span::new(0, 15),
3333 });
3334
3335 let printer = RirPrinter::new(&rir, &interner);
3336 let output = printer.to_string();
3337 assert!(output.contains("branch %0, %1\n"));
3339 }
3340
3341 #[test]
3342 fn test_printer_loop() {
3343 let (mut rir, interner) = create_printer_test_rir();
3344 let cond = rir.add_inst(Inst {
3345 data: InstData::BoolConst(true),
3346 span: Span::new(0, 4),
3347 });
3348 let body = rir.add_inst(Inst {
3349 data: InstData::IntConst(0),
3350 span: Span::new(0, 1),
3351 });
3352
3353 rir.add_inst(Inst {
3354 data: InstData::Loop { cond, body },
3355 span: Span::new(0, 20),
3356 });
3357
3358 let printer = RirPrinter::new(&rir, &interner);
3359 let output = printer.to_string();
3360 assert!(output.contains("loop %0, %1"));
3361 }
3362
3363 #[test]
3364 fn test_printer_infinite_loop() {
3365 let (mut rir, interner) = create_printer_test_rir();
3366 let body = rir.add_inst(Inst {
3367 data: InstData::IntConst(0),
3368 span: Span::new(0, 1),
3369 });
3370
3371 rir.add_inst(Inst {
3372 data: InstData::InfiniteLoop { body },
3373 span: Span::new(0, 15),
3374 });
3375
3376 let printer = RirPrinter::new(&rir, &interner);
3377 let output = printer.to_string();
3378 assert!(output.contains("infinite_loop %0"));
3379 }
3380
3381 #[test]
3382 fn test_printer_break_continue() {
3383 let (mut rir, interner) = create_printer_test_rir();
3384 rir.add_inst(Inst {
3385 data: InstData::Break,
3386 span: Span::new(0, 5),
3387 });
3388 rir.add_inst(Inst {
3389 data: InstData::Continue,
3390 span: Span::new(0, 8),
3391 });
3392
3393 let printer = RirPrinter::new(&rir, &interner);
3394 let output = printer.to_string();
3395 assert!(output.contains("break\n"));
3396 assert!(output.contains("continue\n"));
3397 }
3398
3399 #[test]
3400 fn test_printer_ret() {
3401 let (mut rir, interner) = create_printer_test_rir();
3402 let value = rir.add_inst(Inst {
3403 data: InstData::IntConst(42),
3404 span: Span::new(0, 2),
3405 });
3406
3407 rir.add_inst(Inst {
3409 data: InstData::Ret(Some(value)),
3410 span: Span::new(0, 10),
3411 });
3412 rir.add_inst(Inst {
3414 data: InstData::Ret(None),
3415 span: Span::new(0, 6),
3416 });
3417
3418 let printer = RirPrinter::new(&rir, &interner);
3419 let output = printer.to_string();
3420 assert!(output.contains("ret %0"));
3421 assert!(output.contains("%2 = ret\n"));
3422 }
3423
3424 #[test]
3425 fn test_printer_fn_decl() {
3426 let (mut rir, interner) = create_printer_test_rir();
3427 let body = rir.add_inst(Inst {
3428 data: InstData::IntConst(42),
3429 span: Span::new(0, 2),
3430 });
3431
3432 let name = interner.get_or_intern("main");
3433 let return_type = interner.get_or_intern("i32");
3434 let param_name = interner.get_or_intern("x");
3435 let param_type = interner.get_or_intern("i32");
3436
3437 let (directives_start, directives_len) = rir.add_directives(&[]);
3438 let (params_start, params_len) = rir.add_params(&[RirParam {
3439 name: param_name,
3440 ty: param_type,
3441 mode: RirParamMode::Normal,
3442 is_comptime: false,
3443 }]);
3444
3445 rir.add_inst(Inst {
3446 data: InstData::FnDecl {
3447 directives_start,
3448 directives_len,
3449 is_pub: false,
3450 is_unchecked: false,
3451 name,
3452 params_start,
3453 params_len,
3454 return_type,
3455 body,
3456 has_self: false,
3457 },
3458 span: Span::new(0, 30),
3459 });
3460
3461 let printer = RirPrinter::new(&rir, &interner);
3462 let output = printer.to_string();
3463 assert!(output.contains("fn main(x: i32) -> i32"));
3464 }
3465
3466 #[test]
3467 fn test_printer_fn_decl_with_self() {
3468 let (mut rir, interner) = create_printer_test_rir();
3469 let body = rir.add_inst(Inst {
3470 data: InstData::IntConst(0),
3471 span: Span::new(0, 1),
3472 });
3473
3474 let name = interner.get_or_intern("get_x");
3475 let return_type = interner.get_or_intern("i32");
3476
3477 let (directives_start, directives_len) = rir.add_directives(&[]);
3478 let (params_start, params_len) = rir.add_params(&[]);
3479
3480 rir.add_inst(Inst {
3481 data: InstData::FnDecl {
3482 directives_start,
3483 directives_len,
3484 is_pub: false,
3485 is_unchecked: false,
3486 name,
3487 params_start,
3488 params_len,
3489 return_type,
3490 body,
3491 has_self: true,
3492 },
3493 span: Span::new(0, 30),
3494 });
3495
3496 let printer = RirPrinter::new(&rir, &interner);
3497 let output = printer.to_string();
3498 assert!(output.contains("fn get_x(self, ) -> i32"));
3499 }
3500
3501 #[test]
3502 fn test_printer_fn_decl_param_modes() {
3503 let (mut rir, interner) = create_printer_test_rir();
3504 let body = rir.add_inst(Inst {
3505 data: InstData::UnitConst,
3506 span: Span::new(0, 2),
3507 });
3508
3509 let name = interner.get_or_intern("modify");
3510 let return_type = interner.get_or_intern("()");
3511 let param1_name = interner.get_or_intern("a");
3512 let param1_type = interner.get_or_intern("i32");
3513 let param2_name = interner.get_or_intern("b");
3514 let param2_type = interner.get_or_intern("i32");
3515 let param3_name = interner.get_or_intern("c");
3516 let param3_type = interner.get_or_intern("i32");
3517
3518 let (directives_start, directives_len) = rir.add_directives(&[]);
3519 let (params_start, params_len) = rir.add_params(&[
3520 RirParam {
3521 name: param1_name,
3522 ty: param1_type,
3523 mode: RirParamMode::Normal,
3524 is_comptime: false,
3525 },
3526 RirParam {
3527 name: param2_name,
3528 ty: param2_type,
3529 mode: RirParamMode::Inout,
3530 is_comptime: false,
3531 },
3532 RirParam {
3533 name: param3_name,
3534 ty: param3_type,
3535 mode: RirParamMode::Borrow,
3536 is_comptime: false,
3537 },
3538 ]);
3539
3540 rir.add_inst(Inst {
3541 data: InstData::FnDecl {
3542 directives_start,
3543 directives_len,
3544 is_pub: false,
3545 is_unchecked: false,
3546 name,
3547 params_start,
3548 params_len,
3549 return_type,
3550 body,
3551 has_self: false,
3552 },
3553 span: Span::new(0, 50),
3554 });
3555
3556 let printer = RirPrinter::new(&rir, &interner);
3557 let output = printer.to_string();
3558 assert!(output.contains("a: i32"));
3559 assert!(output.contains("inout b: i32"));
3560 assert!(output.contains("borrow c: i32"));
3561 }
3562
3563 #[test]
3564 fn test_printer_call() {
3565 let (mut rir, interner) = create_printer_test_rir();
3566 let arg = rir.add_inst(Inst {
3567 data: InstData::IntConst(10),
3568 span: Span::new(0, 2),
3569 });
3570
3571 let name = interner.get_or_intern("foo");
3572
3573 let (args_start, args_len) = rir.add_call_args(&[RirCallArg {
3574 value: arg,
3575 mode: RirArgMode::Normal,
3576 }]);
3577
3578 rir.add_inst(Inst {
3579 data: InstData::Call {
3580 name,
3581 args_start,
3582 args_len,
3583 },
3584 span: Span::new(0, 8),
3585 });
3586
3587 let printer = RirPrinter::new(&rir, &interner);
3588 let output = printer.to_string();
3589 assert!(output.contains("call foo(%0)"));
3590 }
3591
3592 #[test]
3593 fn test_printer_call_with_arg_modes() {
3594 let (mut rir, interner) = create_printer_test_rir();
3595 let arg1 = rir.add_inst(Inst {
3596 data: InstData::IntConst(1),
3597 span: Span::new(0, 1),
3598 });
3599 let arg2 = rir.add_inst(Inst {
3600 data: InstData::IntConst(2),
3601 span: Span::new(0, 1),
3602 });
3603 let arg3 = rir.add_inst(Inst {
3604 data: InstData::IntConst(3),
3605 span: Span::new(0, 1),
3606 });
3607
3608 let name = interner.get_or_intern("modify");
3609
3610 let (args_start, args_len) = rir.add_call_args(&[
3611 RirCallArg {
3612 value: arg1,
3613 mode: RirArgMode::Normal,
3614 },
3615 RirCallArg {
3616 value: arg2,
3617 mode: RirArgMode::Inout,
3618 },
3619 RirCallArg {
3620 value: arg3,
3621 mode: RirArgMode::Borrow,
3622 },
3623 ]);
3624
3625 rir.add_inst(Inst {
3626 data: InstData::Call {
3627 name,
3628 args_start,
3629 args_len,
3630 },
3631 span: Span::new(0, 20),
3632 });
3633
3634 let printer = RirPrinter::new(&rir, &interner);
3635 let output = printer.to_string();
3636 assert!(output.contains("call modify(%0, inout %1, borrow %2)"));
3637 }
3638
3639 #[test]
3640 fn test_printer_intrinsic() {
3641 let (mut rir, interner) = create_printer_test_rir();
3642 let arg = rir.add_inst(Inst {
3643 data: InstData::IntConst(42),
3644 span: Span::new(0, 2),
3645 });
3646
3647 let name = interner.get_or_intern("dbg");
3648
3649 let (args_start, args_len) = rir.add_call_args(&[RirCallArg {
3650 value: arg,
3651 mode: RirArgMode::Normal,
3652 }]);
3653
3654 rir.add_inst(Inst {
3655 data: InstData::Intrinsic {
3656 name,
3657 args_start,
3658 args_len,
3659 },
3660 span: Span::new(0, 10),
3661 });
3662
3663 let printer = RirPrinter::new(&rir, &interner);
3664 let output = printer.to_string();
3665 assert!(output.contains("intrinsic @dbg(%0)"));
3666 }
3667
3668 #[test]
3669 fn test_printer_type_intrinsic() {
3670 let (mut rir, interner) = create_printer_test_rir();
3671 let name = interner.get_or_intern("size_of");
3672 let type_arg = interner.get_or_intern("i32");
3673
3674 rir.add_inst(Inst {
3675 data: InstData::TypeIntrinsic { name, type_arg },
3676 span: Span::new(0, 15),
3677 });
3678
3679 let printer = RirPrinter::new(&rir, &interner);
3680 let output = printer.to_string();
3681 assert!(output.contains("type_intrinsic @size_of(i32)"));
3682 }
3683
3684 #[test]
3685 fn test_printer_param_ref() {
3686 let (mut rir, interner) = create_printer_test_rir();
3687 let name = interner.get_or_intern("x");
3688
3689 rir.add_inst(Inst {
3690 data: InstData::ParamRef { index: 0, name },
3691 span: Span::new(0, 1),
3692 });
3693
3694 let printer = RirPrinter::new(&rir, &interner);
3695 let output = printer.to_string();
3696 assert!(output.contains("param 0 (x)"));
3697 }
3698
3699 #[test]
3700 fn test_printer_block() {
3701 let (mut rir, interner) = create_printer_test_rir();
3702 rir.add_inst(Inst {
3703 data: InstData::Block {
3704 extra_start: 0,
3705 len: 3,
3706 },
3707 span: Span::new(0, 20),
3708 });
3709
3710 let printer = RirPrinter::new(&rir, &interner);
3711 let output = printer.to_string();
3712 assert!(output.contains("block(0, 3)"));
3713 }
3714
3715 #[test]
3716 fn test_printer_alloc() {
3717 let (mut rir, interner) = create_printer_test_rir();
3718 let init = rir.add_inst(Inst {
3719 data: InstData::IntConst(42),
3720 span: Span::new(0, 2),
3721 });
3722
3723 let name = interner.get_or_intern("x");
3724 let ty = interner.get_or_intern("i32");
3725
3726 let (directives_start, directives_len) = rir.add_directives(&[]);
3727
3728 rir.add_inst(Inst {
3730 data: InstData::Alloc {
3731 directives_start,
3732 directives_len,
3733 name: Some(name),
3734 is_mut: false,
3735 ty: Some(ty),
3736 init,
3737 },
3738 span: Span::new(0, 15),
3739 });
3740
3741 let printer = RirPrinter::new(&rir, &interner);
3742 let output = printer.to_string();
3743 assert!(output.contains("alloc x: i32= %0"));
3744 }
3745
3746 #[test]
3747 fn test_printer_alloc_mut() {
3748 let (mut rir, interner) = create_printer_test_rir();
3749 let init = rir.add_inst(Inst {
3750 data: InstData::IntConst(42),
3751 span: Span::new(0, 2),
3752 });
3753
3754 let name = interner.get_or_intern("x");
3755
3756 let (directives_start, directives_len) = rir.add_directives(&[]);
3757
3758 rir.add_inst(Inst {
3759 data: InstData::Alloc {
3760 directives_start,
3761 directives_len,
3762 name: Some(name),
3763 is_mut: true,
3764 ty: None,
3765 init,
3766 },
3767 span: Span::new(0, 15),
3768 });
3769
3770 let printer = RirPrinter::new(&rir, &interner);
3771 let output = printer.to_string();
3772 assert!(output.contains("alloc mut x= %0"));
3773 }
3774
3775 #[test]
3776 fn test_printer_alloc_wildcard() {
3777 let (mut rir, interner) = create_printer_test_rir();
3778 let init = rir.add_inst(Inst {
3779 data: InstData::IntConst(42),
3780 span: Span::new(0, 2),
3781 });
3782
3783 let (directives_start, directives_len) = rir.add_directives(&[]);
3784
3785 rir.add_inst(Inst {
3786 data: InstData::Alloc {
3787 directives_start,
3788 directives_len,
3789 name: None,
3790 is_mut: false,
3791 ty: None,
3792 init,
3793 },
3794 span: Span::new(0, 10),
3795 });
3796
3797 let printer = RirPrinter::new(&rir, &interner);
3798 let output = printer.to_string();
3799 assert!(output.contains("alloc _= %0"));
3800 }
3801
3802 #[test]
3803 fn test_printer_var_ref() {
3804 let (mut rir, interner) = create_printer_test_rir();
3805 let name = interner.get_or_intern("x");
3806
3807 rir.add_inst(Inst {
3808 data: InstData::VarRef { name },
3809 span: Span::new(0, 1),
3810 });
3811
3812 let printer = RirPrinter::new(&rir, &interner);
3813 let output = printer.to_string();
3814 assert!(output.contains("var_ref x"));
3815 }
3816
3817 #[test]
3818 fn test_printer_assign() {
3819 let (mut rir, interner) = create_printer_test_rir();
3820 let value = rir.add_inst(Inst {
3821 data: InstData::IntConst(10),
3822 span: Span::new(0, 2),
3823 });
3824
3825 let name = interner.get_or_intern("x");
3826
3827 rir.add_inst(Inst {
3828 data: InstData::Assign { name, value },
3829 span: Span::new(0, 6),
3830 });
3831
3832 let printer = RirPrinter::new(&rir, &interner);
3833 let output = printer.to_string();
3834 assert!(output.contains("assign x = %0"));
3835 }
3836
3837 #[test]
3838 fn test_printer_struct_decl() {
3839 let (mut rir, interner) = create_printer_test_rir();
3840 let name = interner.get_or_intern("Point");
3841 let x_name = interner.get_or_intern("x");
3842 let y_name = interner.get_or_intern("y");
3843 let i32_type = interner.get_or_intern("i32");
3844
3845 let (directives_start, directives_len) = rir.add_directives(&[]);
3846 let (fields_start, fields_len) =
3847 rir.add_field_decls(&[(x_name, i32_type), (y_name, i32_type)]);
3848 let (methods_start, methods_len) = rir.add_inst_refs(&[]);
3849
3850 rir.add_inst(Inst {
3851 data: InstData::StructDecl {
3852 directives_start,
3853 directives_len,
3854 is_pub: false,
3855 is_linear: false,
3856 name,
3857 fields_start,
3858 fields_len,
3859 methods_start,
3860 methods_len,
3861 },
3862 span: Span::new(0, 30),
3863 });
3864
3865 let printer = RirPrinter::new(&rir, &interner);
3866 let output = printer.to_string();
3867 assert!(output.contains("struct Point { x: i32, y: i32 }"));
3868 }
3869
3870 #[test]
3871 fn test_printer_struct_decl_with_directive() {
3872 let (mut rir, interner) = create_printer_test_rir();
3873 let name = interner.get_or_intern("Point");
3874 let x_name = interner.get_or_intern("x");
3875 let i32_type = interner.get_or_intern("i32");
3876 let copy_name = interner.get_or_intern("copy");
3877
3878 let (directives_start, directives_len) = rir.add_directives(&[RirDirective {
3879 name: copy_name,
3880 args: vec![],
3881 span: Span::new(0, 5),
3882 }]);
3883 let (fields_start, fields_len) = rir.add_field_decls(&[(x_name, i32_type)]);
3884 let (methods_start, methods_len) = rir.add_inst_refs(&[]);
3885
3886 rir.add_inst(Inst {
3887 data: InstData::StructDecl {
3888 directives_start,
3889 directives_len,
3890 is_pub: false,
3891 is_linear: false,
3892 name,
3893 fields_start,
3894 fields_len,
3895 methods_start,
3896 methods_len,
3897 },
3898 span: Span::new(0, 30),
3899 });
3900
3901 let printer = RirPrinter::new(&rir, &interner);
3902 let output = printer.to_string();
3903 assert!(output.contains("@copy struct Point { x: i32 }"));
3904 }
3905
3906 #[test]
3907 fn test_printer_struct_init() {
3908 let (mut rir, interner) = create_printer_test_rir();
3909 let x_val = rir.add_inst(Inst {
3910 data: InstData::IntConst(10),
3911 span: Span::new(0, 2),
3912 });
3913 let y_val = rir.add_inst(Inst {
3914 data: InstData::IntConst(20),
3915 span: Span::new(0, 2),
3916 });
3917
3918 let type_name = interner.get_or_intern("Point");
3919 let x_name = interner.get_or_intern("x");
3920 let y_name = interner.get_or_intern("y");
3921
3922 let (fields_start, fields_len) = rir.add_field_inits(&[(x_name, x_val), (y_name, y_val)]);
3923
3924 rir.add_inst(Inst {
3925 data: InstData::StructInit {
3926 module: None,
3927 type_name,
3928 fields_start,
3929 fields_len,
3930 },
3931 span: Span::new(0, 25),
3932 });
3933
3934 let printer = RirPrinter::new(&rir, &interner);
3935 let output = printer.to_string();
3936 assert!(output.contains("struct_init Point { x: %0, y: %1 }"));
3937 }
3938
3939 #[test]
3940 fn test_printer_field_get() {
3941 let (mut rir, interner) = create_printer_test_rir();
3942 let base = rir.add_inst(Inst {
3943 data: InstData::IntConst(0), span: Span::new(0, 1),
3945 });
3946
3947 let field = interner.get_or_intern("x");
3948
3949 rir.add_inst(Inst {
3950 data: InstData::FieldGet { base, field },
3951 span: Span::new(0, 5),
3952 });
3953
3954 let printer = RirPrinter::new(&rir, &interner);
3955 let output = printer.to_string();
3956 assert!(output.contains("field_get %0.x"));
3957 }
3958
3959 #[test]
3960 fn test_printer_field_set() {
3961 let (mut rir, interner) = create_printer_test_rir();
3962 let base = rir.add_inst(Inst {
3963 data: InstData::IntConst(0), span: Span::new(0, 1),
3965 });
3966 let value = rir.add_inst(Inst {
3967 data: InstData::IntConst(42),
3968 span: Span::new(0, 2),
3969 });
3970
3971 let field = interner.get_or_intern("x");
3972
3973 rir.add_inst(Inst {
3974 data: InstData::FieldSet { base, field, value },
3975 span: Span::new(0, 10),
3976 });
3977
3978 let printer = RirPrinter::new(&rir, &interner);
3979 let output = printer.to_string();
3980 assert!(output.contains("field_set %0.x = %1"));
3981 }
3982
3983 #[test]
3984 fn test_printer_enum_decl() {
3985 let (mut rir, interner) = create_printer_test_rir();
3986 let name = interner.get_or_intern("Color");
3987 let red = interner.get_or_intern("Red");
3988 let green = interner.get_or_intern("Green");
3989 let blue = interner.get_or_intern("Blue");
3990
3991 let (variants_start, variants_len) = rir.add_enum_variant_decls(&[
3993 (red, vec![], vec![]),
3994 (green, vec![], vec![]),
3995 (blue, vec![], vec![]),
3996 ]);
3997
3998 rir.add_inst(Inst {
3999 data: InstData::EnumDecl {
4000 is_pub: false,
4001 name,
4002 variants_start,
4003 variants_len,
4004 },
4005 span: Span::new(0, 35),
4006 });
4007
4008 let printer = RirPrinter::new(&rir, &interner);
4009 let output = printer.to_string();
4010 assert!(output.contains("enum Color { Red, Green, Blue }"));
4011 }
4012
4013 #[test]
4014 fn test_printer_enum_decl_with_data() {
4015 let (mut rir, interner) = create_printer_test_rir();
4016 let name = interner.get_or_intern("IntOption");
4017 let none = interner.get_or_intern("None");
4018 let some = interner.get_or_intern("Some");
4019 let i32_ty = interner.get_or_intern("i32");
4020
4021 let (variants_start, variants_len) =
4022 rir.add_enum_variant_decls(&[(none, vec![], vec![]), (some, vec![i32_ty], vec![])]);
4023
4024 rir.add_inst(Inst {
4025 data: InstData::EnumDecl {
4026 is_pub: false,
4027 name,
4028 variants_start,
4029 variants_len,
4030 },
4031 span: Span::new(0, 35),
4032 });
4033
4034 let printer = RirPrinter::new(&rir, &interner);
4035 let output = printer.to_string();
4036 assert!(output.contains("enum IntOption { None, Some(i32) }"));
4037 }
4038
4039 #[test]
4040 fn test_printer_enum_variant() {
4041 let (mut rir, interner) = create_printer_test_rir();
4042 let type_name = interner.get_or_intern("Color");
4043 let variant = interner.get_or_intern("Red");
4044
4045 rir.add_inst(Inst {
4046 data: InstData::EnumVariant {
4047 module: None,
4048 type_name,
4049 variant,
4050 },
4051 span: Span::new(0, 10),
4052 });
4053
4054 let printer = RirPrinter::new(&rir, &interner);
4055 let output = printer.to_string();
4056 assert!(output.contains("enum_variant Color::Red"));
4057 }
4058
4059 #[test]
4060 fn test_printer_array_init() {
4061 let (mut rir, interner) = create_printer_test_rir();
4062 let elem1 = rir.add_inst(Inst {
4063 data: InstData::IntConst(1),
4064 span: Span::new(0, 1),
4065 });
4066 let elem2 = rir.add_inst(Inst {
4067 data: InstData::IntConst(2),
4068 span: Span::new(0, 1),
4069 });
4070 let elem3 = rir.add_inst(Inst {
4071 data: InstData::IntConst(3),
4072 span: Span::new(0, 1),
4073 });
4074
4075 let (elems_start, elems_len) = rir.add_inst_refs(&[elem1, elem2, elem3]);
4076
4077 rir.add_inst(Inst {
4078 data: InstData::ArrayInit {
4079 elems_start,
4080 elems_len,
4081 },
4082 span: Span::new(0, 10),
4083 });
4084
4085 let printer = RirPrinter::new(&rir, &interner);
4086 let output = printer.to_string();
4087 assert!(output.contains("array_init [%0, %1, %2]"));
4088 }
4089
4090 #[test]
4091 fn test_printer_index_get() {
4092 let (mut rir, interner) = create_printer_test_rir();
4093 let base = rir.add_inst(Inst {
4094 data: InstData::IntConst(0), span: Span::new(0, 1),
4096 });
4097 let index = rir.add_inst(Inst {
4098 data: InstData::IntConst(1),
4099 span: Span::new(0, 1),
4100 });
4101
4102 rir.add_inst(Inst {
4103 data: InstData::IndexGet { base, index },
4104 span: Span::new(0, 5),
4105 });
4106
4107 let printer = RirPrinter::new(&rir, &interner);
4108 let output = printer.to_string();
4109 assert!(output.contains("index_get %0[%1]"));
4110 }
4111
4112 #[test]
4113 fn test_printer_index_set() {
4114 let (mut rir, interner) = create_printer_test_rir();
4115 let base = rir.add_inst(Inst {
4116 data: InstData::IntConst(0), span: Span::new(0, 1),
4118 });
4119 let index = rir.add_inst(Inst {
4120 data: InstData::IntConst(1),
4121 span: Span::new(0, 1),
4122 });
4123 let value = rir.add_inst(Inst {
4124 data: InstData::IntConst(42),
4125 span: Span::new(0, 2),
4126 });
4127
4128 rir.add_inst(Inst {
4129 data: InstData::IndexSet { base, index, value },
4130 span: Span::new(0, 10),
4131 });
4132
4133 let printer = RirPrinter::new(&rir, &interner);
4134 let output = printer.to_string();
4135 assert!(output.contains("index_set %0[%1] = %2"));
4136 }
4137
4138 #[test]
4140 fn test_printer_struct_decl_with_methods() {
4141 let (mut rir, interner) = create_printer_test_rir();
4142
4143 let method_body = rir.add_inst(Inst {
4145 data: InstData::IntConst(0),
4146 span: Span::new(0, 1),
4147 });
4148 let method_name = interner.get_or_intern("get_x");
4149 let return_type = interner.get_or_intern("i32");
4150
4151 let (directives_start, directives_len) = rir.add_directives(&[]);
4152 let (params_start, params_len) = rir.add_params(&[]);
4153
4154 let method_ref = rir.add_inst(Inst {
4155 data: InstData::FnDecl {
4156 directives_start,
4157 directives_len,
4158 is_pub: false,
4159 is_unchecked: false,
4160 name: method_name,
4161 params_start,
4162 params_len,
4163 return_type,
4164 body: method_body,
4165 has_self: true,
4166 },
4167 span: Span::new(0, 30),
4168 });
4169
4170 let struct_name = interner.get_or_intern("Point");
4171 let x_field = interner.get_or_intern("x");
4172 let i32_type = interner.get_or_intern("i32");
4173
4174 let (fields_start, fields_len) = rir.add_field_decls(&[(x_field, i32_type)]);
4175 let (methods_start, methods_len) = rir.add_inst_refs(&[method_ref]);
4176
4177 rir.add_inst(Inst {
4178 data: InstData::StructDecl {
4179 directives_start,
4180 directives_len,
4181 is_pub: false,
4182 is_linear: false,
4183 name: struct_name,
4184 fields_start,
4185 fields_len,
4186 methods_start,
4187 methods_len,
4188 },
4189 span: Span::new(0, 50),
4190 });
4191
4192 let printer = RirPrinter::new(&rir, &interner);
4193 let output = printer.to_string();
4194 assert!(output.contains("struct Point { x: i32 } methods: [%1]"));
4195 }
4196
4197 #[test]
4198 fn test_printer_method_call() {
4199 let (mut rir, interner) = create_printer_test_rir();
4200 let receiver = rir.add_inst(Inst {
4201 data: InstData::IntConst(0), span: Span::new(0, 1),
4203 });
4204 let arg = rir.add_inst(Inst {
4205 data: InstData::IntConst(10),
4206 span: Span::new(0, 2),
4207 });
4208
4209 let method = interner.get_or_intern("add");
4210
4211 let (args_start, args_len) = rir.add_call_args(&[RirCallArg {
4212 value: arg,
4213 mode: RirArgMode::Normal,
4214 }]);
4215
4216 rir.add_inst(Inst {
4217 data: InstData::MethodCall {
4218 receiver,
4219 method,
4220 args_start,
4221 args_len,
4222 },
4223 span: Span::new(0, 15),
4224 });
4225
4226 let printer = RirPrinter::new(&rir, &interner);
4227 let output = printer.to_string();
4228 assert!(output.contains("method_call %0.add(%1)"));
4229 }
4230
4231 #[test]
4232 fn test_printer_method_call_with_arg_modes() {
4233 let (mut rir, interner) = create_printer_test_rir();
4234 let receiver = rir.add_inst(Inst {
4235 data: InstData::IntConst(0),
4236 span: Span::new(0, 1),
4237 });
4238 let arg1 = rir.add_inst(Inst {
4239 data: InstData::IntConst(1),
4240 span: Span::new(0, 1),
4241 });
4242 let arg2 = rir.add_inst(Inst {
4243 data: InstData::IntConst(2),
4244 span: Span::new(0, 1),
4245 });
4246
4247 let method = interner.get_or_intern("modify");
4248
4249 let (args_start, args_len) = rir.add_call_args(&[
4250 RirCallArg {
4251 value: arg1,
4252 mode: RirArgMode::Inout,
4253 },
4254 RirCallArg {
4255 value: arg2,
4256 mode: RirArgMode::Borrow,
4257 },
4258 ]);
4259
4260 rir.add_inst(Inst {
4261 data: InstData::MethodCall {
4262 receiver,
4263 method,
4264 args_start,
4265 args_len,
4266 },
4267 span: Span::new(0, 25),
4268 });
4269
4270 let printer = RirPrinter::new(&rir, &interner);
4271 let output = printer.to_string();
4272 assert!(output.contains("method_call %0.modify(inout %1, borrow %2)"));
4273 }
4274
4275 #[test]
4276 fn test_printer_assoc_fn_call() {
4277 let (mut rir, interner) = create_printer_test_rir();
4278
4279 let type_name = interner.get_or_intern("Point");
4280 let function = interner.get_or_intern("origin");
4281
4282 let (args_start, args_len) = rir.add_call_args(&[]);
4283
4284 rir.add_inst(Inst {
4285 data: InstData::AssocFnCall {
4286 type_name,
4287 function,
4288 args_start,
4289 args_len,
4290 },
4291 span: Span::new(0, 15),
4292 });
4293
4294 let printer = RirPrinter::new(&rir, &interner);
4295 let output = printer.to_string();
4296 assert!(output.contains("assoc_fn_call Point::origin()"));
4297 }
4298
4299 #[test]
4300 fn test_printer_assoc_fn_call_with_args() {
4301 let (mut rir, interner) = create_printer_test_rir();
4302 let arg1 = rir.add_inst(Inst {
4303 data: InstData::IntConst(10),
4304 span: Span::new(0, 2),
4305 });
4306 let arg2 = rir.add_inst(Inst {
4307 data: InstData::IntConst(20),
4308 span: Span::new(0, 2),
4309 });
4310
4311 let type_name = interner.get_or_intern("Point");
4312 let function = interner.get_or_intern("new");
4313
4314 let (args_start, args_len) = rir.add_call_args(&[
4315 RirCallArg {
4316 value: arg1,
4317 mode: RirArgMode::Normal,
4318 },
4319 RirCallArg {
4320 value: arg2,
4321 mode: RirArgMode::Normal,
4322 },
4323 ]);
4324
4325 rir.add_inst(Inst {
4326 data: InstData::AssocFnCall {
4327 type_name,
4328 function,
4329 args_start,
4330 args_len,
4331 },
4332 span: Span::new(0, 20),
4333 });
4334
4335 let printer = RirPrinter::new(&rir, &interner);
4336 let output = printer.to_string();
4337 assert!(output.contains("assoc_fn_call Point::new(%0, %1)"));
4338 }
4339
4340 #[test]
4341 fn test_printer_drop_fn_decl() {
4342 let (mut rir, interner) = create_printer_test_rir();
4343 let body = rir.add_inst(Inst {
4344 data: InstData::UnitConst,
4345 span: Span::new(0, 2),
4346 });
4347
4348 let type_name = interner.get_or_intern("Resource");
4349
4350 rir.add_inst(Inst {
4351 data: InstData::DropFnDecl { type_name, body },
4352 span: Span::new(0, 30),
4353 });
4354
4355 let printer = RirPrinter::new(&rir, &interner);
4356 let output = printer.to_string();
4357 assert!(output.contains("drop fn Resource(self)"));
4358 }
4359
4360 #[test]
4362 fn test_printer_match_wildcard() {
4363 let (mut rir, interner) = create_printer_test_rir();
4364 let scrutinee = rir.add_inst(Inst {
4365 data: InstData::IntConst(42),
4366 span: Span::new(0, 2),
4367 });
4368 let body = rir.add_inst(Inst {
4369 data: InstData::IntConst(0),
4370 span: Span::new(0, 1),
4371 });
4372
4373 let (arms_start, arms_len) =
4374 rir.add_match_arms(&[(RirPattern::Wildcard(Span::new(0, 1)), body)]);
4375
4376 rir.add_inst(Inst {
4377 data: InstData::Match {
4378 scrutinee,
4379 arms_start,
4380 arms_len,
4381 },
4382 span: Span::new(0, 20),
4383 });
4384
4385 let printer = RirPrinter::new(&rir, &interner);
4386 let output = printer.to_string();
4387 assert!(output.contains("match %0 { _ => %1 }"));
4388 }
4389
4390 #[test]
4391 fn test_printer_match_int_pattern() {
4392 let (mut rir, interner) = create_printer_test_rir();
4393 let scrutinee = rir.add_inst(Inst {
4394 data: InstData::IntConst(42),
4395 span: Span::new(0, 2),
4396 });
4397 let body1 = rir.add_inst(Inst {
4398 data: InstData::IntConst(1),
4399 span: Span::new(0, 1),
4400 });
4401 let body2 = rir.add_inst(Inst {
4402 data: InstData::IntConst(2),
4403 span: Span::new(0, 1),
4404 });
4405 let body_default = rir.add_inst(Inst {
4406 data: InstData::IntConst(0),
4407 span: Span::new(0, 1),
4408 });
4409
4410 let (arms_start, arms_len) = rir.add_match_arms(&[
4411 (RirPattern::Int(1, Span::new(0, 1)), body1),
4412 (RirPattern::Int(-5, Span::new(0, 2)), body2),
4413 (RirPattern::Wildcard(Span::new(0, 1)), body_default),
4414 ]);
4415
4416 rir.add_inst(Inst {
4417 data: InstData::Match {
4418 scrutinee,
4419 arms_start,
4420 arms_len,
4421 },
4422 span: Span::new(0, 30),
4423 });
4424
4425 let printer = RirPrinter::new(&rir, &interner);
4426 let output = printer.to_string();
4427 assert!(output.contains("match %0 { 1 => %1, -5 => %2, _ => %3 }"));
4428 }
4429
4430 #[test]
4431 fn test_printer_match_bool_pattern() {
4432 let (mut rir, interner) = create_printer_test_rir();
4433 let scrutinee = rir.add_inst(Inst {
4434 data: InstData::BoolConst(true),
4435 span: Span::new(0, 4),
4436 });
4437 let body_true = rir.add_inst(Inst {
4438 data: InstData::IntConst(1),
4439 span: Span::new(0, 1),
4440 });
4441 let body_false = rir.add_inst(Inst {
4442 data: InstData::IntConst(0),
4443 span: Span::new(0, 1),
4444 });
4445
4446 let (arms_start, arms_len) = rir.add_match_arms(&[
4447 (RirPattern::Bool(true, Span::new(0, 4)), body_true),
4448 (RirPattern::Bool(false, Span::new(0, 5)), body_false),
4449 ]);
4450
4451 rir.add_inst(Inst {
4452 data: InstData::Match {
4453 scrutinee,
4454 arms_start,
4455 arms_len,
4456 },
4457 span: Span::new(0, 30),
4458 });
4459
4460 let printer = RirPrinter::new(&rir, &interner);
4461 let output = printer.to_string();
4462 assert!(output.contains("match %0 { true => %1, false => %2 }"));
4463 }
4464
4465 #[test]
4466 fn test_printer_match_path_pattern() {
4467 let (mut rir, interner) = create_printer_test_rir();
4468 let scrutinee = rir.add_inst(Inst {
4469 data: InstData::IntConst(0), span: Span::new(0, 1),
4471 });
4472 let body_red = rir.add_inst(Inst {
4473 data: InstData::IntConst(1),
4474 span: Span::new(0, 1),
4475 });
4476 let body_green = rir.add_inst(Inst {
4477 data: InstData::IntConst(2),
4478 span: Span::new(0, 1),
4479 });
4480 let body_default = rir.add_inst(Inst {
4481 data: InstData::IntConst(0),
4482 span: Span::new(0, 1),
4483 });
4484
4485 let color = interner.get_or_intern("Color");
4486 let red = interner.get_or_intern("Red");
4487 let green = interner.get_or_intern("Green");
4488
4489 let (arms_start, arms_len) = rir.add_match_arms(&[
4490 (
4491 RirPattern::Path {
4492 module: None,
4493 type_name: color,
4494 variant: red,
4495 span: Span::new(0, 10),
4496 },
4497 body_red,
4498 ),
4499 (
4500 RirPattern::Path {
4501 module: None,
4502 type_name: color,
4503 variant: green,
4504 span: Span::new(0, 12),
4505 },
4506 body_green,
4507 ),
4508 (RirPattern::Wildcard(Span::new(0, 1)), body_default),
4509 ]);
4510
4511 rir.add_inst(Inst {
4512 data: InstData::Match {
4513 scrutinee,
4514 arms_start,
4515 arms_len,
4516 },
4517 span: Span::new(0, 50),
4518 });
4519
4520 let printer = RirPrinter::new(&rir, &interner);
4521 let output = printer.to_string();
4522 assert!(output.contains("match %0 { Color::Red => %1, Color::Green => %2, _ => %3 }"));
4523 }
4524
4525 #[test]
4526 fn test_printer_display_trait() {
4527 let (mut rir, interner) = create_printer_test_rir();
4528 rir.add_inst(Inst {
4529 data: InstData::IntConst(42),
4530 span: Span::new(0, 2),
4531 });
4532
4533 let printer = RirPrinter::new(&rir, &interner);
4534 let output = format!("{}", printer);
4536 assert!(output.contains("%0 = const 42"));
4537 }
4538
4539 #[test]
4542 fn test_merge_empty_rirs() {
4543 let merged = Rir::merge(&[]);
4544 assert!(merged.is_empty());
4545 assert!(merged.function_spans().is_empty());
4546 }
4547
4548 #[test]
4549 fn test_merge_single_rir() {
4550 let mut rir = Rir::new();
4551 rir.add_inst(Inst {
4552 data: InstData::IntConst(42),
4553 span: Span::new(0, 2),
4554 });
4555 rir.add_inst(Inst {
4556 data: InstData::BoolConst(true),
4557 span: Span::new(3, 7),
4558 });
4559
4560 let merged = Rir::merge(&[rir]);
4561 assert_eq!(merged.len(), 2);
4562
4563 assert!(matches!(
4565 merged.get(InstRef::from_raw(0)).data,
4566 InstData::IntConst(42)
4567 ));
4568 assert!(matches!(
4569 merged.get(InstRef::from_raw(1)).data,
4570 InstData::BoolConst(true)
4571 ));
4572 }
4573
4574 #[test]
4575 fn test_merge_two_rirs_simple() {
4576 let mut rir1 = Rir::new();
4578 rir1.add_inst(Inst {
4579 data: InstData::IntConst(10),
4580 span: Span::new(0, 2),
4581 });
4582
4583 let mut rir2 = Rir::new();
4585 rir2.add_inst(Inst {
4586 data: InstData::IntConst(20),
4587 span: Span::new(5, 7),
4588 });
4589
4590 let merged = Rir::merge(&[rir1, rir2]);
4591 assert_eq!(merged.len(), 2);
4592
4593 assert!(matches!(
4595 merged.get(InstRef::from_raw(0)).data,
4596 InstData::IntConst(10)
4597 ));
4598 assert!(matches!(
4600 merged.get(InstRef::from_raw(1)).data,
4601 InstData::IntConst(20)
4602 ));
4603 }
4604
4605 #[test]
4606 fn test_merge_renumbers_inst_refs() {
4607 let mut rir1 = Rir::new();
4609 let const1 = rir1.add_inst(Inst {
4610 data: InstData::IntConst(5),
4611 span: Span::new(0, 1),
4612 });
4613 rir1.add_inst(Inst {
4614 data: InstData::Add {
4615 lhs: const1,
4616 rhs: const1,
4617 },
4618 span: Span::new(2, 5),
4619 });
4620
4621 let mut rir2 = Rir::new();
4623 let const2 = rir2.add_inst(Inst {
4624 data: InstData::IntConst(10),
4625 span: Span::new(10, 12),
4626 });
4627 rir2.add_inst(Inst {
4628 data: InstData::Add {
4629 lhs: const2,
4630 rhs: const2,
4631 },
4632 span: Span::new(12, 16),
4633 });
4634
4635 let merged = Rir::merge(&[rir1, rir2]);
4636 assert_eq!(merged.len(), 4);
4637
4638 if let InstData::Add { lhs, rhs } = &merged.get(InstRef::from_raw(1)).data {
4640 assert_eq!(lhs.as_u32(), 0);
4641 assert_eq!(rhs.as_u32(), 0);
4642 } else {
4643 panic!("Expected Add instruction at index 1");
4644 }
4645
4646 if let InstData::Add { lhs, rhs } = &merged.get(InstRef::from_raw(3)).data {
4648 assert_eq!(lhs.as_u32(), 2);
4649 assert_eq!(rhs.as_u32(), 2);
4650 } else {
4651 panic!("Expected Add instruction at index 3");
4652 }
4653 }
4654
4655 #[test]
4656 fn test_merge_renumbers_extra_data() {
4657 let mut rir1 = Rir::new();
4659 let interner = ThreadedRodeo::new();
4660 let fn_name = interner.get_or_intern("foo");
4661
4662 let const1 = rir1.add_inst(Inst {
4663 data: InstData::IntConst(1),
4664 span: Span::new(0, 1),
4665 });
4666 let (args_start, args_len) = rir1.add_call_args(&[RirCallArg {
4667 value: const1,
4668 mode: RirArgMode::Normal,
4669 }]);
4670 rir1.add_inst(Inst {
4671 data: InstData::Call {
4672 name: fn_name,
4673 args_start,
4674 args_len,
4675 },
4676 span: Span::new(2, 8),
4677 });
4678
4679 let mut rir2 = Rir::new();
4681 let const2 = rir2.add_inst(Inst {
4682 data: InstData::IntConst(2),
4683 span: Span::new(10, 11),
4684 });
4685 let (args_start2, args_len2) = rir2.add_call_args(&[RirCallArg {
4686 value: const2,
4687 mode: RirArgMode::Normal,
4688 }]);
4689 rir2.add_inst(Inst {
4690 data: InstData::Call {
4691 name: fn_name,
4692 args_start: args_start2,
4693 args_len: args_len2,
4694 },
4695 span: Span::new(12, 18),
4696 });
4697
4698 let merged = Rir::merge(&[rir1, rir2]);
4699 assert_eq!(merged.len(), 4);
4700
4701 if let InstData::Call {
4703 args_start,
4704 args_len,
4705 ..
4706 } = &merged.get(InstRef::from_raw(1)).data
4707 {
4708 let args = merged.get_call_args(*args_start, *args_len);
4709 assert_eq!(args.len(), 1);
4710 assert_eq!(args[0].value.as_u32(), 0); } else {
4712 panic!("Expected Call instruction at index 1");
4713 }
4714
4715 if let InstData::Call {
4717 args_start,
4718 args_len,
4719 ..
4720 } = &merged.get(InstRef::from_raw(3)).data
4721 {
4722 let args = merged.get_call_args(*args_start, *args_len);
4723 assert_eq!(args.len(), 1);
4724 assert_eq!(args[0].value.as_u32(), 2); } else {
4726 panic!("Expected Call instruction at index 3");
4727 }
4728 }
4729
4730 #[test]
4731 fn test_merge_function_spans() {
4732 let interner = ThreadedRodeo::new();
4733 let main_name = interner.get_or_intern("main");
4734 let helper_name = interner.get_or_intern("helper");
4735
4736 let mut rir1 = Rir::new();
4738 let body_start1 = InstRef::from_raw(rir1.current_inst_index());
4739 let const1 = rir1.add_inst(Inst {
4740 data: InstData::IntConst(0),
4741 span: Span::new(0, 1),
4742 });
4743 let (params_start, params_len) = rir1.add_params(&[]);
4744 let (dirs_start, dirs_len) = rir1.add_directives(&[]);
4745 let ret_type = interner.get_or_intern("i32");
4746 let decl1 = rir1.add_inst(Inst {
4747 data: InstData::FnDecl {
4748 directives_start: dirs_start,
4749 directives_len: dirs_len,
4750 is_pub: false,
4751 is_unchecked: false,
4752 name: main_name,
4753 params_start,
4754 params_len,
4755 return_type: ret_type,
4756 body: const1,
4757 has_self: false,
4758 },
4759 span: Span::new(0, 10),
4760 });
4761 rir1.add_function_span(FunctionSpan::new(main_name, body_start1, decl1));
4762
4763 let mut rir2 = Rir::new();
4765 let body_start2 = InstRef::from_raw(rir2.current_inst_index());
4766 let const2 = rir2.add_inst(Inst {
4767 data: InstData::IntConst(42),
4768 span: Span::new(20, 22),
4769 });
4770 let (params_start2, params_len2) = rir2.add_params(&[]);
4771 let (dirs_start2, dirs_len2) = rir2.add_directives(&[]);
4772 let decl2 = rir2.add_inst(Inst {
4773 data: InstData::FnDecl {
4774 directives_start: dirs_start2,
4775 directives_len: dirs_len2,
4776 is_pub: false,
4777 is_unchecked: false,
4778 name: helper_name,
4779 params_start: params_start2,
4780 params_len: params_len2,
4781 return_type: ret_type,
4782 body: const2,
4783 has_self: false,
4784 },
4785 span: Span::new(20, 35),
4786 });
4787 rir2.add_function_span(FunctionSpan::new(helper_name, body_start2, decl2));
4788
4789 let merged = Rir::merge(&[rir1, rir2]);
4790
4791 assert_eq!(merged.function_spans().len(), 2);
4793
4794 let main_span = &merged.function_spans()[0];
4796 assert_eq!(main_span.name, main_name);
4797 assert_eq!(main_span.body_start.as_u32(), 0);
4798 assert_eq!(main_span.decl.as_u32(), 1);
4799
4800 let helper_span = &merged.function_spans()[1];
4802 assert_eq!(helper_span.name, helper_name);
4803 assert_eq!(helper_span.body_start.as_u32(), 2); assert_eq!(helper_span.decl.as_u32(), 3); }
4806
4807 #[test]
4808 fn test_merge_three_rirs() {
4809 let mut rir1 = Rir::new();
4810 rir1.add_inst(Inst {
4811 data: InstData::IntConst(1),
4812 span: Span::new(0, 1),
4813 });
4814
4815 let mut rir2 = Rir::new();
4816 rir2.add_inst(Inst {
4817 data: InstData::IntConst(2),
4818 span: Span::new(10, 11),
4819 });
4820
4821 let mut rir3 = Rir::new();
4822 rir3.add_inst(Inst {
4823 data: InstData::IntConst(3),
4824 span: Span::new(20, 21),
4825 });
4826
4827 let merged = Rir::merge(&[rir1, rir2, rir3]);
4828 assert_eq!(merged.len(), 3);
4829
4830 assert!(matches!(
4831 merged.get(InstRef::from_raw(0)).data,
4832 InstData::IntConst(1)
4833 ));
4834 assert!(matches!(
4835 merged.get(InstRef::from_raw(1)).data,
4836 InstData::IntConst(2)
4837 ));
4838 assert!(matches!(
4839 merged.get(InstRef::from_raw(2)).data,
4840 InstData::IntConst(3)
4841 ));
4842 }
4843
4844 #[test]
4845 fn test_merge_preserves_spans() {
4846 let mut rir1 = Rir::new();
4847 rir1.add_inst(Inst {
4848 data: InstData::IntConst(1),
4849 span: Span::new(5, 10),
4850 });
4851
4852 let mut rir2 = Rir::new();
4853 rir2.add_inst(Inst {
4854 data: InstData::IntConst(2),
4855 span: Span::new(100, 105),
4856 });
4857
4858 let merged = Rir::merge(&[rir1, rir2]);
4859
4860 assert_eq!(merged.get(InstRef::from_raw(0)).span, Span::new(5, 10));
4862 assert_eq!(merged.get(InstRef::from_raw(1)).span, Span::new(100, 105));
4863 }
4864}