1use std::fmt;
7
8use gruel_builtins::Posture;
9use gruel_util::{BinOp, Span, UnaryOp};
10use lasso::{Key, Spur};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
16pub struct InstRef(u32);
17
18impl InstRef {
19 #[inline]
21 pub const fn from_raw(index: u32) -> Self {
22 Self(index)
23 }
24
25 #[inline]
27 pub const fn as_u32(self) -> u32 {
28 self.0
29 }
30}
31
32#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
34pub struct RirDirective {
35 pub name: Spur,
37 pub args: Vec<Spur>,
39 pub span: Span,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
51pub enum RirParamMode {
52 #[default]
55 Normal,
56 MutRef,
59 Ref,
61 Comptime,
63}
64
65#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
67pub struct RirParam {
68 pub name: Spur,
70 pub ty: Spur,
72 pub mode: RirParamMode,
74 pub is_comptime: bool,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
85pub enum RirArgMode {
86 #[default]
89 Normal,
90 MutRef,
92 Ref,
94}
95
96#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
98pub struct RirCallArg {
99 pub value: InstRef,
101 pub mode: RirArgMode,
103}
104
105#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
115pub enum RirPattern {
116 Wildcard(Span),
118 Int(i64, Span),
120 Bool(bool, Span),
122 Path {
124 module: Option<InstRef>,
126 type_name: Spur,
128 variant: Spur,
130 span: Span,
132 },
133 DataVariant {
135 module: Option<InstRef>,
137 type_name: Spur,
139 variant: Spur,
141 bindings: Vec<RirPatternBinding>,
143 span: Span,
145 },
146 StructVariant {
148 module: Option<InstRef>,
150 type_name: Spur,
152 variant: Spur,
154 field_bindings: Vec<RirStructPatternBinding>,
156 span: Span,
158 },
159 Ident {
162 name: Spur,
163 is_mut: bool,
164 span: Span,
165 },
166 Tuple {
173 elems: Vec<RirPattern>,
174 rest_position: Option<u32>,
175 span: Span,
176 },
177 Struct {
180 module: Option<InstRef>,
181 type_name: Spur,
182 fields: Vec<RirStructField>,
183 has_rest: bool,
184 span: Span,
185 },
186 ComptimeUnrollArm {
191 binding: Spur,
192 iterable: InstRef,
193 span: Span,
194 },
195}
196
197#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
206pub struct RirPatternBinding {
207 pub is_wildcard: bool,
209 pub is_mut: bool,
211 pub name: Option<Spur>,
213 pub sub_pattern: Option<Box<RirPattern>>,
217}
218
219#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
221pub struct RirStructPatternBinding {
222 pub field_name: Spur,
224 pub binding: RirPatternBinding,
226}
227
228#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
231pub struct RirStructField {
232 pub field_name: Spur,
233 pub pattern: RirPattern,
234}
235
236impl RirPattern {
237 pub fn span(&self) -> Span {
239 match self {
240 RirPattern::Wildcard(span) => *span,
241 RirPattern::Int(_, span) => *span,
242 RirPattern::Bool(_, span) => *span,
243 RirPattern::Path { span, .. } => *span,
244 RirPattern::DataVariant { span, .. } => *span,
245 RirPattern::StructVariant { span, .. } => *span,
246 RirPattern::Ident { span, .. } => *span,
247 RirPattern::Tuple { span, .. } => *span,
248 RirPattern::Struct { span, .. } => *span,
249 RirPattern::ComptimeUnrollArm { span, .. } => *span,
250 }
251 }
252}
253
254fn encode_binding(b: &RirPatternBinding, out: &mut Vec<u32>) {
258 let mut flags = if b.is_wildcard { 1u32 } else { 0 };
259 if b.is_mut {
260 flags |= 2;
261 }
262 if b.sub_pattern.is_some() {
263 flags |= 4;
264 }
265 out.push(flags);
266 out.push(b.name.map_or(u32::MAX, |s| s.into_usize() as u32));
267 if let Some(sub) = &b.sub_pattern {
268 encode_pattern_tree(sub, out);
269 }
270}
271
272fn decode_binding(data: &[u32]) -> (RirPatternBinding, usize) {
275 let flags = data[0];
276 let name_raw = data[1];
277 let name = if name_raw == u32::MAX {
278 None
279 } else {
280 Some(Spur::try_from_usize(name_raw as usize).unwrap())
281 };
282 let mut offset = 2;
283 let sub_pattern = if flags & 4 != 0 {
284 let (p, consumed) = decode_pattern_tree(&data[offset..]);
285 offset += consumed;
286 Some(Box::new(p))
287 } else {
288 None
289 };
290 (
291 RirPatternBinding {
292 is_wildcard: flags & 1 != 0,
293 is_mut: flags & 2 != 0,
294 name,
295 sub_pattern,
296 },
297 offset,
298 )
299}
300
301fn encode_struct_binding(fb: &RirStructPatternBinding, out: &mut Vec<u32>) {
304 out.push(fb.field_name.into_usize() as u32);
305 encode_binding(&fb.binding, out);
306}
307
308fn decode_struct_binding(data: &[u32]) -> (RirStructPatternBinding, usize) {
311 let field_name = Spur::try_from_usize(data[0] as usize).unwrap();
312 let (binding, consumed) = decode_binding(&data[1..]);
313 (
314 RirStructPatternBinding {
315 field_name,
316 binding,
317 },
318 1 + consumed,
319 )
320}
321
322fn encode_pattern_tree(pattern: &RirPattern, out: &mut Vec<u32>) {
328 match pattern {
329 RirPattern::Wildcard(span) => {
330 out.push(PatternKind::Wildcard as u32);
331 out.push(span.start());
332 out.push(span.len());
333 }
334 RirPattern::Int(value, span) => {
335 out.push(PatternKind::Int as u32);
336 out.push(span.start());
337 out.push(span.len());
338 out.push(*value as u32);
339 out.push((*value >> 32) as u32);
340 }
341 RirPattern::Bool(value, span) => {
342 out.push(PatternKind::Bool as u32);
343 out.push(span.start());
344 out.push(span.len());
345 out.push(if *value { 1 } else { 0 });
346 }
347 RirPattern::Path {
348 module,
349 type_name,
350 variant,
351 span,
352 } => {
353 out.push(PatternKind::Path as u32);
354 out.push(span.start());
355 out.push(span.len());
356 out.push(module.map_or(u32::MAX, |r| r.as_u32()));
357 out.push(type_name.into_usize() as u32);
358 out.push(variant.into_usize() as u32);
359 }
360 RirPattern::DataVariant {
361 module,
362 type_name,
363 variant,
364 bindings,
365 span,
366 } => {
367 out.push(PatternKind::DataVariant as u32);
368 out.push(span.start());
369 out.push(span.len());
370 out.push(module.map_or(u32::MAX, |r| r.as_u32()));
371 out.push(type_name.into_usize() as u32);
372 out.push(variant.into_usize() as u32);
373 out.push(bindings.len() as u32);
374 for b in bindings {
375 encode_binding(b, out);
376 }
377 }
378 RirPattern::StructVariant {
379 module,
380 type_name,
381 variant,
382 field_bindings,
383 span,
384 } => {
385 out.push(PatternKind::StructVariant as u32);
386 out.push(span.start());
387 out.push(span.len());
388 out.push(module.map_or(u32::MAX, |r| r.as_u32()));
389 out.push(type_name.into_usize() as u32);
390 out.push(variant.into_usize() as u32);
391 out.push(field_bindings.len() as u32);
392 for fb in field_bindings {
393 encode_struct_binding(fb, out);
394 }
395 }
396 RirPattern::Ident { name, is_mut, span } => {
397 out.push(PatternKind::Ident as u32);
398 out.push(span.start());
399 out.push(span.len());
400 out.push(name.into_usize() as u32);
401 out.push(if *is_mut { 1 } else { 0 });
402 }
403 RirPattern::Tuple {
404 elems,
405 rest_position,
406 span,
407 } => {
408 out.push(PatternKind::Tuple as u32);
409 out.push(span.start());
410 out.push(span.len());
411 out.push(rest_position.map_or(u32::MAX, |i| i));
412 out.push(elems.len() as u32);
413 for elem in elems {
414 encode_pattern_tree(elem, out);
415 }
416 }
417 RirPattern::Struct {
418 module,
419 type_name,
420 fields,
421 has_rest,
422 span,
423 } => {
424 out.push(PatternKind::Struct as u32);
425 out.push(span.start());
426 out.push(span.len());
427 out.push(module.map_or(u32::MAX, |r| r.as_u32()));
428 out.push(type_name.into_usize() as u32);
429 out.push(if *has_rest { 1 } else { 0 });
430 out.push(fields.len() as u32);
431 for f in fields {
432 out.push(f.field_name.into_usize() as u32);
433 encode_pattern_tree(&f.pattern, out);
434 }
435 }
436 RirPattern::ComptimeUnrollArm {
442 binding,
443 iterable,
444 span,
445 } => {
446 out.push(PatternKind::ComptimeUnrollArm as u32);
447 out.push(span.start());
448 out.push(span.len());
449 out.push(binding.into_usize() as u32);
450 out.push(iterable.as_u32());
451 }
452 }
453}
454
455fn decode_pattern_tree(data: &[u32]) -> (RirPattern, usize) {
458 let kind = data[0];
459 if kind == PatternKind::Wildcard as u32 {
460 let span = Span::new(data[1], data[1] + data[2]);
461 (RirPattern::Wildcard(span), 3)
462 } else if kind == PatternKind::Int as u32 {
463 let span = Span::new(data[1], data[1] + data[2]);
464 let value_lo = data[3] as i64;
465 let value_hi = data[4] as i64;
466 let value = value_lo | (value_hi << 32);
467 (RirPattern::Int(value, span), 5)
468 } else if kind == PatternKind::Bool as u32 {
469 let span = Span::new(data[1], data[1] + data[2]);
470 let value = data[3] != 0;
471 (RirPattern::Bool(value, span), 4)
472 } else if kind == PatternKind::Path as u32 {
473 let span = Span::new(data[1], data[1] + data[2]);
474 let module_raw = data[3];
475 let module = if module_raw == u32::MAX {
476 None
477 } else {
478 Some(InstRef::from_raw(module_raw))
479 };
480 let type_name = Spur::try_from_usize(data[4] as usize).unwrap();
481 let variant = Spur::try_from_usize(data[5] as usize).unwrap();
482 (
483 RirPattern::Path {
484 module,
485 type_name,
486 variant,
487 span,
488 },
489 6,
490 )
491 } else if kind == PatternKind::DataVariant as u32 {
492 let span = Span::new(data[1], data[1] + data[2]);
493 let module_raw = data[3];
494 let module = if module_raw == u32::MAX {
495 None
496 } else {
497 Some(InstRef::from_raw(module_raw))
498 };
499 let type_name = Spur::try_from_usize(data[4] as usize).unwrap();
500 let variant = Spur::try_from_usize(data[5] as usize).unwrap();
501 let n = data[6] as usize;
502 let mut bindings = Vec::with_capacity(n);
503 let mut offset = 7;
504 for _ in 0..n {
505 let (b, consumed) = decode_binding(&data[offset..]);
506 bindings.push(b);
507 offset += consumed;
508 }
509 (
510 RirPattern::DataVariant {
511 module,
512 type_name,
513 variant,
514 bindings,
515 span,
516 },
517 offset,
518 )
519 } else if kind == PatternKind::StructVariant as u32 {
520 let span = Span::new(data[1], data[1] + data[2]);
521 let module_raw = data[3];
522 let module = if module_raw == u32::MAX {
523 None
524 } else {
525 Some(InstRef::from_raw(module_raw))
526 };
527 let type_name = Spur::try_from_usize(data[4] as usize).unwrap();
528 let variant = Spur::try_from_usize(data[5] as usize).unwrap();
529 let n = data[6] as usize;
530 let mut field_bindings = Vec::with_capacity(n);
531 let mut offset = 7;
532 for _ in 0..n {
533 let (fb, consumed) = decode_struct_binding(&data[offset..]);
534 field_bindings.push(fb);
535 offset += consumed;
536 }
537 (
538 RirPattern::StructVariant {
539 module,
540 type_name,
541 variant,
542 field_bindings,
543 span,
544 },
545 offset,
546 )
547 } else if kind == PatternKind::Ident as u32 {
548 let span = Span::new(data[1], data[1] + data[2]);
549 let name = Spur::try_from_usize(data[3] as usize).unwrap();
550 let is_mut = data[4] != 0;
551 (RirPattern::Ident { name, is_mut, span }, 5)
552 } else if kind == PatternKind::Tuple as u32 {
553 let span = Span::new(data[1], data[1] + data[2]);
554 let rest_raw = data[3];
555 let rest_position = if rest_raw == u32::MAX {
556 None
557 } else {
558 Some(rest_raw)
559 };
560 let n = data[4] as usize;
561 let mut offset = 5;
562 let mut elems = Vec::with_capacity(n);
563 for _ in 0..n {
564 let (p, consumed) = decode_pattern_tree(&data[offset..]);
565 elems.push(p);
566 offset += consumed;
567 }
568 (
569 RirPattern::Tuple {
570 elems,
571 rest_position,
572 span,
573 },
574 offset,
575 )
576 } else if kind == PatternKind::Struct as u32 {
577 let span = Span::new(data[1], data[1] + data[2]);
578 let module_raw = data[3];
579 let module = if module_raw == u32::MAX {
580 None
581 } else {
582 Some(InstRef::from_raw(module_raw))
583 };
584 let type_name = Spur::try_from_usize(data[4] as usize).unwrap();
585 let has_rest = data[5] != 0;
586 let n = data[6] as usize;
587 let mut offset = 7;
588 let mut fields = Vec::with_capacity(n);
589 for _ in 0..n {
590 let field_name = Spur::try_from_usize(data[offset] as usize).unwrap();
591 offset += 1;
592 let (pattern, consumed) = decode_pattern_tree(&data[offset..]);
593 offset += consumed;
594 fields.push(RirStructField {
595 field_name,
596 pattern,
597 });
598 }
599 (
600 RirPattern::Struct {
601 module,
602 type_name,
603 fields,
604 has_rest,
605 span,
606 },
607 offset,
608 )
609 } else if kind == PatternKind::ComptimeUnrollArm as u32 {
610 let span = Span::new(data[1], data[1] + data[2]);
611 let binding = Spur::try_from_usize(data[3] as usize).unwrap();
612 let iterable = InstRef::from_raw(data[4]);
613 (
614 RirPattern::ComptimeUnrollArm {
615 binding,
616 iterable,
617 span,
618 },
619 5,
620 )
621 } else {
622 panic!("Unknown pattern tree tag: {}", kind);
623 }
624}
625
626const CALL_ARG_SIZE: u32 = 2;
631
632const PARAM_SIZE: u32 = 4;
635
636#[repr(u32)]
641#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
642pub enum PatternKind {
643 Wildcard = 0,
645 Int = 1,
647 Bool = 2,
649 Path = 3,
652 DataVariant = 4,
655 StructVariant = 5,
658 Ident = 6,
661 Tuple = 7,
663 Struct = 8,
666 ComptimeUnrollArm = 9,
668}
669
670const 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;
680
681#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
683pub struct RirDestructureField {
684 pub field_name: Spur,
686 pub binding_name: Option<Spur>,
688 pub is_wildcard: bool,
690 pub is_mut: bool,
692}
693
694const FIELD_INIT_SIZE: u32 = 2;
697
698const FIELD_DECL_SIZE: u32 = 3;
701
702#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
710pub struct FunctionSpan {
711 pub name: Spur,
713 pub body_start: InstRef,
716 pub decl: InstRef,
719}
720
721impl FunctionSpan {
722 pub fn new(name: Spur, body_start: InstRef, decl: InstRef) -> Self {
724 Self {
725 name,
726 body_start,
727 decl,
728 }
729 }
730
731 pub fn instruction_count(&self) -> u32 {
733 self.decl.as_u32() - self.body_start.as_u32() + 1
734 }
735}
736
737#[derive(Debug)]
742pub struct RirFunctionView<'a> {
743 rir: &'a Rir,
744 body_start: InstRef,
745 decl: InstRef,
746}
747
748impl<'a> RirFunctionView<'a> {
749 #[inline]
753 pub fn get(&self, inst_ref: InstRef) -> &'a Inst {
754 debug_assert!(
755 inst_ref.as_u32() >= self.body_start.as_u32()
756 && inst_ref.as_u32() <= self.decl.as_u32(),
757 "InstRef {} is outside function range [{}, {}]",
758 inst_ref,
759 self.body_start,
760 self.decl
761 );
762 self.rir.get(inst_ref)
763 }
764
765 #[inline]
767 pub fn fn_decl(&self) -> &'a Inst {
768 self.rir.get(self.decl)
769 }
770
771 pub fn iter(&self) -> impl Iterator<Item = (InstRef, &'a Inst)> {
773 let start = self.body_start.as_u32();
774 let end = self.decl.as_u32() + 1;
775 (start..end).map(move |i| {
776 let inst_ref = InstRef::from_raw(i);
777 (inst_ref, self.rir.get(inst_ref))
778 })
779 }
780
781 pub fn len(&self) -> usize {
783 (self.decl.as_u32() - self.body_start.as_u32() + 1) as usize
784 }
785
786 pub fn is_empty(&self) -> bool {
788 self.body_start.as_u32() > self.decl.as_u32()
789 }
790
791 pub fn rir(&self) -> &'a Rir {
794 self.rir
795 }
796}
797
798#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
806pub struct RirExternFn {
807 pub library: Spur,
809 pub name: Spur,
811 pub directives_start: u32,
813 pub directives_len: u32,
815 pub params_start: u32,
817 pub params_len: u32,
819 pub return_type: Spur,
821 pub span: Span,
823 pub block_span: Span,
825 #[serde(default = "default_rir_link_mode")]
827 pub link_mode: RirLinkMode,
828}
829
830#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
832pub enum RirLinkMode {
833 Dynamic,
834 Static,
835}
836
837fn default_rir_link_mode() -> RirLinkMode {
838 RirLinkMode::Dynamic
839}
840
841#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
843pub struct Rir {
844 instructions: Vec<Inst>,
846 extra: Vec<u32>,
848 function_spans: Vec<FunctionSpan>,
850 extern_fns: Vec<RirExternFn>,
852 empty_link_extern_blocks: Vec<(Spur, RirLinkMode, Span)>,
857}
858
859impl Rir {
860 pub fn new() -> Self {
862 Self::default()
863 }
864
865 pub fn add_inst(&mut self, inst: Inst) -> InstRef {
867 debug_assert!(
869 self.instructions.len() < u32::MAX as usize,
870 "RIR instruction count overflow: {} instructions exceeds u32::MAX - 1",
871 self.instructions.len()
872 );
873
874 let index = self.instructions.len() as u32;
875 self.instructions.push(inst);
876 InstRef::from_raw(index)
877 }
878
879 #[inline]
881 pub fn get(&self, inst_ref: InstRef) -> &Inst {
882 &self.instructions[inst_ref.0 as usize]
883 }
884
885 #[inline]
887 pub fn get_mut(&mut self, inst_ref: InstRef) -> &mut Inst {
888 &mut self.instructions[inst_ref.0 as usize]
889 }
890
891 #[inline]
893 pub fn len(&self) -> usize {
894 self.instructions.len()
895 }
896
897 #[inline]
899 pub fn is_empty(&self) -> bool {
900 self.instructions.is_empty()
901 }
902
903 pub fn iter(&self) -> impl Iterator<Item = (InstRef, &Inst)> {
905 self.instructions
906 .iter()
907 .enumerate()
908 .map(|(i, inst)| (InstRef::from_raw(i as u32), inst))
909 }
910
911 pub fn add_extra(&mut self, data: &[u32]) -> u32 {
913 debug_assert!(
915 self.extra.len() <= u32::MAX as usize,
916 "RIR extra data overflow: {} entries exceeds u32::MAX",
917 self.extra.len()
918 );
919 debug_assert!(
920 self.extra.len().saturating_add(data.len()) <= u32::MAX as usize,
921 "RIR extra data would overflow: {} + {} exceeds u32::MAX",
922 self.extra.len(),
923 data.len()
924 );
925
926 let start = self.extra.len() as u32;
927 self.extra.extend_from_slice(data);
928 start
929 }
930
931 #[inline]
933 pub fn get_extra(&self, start: u32, len: u32) -> &[u32] {
934 let start = start as usize;
935 let end = start + len as usize;
936 &self.extra[start..end]
937 }
938
939 pub fn add_inst_refs(&mut self, refs: &[InstRef]) -> (u32, u32) {
943 let data: Vec<u32> = refs.iter().map(|r| r.as_u32()).collect();
944 let start = self.add_extra(&data);
945 (start, refs.len() as u32)
946 }
947
948 pub fn get_inst_refs(&self, start: u32, len: u32) -> Vec<InstRef> {
950 self.get_extra(start, len)
951 .iter()
952 .map(|&v| InstRef::from_raw(v))
953 .collect()
954 }
955
956 pub fn add_symbols(&mut self, symbols: &[Spur]) -> (u32, u32) {
958 let data: Vec<u32> = symbols.iter().map(|s| s.into_usize() as u32).collect();
959 let start = self.add_extra(&data);
960 (start, symbols.len() as u32)
961 }
962
963 pub fn get_symbols(&self, start: u32, len: u32) -> Vec<Spur> {
965 self.get_extra(start, len)
966 .iter()
967 .map(|&v| Spur::try_from_usize(v as usize).unwrap())
968 .collect()
969 }
970
971 pub fn add_enum_variant_decls(
980 &mut self,
981 variants: &[(Spur, Vec<Spur>, Vec<Spur>)],
982 ) -> (u32, u32) {
983 let start = self.extra.len() as u32;
984 for (name, field_types, field_names) in variants {
985 self.extra.push(name.into_usize() as u32);
986 self.extra.push(field_types.len() as u32);
987 let is_struct = if field_names.is_empty() { 0u32 } else { 1u32 };
988 self.extra.push(is_struct);
989 for field_ty in field_types {
990 self.extra.push(field_ty.into_usize() as u32);
991 }
992 for field_name in field_names {
993 self.extra.push(field_name.into_usize() as u32);
994 }
995 }
996 (start, variants.len() as u32)
997 }
998
999 pub fn get_enum_variant_decls(
1003 &self,
1004 start: u32,
1005 variant_count: u32,
1006 ) -> Vec<(Spur, Vec<Spur>, Vec<Spur>)> {
1007 let mut result = Vec::with_capacity(variant_count as usize);
1008 let mut pos = start as usize;
1009 for _ in 0..variant_count {
1010 let name = Spur::try_from_usize(self.extra[pos] as usize).unwrap();
1011 let field_count = self.extra[pos + 1] as usize;
1012 let is_struct = self.extra[pos + 2] != 0;
1013 pos += 3;
1014 let field_types: Vec<Spur> = (0..field_count)
1015 .map(|i| Spur::try_from_usize(self.extra[pos + i] as usize).unwrap())
1016 .collect();
1017 pos += field_count;
1018 let field_names = if is_struct {
1019 let names: Vec<Spur> = (0..field_count)
1020 .map(|i| Spur::try_from_usize(self.extra[pos + i] as usize).unwrap())
1021 .collect();
1022 pos += field_count;
1023 names
1024 } else {
1025 Vec::new()
1026 };
1027 result.push((name, field_types, field_names));
1028 }
1029 result
1030 }
1031
1032 pub fn add_call_args(&mut self, args: &[RirCallArg]) -> (u32, u32) {
1035 let mut data = Vec::with_capacity(args.len() * CALL_ARG_SIZE as usize);
1036 for arg in args {
1037 data.push(arg.value.as_u32());
1038 data.push(arg.mode as u32);
1039 }
1040 let start = self.add_extra(&data);
1041 (start, args.len() as u32)
1042 }
1043
1044 pub fn get_call_args(&self, start: u32, len: u32) -> Vec<RirCallArg> {
1046 let data = self.get_extra(start, len * CALL_ARG_SIZE);
1047 let mut args = Vec::with_capacity(len as usize);
1048 for chunk in data.chunks(CALL_ARG_SIZE as usize) {
1049 let value = InstRef::from_raw(chunk[0]);
1050 let mode = match chunk[1] {
1051 0 => RirArgMode::Normal,
1052 1 => RirArgMode::MutRef,
1053 2 => RirArgMode::Ref,
1054 _ => RirArgMode::Normal, };
1056 args.push(RirCallArg { value, mode });
1057 }
1058 args
1059 }
1060
1061 pub fn add_params(&mut self, params: &[RirParam]) -> (u32, u32) {
1064 let mut data = Vec::with_capacity(params.len() * PARAM_SIZE as usize);
1065 for param in params {
1066 data.push(param.name.into_usize() as u32);
1067 data.push(param.ty.into_usize() as u32);
1068 data.push(param.mode as u32);
1069 data.push(param.is_comptime as u32);
1070 }
1071 let start = self.add_extra(&data);
1072 (start, params.len() as u32)
1073 }
1074
1075 pub fn get_params(&self, start: u32, len: u32) -> Vec<RirParam> {
1077 let data = self.get_extra(start, len * PARAM_SIZE);
1078 let mut params = Vec::with_capacity(len as usize);
1079 for chunk in data.chunks(PARAM_SIZE as usize) {
1080 let name = Spur::try_from_usize(chunk[0] as usize).unwrap();
1081 let ty = Spur::try_from_usize(chunk[1] as usize).unwrap();
1082 let mode = match chunk[2] {
1083 0 => RirParamMode::Normal,
1084 1 => RirParamMode::MutRef,
1085 2 => RirParamMode::Ref,
1086 3 => RirParamMode::Comptime,
1087 _ => RirParamMode::Normal, };
1089 let is_comptime = chunk[3] != 0;
1090 params.push(RirParam {
1091 name,
1092 ty,
1093 mode,
1094 is_comptime,
1095 });
1096 }
1097 params
1098 }
1099
1100 pub fn add_match_arms(&mut self, arms: &[(RirPattern, InstRef)]) -> (u32, u32) {
1103 let start = self.extra.len() as u32;
1104 for (pattern, body) in arms {
1105 match pattern {
1106 RirPattern::Wildcard(span) => {
1107 self.extra.push(PatternKind::Wildcard as u32);
1108 self.extra.push(span.start());
1109 self.extra.push(span.len());
1110 self.extra.push(body.as_u32());
1111 }
1112 RirPattern::Int(value, span) => {
1113 self.extra.push(PatternKind::Int as u32);
1114 self.extra.push(span.start());
1115 self.extra.push(span.len());
1116 self.extra.push(*value as u32);
1118 self.extra.push((*value >> 32) as u32);
1119 self.extra.push(body.as_u32());
1120 }
1121 RirPattern::Bool(value, span) => {
1122 self.extra.push(PatternKind::Bool as u32);
1123 self.extra.push(span.start());
1124 self.extra.push(span.len());
1125 self.extra.push(if *value { 1 } else { 0 });
1126 self.extra.push(body.as_u32());
1127 }
1128 RirPattern::Path {
1129 module,
1130 type_name,
1131 variant,
1132 span,
1133 } => {
1134 self.extra.push(PatternKind::Path as u32);
1135 self.extra.push(span.start());
1136 self.extra.push(span.len());
1137 self.extra.push(module.map_or(u32::MAX, |r| r.as_u32()));
1139 self.extra.push(type_name.into_usize() as u32);
1140 self.extra.push(variant.into_usize() as u32);
1141 self.extra.push(body.as_u32());
1142 }
1143 RirPattern::DataVariant {
1144 module,
1145 type_name,
1146 variant,
1147 bindings,
1148 span,
1149 } => {
1150 self.extra.push(PatternKind::DataVariant as u32);
1151 self.extra.push(span.start());
1152 self.extra.push(span.len());
1153 self.extra.push(module.map_or(u32::MAX, |r| r.as_u32()));
1154 self.extra.push(type_name.into_usize() as u32);
1155 self.extra.push(variant.into_usize() as u32);
1156 self.extra.push(body.as_u32());
1157 self.extra.push(bindings.len() as u32);
1158 for binding in bindings {
1159 encode_binding(binding, &mut self.extra);
1160 }
1161 }
1162 RirPattern::StructVariant {
1163 module,
1164 type_name,
1165 variant,
1166 field_bindings,
1167 span,
1168 } => {
1169 self.extra.push(PatternKind::StructVariant as u32);
1170 self.extra.push(span.start());
1171 self.extra.push(span.len());
1172 self.extra.push(module.map_or(u32::MAX, |r| r.as_u32()));
1173 self.extra.push(type_name.into_usize() as u32);
1174 self.extra.push(variant.into_usize() as u32);
1175 self.extra.push(body.as_u32());
1176 self.extra.push(field_bindings.len() as u32);
1177 for fb in field_bindings {
1178 encode_struct_binding(fb, &mut self.extra);
1179 }
1180 }
1181 RirPattern::Ident { name, is_mut, span } => {
1182 self.extra.push(PatternKind::Ident as u32);
1183 self.extra.push(span.start());
1184 self.extra.push(span.len());
1185 self.extra.push(body.as_u32());
1186 self.extra.push(name.into_usize() as u32);
1187 self.extra.push(if *is_mut { 1 } else { 0 });
1188 }
1189 RirPattern::Tuple {
1190 elems,
1191 rest_position,
1192 span,
1193 } => {
1194 self.extra.push(PatternKind::Tuple as u32);
1195 self.extra.push(span.start());
1196 self.extra.push(span.len());
1197 self.extra.push(body.as_u32());
1198 self.extra.push(rest_position.map_or(u32::MAX, |i| i));
1199 self.extra.push(elems.len() as u32);
1200 for elem in elems {
1201 encode_pattern_tree(elem, &mut self.extra);
1202 }
1203 }
1204 RirPattern::Struct {
1205 module,
1206 type_name,
1207 fields,
1208 has_rest,
1209 span,
1210 } => {
1211 self.extra.push(PatternKind::Struct as u32);
1212 self.extra.push(span.start());
1213 self.extra.push(span.len());
1214 self.extra.push(body.as_u32());
1215 self.extra.push(module.map_or(u32::MAX, |r| r.as_u32()));
1216 self.extra.push(type_name.into_usize() as u32);
1217 self.extra.push(if *has_rest { 1 } else { 0 });
1218 self.extra.push(fields.len() as u32);
1219 for field in fields {
1220 self.extra.push(field.field_name.into_usize() as u32);
1221 encode_pattern_tree(&field.pattern, &mut self.extra);
1222 }
1223 }
1224 RirPattern::ComptimeUnrollArm {
1225 binding,
1226 iterable,
1227 span,
1228 } => {
1229 self.extra.push(PatternKind::ComptimeUnrollArm as u32);
1230 self.extra.push(span.start());
1231 self.extra.push(span.len());
1232 self.extra.push(body.as_u32());
1233 self.extra.push(binding.into_usize() as u32);
1234 self.extra.push(iterable.as_u32());
1235 }
1236 }
1237 }
1238 (start, arms.len() as u32)
1239 }
1240
1241 pub fn get_match_arms(&self, start: u32, arm_count: u32) -> Vec<(RirPattern, InstRef)> {
1243 let mut arms = Vec::with_capacity(arm_count as usize);
1244 let mut pos = start as usize;
1245
1246 for _ in 0..arm_count {
1247 let kind = self.extra[pos];
1248 match kind {
1249 k if k == PatternKind::Wildcard as u32 => {
1250 let span_start = self.extra[pos + 1];
1251 let span_len = self.extra[pos + 2];
1252 let span = Span::new(span_start, span_start + span_len);
1253 let body = InstRef::from_raw(self.extra[pos + 3]);
1254 arms.push((RirPattern::Wildcard(span), body));
1255 pos += PATTERN_WILDCARD_SIZE as usize;
1256 }
1257 k if k == PatternKind::Int as u32 => {
1258 let span_start = self.extra[pos + 1];
1259 let span_len = self.extra[pos + 2];
1260 let span = Span::new(span_start, span_start + span_len);
1261 let value_lo = self.extra[pos + 3] as i64;
1262 let value_hi = self.extra[pos + 4] as i64;
1263 let value = value_lo | (value_hi << 32);
1264 let body = InstRef::from_raw(self.extra[pos + 5]);
1265 arms.push((RirPattern::Int(value, span), body));
1266 pos += PATTERN_INT_SIZE as usize;
1267 }
1268 k if k == PatternKind::Bool as u32 => {
1269 let span_start = self.extra[pos + 1];
1270 let span_len = self.extra[pos + 2];
1271 let span = Span::new(span_start, span_start + span_len);
1272 let value = self.extra[pos + 3] != 0;
1273 let body = InstRef::from_raw(self.extra[pos + 4]);
1274 arms.push((RirPattern::Bool(value, span), body));
1275 pos += PATTERN_BOOL_SIZE as usize;
1276 }
1277 k if k == PatternKind::Path as u32 => {
1278 let span_start = self.extra[pos + 1];
1279 let span_len = self.extra[pos + 2];
1280 let span = Span::new(span_start, span_start + span_len);
1281 let module_raw = self.extra[pos + 3];
1283 let module = if module_raw == u32::MAX {
1284 None
1285 } else {
1286 Some(InstRef::from_raw(module_raw))
1287 };
1288 let type_name = Spur::try_from_usize(self.extra[pos + 4] as usize).unwrap();
1289 let variant = Spur::try_from_usize(self.extra[pos + 5] as usize).unwrap();
1290 let body = InstRef::from_raw(self.extra[pos + 6]);
1291 arms.push((
1292 RirPattern::Path {
1293 module,
1294 type_name,
1295 variant,
1296 span,
1297 },
1298 body,
1299 ));
1300 pos += PATTERN_PATH_SIZE as usize;
1301 }
1302 k if k == PatternKind::DataVariant as u32 => {
1303 let span_start = self.extra[pos + 1];
1304 let span_len = self.extra[pos + 2];
1305 let span = Span::new(span_start, span_start + span_len);
1306 let module_raw = self.extra[pos + 3];
1307 let module = if module_raw == u32::MAX {
1308 None
1309 } else {
1310 Some(InstRef::from_raw(module_raw))
1311 };
1312 let type_name = Spur::try_from_usize(self.extra[pos + 4] as usize).unwrap();
1313 let variant = Spur::try_from_usize(self.extra[pos + 5] as usize).unwrap();
1314 let body = InstRef::from_raw(self.extra[pos + 6]);
1315 let bindings_len = self.extra[pos + 7] as usize;
1316 let mut bindings = Vec::with_capacity(bindings_len);
1317 let mut offset = 8;
1318 for _ in 0..bindings_len {
1319 let (b, consumed) = decode_binding(&self.extra[pos + offset..]);
1320 bindings.push(b);
1321 offset += consumed;
1322 }
1323 arms.push((
1324 RirPattern::DataVariant {
1325 module,
1326 type_name,
1327 variant,
1328 bindings,
1329 span,
1330 },
1331 body,
1332 ));
1333 pos += offset;
1334 }
1335 k if k == PatternKind::StructVariant as u32 => {
1336 let span_start = self.extra[pos + 1];
1337 let span_len = self.extra[pos + 2];
1338 let span = Span::new(span_start, span_start + span_len);
1339 let module_raw = self.extra[pos + 3];
1340 let module = if module_raw == u32::MAX {
1341 None
1342 } else {
1343 Some(InstRef::from_raw(module_raw))
1344 };
1345 let type_name = Spur::try_from_usize(self.extra[pos + 4] as usize).unwrap();
1346 let variant = Spur::try_from_usize(self.extra[pos + 5] as usize).unwrap();
1347 let body = InstRef::from_raw(self.extra[pos + 6]);
1348 let bindings_len = self.extra[pos + 7] as usize;
1349 let mut field_bindings = Vec::with_capacity(bindings_len);
1350 let mut offset = 8;
1351 for _ in 0..bindings_len {
1352 let (fb, consumed) = decode_struct_binding(&self.extra[pos + offset..]);
1353 field_bindings.push(fb);
1354 offset += consumed;
1355 }
1356 arms.push((
1357 RirPattern::StructVariant {
1358 module,
1359 type_name,
1360 variant,
1361 field_bindings,
1362 span,
1363 },
1364 body,
1365 ));
1366 pos += offset;
1367 }
1368 k if k == PatternKind::Ident as u32 => {
1369 let span_start = self.extra[pos + 1];
1370 let span_len = self.extra[pos + 2];
1371 let span = Span::new(span_start, span_start + span_len);
1372 let body = InstRef::from_raw(self.extra[pos + 3]);
1373 let name = Spur::try_from_usize(self.extra[pos + 4] as usize).unwrap();
1374 let is_mut = self.extra[pos + 5] != 0;
1375 arms.push((RirPattern::Ident { name, is_mut, span }, body));
1376 pos += 6;
1377 }
1378 k if k == PatternKind::Tuple as u32 => {
1379 let span_start = self.extra[pos + 1];
1380 let span_len = self.extra[pos + 2];
1381 let span = Span::new(span_start, span_start + span_len);
1382 let body = InstRef::from_raw(self.extra[pos + 3]);
1383 let rest_raw = self.extra[pos + 4];
1384 let rest_position = if rest_raw == u32::MAX {
1385 None
1386 } else {
1387 Some(rest_raw)
1388 };
1389 let n = self.extra[pos + 5] as usize;
1390 let mut elems = Vec::with_capacity(n);
1391 let mut offset = 6;
1392 for _ in 0..n {
1393 let (p, consumed) = decode_pattern_tree(&self.extra[pos + offset..]);
1394 elems.push(p);
1395 offset += consumed;
1396 }
1397 arms.push((
1398 RirPattern::Tuple {
1399 elems,
1400 rest_position,
1401 span,
1402 },
1403 body,
1404 ));
1405 pos += offset;
1406 }
1407 k if k == PatternKind::Struct as u32 => {
1408 let span_start = self.extra[pos + 1];
1409 let span_len = self.extra[pos + 2];
1410 let span = Span::new(span_start, span_start + span_len);
1411 let body = InstRef::from_raw(self.extra[pos + 3]);
1412 let module_raw = self.extra[pos + 4];
1413 let module = if module_raw == u32::MAX {
1414 None
1415 } else {
1416 Some(InstRef::from_raw(module_raw))
1417 };
1418 let type_name = Spur::try_from_usize(self.extra[pos + 5] as usize).unwrap();
1419 let has_rest = self.extra[pos + 6] != 0;
1420 let n = self.extra[pos + 7] as usize;
1421 let mut fields = Vec::with_capacity(n);
1422 let mut offset = 8;
1423 for _ in 0..n {
1424 let field_name =
1425 Spur::try_from_usize(self.extra[pos + offset] as usize).unwrap();
1426 offset += 1;
1427 let (pattern, consumed) = decode_pattern_tree(&self.extra[pos + offset..]);
1428 offset += consumed;
1429 fields.push(RirStructField {
1430 field_name,
1431 pattern,
1432 });
1433 }
1434 arms.push((
1435 RirPattern::Struct {
1436 module,
1437 type_name,
1438 fields,
1439 has_rest,
1440 span,
1441 },
1442 body,
1443 ));
1444 pos += offset;
1445 }
1446 k if k == PatternKind::ComptimeUnrollArm as u32 => {
1447 let span_start = self.extra[pos + 1];
1448 let span_len = self.extra[pos + 2];
1449 let span = Span::new(span_start, span_start + span_len);
1450 let body = InstRef::from_raw(self.extra[pos + 3]);
1451 let binding = Spur::try_from_usize(self.extra[pos + 4] as usize).unwrap();
1452 let iterable = InstRef::from_raw(self.extra[pos + 5]);
1453 arms.push((
1454 RirPattern::ComptimeUnrollArm {
1455 binding,
1456 iterable,
1457 span,
1458 },
1459 body,
1460 ));
1461 pos += 6;
1462 }
1463 _ => panic!("Unknown pattern kind: {}", kind),
1464 }
1465 }
1466 arms
1467 }
1468
1469 pub fn add_field_inits(&mut self, fields: &[(Spur, InstRef)]) -> (u32, u32) {
1472 let mut data = Vec::with_capacity(fields.len() * FIELD_INIT_SIZE as usize);
1473 for (name, value) in fields {
1474 data.push(name.into_usize() as u32);
1475 data.push(value.as_u32());
1476 }
1477 let start = self.add_extra(&data);
1478 (start, fields.len() as u32)
1479 }
1480
1481 pub fn get_field_inits(&self, start: u32, len: u32) -> Vec<(Spur, InstRef)> {
1483 let data = self.get_extra(start, len * FIELD_INIT_SIZE);
1484 let mut fields = Vec::with_capacity(len as usize);
1485 for chunk in data.chunks(FIELD_INIT_SIZE as usize) {
1486 let name = Spur::try_from_usize(chunk[0] as usize).unwrap();
1487 let value = InstRef::from_raw(chunk[1]);
1488 fields.push((name, value));
1489 }
1490 fields
1491 }
1492
1493 pub fn add_field_decls(&mut self, fields: &[(Spur, Spur)]) -> (u32, u32) {
1497 let with_vis: Vec<(Spur, Spur, bool)> =
1498 fields.iter().map(|(n, t)| (*n, *t, false)).collect();
1499 self.add_field_decls_with_vis(&with_vis)
1500 }
1501
1502 pub fn add_field_decls_with_vis(&mut self, fields: &[(Spur, Spur, bool)]) -> (u32, u32) {
1504 let mut data = Vec::with_capacity(fields.len() * FIELD_DECL_SIZE as usize);
1505 for (name, ty, is_pub) in fields {
1506 data.push(name.into_usize() as u32);
1507 data.push(ty.into_usize() as u32);
1508 data.push(if *is_pub { 1 } else { 0 });
1509 }
1510 let start = self.add_extra(&data);
1511 (start, fields.len() as u32)
1512 }
1513
1514 pub fn get_field_decls(&self, start: u32, len: u32) -> Vec<(Spur, Spur)> {
1516 self.get_field_decls_with_vis(start, len)
1517 .into_iter()
1518 .map(|(n, t, _)| (n, t))
1519 .collect()
1520 }
1521
1522 pub fn get_field_decls_with_vis(&self, start: u32, len: u32) -> Vec<(Spur, Spur, bool)> {
1524 let data = self.get_extra(start, len * FIELD_DECL_SIZE);
1525 let mut fields = Vec::with_capacity(len as usize);
1526 for chunk in data.chunks(FIELD_DECL_SIZE as usize) {
1527 let name = Spur::try_from_usize(chunk[0] as usize).unwrap();
1528 let ty = Spur::try_from_usize(chunk[1] as usize).unwrap();
1529 let is_pub = chunk[2] != 0;
1530 fields.push((name, ty, is_pub));
1531 }
1532 fields
1533 }
1534
1535 pub fn add_directives(&mut self, directives: &[RirDirective]) -> (u32, u32) {
1538 let start = self.extra.len() as u32;
1539 for directive in directives {
1540 self.extra.push(directive.name.into_usize() as u32);
1541 self.extra.push(directive.span.start());
1542 self.extra.push(directive.span.len());
1543 self.extra.push(directive.args.len() as u32);
1544 for arg in &directive.args {
1545 self.extra.push(arg.into_usize() as u32);
1546 }
1547 }
1548 (start, directives.len() as u32)
1549 }
1550
1551 pub fn get_directives(&self, start: u32, directive_count: u32) -> Vec<RirDirective> {
1553 let mut directives = Vec::with_capacity(directive_count as usize);
1554 let mut pos = start as usize;
1555
1556 for _ in 0..directive_count {
1557 let name = Spur::try_from_usize(self.extra[pos] as usize).unwrap();
1558 let span = Span::new(self.extra[pos + 1], self.extra[pos + 2]);
1559 let args_len = self.extra[pos + 3] as usize;
1560 pos += 4;
1561
1562 let args: Vec<Spur> = (0..args_len)
1563 .map(|i| Spur::try_from_usize(self.extra[pos + i] as usize).unwrap())
1564 .collect();
1565 pos += args_len;
1566
1567 directives.push(RirDirective { name, args, span });
1568 }
1569 directives
1570 }
1571
1572 pub fn add_destructure_fields(&mut self, fields: &[RirDestructureField]) -> (u32, u32) {
1581 let start = self.extra.len() as u32;
1582 for field in fields {
1583 self.extra.push(field.field_name.into_usize() as u32);
1584 self.extra.push(
1585 field
1586 .binding_name
1587 .map_or(u32::MAX, |s| s.into_usize() as u32),
1588 );
1589 self.extra.push(field.is_wildcard as u32);
1590 self.extra.push(field.is_mut as u32);
1591 }
1592 (start, fields.len() as u32)
1593 }
1594
1595 pub fn get_destructure_fields(&self, start: u32, count: u32) -> Vec<RirDestructureField> {
1597 let mut fields = Vec::with_capacity(count as usize);
1598 for i in 0..count {
1599 let pos = (start + i * DESTRUCTURE_FIELD_SIZE) as usize;
1600 let field_name = Spur::try_from_usize(self.extra[pos] as usize).unwrap();
1601 let binding_raw = self.extra[pos + 1];
1602 let binding_name = if binding_raw == u32::MAX {
1603 None
1604 } else {
1605 Some(Spur::try_from_usize(binding_raw as usize).unwrap())
1606 };
1607 let is_wildcard = self.extra[pos + 2] != 0;
1608 let is_mut = self.extra[pos + 3] != 0;
1609 fields.push(RirDestructureField {
1610 field_name,
1611 binding_name,
1612 is_wildcard,
1613 is_mut,
1614 });
1615 }
1616 fields
1617 }
1618
1619 pub fn add_extern_fn(&mut self, extern_fn: RirExternFn) {
1625 self.extern_fns.push(extern_fn);
1626 }
1627
1628 pub fn extern_fns(&self) -> &[RirExternFn] {
1630 &self.extern_fns
1631 }
1632
1633 pub fn add_empty_link_extern_block(
1635 &mut self,
1636 library: Spur,
1637 link_mode: RirLinkMode,
1638 span: Span,
1639 ) {
1640 self.empty_link_extern_blocks
1641 .push((library, link_mode, span));
1642 }
1643
1644 pub fn empty_link_extern_blocks(&self) -> &[(Spur, RirLinkMode, Span)] {
1648 &self.empty_link_extern_blocks
1649 }
1650
1651 pub fn add_function_span(&mut self, span: FunctionSpan) {
1652 self.function_spans.push(span);
1653 }
1654
1655 pub fn function_spans(&self) -> &[FunctionSpan] {
1657 &self.function_spans
1658 }
1659
1660 pub fn functions(&self) -> impl Iterator<Item = &FunctionSpan> {
1662 self.function_spans.iter()
1663 }
1664
1665 pub fn function_count(&self) -> usize {
1667 self.function_spans.len()
1668 }
1669
1670 pub fn function_view(&self, fn_span: &FunctionSpan) -> RirFunctionView<'_> {
1672 RirFunctionView {
1673 rir: self,
1674 body_start: fn_span.body_start,
1675 decl: fn_span.decl,
1676 }
1677 }
1678
1679 pub fn find_function(&self, name: Spur) -> Option<&FunctionSpan> {
1681 self.function_spans.iter().find(|span| span.name == name)
1682 }
1683
1684 pub fn current_inst_index(&self) -> u32 {
1686 self.instructions.len() as u32
1687 }
1688
1689 pub fn merge(rirs: &[Rir]) -> Rir {
1703 if rirs.is_empty() {
1704 return Rir::new();
1705 }
1706
1707 if rirs.len() == 1 {
1708 return Rir {
1710 instructions: rirs[0].instructions.clone(),
1711 extra: rirs[0].extra.clone(),
1712 function_spans: rirs[0].function_spans.clone(),
1713 extern_fns: rirs[0].extern_fns.clone(),
1714 empty_link_extern_blocks: rirs[0].empty_link_extern_blocks.clone(),
1715 };
1716 }
1717
1718 let total_instructions: usize = rirs.iter().map(|r| r.instructions.len()).sum();
1720 let total_extra: usize = rirs.iter().map(|r| r.extra.len()).sum();
1721 let total_functions: usize = rirs.iter().map(|r| r.function_spans.len()).sum();
1722 let total_extern: usize = rirs.iter().map(|r| r.extern_fns.len()).sum();
1723 let total_empty_blocks: usize = rirs.iter().map(|r| r.empty_link_extern_blocks.len()).sum();
1724
1725 let mut merged = Rir {
1726 instructions: Vec::with_capacity(total_instructions),
1727 extra: Vec::with_capacity(total_extra),
1728 function_spans: Vec::with_capacity(total_functions),
1729 extern_fns: Vec::with_capacity(total_extern),
1730 empty_link_extern_blocks: Vec::with_capacity(total_empty_blocks),
1731 };
1732
1733 let mut inst_offset: u32 = 0;
1735 let mut extra_offset: u32 = 0;
1736
1737 for rir in rirs {
1738 merged.extra.extend_from_slice(&rir.extra);
1740
1741 for inst in &rir.instructions {
1743 let renumbered = Self::renumber_instruction(inst, inst_offset, extra_offset);
1744 merged.instructions.push(renumbered);
1745 }
1746
1747 Self::renumber_extra_inst_refs(
1750 &mut merged.extra,
1751 &rir.instructions,
1752 inst_offset,
1753 extra_offset,
1754 );
1755
1756 for fn_span in &rir.function_spans {
1758 merged.function_spans.push(FunctionSpan {
1759 name: fn_span.name,
1760 body_start: InstRef::from_raw(fn_span.body_start.as_u32() + inst_offset),
1761 decl: InstRef::from_raw(fn_span.decl.as_u32() + inst_offset),
1762 });
1763 }
1764
1765 for ext in &rir.extern_fns {
1769 merged.extern_fns.push(RirExternFn {
1770 library: ext.library,
1771 name: ext.name,
1772 directives_start: ext.directives_start + extra_offset,
1773 directives_len: ext.directives_len,
1774 params_start: ext.params_start + extra_offset,
1775 params_len: ext.params_len,
1776 return_type: ext.return_type,
1777 span: ext.span,
1778 block_span: ext.block_span,
1779 link_mode: ext.link_mode,
1780 });
1781 }
1782
1783 merged
1787 .empty_link_extern_blocks
1788 .extend_from_slice(&rir.empty_link_extern_blocks);
1789
1790 inst_offset += rir.instructions.len() as u32;
1792 extra_offset += rir.extra.len() as u32;
1793 }
1794
1795 merged
1796 }
1797
1798 fn renumber_instruction(inst: &Inst, inst_offset: u32, extra_offset: u32) -> Inst {
1800 let renumber = |r: InstRef| InstRef::from_raw(r.as_u32() + inst_offset);
1801 let renumber_opt = |r: Option<InstRef>| r.map(renumber);
1802
1803 let data = match &inst.data {
1804 InstData::IntConst(v) => InstData::IntConst(*v),
1806 InstData::FloatConst(bits) => InstData::FloatConst(*bits),
1807 InstData::BoolConst(v) => InstData::BoolConst(*v),
1808 InstData::CharConst(v) => InstData::CharConst(*v),
1809 InstData::StringConst(s) => InstData::StringConst(*s),
1810 InstData::UnitConst => InstData::UnitConst,
1811 InstData::Break => InstData::Break,
1812 InstData::Continue => InstData::Continue,
1813 InstData::VarRef { name } => InstData::VarRef { name: *name },
1814 InstData::ParamRef { index, name } => InstData::ParamRef {
1815 index: *index,
1816 name: *name,
1817 },
1818 InstData::EnumVariant {
1819 module,
1820 type_name,
1821 variant,
1822 } => InstData::EnumVariant {
1823 module: module.map(renumber),
1824 type_name: *type_name,
1825 variant: *variant,
1826 },
1827 InstData::EnumStructVariant {
1828 module,
1829 type_name,
1830 variant,
1831 fields_start,
1832 fields_len,
1833 } => InstData::EnumStructVariant {
1834 module: module.map(renumber),
1835 type_name: *type_name,
1836 variant: *variant,
1837 fields_start: *fields_start,
1838 fields_len: *fields_len,
1839 },
1840 InstData::TypeIntrinsic { name, type_arg } => InstData::TypeIntrinsic {
1841 name: *name,
1842 type_arg: *type_arg,
1843 },
1844 InstData::TypeInterfaceIntrinsic {
1845 name,
1846 type_arg,
1847 type_inst,
1848 interface_arg,
1849 } => InstData::TypeInterfaceIntrinsic {
1850 name: *name,
1851 type_arg: *type_arg,
1852 type_inst: type_inst.map(renumber),
1853 interface_arg: *interface_arg,
1854 },
1855
1856 InstData::Bin { op, lhs, rhs } => InstData::Bin {
1857 op: *op,
1858 lhs: renumber(*lhs),
1859 rhs: renumber(*rhs),
1860 },
1861 InstData::Unary { op, operand } => InstData::Unary {
1862 op: *op,
1863 operand: renumber(*operand),
1864 },
1865 InstData::MakeRef { operand, is_mut } => InstData::MakeRef {
1866 operand: renumber(*operand),
1867 is_mut: *is_mut,
1868 },
1869 InstData::BareRangeSubscript => InstData::BareRangeSubscript,
1870 InstData::MakeSlice {
1871 base,
1872 lo,
1873 hi,
1874 is_mut,
1875 } => InstData::MakeSlice {
1876 base: renumber(*base),
1877 lo: renumber_opt(*lo),
1878 hi: renumber_opt(*hi),
1879 is_mut: *is_mut,
1880 },
1881
1882 InstData::Branch {
1884 cond,
1885 then_block,
1886 else_block,
1887 is_comptime,
1888 } => InstData::Branch {
1889 cond: renumber(*cond),
1890 then_block: renumber(*then_block),
1891 else_block: renumber_opt(*else_block),
1892 is_comptime: *is_comptime,
1893 },
1894 InstData::Loop { cond, body } => InstData::Loop {
1895 cond: renumber(*cond),
1896 body: renumber(*body),
1897 },
1898 InstData::For {
1899 binding,
1900 is_mut,
1901 iterable,
1902 body,
1903 } => InstData::For {
1904 binding: *binding,
1905 is_mut: *is_mut,
1906 iterable: renumber(*iterable),
1907 body: renumber(*body),
1908 },
1909 InstData::InfiniteLoop { body } => InstData::InfiniteLoop {
1910 body: renumber(*body),
1911 },
1912 InstData::Ret(value) => InstData::Ret(renumber_opt(*value)),
1913
1914 InstData::Match {
1916 scrutinee,
1917 arms_start,
1918 arms_len,
1919 } => InstData::Match {
1920 scrutinee: renumber(*scrutinee),
1921 arms_start: *arms_start + extra_offset,
1922 arms_len: *arms_len,
1923 },
1924
1925 InstData::Block { extra_start, len } => InstData::Block {
1927 extra_start: *extra_start + extra_offset,
1928 len: *len,
1929 },
1930
1931 InstData::Alloc {
1933 directives_start,
1934 directives_len,
1935 name,
1936 is_mut,
1937 ty,
1938 init,
1939 } => InstData::Alloc {
1940 directives_start: *directives_start + extra_offset,
1941 directives_len: *directives_len,
1942 name: *name,
1943 is_mut: *is_mut,
1944 ty: *ty,
1945 init: renumber(*init),
1946 },
1947 InstData::StructDestructure {
1948 type_name,
1949 fields_start,
1950 fields_len,
1951 init,
1952 } => InstData::StructDestructure {
1953 type_name: *type_name,
1954 fields_start: *fields_start + extra_offset,
1955 fields_len: *fields_len,
1956 init: renumber(*init),
1957 },
1958 InstData::Assign { name, value } => InstData::Assign {
1959 name: *name,
1960 value: renumber(*value),
1961 },
1962
1963 InstData::FnDecl {
1965 directives_start,
1966 directives_len,
1967 is_pub,
1968 is_unchecked,
1969 name,
1970 params_start,
1971 params_len,
1972 return_type,
1973 body,
1974 has_self,
1975 receiver_mode,
1976 } => InstData::FnDecl {
1977 directives_start: *directives_start + extra_offset,
1978 directives_len: *directives_len,
1979 is_pub: *is_pub,
1980 is_unchecked: *is_unchecked,
1981 name: *name,
1982 params_start: *params_start + extra_offset,
1983 params_len: *params_len,
1984 return_type: *return_type,
1985 body: renumber(*body),
1986 has_self: *has_self,
1987 receiver_mode: *receiver_mode,
1988 },
1989
1990 InstData::ConstDecl {
1992 directives_start,
1993 directives_len,
1994 is_pub,
1995 name,
1996 ty,
1997 init,
1998 } => InstData::ConstDecl {
1999 directives_start: *directives_start + extra_offset,
2000 directives_len: *directives_len,
2001 is_pub: *is_pub,
2002 name: *name,
2003 ty: *ty,
2004 init: renumber(*init),
2005 },
2006
2007 InstData::Call {
2009 name,
2010 args_start,
2011 args_len,
2012 } => InstData::Call {
2013 name: *name,
2014 args_start: *args_start + extra_offset,
2015 args_len: *args_len,
2016 },
2017
2018 InstData::Intrinsic {
2020 name,
2021 args_start,
2022 args_len,
2023 } => InstData::Intrinsic {
2024 name: *name,
2025 args_start: *args_start + extra_offset,
2026 args_len: *args_len,
2027 },
2028
2029 InstData::StructDecl {
2031 directives_start,
2032 directives_len,
2033 is_pub,
2034 posture,
2035 name,
2036 fields_start,
2037 fields_len,
2038 methods_start,
2039 methods_len,
2040 } => InstData::StructDecl {
2041 directives_start: *directives_start + extra_offset,
2042 directives_len: *directives_len,
2043 is_pub: *is_pub,
2044 posture: *posture,
2045 name: *name,
2046 fields_start: *fields_start + extra_offset,
2047 fields_len: *fields_len,
2048 methods_start: *methods_start + extra_offset,
2049 methods_len: *methods_len,
2050 },
2051 InstData::StructInit {
2052 module,
2053 type_name,
2054 fields_start,
2055 fields_len,
2056 } => InstData::StructInit {
2057 module: module.map(renumber),
2058 type_name: *type_name,
2059 fields_start: *fields_start + extra_offset,
2060 fields_len: *fields_len,
2061 },
2062 InstData::FieldGet { base, field } => InstData::FieldGet {
2063 base: renumber(*base),
2064 field: *field,
2065 },
2066 InstData::FieldSet { base, field, value } => InstData::FieldSet {
2067 base: renumber(*base),
2068 field: *field,
2069 value: renumber(*value),
2070 },
2071
2072 InstData::InterfaceDecl {
2074 is_pub,
2075 name,
2076 methods_start,
2077 methods_len,
2078 directives_start,
2079 directives_len,
2080 } => InstData::InterfaceDecl {
2081 is_pub: *is_pub,
2082 name: *name,
2083 methods_start: *methods_start + extra_offset,
2084 methods_len: *methods_len,
2085 directives_start: if *directives_len == 0 {
2086 *directives_start
2087 } else {
2088 *directives_start + extra_offset
2089 },
2090 directives_len: *directives_len,
2091 },
2092 InstData::InterfaceMethodSig {
2093 name,
2094 params_start,
2095 params_len,
2096 return_type,
2097 receiver_mode,
2098 is_unchecked,
2099 directives_start,
2100 directives_len,
2101 } => InstData::InterfaceMethodSig {
2102 name: *name,
2103 params_start: *params_start + extra_offset,
2104 params_len: *params_len,
2105 return_type: *return_type,
2106 receiver_mode: *receiver_mode,
2107 is_unchecked: *is_unchecked,
2108 directives_start: if *directives_len == 0 {
2109 *directives_start
2110 } else {
2111 *directives_start + extra_offset
2112 },
2113 directives_len: *directives_len,
2114 },
2115
2116 InstData::EnumDecl {
2118 is_pub,
2119 posture,
2120 name,
2121 variants_start,
2122 variants_len,
2123 methods_start,
2124 methods_len,
2125 directives_start,
2126 directives_len,
2127 } => InstData::EnumDecl {
2128 is_pub: *is_pub,
2129 posture: *posture,
2130 name: *name,
2131 variants_start: *variants_start + extra_offset,
2132 variants_len: *variants_len,
2133 methods_start: *methods_start + extra_offset,
2134 methods_len: *methods_len,
2135 directives_start: if *directives_len == 0 {
2136 *directives_start
2137 } else {
2138 *directives_start + extra_offset
2139 },
2140 directives_len: *directives_len,
2141 },
2142
2143 InstData::ArrayInit {
2145 elems_start,
2146 elems_len,
2147 } => InstData::ArrayInit {
2148 elems_start: *elems_start + extra_offset,
2149 elems_len: *elems_len,
2150 },
2151 InstData::IndexGet { base, index } => InstData::IndexGet {
2152 base: renumber(*base),
2153 index: renumber(*index),
2154 },
2155 InstData::IndexSet { base, index, value } => InstData::IndexSet {
2156 base: renumber(*base),
2157 index: renumber(*index),
2158 value: renumber(*value),
2159 },
2160
2161 InstData::MethodCall {
2163 receiver,
2164 method,
2165 args_start,
2166 args_len,
2167 } => InstData::MethodCall {
2168 receiver: renumber(*receiver),
2169 method: *method,
2170 args_start: *args_start + extra_offset,
2171 args_len: *args_len,
2172 },
2173 InstData::AssocFnCall {
2174 type_name,
2175 function,
2176 args_start,
2177 args_len,
2178 } => InstData::AssocFnCall {
2179 type_name: *type_name,
2180 function: *function,
2181 args_start: *args_start + extra_offset,
2182 args_len: *args_len,
2183 },
2184 InstData::DeriveDecl {
2185 name,
2186 methods_start,
2187 methods_len,
2188 } => InstData::DeriveDecl {
2189 name: *name,
2190 methods_start: *methods_start + extra_offset,
2191 methods_len: *methods_len,
2192 },
2193 InstData::Comptime { expr } => InstData::Comptime {
2194 expr: renumber(*expr),
2195 },
2196 InstData::ComptimeUnrollFor {
2197 binding,
2198 iterable,
2199 body,
2200 } => InstData::ComptimeUnrollFor {
2201 binding: *binding,
2202 iterable: renumber(*iterable),
2203 body: renumber(*body),
2204 },
2205 InstData::Checked { expr } => InstData::Checked {
2206 expr: renumber(*expr),
2207 },
2208 InstData::TypeConst { type_name } => InstData::TypeConst {
2209 type_name: *type_name,
2210 },
2211 InstData::AnonStructType {
2212 directives_start,
2213 directives_len,
2214 fields_start,
2215 fields_len,
2216 methods_start,
2217 methods_len,
2218 } => InstData::AnonStructType {
2219 directives_start: if *directives_len == 0 {
2220 *directives_start
2221 } else {
2222 *directives_start + extra_offset
2223 },
2224 directives_len: *directives_len,
2225 fields_start: *fields_start + extra_offset,
2226 fields_len: *fields_len,
2227 methods_start: *methods_start + extra_offset,
2228 methods_len: *methods_len,
2229 },
2230 InstData::AnonEnumType {
2231 directives_start,
2232 directives_len,
2233 variants_start,
2234 variants_len,
2235 methods_start,
2236 methods_len,
2237 } => InstData::AnonEnumType {
2238 directives_start: if *directives_len == 0 {
2239 *directives_start
2240 } else {
2241 *directives_start + extra_offset
2242 },
2243 directives_len: *directives_len,
2244 variants_start: *variants_start + extra_offset,
2245 variants_len: *variants_len,
2246 methods_start: *methods_start + extra_offset,
2247 methods_len: *methods_len,
2248 },
2249 InstData::AnonInterfaceType {
2250 methods_start,
2251 methods_len,
2252 } => InstData::AnonInterfaceType {
2253 methods_start: *methods_start + extra_offset,
2254 methods_len: *methods_len,
2255 },
2256 InstData::TupleInit {
2257 elems_start,
2258 elems_len,
2259 } => InstData::TupleInit {
2260 elems_start: *elems_start + extra_offset,
2261 elems_len: *elems_len,
2262 },
2263 InstData::AnonFnValue { method } => InstData::AnonFnValue {
2264 method: renumber(*method),
2265 },
2266 };
2267
2268 Inst {
2269 data,
2270 span: inst.span,
2271 }
2272 }
2273
2274 fn renumber_extra_inst_refs(
2285 extra: &mut [u32],
2286 instructions: &[Inst],
2287 inst_offset: u32,
2288 extra_offset: u32,
2289 ) {
2290 for inst in instructions {
2291 match &inst.data {
2292 InstData::Block { extra_start, len } => {
2294 let start = (*extra_start + extra_offset) as usize;
2295 for i in 0..*len as usize {
2296 extra[start + i] += inst_offset;
2297 }
2298 }
2299
2300 InstData::ArrayInit {
2302 elems_start,
2303 elems_len,
2304 } => {
2305 let start = (*elems_start + extra_offset) as usize;
2306 for i in 0..*elems_len as usize {
2307 extra[start + i] += inst_offset;
2308 }
2309 }
2310
2311 InstData::TupleInit {
2313 elems_start,
2314 elems_len,
2315 } => {
2316 let start = (*elems_start + extra_offset) as usize;
2317 for i in 0..*elems_len as usize {
2318 extra[start + i] += inst_offset;
2319 }
2320 }
2321
2322 InstData::Intrinsic {
2324 args_start,
2325 args_len,
2326 ..
2327 } => {
2328 let start = (*args_start + extra_offset) as usize;
2329 for i in 0..*args_len as usize {
2330 extra[start + i] += inst_offset;
2331 }
2332 }
2333
2334 InstData::StructDecl {
2336 methods_start,
2337 methods_len,
2338 ..
2339 } => {
2340 let start = (*methods_start + extra_offset) as usize;
2341 for i in 0..*methods_len as usize {
2342 extra[start + i] += inst_offset;
2343 }
2344 }
2345
2346 InstData::InterfaceDecl {
2348 methods_start,
2349 methods_len,
2350 ..
2351 } => {
2352 let start = (*methods_start + extra_offset) as usize;
2353 for i in 0..*methods_len as usize {
2354 extra[start + i] += inst_offset;
2355 }
2356 }
2357
2358 InstData::DeriveDecl {
2360 methods_start,
2361 methods_len,
2362 ..
2363 } => {
2364 let start = (*methods_start + extra_offset) as usize;
2365 for i in 0..*methods_len as usize {
2366 extra[start + i] += inst_offset;
2367 }
2368 }
2369
2370 InstData::AnonInterfaceType {
2372 methods_start,
2373 methods_len,
2374 } => {
2375 let start = (*methods_start + extra_offset) as usize;
2376 for i in 0..*methods_len as usize {
2377 extra[start + i] += inst_offset;
2378 }
2379 }
2380
2381 InstData::AnonStructType {
2383 methods_start,
2384 methods_len,
2385 ..
2386 } => {
2387 let start = (*methods_start + extra_offset) as usize;
2388 for i in 0..*methods_len as usize {
2389 extra[start + i] += inst_offset;
2390 }
2391 }
2392
2393 InstData::AnonEnumType {
2395 methods_start,
2396 methods_len,
2397 ..
2398 } => {
2399 let start = (*methods_start + extra_offset) as usize;
2400 for i in 0..*methods_len as usize {
2401 extra[start + i] += inst_offset;
2402 }
2403 }
2404
2405 InstData::Call {
2407 args_start,
2408 args_len,
2409 ..
2410 }
2411 | InstData::MethodCall {
2412 args_start,
2413 args_len,
2414 ..
2415 }
2416 | InstData::AssocFnCall {
2417 args_start,
2418 args_len,
2419 ..
2420 } => {
2421 let start = (*args_start + extra_offset) as usize;
2422 for i in 0..*args_len as usize {
2423 extra[start + i * 2] += inst_offset;
2425 }
2426 }
2427
2428 InstData::StructInit {
2430 fields_start,
2431 fields_len,
2432 ..
2433 }
2434 | InstData::EnumStructVariant {
2435 fields_start,
2436 fields_len,
2437 ..
2438 } => {
2439 let start = (*fields_start + extra_offset) as usize;
2440 for i in 0..*fields_len as usize {
2441 extra[start + i * 2 + 1] += inst_offset;
2443 }
2444 }
2445
2446 InstData::Match {
2448 arms_start,
2449 arms_len,
2450 ..
2451 } => {
2452 let mut pos = (*arms_start + extra_offset) as usize;
2453 for _ in 0..*arms_len {
2454 let kind = extra[pos];
2455 let pattern_size = match kind {
2456 k if k == PatternKind::Wildcard as u32 => {
2457 PATTERN_WILDCARD_SIZE as usize
2458 }
2459 k if k == PatternKind::Int as u32 => PATTERN_INT_SIZE as usize,
2460 k if k == PatternKind::Bool as u32 => PATTERN_BOOL_SIZE as usize,
2461 k if k == PatternKind::Path as u32 => PATTERN_PATH_SIZE as usize,
2462 _ => panic!("Unknown pattern kind during merge: {}", kind),
2463 };
2464 extra[pos + pattern_size - 1] += inst_offset;
2466 pos += pattern_size;
2467 }
2468 }
2469
2470 InstData::IntConst(_)
2472 | InstData::FloatConst(_)
2473 | InstData::BoolConst(_)
2474 | InstData::CharConst(_)
2475 | InstData::StringConst(_)
2476 | InstData::UnitConst
2477 | InstData::Bin { .. }
2478 | InstData::Unary { .. }
2479 | InstData::MakeRef { .. }
2480 | InstData::BareRangeSubscript
2481 | InstData::MakeSlice { .. }
2482 | InstData::Branch { .. }
2483 | InstData::Loop { .. }
2484 | InstData::For { .. }
2485 | InstData::InfiniteLoop { .. }
2486 | InstData::Break
2487 | InstData::Continue
2488 | InstData::Ret(_)
2489 | InstData::VarRef { .. }
2490 | InstData::ParamRef { .. }
2491 | InstData::Alloc { .. }
2492 | InstData::Assign { .. }
2493 | InstData::FnDecl { .. }
2494 | InstData::ConstDecl { .. }
2495 | InstData::FieldGet { .. }
2496 | InstData::FieldSet { .. }
2497 | InstData::EnumDecl { .. }
2498 | InstData::EnumVariant { .. }
2499 | InstData::IndexGet { .. }
2500 | InstData::IndexSet { .. }
2501 | InstData::TypeIntrinsic { .. }
2502 | InstData::TypeInterfaceIntrinsic { .. }
2503 | InstData::InterfaceMethodSig { .. }
2504 | InstData::Comptime { .. }
2505 | InstData::ComptimeUnrollFor { .. }
2506 | InstData::Checked { .. }
2507 | InstData::TypeConst { .. }
2508 | InstData::StructDestructure { .. }
2509 | InstData::AnonFnValue { .. } => {}
2510 }
2511 }
2512 }
2513}
2514
2515#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
2517pub struct Inst {
2518 pub data: InstData,
2519 pub span: Span,
2520}
2521
2522#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
2524pub enum InstData {
2525 IntConst(u64),
2527
2528 FloatConst(u64),
2531
2532 BoolConst(bool),
2534
2535 CharConst(u32),
2537
2538 StringConst(Spur),
2540
2541 UnitConst,
2543
2544 Bin {
2549 op: BinOp,
2550 lhs: InstRef,
2551 rhs: InstRef,
2552 },
2553
2554 Unary { op: UnaryOp, operand: InstRef },
2556
2557 MakeRef { operand: InstRef, is_mut: bool },
2561
2562 BareRangeSubscript,
2566
2567 MakeSlice {
2574 base: InstRef,
2575 lo: Option<InstRef>,
2576 hi: Option<InstRef>,
2577 is_mut: bool,
2578 },
2579
2580 Branch {
2583 cond: InstRef,
2584 then_block: InstRef,
2585 else_block: Option<InstRef>,
2586 is_comptime: bool,
2593 },
2594
2595 Loop { cond: InstRef, body: InstRef },
2597
2598 For {
2600 binding: Spur,
2602 is_mut: bool,
2604 iterable: InstRef,
2606 body: InstRef,
2608 },
2609
2610 InfiniteLoop { body: InstRef },
2612
2613 Match {
2616 scrutinee: InstRef,
2618 arms_start: u32,
2620 arms_len: u32,
2622 },
2623
2624 Break,
2626
2627 Continue,
2629
2630 FnDecl {
2634 directives_start: u32,
2636 directives_len: u32,
2638 is_pub: bool,
2640 is_unchecked: bool,
2642 name: Spur,
2643 params_start: u32,
2645 params_len: u32,
2647 return_type: Spur,
2648 body: InstRef,
2649 has_self: bool,
2653 receiver_mode: u8,
2657 },
2658
2659 ConstDecl {
2664 directives_start: u32,
2666 directives_len: u32,
2668 is_pub: bool,
2670 name: Spur,
2672 ty: Option<Spur>,
2674 init: InstRef,
2676 },
2677
2678 Call {
2681 name: Spur,
2683 args_start: u32,
2685 args_len: u32,
2687 },
2688
2689 Intrinsic {
2692 name: Spur,
2694 args_start: u32,
2696 args_len: u32,
2698 },
2699
2700 TypeIntrinsic {
2702 name: Spur,
2704 type_arg: Spur,
2706 },
2707
2708 TypeInterfaceIntrinsic {
2717 name: Spur,
2719 type_arg: Spur,
2721 type_inst: Option<InstRef>,
2724 interface_arg: Spur,
2726 },
2727
2728 ParamRef {
2730 index: u32,
2732 name: Spur,
2734 },
2735
2736 Ret(Option<InstRef>),
2738
2739 Block {
2742 extra_start: u32,
2744 len: u32,
2746 },
2747
2748 Alloc {
2753 directives_start: u32,
2755 directives_len: u32,
2757 name: Option<Spur>,
2759 is_mut: bool,
2761 ty: Option<Spur>,
2763 init: InstRef,
2765 },
2766
2767 StructDestructure {
2771 type_name: Spur,
2773 fields_start: u32,
2775 fields_len: u32,
2777 init: InstRef,
2779 },
2780
2781 VarRef {
2783 name: Spur,
2785 },
2786
2787 Assign {
2789 name: Spur,
2791 value: InstRef,
2793 },
2794
2795 StructDecl {
2799 directives_start: u32,
2801 directives_len: u32,
2803 is_pub: bool,
2805 posture: Posture,
2808 name: Spur,
2810 fields_start: u32,
2812 fields_len: u32,
2814 methods_start: u32,
2816 methods_len: u32,
2818 },
2819
2820 StructInit {
2823 module: Option<InstRef>,
2826 type_name: Spur,
2828 fields_start: u32,
2830 fields_len: u32,
2832 },
2833
2834 FieldGet {
2836 base: InstRef,
2838 field: Spur,
2840 },
2841
2842 FieldSet {
2844 base: InstRef,
2846 field: Spur,
2848 value: InstRef,
2850 },
2851
2852 EnumDecl {
2857 is_pub: bool,
2859 posture: Posture,
2862 name: Spur,
2864 variants_start: u32,
2866 variants_len: u32,
2868 methods_start: u32,
2870 methods_len: u32,
2872 directives_start: u32,
2874 directives_len: u32,
2876 },
2877
2878 EnumVariant {
2880 module: Option<InstRef>,
2883 type_name: Spur,
2885 variant: Spur,
2887 },
2888
2889 EnumStructVariant {
2892 module: Option<InstRef>,
2894 type_name: Spur,
2896 variant: Spur,
2898 fields_start: u32,
2900 fields_len: u32,
2902 },
2903
2904 ArrayInit {
2908 elems_start: u32,
2910 elems_len: u32,
2912 },
2913
2914 IndexGet {
2916 base: InstRef,
2918 index: InstRef,
2920 },
2921
2922 IndexSet {
2924 base: InstRef,
2926 index: InstRef,
2928 value: InstRef,
2930 },
2931
2932 MethodCall {
2936 receiver: InstRef,
2938 method: Spur,
2940 args_start: u32,
2942 args_len: u32,
2944 },
2945
2946 AssocFnCall {
2949 type_name: Spur,
2951 function: Spur,
2953 args_start: u32,
2955 args_len: u32,
2957 },
2958
2959 InterfaceDecl {
2965 is_pub: bool,
2967 name: Spur,
2969 methods_start: u32,
2971 methods_len: u32,
2973 directives_start: u32,
2975 directives_len: u32,
2977 },
2978
2979 InterfaceMethodSig {
2986 name: Spur,
2988 params_start: u32,
2990 params_len: u32,
2992 return_type: Spur,
2994 receiver_mode: u8,
2996 is_unchecked: bool,
2998 directives_start: u32,
3002 directives_len: u32,
3004 },
3005
3006 DeriveDecl {
3014 name: Spur,
3016 methods_start: u32,
3018 methods_len: u32,
3020 },
3021
3022 Comptime {
3025 expr: InstRef,
3027 },
3028
3029 ComptimeUnrollFor {
3033 binding: Spur,
3035 iterable: InstRef,
3037 body: InstRef,
3039 },
3040
3041 Checked {
3045 expr: InstRef,
3047 },
3048
3049 TypeConst {
3052 type_name: Spur,
3054 },
3055
3056 AnonStructType {
3061 directives_start: u32,
3063 directives_len: u32,
3065 fields_start: u32,
3067 fields_len: u32,
3069 methods_start: u32,
3071 methods_len: u32,
3073 },
3074
3075 AnonEnumType {
3080 directives_start: u32,
3082 directives_len: u32,
3084 variants_start: u32,
3086 variants_len: u32,
3088 methods_start: u32,
3090 methods_len: u32,
3092 },
3093
3094 AnonInterfaceType {
3101 methods_start: u32,
3103 methods_len: u32,
3105 },
3106
3107 TupleInit {
3117 elems_start: u32,
3119 elems_len: u32,
3121 },
3122
3123 AnonFnValue {
3129 method: InstRef,
3131 },
3132}
3133
3134impl fmt::Display for InstRef {
3135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3136 write!(f, "%{}", self.0)
3137 }
3138}
3139
3140#[cfg(test)]
3141mod tests {
3142 use super::*;
3143 use crate::print::RirPrinter;
3144 use lasso::ThreadedRodeo;
3145
3146 #[test]
3147 fn test_inst_ref_size() {
3148 assert_eq!(std::mem::size_of::<InstRef>(), 4);
3149 }
3150
3151 #[test]
3152 fn test_add_and_get_inst() {
3153 let mut rir = Rir::new();
3154 let inst = Inst {
3155 data: InstData::IntConst(42),
3156 span: Span::new(0, 2),
3157 };
3158 let inst_ref = rir.add_inst(inst);
3159
3160 let retrieved = rir.get(inst_ref);
3161 assert!(matches!(retrieved.data, InstData::IntConst(42)));
3162 }
3163
3164 #[test]
3165 fn test_rir_is_empty() {
3166 let rir = Rir::new();
3167 assert!(rir.is_empty());
3168 assert_eq!(rir.len(), 0);
3169 }
3170
3171 #[test]
3172 fn test_rir_extra_data() {
3173 let mut rir = Rir::new();
3174 let data = [1, 2, 3, 4, 5];
3175 let start = rir.add_extra(&data);
3176 assert_eq!(start, 0);
3177
3178 let retrieved = rir.get_extra(start, 5);
3179 assert_eq!(retrieved, &data);
3180
3181 let data2 = [10, 20];
3183 let start2 = rir.add_extra(&data2);
3184 assert_eq!(start2, 5);
3185 }
3186
3187 #[test]
3188 fn test_rir_iter() {
3189 let mut rir = Rir::new();
3190 rir.add_inst(Inst {
3191 data: InstData::IntConst(1),
3192 span: Span::new(0, 1),
3193 });
3194 rir.add_inst(Inst {
3195 data: InstData::IntConst(2),
3196 span: Span::new(2, 3),
3197 });
3198
3199 let items: Vec<_> = rir.iter().collect();
3200 assert_eq!(items.len(), 2);
3201 assert_eq!(items[0].0.as_u32(), 0);
3202 assert_eq!(items[1].0.as_u32(), 1);
3203 }
3204
3205 #[test]
3206 fn test_inst_ref_display() {
3207 let inst_ref = InstRef::from_raw(42);
3208 assert_eq!(format!("{}", inst_ref), "%42");
3209 }
3210
3211 #[test]
3213 fn test_rir_pattern_wildcard_span() {
3214 let span = Span::new(10, 11);
3215 let pattern = RirPattern::Wildcard(span);
3216 assert_eq!(pattern.span(), span);
3217 }
3218
3219 #[test]
3220 fn test_rir_pattern_int_span() {
3221 let span = Span::new(20, 22);
3222 let pattern = RirPattern::Int(42, span);
3223 assert_eq!(pattern.span(), span);
3224
3225 let pattern_neg = RirPattern::Int(-100, span);
3227 assert_eq!(pattern_neg.span(), span);
3228 }
3229
3230 #[test]
3231 fn test_rir_pattern_bool_span() {
3232 let span = Span::new(30, 34);
3233 let pattern = RirPattern::Bool(true, span);
3234 assert_eq!(pattern.span(), span);
3235
3236 let pattern_false = RirPattern::Bool(false, span);
3237 assert_eq!(pattern_false.span(), span);
3238 }
3239
3240 #[test]
3241 fn test_rir_pattern_path_span() {
3242 let span = Span::new(40, 50);
3243 let interner = ThreadedRodeo::new();
3244 let type_name = interner.get_or_intern("Color");
3245 let variant = interner.get_or_intern("Red");
3246
3247 let pattern = RirPattern::Path {
3248 module: None,
3249 type_name,
3250 variant,
3251 span,
3252 };
3253 assert_eq!(pattern.span(), span);
3254 }
3255
3256 #[test]
3258 fn test_rir_call_arg_modes_distinct() {
3259 let arg_normal = RirCallArg {
3260 value: InstRef::from_raw(0),
3261 mode: RirArgMode::Normal,
3262 };
3263 let arg_mut_ref = RirCallArg {
3264 value: InstRef::from_raw(0),
3265 mode: RirArgMode::MutRef,
3266 };
3267 let arg_ref = RirCallArg {
3268 value: InstRef::from_raw(0),
3269 mode: RirArgMode::Ref,
3270 };
3271 assert_eq!(arg_normal.mode, RirArgMode::Normal);
3272 assert_eq!(arg_mut_ref.mode, RirArgMode::MutRef);
3273 assert_eq!(arg_ref.mode, RirArgMode::Ref);
3274 assert_ne!(arg_normal.mode, arg_mut_ref.mode);
3275 assert_ne!(arg_normal.mode, arg_ref.mode);
3276 assert_ne!(arg_mut_ref.mode, arg_ref.mode);
3277 }
3278
3279 fn create_printer_test_rir() -> (Rir, ThreadedRodeo) {
3281 let rir = Rir::new();
3282 let interner = ThreadedRodeo::new();
3283 (rir, interner)
3284 }
3285
3286 #[test]
3287 fn test_printer_int_const() {
3288 let (mut rir, interner) = create_printer_test_rir();
3289 rir.add_inst(Inst {
3290 data: InstData::IntConst(42),
3291 span: Span::new(0, 2),
3292 });
3293
3294 let printer = RirPrinter::new(&rir, &interner);
3295 let output = printer.to_string();
3296 assert!(output.contains("%0 = const 42"));
3297 }
3298
3299 #[test]
3300 fn test_printer_bool_const() {
3301 let (mut rir, interner) = create_printer_test_rir();
3302 rir.add_inst(Inst {
3303 data: InstData::BoolConst(true),
3304 span: Span::new(0, 4),
3305 });
3306 rir.add_inst(Inst {
3307 data: InstData::BoolConst(false),
3308 span: Span::new(0, 5),
3309 });
3310
3311 let printer = RirPrinter::new(&rir, &interner);
3312 let output = printer.to_string();
3313 assert!(output.contains("%0 = const true"));
3314 assert!(output.contains("%1 = const false"));
3315 }
3316
3317 #[test]
3318 fn test_printer_string_const() {
3319 let (mut rir, interner) = create_printer_test_rir();
3320 let hello = interner.get_or_intern("hello world");
3321 rir.add_inst(Inst {
3322 data: InstData::StringConst(hello),
3323 span: Span::new(0, 13),
3324 });
3325
3326 let printer = RirPrinter::new(&rir, &interner);
3327 let output = printer.to_string();
3328 assert!(output.contains("%0 = const \"hello world\""));
3329 }
3330
3331 #[test]
3332 fn test_printer_unit_const() {
3333 let (mut rir, interner) = create_printer_test_rir();
3334 rir.add_inst(Inst {
3335 data: InstData::UnitConst,
3336 span: Span::new(0, 2),
3337 });
3338
3339 let printer = RirPrinter::new(&rir, &interner);
3340 let output = printer.to_string();
3341 assert!(output.contains("%0 = const ()"));
3342 }
3343
3344 #[test]
3345 fn test_printer_binary_ops() {
3346 let (mut rir, interner) = create_printer_test_rir();
3347 let lhs = rir.add_inst(Inst {
3348 data: InstData::IntConst(1),
3349 span: Span::new(0, 1),
3350 });
3351 let rhs = rir.add_inst(Inst {
3352 data: InstData::IntConst(2),
3353 span: Span::new(2, 3),
3354 });
3355
3356 let ops = [
3358 BinOp::Add,
3359 BinOp::Sub,
3360 BinOp::Mul,
3361 BinOp::Div,
3362 BinOp::Mod,
3363 BinOp::Eq,
3364 BinOp::Ne,
3365 BinOp::Lt,
3366 BinOp::Gt,
3367 BinOp::Le,
3368 BinOp::Ge,
3369 BinOp::And,
3370 BinOp::Or,
3371 BinOp::BitAnd,
3372 BinOp::BitOr,
3373 BinOp::BitXor,
3374 BinOp::Shl,
3375 BinOp::Shr,
3376 ];
3377 let _ = (lhs, rhs);
3378
3379 for op in ops {
3380 let mut test_rir = Rir::new();
3381 let lhs = test_rir.add_inst(Inst {
3382 data: InstData::IntConst(1),
3383 span: Span::new(0, 1),
3384 });
3385 let rhs = test_rir.add_inst(Inst {
3386 data: InstData::IntConst(2),
3387 span: Span::new(2, 3),
3388 });
3389 let data = InstData::Bin { op, lhs, rhs };
3390 let op_name = op.as_str();
3391 test_rir.add_inst(Inst {
3392 data,
3393 span: Span::new(0, 5),
3394 });
3395
3396 let printer = RirPrinter::new(&test_rir, &interner);
3397 let output = printer.to_string();
3398 let expected = format!("%2 = {} %0, %1", op_name);
3399 assert!(
3400 output.contains(&expected),
3401 "Expected '{}' in output:\n{}",
3402 expected,
3403 output
3404 );
3405 }
3406 }
3407
3408 #[test]
3409 fn test_printer_unary_ops() {
3410 let (mut rir, interner) = create_printer_test_rir();
3411 let operand = rir.add_inst(Inst {
3412 data: InstData::IntConst(42),
3413 span: Span::new(0, 2),
3414 });
3415
3416 rir.add_inst(Inst {
3417 data: InstData::Unary {
3418 op: UnaryOp::Neg,
3419 operand,
3420 },
3421 span: Span::new(0, 3),
3422 });
3423 rir.add_inst(Inst {
3424 data: InstData::Unary {
3425 op: UnaryOp::Not,
3426 operand,
3427 },
3428 span: Span::new(0, 3),
3429 });
3430 rir.add_inst(Inst {
3431 data: InstData::Unary {
3432 op: UnaryOp::BitNot,
3433 operand,
3434 },
3435 span: Span::new(0, 3),
3436 });
3437
3438 let printer = RirPrinter::new(&rir, &interner);
3439 let output = printer.to_string();
3440 assert!(output.contains("neg %0"));
3441 assert!(output.contains("not %0"));
3442 assert!(output.contains("bit_not %0"));
3443 }
3444
3445 #[test]
3446 fn test_printer_branch() {
3447 let (mut rir, interner) = create_printer_test_rir();
3448 let cond = rir.add_inst(Inst {
3449 data: InstData::BoolConst(true),
3450 span: Span::new(0, 4),
3451 });
3452 let then_block = rir.add_inst(Inst {
3453 data: InstData::IntConst(1),
3454 span: Span::new(0, 1),
3455 });
3456 let else_block = rir.add_inst(Inst {
3457 data: InstData::IntConst(0),
3458 span: Span::new(0, 1),
3459 });
3460
3461 rir.add_inst(Inst {
3463 data: InstData::Branch {
3464 cond,
3465 then_block,
3466 else_block: Some(else_block),
3467 is_comptime: false,
3468 },
3469 span: Span::new(0, 20),
3470 });
3471
3472 let printer = RirPrinter::new(&rir, &interner);
3473 let output = printer.to_string();
3474 assert!(output.contains("branch %0, %1, %2"));
3475 }
3476
3477 #[test]
3478 fn test_printer_branch_no_else() {
3479 let (mut rir, interner) = create_printer_test_rir();
3480 let cond = rir.add_inst(Inst {
3481 data: InstData::BoolConst(true),
3482 span: Span::new(0, 4),
3483 });
3484 let then_block = rir.add_inst(Inst {
3485 data: InstData::IntConst(1),
3486 span: Span::new(0, 1),
3487 });
3488
3489 rir.add_inst(Inst {
3490 data: InstData::Branch {
3491 cond,
3492 then_block,
3493 else_block: None,
3494 is_comptime: false,
3495 },
3496 span: Span::new(0, 15),
3497 });
3498
3499 let printer = RirPrinter::new(&rir, &interner);
3500 let output = printer.to_string();
3501 assert!(output.contains("branch %0, %1\n"));
3503 }
3504
3505 #[test]
3506 fn test_printer_loop() {
3507 let (mut rir, interner) = create_printer_test_rir();
3508 let cond = rir.add_inst(Inst {
3509 data: InstData::BoolConst(true),
3510 span: Span::new(0, 4),
3511 });
3512 let body = rir.add_inst(Inst {
3513 data: InstData::IntConst(0),
3514 span: Span::new(0, 1),
3515 });
3516
3517 rir.add_inst(Inst {
3518 data: InstData::Loop { cond, body },
3519 span: Span::new(0, 20),
3520 });
3521
3522 let printer = RirPrinter::new(&rir, &interner);
3523 let output = printer.to_string();
3524 assert!(output.contains("loop %0, %1"));
3525 }
3526
3527 #[test]
3528 fn test_printer_infinite_loop() {
3529 let (mut rir, interner) = create_printer_test_rir();
3530 let body = rir.add_inst(Inst {
3531 data: InstData::IntConst(0),
3532 span: Span::new(0, 1),
3533 });
3534
3535 rir.add_inst(Inst {
3536 data: InstData::InfiniteLoop { body },
3537 span: Span::new(0, 15),
3538 });
3539
3540 let printer = RirPrinter::new(&rir, &interner);
3541 let output = printer.to_string();
3542 assert!(output.contains("infinite_loop %0"));
3543 }
3544
3545 #[test]
3546 fn test_printer_break_continue() {
3547 let (mut rir, interner) = create_printer_test_rir();
3548 rir.add_inst(Inst {
3549 data: InstData::Break,
3550 span: Span::new(0, 5),
3551 });
3552 rir.add_inst(Inst {
3553 data: InstData::Continue,
3554 span: Span::new(0, 8),
3555 });
3556
3557 let printer = RirPrinter::new(&rir, &interner);
3558 let output = printer.to_string();
3559 assert!(output.contains("break\n"));
3560 assert!(output.contains("continue\n"));
3561 }
3562
3563 #[test]
3564 fn test_printer_ret() {
3565 let (mut rir, interner) = create_printer_test_rir();
3566 let value = rir.add_inst(Inst {
3567 data: InstData::IntConst(42),
3568 span: Span::new(0, 2),
3569 });
3570
3571 rir.add_inst(Inst {
3573 data: InstData::Ret(Some(value)),
3574 span: Span::new(0, 10),
3575 });
3576 rir.add_inst(Inst {
3578 data: InstData::Ret(None),
3579 span: Span::new(0, 6),
3580 });
3581
3582 let printer = RirPrinter::new(&rir, &interner);
3583 let output = printer.to_string();
3584 assert!(output.contains("ret %0"));
3585 assert!(output.contains("%2 = ret\n"));
3586 }
3587
3588 #[test]
3589 fn test_printer_fn_decl() {
3590 let (mut rir, interner) = create_printer_test_rir();
3591 let body = rir.add_inst(Inst {
3592 data: InstData::IntConst(42),
3593 span: Span::new(0, 2),
3594 });
3595
3596 let name = interner.get_or_intern("main");
3597 let return_type = interner.get_or_intern("i32");
3598 let param_name = interner.get_or_intern("x");
3599 let param_type = interner.get_or_intern("i32");
3600
3601 let (directives_start, directives_len) = rir.add_directives(&[]);
3602 let (params_start, params_len) = rir.add_params(&[RirParam {
3603 name: param_name,
3604 ty: param_type,
3605 mode: RirParamMode::Normal,
3606 is_comptime: false,
3607 }]);
3608
3609 rir.add_inst(Inst {
3610 data: InstData::FnDecl {
3611 directives_start,
3612 directives_len,
3613 is_pub: false,
3614 is_unchecked: false,
3615 name,
3616 params_start,
3617 params_len,
3618 return_type,
3619 body,
3620 has_self: false,
3621 receiver_mode: 0,
3622 },
3623 span: Span::new(0, 30),
3624 });
3625
3626 let printer = RirPrinter::new(&rir, &interner);
3627 let output = printer.to_string();
3628 assert!(output.contains("fn main(x: i32) -> i32"));
3629 }
3630
3631 #[test]
3632 fn test_printer_fn_decl_with_self() {
3633 let (mut rir, interner) = create_printer_test_rir();
3634 let body = rir.add_inst(Inst {
3635 data: InstData::IntConst(0),
3636 span: Span::new(0, 1),
3637 });
3638
3639 let name = interner.get_or_intern("get_x");
3640 let return_type = interner.get_or_intern("i32");
3641
3642 let (directives_start, directives_len) = rir.add_directives(&[]);
3643 let (params_start, params_len) = rir.add_params(&[]);
3644
3645 rir.add_inst(Inst {
3646 data: InstData::FnDecl {
3647 directives_start,
3648 directives_len,
3649 is_pub: false,
3650 is_unchecked: false,
3651 name,
3652 params_start,
3653 params_len,
3654 return_type,
3655 body,
3656 has_self: true,
3657 receiver_mode: 0,
3658 },
3659 span: Span::new(0, 30),
3660 });
3661
3662 let printer = RirPrinter::new(&rir, &interner);
3663 let output = printer.to_string();
3664 assert!(output.contains("fn get_x(self, ) -> i32"));
3665 }
3666
3667 #[test]
3668 fn test_printer_fn_decl_param_modes() {
3669 let (mut rir, interner) = create_printer_test_rir();
3670 let body = rir.add_inst(Inst {
3671 data: InstData::UnitConst,
3672 span: Span::new(0, 2),
3673 });
3674
3675 let name = interner.get_or_intern("modify");
3676 let return_type = interner.get_or_intern("()");
3677 let param1_name = interner.get_or_intern("a");
3678 let param1_type = interner.get_or_intern("i32");
3679 let param2_name = interner.get_or_intern("b");
3680 let param2_type = interner.get_or_intern("i32");
3681 let param3_name = interner.get_or_intern("c");
3682 let param3_type = interner.get_or_intern("i32");
3683
3684 let (directives_start, directives_len) = rir.add_directives(&[]);
3685 let (params_start, params_len) = rir.add_params(&[
3686 RirParam {
3687 name: param1_name,
3688 ty: param1_type,
3689 mode: RirParamMode::Normal,
3690 is_comptime: false,
3691 },
3692 RirParam {
3693 name: param2_name,
3694 ty: param2_type,
3695 mode: RirParamMode::MutRef,
3696 is_comptime: false,
3697 },
3698 RirParam {
3699 name: param3_name,
3700 ty: param3_type,
3701 mode: RirParamMode::Ref,
3702 is_comptime: false,
3703 },
3704 ]);
3705
3706 rir.add_inst(Inst {
3707 data: InstData::FnDecl {
3708 directives_start,
3709 directives_len,
3710 is_pub: false,
3711 is_unchecked: false,
3712 name,
3713 params_start,
3714 params_len,
3715 return_type,
3716 body,
3717 has_self: false,
3718 receiver_mode: 0,
3719 },
3720 span: Span::new(0, 50),
3721 });
3722
3723 let printer = RirPrinter::new(&rir, &interner);
3724 let output = printer.to_string();
3725 assert!(output.contains("a: i32"));
3726 assert!(output.contains("mut_ref b: i32"));
3727 assert!(output.contains("ref c: i32"));
3728 }
3729
3730 #[test]
3731 fn test_printer_call() {
3732 let (mut rir, interner) = create_printer_test_rir();
3733 let arg = rir.add_inst(Inst {
3734 data: InstData::IntConst(10),
3735 span: Span::new(0, 2),
3736 });
3737
3738 let name = interner.get_or_intern("foo");
3739
3740 let (args_start, args_len) = rir.add_call_args(&[RirCallArg {
3741 value: arg,
3742 mode: RirArgMode::Normal,
3743 }]);
3744
3745 rir.add_inst(Inst {
3746 data: InstData::Call {
3747 name,
3748 args_start,
3749 args_len,
3750 },
3751 span: Span::new(0, 8),
3752 });
3753
3754 let printer = RirPrinter::new(&rir, &interner);
3755 let output = printer.to_string();
3756 assert!(output.contains("call foo(%0)"));
3757 }
3758
3759 #[test]
3760 fn test_printer_call_with_arg_modes() {
3761 let (mut rir, interner) = create_printer_test_rir();
3762 let arg1 = rir.add_inst(Inst {
3763 data: InstData::IntConst(1),
3764 span: Span::new(0, 1),
3765 });
3766 let arg2 = rir.add_inst(Inst {
3767 data: InstData::IntConst(2),
3768 span: Span::new(0, 1),
3769 });
3770 let arg3 = rir.add_inst(Inst {
3771 data: InstData::IntConst(3),
3772 span: Span::new(0, 1),
3773 });
3774
3775 let name = interner.get_or_intern("modify");
3776
3777 let (args_start, args_len) = rir.add_call_args(&[
3778 RirCallArg {
3779 value: arg1,
3780 mode: RirArgMode::Normal,
3781 },
3782 RirCallArg {
3783 value: arg2,
3784 mode: RirArgMode::MutRef,
3785 },
3786 RirCallArg {
3787 value: arg3,
3788 mode: RirArgMode::Ref,
3789 },
3790 ]);
3791
3792 rir.add_inst(Inst {
3793 data: InstData::Call {
3794 name,
3795 args_start,
3796 args_len,
3797 },
3798 span: Span::new(0, 20),
3799 });
3800
3801 let printer = RirPrinter::new(&rir, &interner);
3802 let output = printer.to_string();
3803 assert!(output.contains("call modify(%0, mut_ref %1, ref %2)"));
3804 }
3805
3806 #[test]
3807 fn test_printer_intrinsic() {
3808 let (mut rir, interner) = create_printer_test_rir();
3809 let arg = rir.add_inst(Inst {
3810 data: InstData::IntConst(42),
3811 span: Span::new(0, 2),
3812 });
3813
3814 let name = interner.get_or_intern("dbg");
3815
3816 let (args_start, args_len) = rir.add_call_args(&[RirCallArg {
3817 value: arg,
3818 mode: RirArgMode::Normal,
3819 }]);
3820
3821 rir.add_inst(Inst {
3822 data: InstData::Intrinsic {
3823 name,
3824 args_start,
3825 args_len,
3826 },
3827 span: Span::new(0, 10),
3828 });
3829
3830 let printer = RirPrinter::new(&rir, &interner);
3831 let output = printer.to_string();
3832 assert!(output.contains("intrinsic @dbg(%0)"));
3833 }
3834
3835 #[test]
3836 fn test_printer_type_intrinsic() {
3837 let (mut rir, interner) = create_printer_test_rir();
3838 let name = interner.get_or_intern("size_of");
3839 let type_arg = interner.get_or_intern("i32");
3840
3841 rir.add_inst(Inst {
3842 data: InstData::TypeIntrinsic { name, type_arg },
3843 span: Span::new(0, 15),
3844 });
3845
3846 let printer = RirPrinter::new(&rir, &interner);
3847 let output = printer.to_string();
3848 assert!(output.contains("type_intrinsic @size_of(i32)"));
3849 }
3850
3851 #[test]
3852 fn test_printer_param_ref() {
3853 let (mut rir, interner) = create_printer_test_rir();
3854 let name = interner.get_or_intern("x");
3855
3856 rir.add_inst(Inst {
3857 data: InstData::ParamRef { index: 0, name },
3858 span: Span::new(0, 1),
3859 });
3860
3861 let printer = RirPrinter::new(&rir, &interner);
3862 let output = printer.to_string();
3863 assert!(output.contains("param 0 (x)"));
3864 }
3865
3866 #[test]
3867 fn test_printer_block() {
3868 let (mut rir, interner) = create_printer_test_rir();
3869 rir.add_inst(Inst {
3870 data: InstData::Block {
3871 extra_start: 0,
3872 len: 3,
3873 },
3874 span: Span::new(0, 20),
3875 });
3876
3877 let printer = RirPrinter::new(&rir, &interner);
3878 let output = printer.to_string();
3879 assert!(output.contains("block(0, 3)"));
3880 }
3881
3882 #[test]
3883 fn test_printer_alloc() {
3884 let (mut rir, interner) = create_printer_test_rir();
3885 let init = rir.add_inst(Inst {
3886 data: InstData::IntConst(42),
3887 span: Span::new(0, 2),
3888 });
3889
3890 let name = interner.get_or_intern("x");
3891 let ty = interner.get_or_intern("i32");
3892
3893 let (directives_start, directives_len) = rir.add_directives(&[]);
3894
3895 rir.add_inst(Inst {
3897 data: InstData::Alloc {
3898 directives_start,
3899 directives_len,
3900 name: Some(name),
3901 is_mut: false,
3902 ty: Some(ty),
3903 init,
3904 },
3905 span: Span::new(0, 15),
3906 });
3907
3908 let printer = RirPrinter::new(&rir, &interner);
3909 let output = printer.to_string();
3910 assert!(output.contains("alloc x: i32= %0"));
3911 }
3912
3913 #[test]
3914 fn test_printer_alloc_mut() {
3915 let (mut rir, interner) = create_printer_test_rir();
3916 let init = rir.add_inst(Inst {
3917 data: InstData::IntConst(42),
3918 span: Span::new(0, 2),
3919 });
3920
3921 let name = interner.get_or_intern("x");
3922
3923 let (directives_start, directives_len) = rir.add_directives(&[]);
3924
3925 rir.add_inst(Inst {
3926 data: InstData::Alloc {
3927 directives_start,
3928 directives_len,
3929 name: Some(name),
3930 is_mut: true,
3931 ty: None,
3932 init,
3933 },
3934 span: Span::new(0, 15),
3935 });
3936
3937 let printer = RirPrinter::new(&rir, &interner);
3938 let output = printer.to_string();
3939 assert!(output.contains("alloc mut x= %0"));
3940 }
3941
3942 #[test]
3943 fn test_printer_alloc_wildcard() {
3944 let (mut rir, interner) = create_printer_test_rir();
3945 let init = rir.add_inst(Inst {
3946 data: InstData::IntConst(42),
3947 span: Span::new(0, 2),
3948 });
3949
3950 let (directives_start, directives_len) = rir.add_directives(&[]);
3951
3952 rir.add_inst(Inst {
3953 data: InstData::Alloc {
3954 directives_start,
3955 directives_len,
3956 name: None,
3957 is_mut: false,
3958 ty: None,
3959 init,
3960 },
3961 span: Span::new(0, 10),
3962 });
3963
3964 let printer = RirPrinter::new(&rir, &interner);
3965 let output = printer.to_string();
3966 assert!(output.contains("alloc _= %0"));
3967 }
3968
3969 #[test]
3970 fn test_printer_var_ref() {
3971 let (mut rir, interner) = create_printer_test_rir();
3972 let name = interner.get_or_intern("x");
3973
3974 rir.add_inst(Inst {
3975 data: InstData::VarRef { name },
3976 span: Span::new(0, 1),
3977 });
3978
3979 let printer = RirPrinter::new(&rir, &interner);
3980 let output = printer.to_string();
3981 assert!(output.contains("var_ref x"));
3982 }
3983
3984 #[test]
3985 fn test_printer_assign() {
3986 let (mut rir, interner) = create_printer_test_rir();
3987 let value = rir.add_inst(Inst {
3988 data: InstData::IntConst(10),
3989 span: Span::new(0, 2),
3990 });
3991
3992 let name = interner.get_or_intern("x");
3993
3994 rir.add_inst(Inst {
3995 data: InstData::Assign { name, value },
3996 span: Span::new(0, 6),
3997 });
3998
3999 let printer = RirPrinter::new(&rir, &interner);
4000 let output = printer.to_string();
4001 assert!(output.contains("assign x = %0"));
4002 }
4003
4004 #[test]
4005 fn test_printer_struct_decl() {
4006 let (mut rir, interner) = create_printer_test_rir();
4007 let name = interner.get_or_intern("Point");
4008 let x_name = interner.get_or_intern("x");
4009 let y_name = interner.get_or_intern("y");
4010 let i32_type = interner.get_or_intern("i32");
4011
4012 let (directives_start, directives_len) = rir.add_directives(&[]);
4013 let (fields_start, fields_len) =
4014 rir.add_field_decls(&[(x_name, i32_type), (y_name, i32_type)]);
4015 let (methods_start, methods_len) = rir.add_inst_refs(&[]);
4016
4017 rir.add_inst(Inst {
4018 data: InstData::StructDecl {
4019 directives_start,
4020 directives_len,
4021 is_pub: false,
4022 posture: Posture::Affine,
4023 name,
4024 fields_start,
4025 fields_len,
4026 methods_start,
4027 methods_len,
4028 },
4029 span: Span::new(0, 30),
4030 });
4031
4032 let printer = RirPrinter::new(&rir, &interner);
4033 let output = printer.to_string();
4034 assert!(output.contains("struct Point { x: i32, y: i32 }"));
4035 }
4036
4037 #[test]
4038 fn test_printer_struct_decl_with_directive() {
4039 let (mut rir, interner) = create_printer_test_rir();
4040 let name = interner.get_or_intern("Point");
4041 let x_name = interner.get_or_intern("x");
4042 let i32_type = interner.get_or_intern("i32");
4043 let directive_name = interner.get_or_intern("handle");
4044
4045 let (directives_start, directives_len) = rir.add_directives(&[RirDirective {
4046 name: directive_name,
4047 args: vec![],
4048 span: Span::new(0, 7),
4049 }]);
4050 let (fields_start, fields_len) = rir.add_field_decls(&[(x_name, i32_type)]);
4051 let (methods_start, methods_len) = rir.add_inst_refs(&[]);
4052
4053 rir.add_inst(Inst {
4054 data: InstData::StructDecl {
4055 directives_start,
4056 directives_len,
4057 is_pub: false,
4058 posture: Posture::Affine,
4059 name,
4060 fields_start,
4061 fields_len,
4062 methods_start,
4063 methods_len,
4064 },
4065 span: Span::new(0, 30),
4066 });
4067
4068 let printer = RirPrinter::new(&rir, &interner);
4069 let output = printer.to_string();
4070 assert!(output.contains("@handle struct Point { x: i32 }"));
4071 }
4072
4073 #[test]
4074 fn test_printer_struct_init() {
4075 let (mut rir, interner) = create_printer_test_rir();
4076 let x_val = rir.add_inst(Inst {
4077 data: InstData::IntConst(10),
4078 span: Span::new(0, 2),
4079 });
4080 let y_val = rir.add_inst(Inst {
4081 data: InstData::IntConst(20),
4082 span: Span::new(0, 2),
4083 });
4084
4085 let type_name = interner.get_or_intern("Point");
4086 let x_name = interner.get_or_intern("x");
4087 let y_name = interner.get_or_intern("y");
4088
4089 let (fields_start, fields_len) = rir.add_field_inits(&[(x_name, x_val), (y_name, y_val)]);
4090
4091 rir.add_inst(Inst {
4092 data: InstData::StructInit {
4093 module: None,
4094 type_name,
4095 fields_start,
4096 fields_len,
4097 },
4098 span: Span::new(0, 25),
4099 });
4100
4101 let printer = RirPrinter::new(&rir, &interner);
4102 let output = printer.to_string();
4103 assert!(output.contains("struct_init Point { x: %0, y: %1 }"));
4104 }
4105
4106 #[test]
4107 fn test_printer_field_get() {
4108 let (mut rir, interner) = create_printer_test_rir();
4109 let base = rir.add_inst(Inst {
4110 data: InstData::IntConst(0), span: Span::new(0, 1),
4112 });
4113
4114 let field = interner.get_or_intern("x");
4115
4116 rir.add_inst(Inst {
4117 data: InstData::FieldGet { base, field },
4118 span: Span::new(0, 5),
4119 });
4120
4121 let printer = RirPrinter::new(&rir, &interner);
4122 let output = printer.to_string();
4123 assert!(output.contains("field_get %0.x"));
4124 }
4125
4126 #[test]
4127 fn test_printer_field_set() {
4128 let (mut rir, interner) = create_printer_test_rir();
4129 let base = rir.add_inst(Inst {
4130 data: InstData::IntConst(0), span: Span::new(0, 1),
4132 });
4133 let value = rir.add_inst(Inst {
4134 data: InstData::IntConst(42),
4135 span: Span::new(0, 2),
4136 });
4137
4138 let field = interner.get_or_intern("x");
4139
4140 rir.add_inst(Inst {
4141 data: InstData::FieldSet { base, field, value },
4142 span: Span::new(0, 10),
4143 });
4144
4145 let printer = RirPrinter::new(&rir, &interner);
4146 let output = printer.to_string();
4147 assert!(output.contains("field_set %0.x = %1"));
4148 }
4149
4150 #[test]
4151 fn test_printer_enum_decl() {
4152 let (mut rir, interner) = create_printer_test_rir();
4153 let name = interner.get_or_intern("Color");
4154 let red = interner.get_or_intern("Red");
4155 let green = interner.get_or_intern("Green");
4156 let blue = interner.get_or_intern("Blue");
4157
4158 let (variants_start, variants_len) = rir.add_enum_variant_decls(&[
4160 (red, vec![], vec![]),
4161 (green, vec![], vec![]),
4162 (blue, vec![], vec![]),
4163 ]);
4164
4165 rir.add_inst(Inst {
4166 data: InstData::EnumDecl {
4167 is_pub: false,
4168 posture: Posture::Affine,
4169 name,
4170 variants_start,
4171 variants_len,
4172 methods_start: 0,
4173 methods_len: 0,
4174 directives_start: 0,
4175 directives_len: 0,
4176 },
4177 span: Span::new(0, 35),
4178 });
4179
4180 let printer = RirPrinter::new(&rir, &interner);
4181 let output = printer.to_string();
4182 assert!(output.contains("enum Color { Red, Green, Blue }"));
4183 }
4184
4185 #[test]
4186 fn test_printer_enum_decl_with_data() {
4187 let (mut rir, interner) = create_printer_test_rir();
4188 let name = interner.get_or_intern("IntOption");
4189 let none = interner.get_or_intern("None");
4190 let some = interner.get_or_intern("Some");
4191 let i32_ty = interner.get_or_intern("i32");
4192
4193 let (variants_start, variants_len) =
4194 rir.add_enum_variant_decls(&[(none, vec![], vec![]), (some, vec![i32_ty], vec![])]);
4195
4196 rir.add_inst(Inst {
4197 data: InstData::EnumDecl {
4198 is_pub: false,
4199 posture: Posture::Affine,
4200 name,
4201 variants_start,
4202 variants_len,
4203 methods_start: 0,
4204 methods_len: 0,
4205 directives_start: 0,
4206 directives_len: 0,
4207 },
4208 span: Span::new(0, 35),
4209 });
4210
4211 let printer = RirPrinter::new(&rir, &interner);
4212 let output = printer.to_string();
4213 assert!(output.contains("enum IntOption { None, Some(i32) }"));
4214 }
4215
4216 #[test]
4217 fn test_printer_enum_variant() {
4218 let (mut rir, interner) = create_printer_test_rir();
4219 let type_name = interner.get_or_intern("Color");
4220 let variant = interner.get_or_intern("Red");
4221
4222 rir.add_inst(Inst {
4223 data: InstData::EnumVariant {
4224 module: None,
4225 type_name,
4226 variant,
4227 },
4228 span: Span::new(0, 10),
4229 });
4230
4231 let printer = RirPrinter::new(&rir, &interner);
4232 let output = printer.to_string();
4233 assert!(output.contains("enum_variant Color::Red"));
4234 }
4235
4236 #[test]
4237 fn test_printer_array_init() {
4238 let (mut rir, interner) = create_printer_test_rir();
4239 let elem1 = rir.add_inst(Inst {
4240 data: InstData::IntConst(1),
4241 span: Span::new(0, 1),
4242 });
4243 let elem2 = rir.add_inst(Inst {
4244 data: InstData::IntConst(2),
4245 span: Span::new(0, 1),
4246 });
4247 let elem3 = rir.add_inst(Inst {
4248 data: InstData::IntConst(3),
4249 span: Span::new(0, 1),
4250 });
4251
4252 let (elems_start, elems_len) = rir.add_inst_refs(&[elem1, elem2, elem3]);
4253
4254 rir.add_inst(Inst {
4255 data: InstData::ArrayInit {
4256 elems_start,
4257 elems_len,
4258 },
4259 span: Span::new(0, 10),
4260 });
4261
4262 let printer = RirPrinter::new(&rir, &interner);
4263 let output = printer.to_string();
4264 assert!(output.contains("array_init [%0, %1, %2]"));
4265 }
4266
4267 #[test]
4268 fn test_printer_index_get() {
4269 let (mut rir, interner) = create_printer_test_rir();
4270 let base = rir.add_inst(Inst {
4271 data: InstData::IntConst(0), span: Span::new(0, 1),
4273 });
4274 let index = rir.add_inst(Inst {
4275 data: InstData::IntConst(1),
4276 span: Span::new(0, 1),
4277 });
4278
4279 rir.add_inst(Inst {
4280 data: InstData::IndexGet { base, index },
4281 span: Span::new(0, 5),
4282 });
4283
4284 let printer = RirPrinter::new(&rir, &interner);
4285 let output = printer.to_string();
4286 assert!(output.contains("index_get %0[%1]"));
4287 }
4288
4289 #[test]
4290 fn test_printer_index_set() {
4291 let (mut rir, interner) = create_printer_test_rir();
4292 let base = rir.add_inst(Inst {
4293 data: InstData::IntConst(0), span: Span::new(0, 1),
4295 });
4296 let index = rir.add_inst(Inst {
4297 data: InstData::IntConst(1),
4298 span: Span::new(0, 1),
4299 });
4300 let value = rir.add_inst(Inst {
4301 data: InstData::IntConst(42),
4302 span: Span::new(0, 2),
4303 });
4304
4305 rir.add_inst(Inst {
4306 data: InstData::IndexSet { base, index, value },
4307 span: Span::new(0, 10),
4308 });
4309
4310 let printer = RirPrinter::new(&rir, &interner);
4311 let output = printer.to_string();
4312 assert!(output.contains("index_set %0[%1] = %2"));
4313 }
4314
4315 #[test]
4317 fn test_printer_struct_decl_with_methods() {
4318 let (mut rir, interner) = create_printer_test_rir();
4319
4320 let method_body = rir.add_inst(Inst {
4322 data: InstData::IntConst(0),
4323 span: Span::new(0, 1),
4324 });
4325 let method_name = interner.get_or_intern("get_x");
4326 let return_type = interner.get_or_intern("i32");
4327
4328 let (directives_start, directives_len) = rir.add_directives(&[]);
4329 let (params_start, params_len) = rir.add_params(&[]);
4330
4331 let method_ref = rir.add_inst(Inst {
4332 data: InstData::FnDecl {
4333 directives_start,
4334 directives_len,
4335 is_pub: false,
4336 is_unchecked: false,
4337 name: method_name,
4338 params_start,
4339 params_len,
4340 return_type,
4341 body: method_body,
4342 has_self: true,
4343 receiver_mode: 0,
4344 },
4345 span: Span::new(0, 30),
4346 });
4347
4348 let struct_name = interner.get_or_intern("Point");
4349 let x_field = interner.get_or_intern("x");
4350 let i32_type = interner.get_or_intern("i32");
4351
4352 let (fields_start, fields_len) = rir.add_field_decls(&[(x_field, i32_type)]);
4353 let (methods_start, methods_len) = rir.add_inst_refs(&[method_ref]);
4354
4355 rir.add_inst(Inst {
4356 data: InstData::StructDecl {
4357 directives_start,
4358 directives_len,
4359 is_pub: false,
4360 posture: Posture::Affine,
4361 name: struct_name,
4362 fields_start,
4363 fields_len,
4364 methods_start,
4365 methods_len,
4366 },
4367 span: Span::new(0, 50),
4368 });
4369
4370 let printer = RirPrinter::new(&rir, &interner);
4371 let output = printer.to_string();
4372 assert!(output.contains("struct Point { x: i32 } methods: [%1]"));
4373 }
4374
4375 #[test]
4376 fn test_printer_method_call() {
4377 let (mut rir, interner) = create_printer_test_rir();
4378 let receiver = rir.add_inst(Inst {
4379 data: InstData::IntConst(0), span: Span::new(0, 1),
4381 });
4382 let arg = rir.add_inst(Inst {
4383 data: InstData::IntConst(10),
4384 span: Span::new(0, 2),
4385 });
4386
4387 let method = interner.get_or_intern("add");
4388
4389 let (args_start, args_len) = rir.add_call_args(&[RirCallArg {
4390 value: arg,
4391 mode: RirArgMode::Normal,
4392 }]);
4393
4394 rir.add_inst(Inst {
4395 data: InstData::MethodCall {
4396 receiver,
4397 method,
4398 args_start,
4399 args_len,
4400 },
4401 span: Span::new(0, 15),
4402 });
4403
4404 let printer = RirPrinter::new(&rir, &interner);
4405 let output = printer.to_string();
4406 assert!(output.contains("method_call %0.add(%1)"));
4407 }
4408
4409 #[test]
4410 fn test_printer_method_call_with_arg_modes() {
4411 let (mut rir, interner) = create_printer_test_rir();
4412 let receiver = rir.add_inst(Inst {
4413 data: InstData::IntConst(0),
4414 span: Span::new(0, 1),
4415 });
4416 let arg1 = rir.add_inst(Inst {
4417 data: InstData::IntConst(1),
4418 span: Span::new(0, 1),
4419 });
4420 let arg2 = rir.add_inst(Inst {
4421 data: InstData::IntConst(2),
4422 span: Span::new(0, 1),
4423 });
4424
4425 let method = interner.get_or_intern("modify");
4426
4427 let (args_start, args_len) = rir.add_call_args(&[
4428 RirCallArg {
4429 value: arg1,
4430 mode: RirArgMode::MutRef,
4431 },
4432 RirCallArg {
4433 value: arg2,
4434 mode: RirArgMode::Ref,
4435 },
4436 ]);
4437
4438 rir.add_inst(Inst {
4439 data: InstData::MethodCall {
4440 receiver,
4441 method,
4442 args_start,
4443 args_len,
4444 },
4445 span: Span::new(0, 25),
4446 });
4447
4448 let printer = RirPrinter::new(&rir, &interner);
4449 let output = printer.to_string();
4450 assert!(output.contains("method_call %0.modify(mut_ref %1, ref %2)"));
4451 }
4452
4453 #[test]
4454 fn test_printer_assoc_fn_call() {
4455 let (mut rir, interner) = create_printer_test_rir();
4456
4457 let type_name = interner.get_or_intern("Point");
4458 let function = interner.get_or_intern("origin");
4459
4460 let (args_start, args_len) = rir.add_call_args(&[]);
4461
4462 rir.add_inst(Inst {
4463 data: InstData::AssocFnCall {
4464 type_name,
4465 function,
4466 args_start,
4467 args_len,
4468 },
4469 span: Span::new(0, 15),
4470 });
4471
4472 let printer = RirPrinter::new(&rir, &interner);
4473 let output = printer.to_string();
4474 assert!(output.contains("assoc_fn_call Point::origin()"));
4475 }
4476
4477 #[test]
4478 fn test_printer_assoc_fn_call_with_args() {
4479 let (mut rir, interner) = create_printer_test_rir();
4480 let arg1 = rir.add_inst(Inst {
4481 data: InstData::IntConst(10),
4482 span: Span::new(0, 2),
4483 });
4484 let arg2 = rir.add_inst(Inst {
4485 data: InstData::IntConst(20),
4486 span: Span::new(0, 2),
4487 });
4488
4489 let type_name = interner.get_or_intern("Point");
4490 let function = interner.get_or_intern("new");
4491
4492 let (args_start, args_len) = rir.add_call_args(&[
4493 RirCallArg {
4494 value: arg1,
4495 mode: RirArgMode::Normal,
4496 },
4497 RirCallArg {
4498 value: arg2,
4499 mode: RirArgMode::Normal,
4500 },
4501 ]);
4502
4503 rir.add_inst(Inst {
4504 data: InstData::AssocFnCall {
4505 type_name,
4506 function,
4507 args_start,
4508 args_len,
4509 },
4510 span: Span::new(0, 20),
4511 });
4512
4513 let printer = RirPrinter::new(&rir, &interner);
4514 let output = printer.to_string();
4515 assert!(output.contains("assoc_fn_call Point::new(%0, %1)"));
4516 }
4517
4518 #[test]
4520 fn test_printer_match_wildcard() {
4521 let (mut rir, interner) = create_printer_test_rir();
4522 let scrutinee = rir.add_inst(Inst {
4523 data: InstData::IntConst(42),
4524 span: Span::new(0, 2),
4525 });
4526 let body = rir.add_inst(Inst {
4527 data: InstData::IntConst(0),
4528 span: Span::new(0, 1),
4529 });
4530
4531 let (arms_start, arms_len) =
4532 rir.add_match_arms(&[(RirPattern::Wildcard(Span::new(0, 1)), body)]);
4533
4534 rir.add_inst(Inst {
4535 data: InstData::Match {
4536 scrutinee,
4537 arms_start,
4538 arms_len,
4539 },
4540 span: Span::new(0, 20),
4541 });
4542
4543 let printer = RirPrinter::new(&rir, &interner);
4544 let output = printer.to_string();
4545 assert!(output.contains("match %0 { _ => %1 }"));
4546 }
4547
4548 #[test]
4549 fn test_printer_match_int_pattern() {
4550 let (mut rir, interner) = create_printer_test_rir();
4551 let scrutinee = rir.add_inst(Inst {
4552 data: InstData::IntConst(42),
4553 span: Span::new(0, 2),
4554 });
4555 let body1 = rir.add_inst(Inst {
4556 data: InstData::IntConst(1),
4557 span: Span::new(0, 1),
4558 });
4559 let body2 = rir.add_inst(Inst {
4560 data: InstData::IntConst(2),
4561 span: Span::new(0, 1),
4562 });
4563 let body_default = rir.add_inst(Inst {
4564 data: InstData::IntConst(0),
4565 span: Span::new(0, 1),
4566 });
4567
4568 let (arms_start, arms_len) = rir.add_match_arms(&[
4569 (RirPattern::Int(1, Span::new(0, 1)), body1),
4570 (RirPattern::Int(-5, Span::new(0, 2)), body2),
4571 (RirPattern::Wildcard(Span::new(0, 1)), body_default),
4572 ]);
4573
4574 rir.add_inst(Inst {
4575 data: InstData::Match {
4576 scrutinee,
4577 arms_start,
4578 arms_len,
4579 },
4580 span: Span::new(0, 30),
4581 });
4582
4583 let printer = RirPrinter::new(&rir, &interner);
4584 let output = printer.to_string();
4585 assert!(output.contains("match %0 { 1 => %1, -5 => %2, _ => %3 }"));
4586 }
4587
4588 #[test]
4589 fn test_printer_match_bool_pattern() {
4590 let (mut rir, interner) = create_printer_test_rir();
4591 let scrutinee = rir.add_inst(Inst {
4592 data: InstData::BoolConst(true),
4593 span: Span::new(0, 4),
4594 });
4595 let body_true = rir.add_inst(Inst {
4596 data: InstData::IntConst(1),
4597 span: Span::new(0, 1),
4598 });
4599 let body_false = rir.add_inst(Inst {
4600 data: InstData::IntConst(0),
4601 span: Span::new(0, 1),
4602 });
4603
4604 let (arms_start, arms_len) = rir.add_match_arms(&[
4605 (RirPattern::Bool(true, Span::new(0, 4)), body_true),
4606 (RirPattern::Bool(false, Span::new(0, 5)), body_false),
4607 ]);
4608
4609 rir.add_inst(Inst {
4610 data: InstData::Match {
4611 scrutinee,
4612 arms_start,
4613 arms_len,
4614 },
4615 span: Span::new(0, 30),
4616 });
4617
4618 let printer = RirPrinter::new(&rir, &interner);
4619 let output = printer.to_string();
4620 assert!(output.contains("match %0 { true => %1, false => %2 }"));
4621 }
4622
4623 #[test]
4624 fn test_printer_match_path_pattern() {
4625 let (mut rir, interner) = create_printer_test_rir();
4626 let scrutinee = rir.add_inst(Inst {
4627 data: InstData::IntConst(0), span: Span::new(0, 1),
4629 });
4630 let body_red = rir.add_inst(Inst {
4631 data: InstData::IntConst(1),
4632 span: Span::new(0, 1),
4633 });
4634 let body_green = rir.add_inst(Inst {
4635 data: InstData::IntConst(2),
4636 span: Span::new(0, 1),
4637 });
4638 let body_default = rir.add_inst(Inst {
4639 data: InstData::IntConst(0),
4640 span: Span::new(0, 1),
4641 });
4642
4643 let color = interner.get_or_intern("Color");
4644 let red = interner.get_or_intern("Red");
4645 let green = interner.get_or_intern("Green");
4646
4647 let (arms_start, arms_len) = rir.add_match_arms(&[
4648 (
4649 RirPattern::Path {
4650 module: None,
4651 type_name: color,
4652 variant: red,
4653 span: Span::new(0, 10),
4654 },
4655 body_red,
4656 ),
4657 (
4658 RirPattern::Path {
4659 module: None,
4660 type_name: color,
4661 variant: green,
4662 span: Span::new(0, 12),
4663 },
4664 body_green,
4665 ),
4666 (RirPattern::Wildcard(Span::new(0, 1)), body_default),
4667 ]);
4668
4669 rir.add_inst(Inst {
4670 data: InstData::Match {
4671 scrutinee,
4672 arms_start,
4673 arms_len,
4674 },
4675 span: Span::new(0, 50),
4676 });
4677
4678 let printer = RirPrinter::new(&rir, &interner);
4679 let output = printer.to_string();
4680 assert!(output.contains("match %0 { Color::Red => %1, Color::Green => %2, _ => %3 }"));
4681 }
4682
4683 #[test]
4684 fn test_printer_display_trait() {
4685 let (mut rir, interner) = create_printer_test_rir();
4686 rir.add_inst(Inst {
4687 data: InstData::IntConst(42),
4688 span: Span::new(0, 2),
4689 });
4690
4691 let printer = RirPrinter::new(&rir, &interner);
4692 let output = format!("{}", printer);
4694 assert!(output.contains("%0 = const 42"));
4695 }
4696
4697 #[test]
4700 fn test_merge_empty_rirs() {
4701 let merged = Rir::merge(&[]);
4702 assert!(merged.is_empty());
4703 assert!(merged.function_spans().is_empty());
4704 }
4705
4706 #[test]
4707 fn test_merge_single_rir() {
4708 let mut rir = Rir::new();
4709 rir.add_inst(Inst {
4710 data: InstData::IntConst(42),
4711 span: Span::new(0, 2),
4712 });
4713 rir.add_inst(Inst {
4714 data: InstData::BoolConst(true),
4715 span: Span::new(3, 7),
4716 });
4717
4718 let merged = Rir::merge(&[rir]);
4719 assert_eq!(merged.len(), 2);
4720
4721 assert!(matches!(
4723 merged.get(InstRef::from_raw(0)).data,
4724 InstData::IntConst(42)
4725 ));
4726 assert!(matches!(
4727 merged.get(InstRef::from_raw(1)).data,
4728 InstData::BoolConst(true)
4729 ));
4730 }
4731
4732 #[test]
4733 fn test_merge_two_rirs_simple() {
4734 let mut rir1 = Rir::new();
4736 rir1.add_inst(Inst {
4737 data: InstData::IntConst(10),
4738 span: Span::new(0, 2),
4739 });
4740
4741 let mut rir2 = Rir::new();
4743 rir2.add_inst(Inst {
4744 data: InstData::IntConst(20),
4745 span: Span::new(5, 7),
4746 });
4747
4748 let merged = Rir::merge(&[rir1, rir2]);
4749 assert_eq!(merged.len(), 2);
4750
4751 assert!(matches!(
4753 merged.get(InstRef::from_raw(0)).data,
4754 InstData::IntConst(10)
4755 ));
4756 assert!(matches!(
4758 merged.get(InstRef::from_raw(1)).data,
4759 InstData::IntConst(20)
4760 ));
4761 }
4762
4763 #[test]
4764 fn test_merge_renumbers_inst_refs() {
4765 let mut rir1 = Rir::new();
4767 let const1 = rir1.add_inst(Inst {
4768 data: InstData::IntConst(5),
4769 span: Span::new(0, 1),
4770 });
4771 rir1.add_inst(Inst {
4772 data: InstData::Bin {
4773 op: BinOp::Add,
4774 lhs: const1,
4775 rhs: const1,
4776 },
4777 span: Span::new(2, 5),
4778 });
4779
4780 let mut rir2 = Rir::new();
4782 let const2 = rir2.add_inst(Inst {
4783 data: InstData::IntConst(10),
4784 span: Span::new(10, 12),
4785 });
4786 rir2.add_inst(Inst {
4787 data: InstData::Bin {
4788 op: BinOp::Add,
4789 lhs: const2,
4790 rhs: const2,
4791 },
4792 span: Span::new(12, 16),
4793 });
4794
4795 let merged = Rir::merge(&[rir1, rir2]);
4796 assert_eq!(merged.len(), 4);
4797
4798 if let InstData::Bin {
4800 op: BinOp::Add,
4801 lhs,
4802 rhs,
4803 } = &merged.get(InstRef::from_raw(1)).data
4804 {
4805 assert_eq!(lhs.as_u32(), 0);
4806 assert_eq!(rhs.as_u32(), 0);
4807 } else {
4808 panic!("Expected Add instruction at index 1");
4809 }
4810
4811 if let InstData::Bin {
4813 op: BinOp::Add,
4814 lhs,
4815 rhs,
4816 } = &merged.get(InstRef::from_raw(3)).data
4817 {
4818 assert_eq!(lhs.as_u32(), 2);
4819 assert_eq!(rhs.as_u32(), 2);
4820 } else {
4821 panic!("Expected Add instruction at index 3");
4822 }
4823 }
4824
4825 #[test]
4826 fn test_merge_renumbers_extra_data() {
4827 let mut rir1 = Rir::new();
4829 let interner = ThreadedRodeo::new();
4830 let fn_name = interner.get_or_intern("foo");
4831
4832 let const1 = rir1.add_inst(Inst {
4833 data: InstData::IntConst(1),
4834 span: Span::new(0, 1),
4835 });
4836 let (args_start, args_len) = rir1.add_call_args(&[RirCallArg {
4837 value: const1,
4838 mode: RirArgMode::Normal,
4839 }]);
4840 rir1.add_inst(Inst {
4841 data: InstData::Call {
4842 name: fn_name,
4843 args_start,
4844 args_len,
4845 },
4846 span: Span::new(2, 8),
4847 });
4848
4849 let mut rir2 = Rir::new();
4851 let const2 = rir2.add_inst(Inst {
4852 data: InstData::IntConst(2),
4853 span: Span::new(10, 11),
4854 });
4855 let (args_start2, args_len2) = rir2.add_call_args(&[RirCallArg {
4856 value: const2,
4857 mode: RirArgMode::Normal,
4858 }]);
4859 rir2.add_inst(Inst {
4860 data: InstData::Call {
4861 name: fn_name,
4862 args_start: args_start2,
4863 args_len: args_len2,
4864 },
4865 span: Span::new(12, 18),
4866 });
4867
4868 let merged = Rir::merge(&[rir1, rir2]);
4869 assert_eq!(merged.len(), 4);
4870
4871 if let InstData::Call {
4873 args_start,
4874 args_len,
4875 ..
4876 } = &merged.get(InstRef::from_raw(1)).data
4877 {
4878 let args = merged.get_call_args(*args_start, *args_len);
4879 assert_eq!(args.len(), 1);
4880 assert_eq!(args[0].value.as_u32(), 0); } else {
4882 panic!("Expected Call instruction at index 1");
4883 }
4884
4885 if let InstData::Call {
4887 args_start,
4888 args_len,
4889 ..
4890 } = &merged.get(InstRef::from_raw(3)).data
4891 {
4892 let args = merged.get_call_args(*args_start, *args_len);
4893 assert_eq!(args.len(), 1);
4894 assert_eq!(args[0].value.as_u32(), 2); } else {
4896 panic!("Expected Call instruction at index 3");
4897 }
4898 }
4899
4900 #[test]
4901 fn test_merge_function_spans() {
4902 let interner = ThreadedRodeo::new();
4903 let main_name = interner.get_or_intern("main");
4904 let helper_name = interner.get_or_intern("helper");
4905
4906 let mut rir1 = Rir::new();
4908 let body_start1 = InstRef::from_raw(rir1.current_inst_index());
4909 let const1 = rir1.add_inst(Inst {
4910 data: InstData::IntConst(0),
4911 span: Span::new(0, 1),
4912 });
4913 let (params_start, params_len) = rir1.add_params(&[]);
4914 let (dirs_start, dirs_len) = rir1.add_directives(&[]);
4915 let ret_type = interner.get_or_intern("i32");
4916 let decl1 = rir1.add_inst(Inst {
4917 data: InstData::FnDecl {
4918 directives_start: dirs_start,
4919 directives_len: dirs_len,
4920 is_pub: false,
4921 is_unchecked: false,
4922 name: main_name,
4923 params_start,
4924 params_len,
4925 return_type: ret_type,
4926 body: const1,
4927 has_self: false,
4928 receiver_mode: 0,
4929 },
4930 span: Span::new(0, 10),
4931 });
4932 rir1.add_function_span(FunctionSpan::new(main_name, body_start1, decl1));
4933
4934 let mut rir2 = Rir::new();
4936 let body_start2 = InstRef::from_raw(rir2.current_inst_index());
4937 let const2 = rir2.add_inst(Inst {
4938 data: InstData::IntConst(42),
4939 span: Span::new(20, 22),
4940 });
4941 let (params_start2, params_len2) = rir2.add_params(&[]);
4942 let (dirs_start2, dirs_len2) = rir2.add_directives(&[]);
4943 let decl2 = rir2.add_inst(Inst {
4944 data: InstData::FnDecl {
4945 directives_start: dirs_start2,
4946 directives_len: dirs_len2,
4947 is_pub: false,
4948 is_unchecked: false,
4949 name: helper_name,
4950 params_start: params_start2,
4951 params_len: params_len2,
4952 return_type: ret_type,
4953 body: const2,
4954 has_self: false,
4955 receiver_mode: 0,
4956 },
4957 span: Span::new(20, 35),
4958 });
4959 rir2.add_function_span(FunctionSpan::new(helper_name, body_start2, decl2));
4960
4961 let merged = Rir::merge(&[rir1, rir2]);
4962
4963 assert_eq!(merged.function_spans().len(), 2);
4965
4966 let main_span = &merged.function_spans()[0];
4968 assert_eq!(main_span.name, main_name);
4969 assert_eq!(main_span.body_start.as_u32(), 0);
4970 assert_eq!(main_span.decl.as_u32(), 1);
4971
4972 let helper_span = &merged.function_spans()[1];
4974 assert_eq!(helper_span.name, helper_name);
4975 assert_eq!(helper_span.body_start.as_u32(), 2); assert_eq!(helper_span.decl.as_u32(), 3); }
4978
4979 #[test]
4980 fn test_merge_three_rirs() {
4981 let mut rir1 = Rir::new();
4982 rir1.add_inst(Inst {
4983 data: InstData::IntConst(1),
4984 span: Span::new(0, 1),
4985 });
4986
4987 let mut rir2 = Rir::new();
4988 rir2.add_inst(Inst {
4989 data: InstData::IntConst(2),
4990 span: Span::new(10, 11),
4991 });
4992
4993 let mut rir3 = Rir::new();
4994 rir3.add_inst(Inst {
4995 data: InstData::IntConst(3),
4996 span: Span::new(20, 21),
4997 });
4998
4999 let merged = Rir::merge(&[rir1, rir2, rir3]);
5000 assert_eq!(merged.len(), 3);
5001
5002 assert!(matches!(
5003 merged.get(InstRef::from_raw(0)).data,
5004 InstData::IntConst(1)
5005 ));
5006 assert!(matches!(
5007 merged.get(InstRef::from_raw(1)).data,
5008 InstData::IntConst(2)
5009 ));
5010 assert!(matches!(
5011 merged.get(InstRef::from_raw(2)).data,
5012 InstData::IntConst(3)
5013 ));
5014 }
5015
5016 #[test]
5017 fn test_merge_preserves_spans() {
5018 let mut rir1 = Rir::new();
5019 rir1.add_inst(Inst {
5020 data: InstData::IntConst(1),
5021 span: Span::new(5, 10),
5022 });
5023
5024 let mut rir2 = Rir::new();
5025 rir2.add_inst(Inst {
5026 data: InstData::IntConst(2),
5027 span: Span::new(100, 105),
5028 });
5029
5030 let merged = Rir::merge(&[rir1, rir2]);
5031
5032 assert_eq!(merged.get(InstRef::from_raw(0)).span, Span::new(5, 10));
5034 assert_eq!(merged.get(InstRef::from_raw(1)).span, Span::new(100, 105));
5035 }
5036}