1use lasso::{Spur, ThreadedRodeo};
7
8use gruel_intrinsics::{IntrinsicKind, is_type_intrinsic, lookup_by_name};
9use gruel_parser::ast::{
10 BlockExpr, ConstDecl, DeriveDecl, Directives, FieldPattern, Ident, SelfParam, SelfReceiverKind,
11 TupleElemPattern,
12};
13use gruel_parser::{
14 ArgMode, AssignTarget, Ast, BinaryOp as AstBinOp, CallArg, Directive, DirectiveArg, EnumDecl,
15 Expr, Function, IntrinsicArg, Item, Method, ParamMode, Pattern, Statement, StructDecl,
16 TypeExpr, UnaryOp as AstUnaryOp, ast::Visibility,
17};
18use gruel_util::{BinOp, UnaryOp};
19
20fn encode_self_receiver_kind(kind: SelfReceiverKind) -> u8 {
27 match kind {
28 SelfReceiverKind::ByValue => 0,
29 SelfReceiverKind::MutRef => 1,
30 SelfReceiverKind::Ref => 2,
31 }
32}
33
34use crate::inst::{
35 FunctionSpan, Inst, InstData, InstRef, Rir, RirArgMode, RirCallArg, RirDestructureField,
36 RirDirective, RirParam, RirParamMode, RirPattern, RirPatternBinding, RirStructField,
37 RirStructPatternBinding,
38};
39
40fn ast_binop_to_ir(op: AstBinOp) -> BinOp {
41 match op {
42 AstBinOp::Add => BinOp::Add,
43 AstBinOp::Sub => BinOp::Sub,
44 AstBinOp::Mul => BinOp::Mul,
45 AstBinOp::Div => BinOp::Div,
46 AstBinOp::Mod => BinOp::Mod,
47 AstBinOp::Eq => BinOp::Eq,
48 AstBinOp::Ne => BinOp::Ne,
49 AstBinOp::Lt => BinOp::Lt,
50 AstBinOp::Gt => BinOp::Gt,
51 AstBinOp::Le => BinOp::Le,
52 AstBinOp::Ge => BinOp::Ge,
53 AstBinOp::And => BinOp::And,
54 AstBinOp::Or => BinOp::Or,
55 AstBinOp::BitAnd => BinOp::BitAnd,
56 AstBinOp::BitOr => BinOp::BitOr,
57 AstBinOp::BitXor => BinOp::BitXor,
58 AstBinOp::Shl => BinOp::Shl,
59 AstBinOp::Shr => BinOp::Shr,
60 }
61}
62
63pub struct AstGen<'a> {
65 ast: &'a Ast,
67 interner: &'a ThreadedRodeo,
69 rir: Rir,
71 nested_pat_counter: u32,
75}
76
77impl<'a> AstGen<'a> {
78 pub fn new(ast: &'a Ast, interner: &'a ThreadedRodeo) -> Self {
80 Self {
81 ast,
82 interner,
83 rir: Rir::new(),
84 nested_pat_counter: 0,
85 }
86 }
87
88 fn fresh_nested_pat_name(&mut self) -> Spur {
93 let n = self.nested_pat_counter;
94 self.nested_pat_counter += 1;
95 self.interner.get_or_intern(format!("__nested_pat_{}", n))
96 }
97
98 pub fn generate(mut self) -> Rir {
100 for item in &self.ast.items {
101 self.gen_item(item);
102 }
103 self.rir
104 }
105
106 fn gen_item(&mut self, item: &Item) {
107 match item {
108 Item::Function(func) => {
109 self.gen_function(func);
110 }
111 Item::Struct(struct_decl) => {
112 self.gen_struct(struct_decl);
113 }
114 Item::Enum(enum_decl) => {
115 self.gen_enum(enum_decl);
116 }
117 Item::Interface(iface) => {
118 self.gen_interface(iface);
119 }
120 Item::Derive(derive_decl) => {
121 self.gen_derive(derive_decl);
122 }
123 Item::Const(const_decl) => {
124 self.gen_const(const_decl);
125 }
126 Item::LinkExtern(block) => {
127 self.gen_link_extern(block);
128 }
129 Item::Error(_) => {}
131 }
132 }
133
134 fn gen_link_extern(&mut self, block: &gruel_parser::ast::LinkExternBlock) {
137 let link_mode = match block.link_mode {
138 gruel_parser::ast::LinkMode::Dynamic => crate::inst::RirLinkMode::Dynamic,
139 gruel_parser::ast::LinkMode::Static => crate::inst::RirLinkMode::Static,
140 };
141 if block.items.is_empty() {
142 self.rir
146 .add_empty_link_extern_block(block.library.value, link_mode, block.span);
147 return;
148 }
149 for item in &block.items {
150 let directives = self.convert_directives(&item.directives);
151 let (directives_start, directives_len) = self.rir.add_directives(&directives);
152
153 let params: Vec<_> = item
154 .params
155 .iter()
156 .map(|p| RirParam {
157 name: p.name.name,
158 ty: self.intern_type(&p.ty),
159 mode: self.convert_param_mode(p.mode),
160 is_comptime: p.is_comptime,
161 })
162 .collect();
163 let (params_start, params_len) = self.rir.add_params(¶ms);
164
165 let return_type = match &item.return_type {
166 Some(ty) => self.intern_type(ty),
167 None => self.interner.get_or_intern("()"),
168 };
169
170 self.rir.add_extern_fn(crate::inst::RirExternFn {
171 library: block.library.value,
172 name: item.name.name,
173 directives_start,
174 directives_len,
175 params_start,
176 params_len,
177 return_type,
178 span: item.span,
179 block_span: block.span,
180 link_mode,
181 });
182 }
183 }
184
185 fn expr_as_type_name(&mut self, expr: &Expr) -> String {
197 match expr {
198 Expr::Ident(ident) => self.interner.resolve(&ident.name).to_string(),
199 Expr::TypeLit(lit) => {
200 let sym = self.intern_type(&lit.type_expr);
201 self.interner.resolve(&sym).to_string()
202 }
203 Expr::Call(call) => {
204 let mut s = String::new();
205 s.push_str(self.interner.resolve(&call.name.name));
206 s.push('(');
207 for (i, arg) in call.args.iter().enumerate() {
208 if i > 0 {
209 s.push_str(", ");
210 }
211 s.push_str(&self.expr_as_type_name(&arg.expr));
212 }
213 s.push(')');
214 s
215 }
216 other => format!("<unsupported type-arg: {:?}>", other),
217 }
218 }
219
220 fn intern_type(&mut self, ty: &TypeExpr) -> Spur {
223 match ty {
224 TypeExpr::Named(ident) => ident.name, TypeExpr::Unit(_) => self.interner.get_or_intern("()"),
226 TypeExpr::Never(_) => self.interner.get_or_intern("!"),
227 TypeExpr::Array {
228 element, length, ..
229 } => {
230 let elem_sym = self.intern_type(element);
233 let elem_name = self.interner.resolve(&elem_sym);
234 let s = format!("[{}; {}]", elem_name, length);
235 self.interner.get_or_intern(&s)
236 }
237 TypeExpr::AnonymousStruct { fields, .. } => {
238 let mut s = String::from("struct { ");
240 for (i, field) in fields.iter().enumerate() {
241 if i > 0 {
242 s.push_str(", ");
243 }
244 let name = self.interner.resolve(&field.name.name);
245 let ty_sym = self.intern_type(&field.ty);
246 let ty_name = self.interner.resolve(&ty_sym);
247 s.push_str(name);
248 s.push_str(": ");
249 s.push_str(ty_name);
250 }
251 s.push_str(" }");
252 self.interner.get_or_intern(&s)
253 }
254 TypeExpr::AnonymousEnum { variants, .. } => {
255 use gruel_parser::ast::EnumVariantKind;
257 let mut s = String::from("enum { ");
258 for (i, v) in variants.iter().enumerate() {
259 if i > 0 {
260 s.push_str(", ");
261 }
262 let name = self.interner.resolve(&v.name.name);
263 s.push_str(name);
264 match &v.kind {
265 EnumVariantKind::Unit => {}
266 EnumVariantKind::Tuple(types) => {
267 s.push('(');
268 for (j, ty) in types.iter().enumerate() {
269 if j > 0 {
270 s.push_str(", ");
271 }
272 let ty_sym = self.intern_type(ty);
273 s.push_str(self.interner.resolve(&ty_sym));
274 }
275 s.push(')');
276 }
277 EnumVariantKind::Struct(fields) => {
278 s.push_str(" { ");
279 for (j, f) in fields.iter().enumerate() {
280 if j > 0 {
281 s.push_str(", ");
282 }
283 let fname = self.interner.resolve(&f.name.name);
284 let ty_sym = self.intern_type(&f.ty);
285 s.push_str(fname);
286 s.push_str(": ");
287 s.push_str(self.interner.resolve(&ty_sym));
288 }
289 s.push_str(" }");
290 }
291 }
292 }
293 s.push_str(" }");
294 self.interner.get_or_intern(&s)
295 }
296 TypeExpr::Tuple { elems, .. } => {
297 let mut s = String::from("(");
300 for (i, elem) in elems.iter().enumerate() {
301 if i > 0 {
302 s.push_str(", ");
303 }
304 let elem_sym = self.intern_type(elem);
305 s.push_str(self.interner.resolve(&elem_sym));
306 }
307 if elems.len() == 1 {
308 s.push(',');
309 }
310 s.push(')');
311 self.interner.get_or_intern(&s)
312 }
313 TypeExpr::AnonymousInterface { methods, .. } => {
314 let mut s = String::from("interface { ");
319 for (i, m) in methods.iter().enumerate() {
320 if i > 0 {
321 s.push_str(", ");
322 }
323 let mname = self.interner.resolve(&m.name.name);
324 s.push_str(mname);
325 }
326 s.push_str(" }");
327 self.interner.get_or_intern(&s)
328 }
329 TypeExpr::TypeCall { callee, args, .. } => {
330 let mut s = String::from(self.interner.resolve(&callee.name));
334 s.push('(');
335 for (i, a) in args.iter().enumerate() {
336 if i > 0 {
337 s.push_str(", ");
338 }
339 let arg_sym = self.intern_type(a);
340 s.push_str(self.interner.resolve(&arg_sym));
341 }
342 s.push(')');
343 self.interner.get_or_intern(&s)
344 }
345 }
346 }
347
348 fn gen_struct(&mut self, struct_decl: &StructDecl) -> InstRef {
349 let directives = self.convert_directives(&struct_decl.directives);
350 let (directives_start, directives_len) = self.rir.add_directives(&directives);
351 let name = struct_decl.name.name; let fields: Vec<_> = struct_decl
353 .fields
354 .iter()
355 .map(|f| {
356 let field_name = f.name.name; let field_type = self.intern_type(&f.ty);
358 let is_pub = f.visibility == gruel_parser::ast::Visibility::Public;
359 (field_name, field_type, is_pub)
360 })
361 .collect();
362 let (fields_start, fields_len) = self.rir.add_field_decls_with_vis(&fields);
363
364 let methods: Vec<_> = struct_decl
366 .methods
367 .iter()
368 .map(|m| self.gen_method(m))
369 .collect();
370 let (methods_start, methods_len) = self.rir.add_inst_refs(&methods);
371
372 self.rir.add_inst(Inst {
373 data: InstData::StructDecl {
374 directives_start,
375 directives_len,
376 is_pub: struct_decl.visibility == Visibility::Public,
377 posture: struct_decl.posture,
378 name,
379 fields_start,
380 fields_len,
381 methods_start,
382 methods_len,
383 },
384 span: struct_decl.span,
385 })
386 }
387
388 fn gen_enum(&mut self, enum_decl: &EnumDecl) -> InstRef {
389 use gruel_parser::ast::EnumVariantKind;
390
391 let name = enum_decl.name.name; let variants: Vec<(Spur, Vec<Spur>, Vec<Spur>)> = enum_decl
393 .variants
394 .iter()
395 .map(|v| {
396 let variant_name = v.name.name;
397 match &v.kind {
398 EnumVariantKind::Unit => (variant_name, vec![], vec![]),
399 EnumVariantKind::Tuple(types) => {
400 let field_types: Vec<Spur> =
401 types.iter().map(|ty| self.intern_type(ty)).collect();
402 (variant_name, field_types, vec![])
403 }
404 EnumVariantKind::Struct(fields) => {
405 let field_types: Vec<Spur> =
406 fields.iter().map(|f| self.intern_type(&f.ty)).collect();
407 let field_names: Vec<Spur> = fields.iter().map(|f| f.name.name).collect();
408 (variant_name, field_types, field_names)
409 }
410 }
411 })
412 .collect();
413 let (variants_start, variants_len) = self.rir.add_enum_variant_decls(&variants);
414
415 let methods: Vec<_> = enum_decl
417 .methods
418 .iter()
419 .map(|m| self.gen_method(m))
420 .collect();
421 let (methods_start, methods_len) = self.rir.add_inst_refs(&methods);
422
423 let directives = self.convert_directives(&enum_decl.directives);
424 let (directives_start, directives_len) = self.rir.add_directives(&directives);
425
426 self.rir.add_inst(Inst {
427 data: InstData::EnumDecl {
428 is_pub: enum_decl.visibility == Visibility::Public,
429 posture: enum_decl.posture,
430 name,
431 variants_start,
432 variants_len,
433 methods_start,
434 methods_len,
435 directives_start,
436 directives_len,
437 },
438 span: enum_decl.span,
439 })
440 }
441
442 fn gen_interface(&mut self, iface: &gruel_parser::ast::InterfaceDecl) -> InstRef {
443 use gruel_parser::ast::Visibility;
444
445 let method_refs: Vec<InstRef> = iface
448 .methods
449 .iter()
450 .map(|sig| {
451 let name = sig.name.name;
452 let return_type = match &sig.return_type {
453 Some(ty) => self.intern_type(ty),
454 None => self.interner.get_or_intern("()"),
455 };
456 let params: Vec<_> = sig
457 .params
458 .iter()
459 .map(|p| RirParam {
460 name: p.name.name,
461 ty: self.intern_type(&p.ty),
462 mode: self.convert_param_mode(p.mode),
463 is_comptime: p.is_comptime,
464 })
465 .collect();
466 let (params_start, params_len) = self.rir.add_params(¶ms);
467
468 let directives = self.convert_directives(&sig.directives);
469 let (directives_start, directives_len) = self.rir.add_directives(&directives);
470
471 let receiver_mode = encode_self_receiver_kind(sig.receiver.kind);
472 self.rir.add_inst(Inst {
473 data: InstData::InterfaceMethodSig {
474 name,
475 params_start,
476 params_len,
477 return_type,
478 receiver_mode,
479 is_unchecked: sig.is_unchecked,
480 directives_start,
481 directives_len,
482 },
483 span: sig.span,
484 })
485 })
486 .collect();
487 let (methods_start, methods_len) = self.rir.add_inst_refs(&method_refs);
488
489 let directives = self.convert_directives(&iface.directives);
490 let (directives_start, directives_len) = self.rir.add_directives(&directives);
491
492 self.rir.add_inst(Inst {
493 data: InstData::InterfaceDecl {
494 is_pub: iface.visibility == Visibility::Public,
495 name: iface.name.name,
496 methods_start,
497 methods_len,
498 directives_start,
499 directives_len,
500 },
501 span: iface.span,
502 })
503 }
504
505 fn gen_derive(&mut self, derive_decl: &DeriveDecl) -> InstRef {
506 let method_refs: Vec<InstRef> = derive_decl
510 .methods
511 .iter()
512 .map(|m| self.gen_method(m))
513 .collect();
514 let (methods_start, methods_len) = self.rir.add_inst_refs(&method_refs);
515
516 self.rir.add_inst(Inst {
517 data: InstData::DeriveDecl {
518 name: derive_decl.name.name,
519 methods_start,
520 methods_len,
521 },
522 span: derive_decl.span,
523 })
524 }
525
526 fn gen_const(&mut self, const_decl: &ConstDecl) -> InstRef {
527 let directives = self.convert_directives(&const_decl.directives);
528 let (directives_start, directives_len) = self.rir.add_directives(&directives);
529 let name = const_decl.name.name; let ty = const_decl.ty.as_ref().map(|t| self.intern_type(t));
531 let init = self.gen_expr(&const_decl.init);
532
533 self.rir.add_inst(Inst {
534 data: InstData::ConstDecl {
535 directives_start,
536 directives_len,
537 is_pub: const_decl.visibility == Visibility::Public,
538 name,
539 ty,
540 init,
541 },
542 span: const_decl.span,
543 })
544 }
545
546 fn gen_method(&mut self, method: &Method) -> InstRef {
547 let directives = self.convert_directives(&method.directives);
549 let (directives_start, directives_len) = self.rir.add_directives(&directives);
550
551 let name = method.name.name; let return_type = match &method.return_type {
554 Some(ty) => self.intern_type(ty),
555 None => self.interner.get_or_intern("()"), };
557
558 let params: Vec<_> = method
560 .params
561 .iter()
562 .map(|p| RirParam {
563 name: p.name.name, ty: self.intern_type(&p.ty),
565 mode: self.convert_param_mode(p.mode),
566 is_comptime: p.is_comptime,
567 })
568 .collect();
569 let (params_start, params_len) = self.rir.add_params(¶ms);
570
571 let body_start = InstRef::from_raw(self.rir.current_inst_index());
573
574 let body = self.gen_expr(&method.body);
576
577 let has_self = method.receiver.is_some();
579 let receiver_mode = method
580 .receiver
581 .as_ref()
582 .map(|r| encode_self_receiver_kind(r.kind))
583 .unwrap_or(0u8);
584
585 let is_pub = method.visibility == gruel_parser::ast::Visibility::Public;
592 let decl = self.rir.add_inst(Inst {
593 data: InstData::FnDecl {
594 directives_start,
595 directives_len,
596 is_pub,
597 is_unchecked: method.is_unchecked,
598 name,
599 params_start,
600 params_len,
601 return_type,
602 body,
603 has_self,
604 receiver_mode,
605 },
606 span: method.span,
607 });
608
609 self.rir
612 .add_function_span(FunctionSpan::new(name, body_start, decl));
613
614 decl
615 }
616
617 fn convert_directives(&mut self, directives: &[Directive]) -> Vec<RirDirective> {
619 directives
620 .iter()
621 .map(|d| RirDirective {
622 name: d.name.name, args: d
624 .args
625 .iter()
626 .map(|arg| match arg {
627 DirectiveArg::Ident(ident) => ident.name, DirectiveArg::String(s) => s.value,
632 })
633 .collect(),
634 span: d.span,
635 })
636 .collect()
637 }
638
639 fn convert_param_mode(&self, mode: ParamMode) -> RirParamMode {
641 match mode {
642 ParamMode::Normal => RirParamMode::Normal,
643 ParamMode::Comptime => RirParamMode::Comptime,
644 }
645 }
646
647 fn convert_arg_mode(&self, mode: ArgMode) -> RirArgMode {
649 match mode {
650 ArgMode::Normal => RirArgMode::Normal,
651 }
652 }
653
654 fn convert_call_arg(&mut self, arg: &CallArg) -> RirCallArg {
656 RirCallArg {
657 value: self.gen_expr(&arg.expr),
658 mode: self.convert_arg_mode(arg.mode),
659 }
660 }
661
662 fn gen_function(&mut self, func: &Function) -> InstRef {
663 let directives = self.convert_directives(&func.directives);
665 let (directives_start, directives_len) = self.rir.add_directives(&directives);
666
667 let name = func.name.name; let return_type = match &func.return_type {
670 Some(ty) => self.intern_type(ty),
671 None => self.interner.get_or_intern("()"), };
673
674 let params: Vec<_> = func
676 .params
677 .iter()
678 .map(|p| RirParam {
679 name: p.name.name, ty: self.intern_type(&p.ty),
681 mode: self.convert_param_mode(p.mode),
682 is_comptime: p.is_comptime,
683 })
684 .collect();
685 let (params_start, params_len) = self.rir.add_params(¶ms);
686
687 let body_start = InstRef::from_raw(self.rir.current_inst_index());
689
690 let body = self.gen_expr(&func.body);
692
693 let decl = self.rir.add_inst(Inst {
696 data: InstData::FnDecl {
697 directives_start,
698 directives_len,
699 is_pub: func.visibility == Visibility::Public,
700 is_unchecked: func.is_unchecked,
701 name,
702 params_start,
703 params_len,
704 return_type,
705 body,
706 has_self: false,
707 receiver_mode: 0,
708 },
709 span: func.span,
710 });
711
712 self.rir
714 .add_function_span(FunctionSpan::new(name, body_start, decl));
715
716 decl
717 }
718
719 fn gen_expr(&mut self, expr: &Expr) -> InstRef {
720 match expr {
721 Expr::Int(lit) => self.rir.add_inst(Inst {
722 data: InstData::IntConst(lit.value),
723 span: lit.span,
724 }),
725 Expr::Float(lit) => self.rir.add_inst(Inst {
726 data: InstData::FloatConst(lit.bits),
727 span: lit.span,
728 }),
729 Expr::Bool(lit) => self.rir.add_inst(Inst {
730 data: InstData::BoolConst(lit.value),
731 span: lit.span,
732 }),
733 Expr::Char(lit) => self.rir.add_inst(Inst {
734 data: InstData::CharConst(lit.value),
735 span: lit.span,
736 }),
737 Expr::String(lit) => {
738 self.rir.add_inst(Inst {
739 data: InstData::StringConst(lit.value), span: lit.span,
741 })
742 }
743 Expr::Unit(lit) => self.rir.add_inst(Inst {
744 data: InstData::UnitConst,
745 span: lit.span,
746 }),
747 Expr::Ident(ident) => {
748 self.rir.add_inst(Inst {
749 data: InstData::VarRef { name: ident.name }, span: ident.span,
751 })
752 }
753 Expr::Binary(bin) => {
754 let lhs = self.gen_expr(&bin.left);
755 let rhs = self.gen_expr(&bin.right);
756 let op = ast_binop_to_ir(bin.op);
757 self.rir.add_inst(Inst {
758 data: InstData::Bin { op, lhs, rhs },
759 span: bin.span,
760 })
761 }
762 Expr::Unary(un) => {
763 if matches!(un.op, AstUnaryOp::Ref | AstUnaryOp::MutRef)
769 && let Expr::Index(index_expr) = &*un.operand
770 && let Expr::Range(range_expr) = &*index_expr.index
771 {
772 let base = self.gen_expr(&index_expr.base);
773 let lo = range_expr.lo.as_ref().map(|e| self.gen_expr(e));
774 let hi = range_expr.hi.as_ref().map(|e| self.gen_expr(e));
775 let is_mut = matches!(un.op, AstUnaryOp::MutRef);
776 return self.rir.add_inst(Inst {
777 data: InstData::MakeSlice {
778 base,
779 lo,
780 hi,
781 is_mut,
782 },
783 span: un.span,
784 });
785 }
786 let operand = self.gen_expr(&un.operand);
787 let data = match un.op {
788 AstUnaryOp::Neg => InstData::Unary {
789 op: UnaryOp::Neg,
790 operand,
791 },
792 AstUnaryOp::Not => InstData::Unary {
793 op: UnaryOp::Not,
794 operand,
795 },
796 AstUnaryOp::BitNot => InstData::Unary {
797 op: UnaryOp::BitNot,
798 operand,
799 },
800 AstUnaryOp::Ref => InstData::MakeRef {
801 operand,
802 is_mut: false,
803 },
804 AstUnaryOp::MutRef => InstData::MakeRef {
805 operand,
806 is_mut: true,
807 },
808 };
809 self.rir.add_inst(Inst {
810 data,
811 span: un.span,
812 })
813 }
814 Expr::Paren(paren) => {
815 self.gen_expr(&paren.inner)
817 }
818 Expr::Block(block) => self.gen_block(block),
819 Expr::If(if_expr) => {
820 let cond = self.gen_expr(&if_expr.cond);
821 let then_block = self.gen_block(&if_expr.then_block);
822 let else_block = if_expr.else_block.as_ref().map(|b| self.gen_block(b));
823
824 self.rir.add_inst(Inst {
825 data: InstData::Branch {
826 cond,
827 then_block,
828 else_block,
829 is_comptime: if_expr.is_comptime,
830 },
831 span: if_expr.span,
832 })
833 }
834 Expr::While(while_expr) => {
835 let cond = self.gen_expr(&while_expr.cond);
836 let body = self.gen_block(&while_expr.body);
837 self.rir.add_inst(Inst {
838 data: InstData::Loop { cond, body },
839 span: while_expr.span,
840 })
841 }
842 Expr::For(for_expr) => {
843 let iterable = self.gen_expr(&for_expr.iterable);
844 let body = self.gen_block(&for_expr.body);
845 self.rir.add_inst(Inst {
846 data: InstData::For {
847 binding: for_expr.binding.name,
848 is_mut: for_expr.is_mut,
849 iterable,
850 body,
851 },
852 span: for_expr.span,
853 })
854 }
855 Expr::Loop(loop_expr) => {
856 let body = self.gen_block(&loop_expr.body);
857 self.rir.add_inst(Inst {
858 data: InstData::InfiniteLoop { body },
859 span: loop_expr.span,
860 })
861 }
862 Expr::Match(match_expr) => {
863 if let Some(elaborated) = self.try_elaborate_irrefutable_match(match_expr) {
867 return elaborated;
868 }
869
870 let scrutinee = self.gen_expr(&match_expr.scrutinee);
871 let mut arms: Vec<(RirPattern, InstRef)> =
872 Vec::with_capacity(match_expr.arms.len());
873 for arm in &match_expr.arms {
874 let mut nested: Vec<(Spur, Pattern)> = Vec::new();
875 let pattern = self.gen_match_arm_pattern(&arm.pattern, &mut nested);
876 let body = self.gen_expr(&arm.body);
877 debug_assert!(
878 nested.is_empty(),
879 "ADR-0051: nested-pattern capture is superseded by RirPatternBinding.sub_pattern"
880 );
881 arms.push((pattern, body));
882 }
883 let (arms_start, arms_len) = self.rir.add_match_arms(&arms);
884
885 self.rir.add_inst(Inst {
886 data: InstData::Match {
887 scrutinee,
888 arms_start,
889 arms_len,
890 },
891 span: match_expr.span,
892 })
893 }
894 Expr::Call(call) => {
895 let args: Vec<_> = call.args.iter().map(|a| self.convert_call_arg(a)).collect();
896 let (args_start, args_len) = self.rir.add_call_args(&args);
897
898 self.rir.add_inst(Inst {
899 data: InstData::Call {
900 name: call.name.name, args_start,
902 args_len,
903 },
904 span: call.span,
905 })
906 }
907 Expr::Break(break_expr) => self.rir.add_inst(Inst {
908 data: InstData::Break,
909 span: break_expr.span,
910 }),
911 Expr::Continue(continue_expr) => self.rir.add_inst(Inst {
912 data: InstData::Continue,
913 span: continue_expr.span,
914 }),
915 Expr::Return(return_expr) => {
916 let value = return_expr.value.as_ref().map(|v| self.gen_expr(v));
917 self.rir.add_inst(Inst {
918 data: InstData::Ret(value),
919 span: return_expr.span,
920 })
921 }
922 Expr::StructLit(struct_lit) => {
923 let module = struct_lit
925 .base
926 .as_ref()
927 .map(|base_expr| self.gen_expr(base_expr));
928
929 let fields: Vec<_> = struct_lit
930 .fields
931 .iter()
932 .map(|f| {
933 let field_value = self.gen_expr(&f.value);
934 (f.name.name, field_value) })
936 .collect();
937 let (fields_start, fields_len) = self.rir.add_field_inits(&fields);
938
939 self.rir.add_inst(Inst {
940 data: InstData::StructInit {
941 module,
942 type_name: struct_lit.name.name, fields_start,
944 fields_len,
945 },
946 span: struct_lit.span,
947 })
948 }
949 Expr::EnumStructLit(lit) => {
950 let module = lit.base.as_ref().map(|base_expr| self.gen_expr(base_expr));
951
952 let fields: Vec<_> = lit
953 .fields
954 .iter()
955 .map(|f| {
956 let field_value = self.gen_expr(&f.value);
957 (f.name.name, field_value)
958 })
959 .collect();
960 let (fields_start, fields_len) = self.rir.add_field_inits(&fields);
961
962 self.rir.add_inst(Inst {
963 data: InstData::EnumStructVariant {
964 module,
965 type_name: lit.type_name.name,
966 variant: lit.variant.name,
967 fields_start,
968 fields_len,
969 },
970 span: lit.span,
971 })
972 }
973 Expr::Field(field_expr) => {
974 let base = self.gen_expr(&field_expr.base);
975
976 self.rir.add_inst(Inst {
977 data: InstData::FieldGet {
978 base,
979 field: field_expr.field.name, },
981 span: field_expr.span,
982 })
983 }
984 Expr::IntrinsicCall(intrinsic) => {
985 let name = intrinsic.name.name; let intrinsic_name_str = self.interner.resolve(&name);
987
988 let is_type = is_type_intrinsic(intrinsic_name_str);
989 let kind = lookup_by_name(intrinsic_name_str).map(|d| d.kind);
990
991 if is_type && intrinsic.args.len() == 1 {
992 if let IntrinsicArg::Type(ty) = &intrinsic.args[0] {
994 let type_arg = self.intern_type(ty);
995 return self.rir.add_inst(Inst {
996 data: InstData::TypeIntrinsic { name, type_arg },
997 span: intrinsic.span,
998 });
999 }
1000
1001 if let IntrinsicArg::Expr(Expr::Ident(ident)) = &intrinsic.args[0] {
1004 return self.rir.add_inst(Inst {
1005 data: InstData::TypeIntrinsic {
1006 name,
1007 type_arg: ident.name, },
1009 span: intrinsic.span,
1010 });
1011 }
1012 }
1013
1014 if kind == Some(IntrinsicKind::TypeInterface) && intrinsic.args.len() == 2 {
1025 let interface_arg = match &intrinsic.args[1] {
1026 IntrinsicArg::Type(ty) => Some(self.intern_type(ty)),
1027 IntrinsicArg::Expr(Expr::Ident(ident)) => Some(ident.name),
1028 _ => None,
1029 };
1030 if let Some(interface_arg) = interface_arg {
1031 let (type_arg, type_inst) = match &intrinsic.args[0] {
1032 IntrinsicArg::Type(ty) => (self.intern_type(ty), None),
1033 IntrinsicArg::Expr(Expr::Ident(ident)) => (ident.name, None),
1034 IntrinsicArg::Expr(expr) => {
1035 let inst = self.gen_expr(expr);
1036 (self.interner.get_or_intern_static("__expr__"), Some(inst))
1040 }
1041 };
1042 return self.rir.add_inst(Inst {
1043 data: InstData::TypeInterfaceIntrinsic {
1044 name,
1045 type_arg,
1046 type_inst,
1047 interface_arg,
1048 },
1049 span: intrinsic.span,
1050 });
1051 }
1052 }
1053
1054 let preserve_type_args =
1076 matches!(intrinsic_name_str, "variant_uninit" | "variant_field");
1077 let promote_leading_ident_as_type = intrinsic_name_str == "variant_uninit";
1081 let args: Vec<_> = intrinsic
1082 .args
1083 .iter()
1084 .enumerate()
1085 .filter_map(|(idx, a)| match a {
1086 IntrinsicArg::Type(ty) if preserve_type_args => {
1087 let type_name = self.intern_type(ty);
1088 Some(self.rir.add_inst(Inst {
1089 data: InstData::TypeConst { type_name },
1090 span: intrinsic.span,
1091 }))
1092 }
1093 IntrinsicArg::Type(_) => None,
1094 IntrinsicArg::Expr(Expr::Ident(ident))
1099 if promote_leading_ident_as_type && idx == 0 =>
1100 {
1101 Some(self.rir.add_inst(Inst {
1102 data: InstData::TypeConst {
1103 type_name: ident.name,
1104 },
1105 span: intrinsic.span,
1106 }))
1107 }
1108 IntrinsicArg::Expr(expr) => Some(self.gen_expr(expr)),
1109 })
1110 .collect();
1111 let (args_start, args_len) = self.rir.add_inst_refs(&args);
1112
1113 self.rir.add_inst(Inst {
1114 data: InstData::Intrinsic {
1115 name,
1116 args_start,
1117 args_len,
1118 },
1119 span: intrinsic.span,
1120 })
1121 }
1122 Expr::ArrayLit(array_lit) => {
1123 let elements: Vec<_> = array_lit
1124 .elements
1125 .iter()
1126 .map(|e| self.gen_expr(e))
1127 .collect();
1128 let (elems_start, elems_len) = self.rir.add_inst_refs(&elements);
1129
1130 self.rir.add_inst(Inst {
1131 data: InstData::ArrayInit {
1132 elems_start,
1133 elems_len,
1134 },
1135 span: array_lit.span,
1136 })
1137 }
1138 Expr::Index(index_expr) => {
1139 if matches!(&*index_expr.index, Expr::Range(_)) {
1146 return self.rir.add_inst(Inst {
1147 data: InstData::BareRangeSubscript,
1148 span: index_expr.span,
1149 });
1150 }
1151 let base = self.gen_expr(&index_expr.base);
1152 let index = self.gen_expr(&index_expr.index);
1153
1154 self.rir.add_inst(Inst {
1155 data: InstData::IndexGet { base, index },
1156 span: index_expr.span,
1157 })
1158 }
1159 Expr::Path(path_expr) => {
1160 let module = path_expr
1162 .base
1163 .as_ref()
1164 .map(|base_expr| self.gen_expr(base_expr));
1165
1166 self.rir.add_inst(Inst {
1167 data: InstData::EnumVariant {
1168 module,
1169 type_name: path_expr.type_name.name, variant: path_expr.variant.name, },
1172 span: path_expr.span,
1173 })
1174 }
1175 Expr::MethodCall(method_call) => {
1176 let receiver = self.gen_expr(&method_call.receiver);
1177 let args: Vec<_> = method_call
1178 .args
1179 .iter()
1180 .map(|a| self.convert_call_arg(a))
1181 .collect();
1182 let (args_start, args_len) = self.rir.add_call_args(&args);
1183
1184 self.rir.add_inst(Inst {
1185 data: InstData::MethodCall {
1186 receiver,
1187 method: method_call.method.name, args_start,
1189 args_len,
1190 },
1191 span: method_call.span,
1192 })
1193 }
1194 Expr::AssocFnCall(assoc_fn_call) => {
1195 let args: Vec<_> = assoc_fn_call
1196 .args
1197 .iter()
1198 .map(|a| self.convert_call_arg(a))
1199 .collect();
1200 let (args_start, args_len) = self.rir.add_call_args(&args);
1201
1202 let type_name = if assoc_fn_call.type_args.is_empty() {
1206 assoc_fn_call.type_name.name
1207 } else {
1208 let mut s = String::new();
1209 s.push_str(self.interner.resolve(&assoc_fn_call.type_name.name));
1210 s.push('(');
1211 for (i, arg) in assoc_fn_call.type_args.iter().enumerate() {
1212 if i > 0 {
1213 s.push_str(", ");
1214 }
1215 s.push_str(&self.expr_as_type_name(arg));
1216 }
1217 s.push(')');
1218 self.interner.get_or_intern(&s)
1219 };
1220
1221 self.rir.add_inst(Inst {
1222 data: InstData::AssocFnCall {
1223 type_name,
1224 function: assoc_fn_call.function.name, args_start,
1226 args_len,
1227 },
1228 span: assoc_fn_call.span,
1229 })
1230 }
1231 Expr::SelfExpr(self_expr) => {
1232 let name = self.interner.get_or_intern("self");
1234 self.rir.add_inst(Inst {
1235 data: InstData::VarRef { name },
1236 span: self_expr.span,
1237 })
1238 }
1239 Expr::Comptime(comptime_block) => {
1240 let inner_expr = self.gen_expr(&comptime_block.expr);
1243 self.rir.add_inst(Inst {
1244 data: InstData::Comptime { expr: inner_expr },
1245 span: comptime_block.span,
1246 })
1247 }
1248 Expr::ComptimeUnrollFor(unroll) => {
1249 let iterable = self.gen_expr(&unroll.iterable);
1250 let body = self.gen_block(&unroll.body);
1251 self.rir.add_inst(Inst {
1252 data: InstData::ComptimeUnrollFor {
1253 binding: unroll.binding.name,
1254 iterable,
1255 body,
1256 },
1257 span: unroll.span,
1258 })
1259 }
1260 Expr::Checked(checked_block) => {
1261 let inner_expr = self.gen_expr(&checked_block.expr);
1264 self.rir.add_inst(Inst {
1265 data: InstData::Checked { expr: inner_expr },
1266 span: checked_block.span,
1267 })
1268 }
1269 Expr::TypeLit(type_lit) => {
1270 match &type_lit.type_expr {
1272 TypeExpr::AnonymousStruct {
1273 directives,
1274 fields,
1275 methods,
1276 ..
1277 } => {
1278 let rir_directives = self.convert_directives(directives);
1280 let (directives_start, directives_len) =
1281 self.rir.add_directives(&rir_directives);
1282 let field_decls: Vec<(Spur, Spur, bool)> = fields
1287 .iter()
1288 .map(|f| {
1289 let name = f.name.name;
1290 let ty = self.intern_type(&f.ty);
1291 (name, ty, true)
1292 })
1293 .collect();
1294 let (fields_start, fields_len) =
1295 self.rir.add_field_decls_with_vis(&field_decls);
1296
1297 let method_refs: Vec<InstRef> =
1300 methods.iter().map(|m| self.gen_method(m)).collect();
1301 let (methods_start, methods_len) = self.rir.add_inst_refs(&method_refs);
1302
1303 self.rir.add_inst(Inst {
1304 data: InstData::AnonStructType {
1305 directives_start,
1306 directives_len,
1307 fields_start,
1308 fields_len,
1309 methods_start,
1310 methods_len,
1311 },
1312 span: type_lit.span,
1313 })
1314 }
1315 TypeExpr::AnonymousInterface { methods, .. } => {
1316 let method_refs: Vec<InstRef> = methods
1322 .iter()
1323 .map(|sig| {
1324 let name = sig.name.name;
1325 let return_type = match &sig.return_type {
1326 Some(ty) => self.intern_type(ty),
1327 None => self.interner.get_or_intern("()"),
1328 };
1329 let params: Vec<_> = sig
1330 .params
1331 .iter()
1332 .map(|p| RirParam {
1333 name: p.name.name,
1334 ty: self.intern_type(&p.ty),
1335 mode: self.convert_param_mode(p.mode),
1336 is_comptime: p.is_comptime,
1337 })
1338 .collect();
1339 let (params_start, params_len) = self.rir.add_params(¶ms);
1340 let directives = self.convert_directives(&sig.directives);
1341 let (directives_start, directives_len) =
1342 self.rir.add_directives(&directives);
1343 let receiver_mode = encode_self_receiver_kind(sig.receiver.kind);
1344 self.rir.add_inst(Inst {
1345 data: InstData::InterfaceMethodSig {
1346 name,
1347 params_start,
1348 params_len,
1349 return_type,
1350 receiver_mode,
1351 is_unchecked: sig.is_unchecked,
1352 directives_start,
1353 directives_len,
1354 },
1355 span: sig.span,
1356 })
1357 })
1358 .collect();
1359 let (methods_start, methods_len) = self.rir.add_inst_refs(&method_refs);
1360 self.rir.add_inst(Inst {
1361 data: InstData::AnonInterfaceType {
1362 methods_start,
1363 methods_len,
1364 },
1365 span: type_lit.span,
1366 })
1367 }
1368 TypeExpr::AnonymousEnum {
1369 directives,
1370 variants,
1371 methods,
1372 ..
1373 } => {
1374 use gruel_parser::ast::EnumVariantKind;
1376 let rir_directives = self.convert_directives(directives);
1377 let (directives_start, directives_len) =
1378 self.rir.add_directives(&rir_directives);
1379 let variant_decls: Vec<(Spur, Vec<Spur>, Vec<Spur>)> = variants
1380 .iter()
1381 .map(|v| {
1382 let variant_name = v.name.name;
1383 match &v.kind {
1384 EnumVariantKind::Unit => (variant_name, vec![], vec![]),
1385 EnumVariantKind::Tuple(types) => {
1386 let field_types: Vec<Spur> =
1387 types.iter().map(|ty| self.intern_type(ty)).collect();
1388 (variant_name, field_types, vec![])
1389 }
1390 EnumVariantKind::Struct(fields) => {
1391 let field_types: Vec<Spur> = fields
1392 .iter()
1393 .map(|f| self.intern_type(&f.ty))
1394 .collect();
1395 let field_names: Vec<Spur> =
1396 fields.iter().map(|f| f.name.name).collect();
1397 (variant_name, field_types, field_names)
1398 }
1399 }
1400 })
1401 .collect();
1402 let (variants_start, variants_len) =
1403 self.rir.add_enum_variant_decls(&variant_decls);
1404
1405 let method_refs: Vec<InstRef> =
1407 methods.iter().map(|m| self.gen_method(m)).collect();
1408 let (methods_start, methods_len) = self.rir.add_inst_refs(&method_refs);
1409
1410 self.rir.add_inst(Inst {
1411 data: InstData::AnonEnumType {
1412 directives_start,
1413 directives_len,
1414 variants_start,
1415 variants_len,
1416 methods_start,
1417 methods_len,
1418 },
1419 span: type_lit.span,
1420 })
1421 }
1422 _ => {
1423 let type_name = match &type_lit.type_expr {
1425 TypeExpr::Named(ident) => ident.name,
1426 TypeExpr::Unit(_) => self.interner.get_or_intern_static("()"),
1427 TypeExpr::Never(_) => self.interner.get_or_intern_static("!"),
1428 TypeExpr::Array { .. } => {
1429 self.interner.get_or_intern_static("array")
1432 }
1433 TypeExpr::AnonymousStruct { .. }
1434 | TypeExpr::AnonymousEnum { .. }
1435 | TypeExpr::AnonymousInterface { .. } => {
1436 unreachable!("handled above")
1437 }
1438 TypeExpr::TypeCall { .. } => {
1439 self.intern_type(&type_lit.type_expr)
1444 }
1445 TypeExpr::Tuple { .. } => {
1446 self.intern_type(&type_lit.type_expr)
1449 }
1450 };
1451 self.rir.add_inst(Inst {
1452 data: InstData::TypeConst { type_name },
1453 span: type_lit.span,
1454 })
1455 }
1456 }
1457 }
1458 Expr::Error(span) => self.rir.add_inst(Inst {
1461 data: InstData::UnitConst,
1462 span: *span,
1463 }),
1464 Expr::Tuple(tuple) => {
1467 let elem_refs: Vec<InstRef> =
1468 tuple.elems.iter().map(|e| self.gen_expr(e)).collect();
1469 let elem_u32s: Vec<u32> = elem_refs.iter().map(|r| r.as_u32()).collect();
1470 let elems_start = self.rir.add_extra(&elem_u32s);
1471 let elems_len = elem_refs.len() as u32;
1472 self.rir.add_inst(Inst {
1473 data: InstData::TupleInit {
1474 elems_start,
1475 elems_len,
1476 },
1477 span: tuple.span,
1478 })
1479 }
1480 Expr::TupleIndex(ti) => {
1484 let base = self.gen_expr(&ti.base);
1485 let field = self.interner.get_or_intern(ti.index.to_string());
1486 self.rir.add_inst(Inst {
1487 data: InstData::FieldGet { base, field },
1488 span: ti.span,
1489 })
1490 }
1491 Expr::AnonFn(anon_fn) => {
1501 let call_name_sym = self.interner.get_or_intern_static("__call");
1502 let call_ident = Ident {
1503 name: call_name_sym,
1504 span: anon_fn.span,
1505 };
1506 let synth_method = Method {
1507 doc: None,
1508 directives: Directives::new(),
1509 visibility: gruel_parser::ast::Visibility::Public,
1510 is_unchecked: false,
1511 name: call_ident,
1512 receiver: Some(SelfParam {
1513 kind: gruel_parser::ast::SelfReceiverKind::ByValue,
1514 span: anon_fn.span,
1515 }),
1516 params: anon_fn.params.clone(),
1517 return_type: anon_fn.return_type.clone(),
1518 body: Expr::Block(BlockExpr {
1519 statements: anon_fn.body.statements.clone(),
1520 expr: anon_fn.body.expr.clone(),
1521 span: anon_fn.body.span,
1522 }),
1523 span: anon_fn.span,
1524 };
1525 let method_ref = self.gen_method(&synth_method);
1526 self.rir.add_inst(Inst {
1527 data: InstData::AnonFnValue { method: method_ref },
1528 span: anon_fn.span,
1529 })
1530 }
1531 Expr::Range(range_expr) => self.rir.add_inst(Inst {
1536 data: InstData::BareRangeSubscript,
1537 span: range_expr.span,
1538 }),
1539 }
1540 }
1541
1542 fn try_elaborate_irrefutable_match(
1552 &mut self,
1553 match_expr: &gruel_parser::MatchExpr,
1554 ) -> Option<InstRef> {
1555 if match_expr.arms.len() != 1 {
1556 return None;
1557 }
1558 let arm = &match_expr.arms[0];
1559 match &arm.pattern {
1560 Pattern::Ident { is_mut, name, span } => {
1561 let init = self.gen_expr(&match_expr.scrutinee);
1563 let alloc = self.rir.add_inst(Inst {
1564 data: InstData::Alloc {
1565 directives_start: 0,
1566 directives_len: 0,
1567 name: Some(name.name),
1568 is_mut: *is_mut,
1569 ty: None,
1570 init,
1571 },
1572 span: *span,
1573 });
1574 let body = self.gen_expr(&arm.body);
1575 let extra_start = self.rir.add_extra(&[alloc.as_u32(), body.as_u32()]);
1576 Some(self.rir.add_inst(Inst {
1577 data: InstData::Block {
1578 extra_start,
1579 len: 2,
1580 },
1581 span: match_expr.span,
1582 }))
1583 }
1584 Pattern::Struct { .. } | Pattern::Tuple { .. }
1585 if is_irrefutable_destructure(&arm.pattern) =>
1586 {
1587 let init = self.gen_expr(&match_expr.scrutinee);
1589 let mut stmts: Vec<u32> = Vec::new();
1590 let mut emitted = Vec::new();
1591 self.emit_let_destructure_into(
1592 &arm.pattern,
1593 init,
1594 arm.pattern.span(),
1595 &mut emitted,
1596 );
1597 for r in emitted {
1598 stmts.push(r.as_u32());
1599 }
1600 let body = self.gen_expr(&arm.body);
1601 stmts.push(body.as_u32());
1602 let extra_start = self.rir.add_extra(&stmts);
1603 let len = stmts.len() as u32;
1604 Some(self.rir.add_inst(Inst {
1605 data: InstData::Block { extra_start, len },
1606 span: match_expr.span,
1607 }))
1608 }
1609 _ => None,
1610 }
1611 }
1612
1613 fn gen_match_arm_pattern(
1623 &mut self,
1624 pattern: &Pattern,
1625 nested: &mut Vec<(Spur, Pattern)>,
1626 ) -> RirPattern {
1627 match pattern {
1628 Pattern::Wildcard(span) => RirPattern::Wildcard(*span),
1629 Pattern::Int(lit) => RirPattern::Int(lit.value as i64, lit.span),
1630 Pattern::NegInt(lit) => RirPattern::Int((lit.value as i64).wrapping_neg(), lit.span),
1632 Pattern::Bool(lit) => RirPattern::Bool(lit.value, lit.span),
1633 Pattern::Path(path) => {
1634 let module = path.base.as_ref().map(|base| self.gen_expr(base));
1636 RirPattern::Path {
1637 module,
1638 type_name: path.type_name.name, variant: path.variant.name, span: path.span,
1641 }
1642 }
1643 Pattern::DataVariant {
1644 base,
1645 type_name,
1646 variant,
1647 fields,
1648 span,
1649 } => {
1650 let module = base.as_ref().map(|b| self.gen_expr(b));
1651 let rir_bindings = fields
1652 .iter()
1653 .map(|elem| self.tuple_elem_to_rir_binding_or_capture(elem, nested))
1654 .collect();
1655 RirPattern::DataVariant {
1656 module,
1657 type_name: type_name.name,
1658 variant: variant.name,
1659 bindings: rir_bindings,
1660 span: *span,
1661 }
1662 }
1663 Pattern::StructVariant {
1664 base,
1665 type_name,
1666 variant,
1667 fields,
1668 span,
1669 } => {
1670 let module = base.as_ref().map(|b| self.gen_expr(b));
1671 let rest_marker = self.interner.get_or_intern_static("..");
1672 let field_bindings = fields
1673 .iter()
1674 .map(|fb| {
1675 let field_name = fb
1679 .field_name
1680 .as_ref()
1681 .map(|ident| ident.name)
1682 .unwrap_or(rest_marker);
1683 RirStructPatternBinding {
1684 field_name,
1685 binding: self.field_pattern_to_rir_binding_or_capture(fb, nested),
1686 }
1687 })
1688 .collect();
1689 RirPattern::StructVariant {
1690 module,
1691 type_name: type_name.name,
1692 variant: variant.name,
1693 field_bindings,
1694 span: *span,
1695 }
1696 }
1697 Pattern::Ident { name, is_mut, span } => {
1701 let _ = nested;
1702 RirPattern::Ident {
1703 name: name.name,
1704 is_mut: *is_mut,
1705 span: *span,
1706 }
1707 }
1708 Pattern::Tuple { elems, span } => {
1709 let mut rir_elems: Vec<RirPattern> = Vec::with_capacity(elems.len());
1715 let mut rest_position: Option<u32> = None;
1716 for (i, e) in elems.iter().enumerate() {
1717 match e {
1718 TupleElemPattern::Pattern(p) => {
1719 rir_elems.push(self.gen_match_arm_pattern(p, nested));
1720 }
1721 TupleElemPattern::Rest(_) => {
1722 rest_position = Some(i as u32);
1723 }
1724 }
1725 }
1726 RirPattern::Tuple {
1727 elems: rir_elems,
1728 rest_position,
1729 span: *span,
1730 }
1731 }
1732 Pattern::Struct {
1733 type_name,
1734 fields,
1735 span,
1736 } => {
1737 let has_rest = fields.iter().any(|f| f.field_name.is_none());
1742 let rir_fields: Vec<RirStructField> = fields
1743 .iter()
1744 .filter_map(|f| {
1745 let field_name = f.field_name.as_ref()?.name;
1746 let pat = match &f.sub {
1747 Some(p) => self.gen_match_arm_pattern(p, nested),
1748 None => {
1749 RirPattern::Ident {
1752 name: field_name,
1753 is_mut: f.is_mut,
1754 span: f.span,
1755 }
1756 }
1757 };
1758 Some(RirStructField {
1759 field_name,
1760 pattern: pat,
1761 })
1762 })
1763 .collect();
1764 RirPattern::Struct {
1765 module: None,
1766 type_name: type_name.name,
1767 fields: rir_fields,
1768 has_rest,
1769 span: *span,
1770 }
1771 }
1772 Pattern::ComptimeUnrollArm {
1773 binding,
1774 iterable,
1775 span,
1776 } => {
1777 let _ = nested;
1778 let iterable_ref = self.gen_expr(iterable);
1779 RirPattern::ComptimeUnrollArm {
1780 binding: binding.name,
1781 iterable: iterable_ref,
1782 span: *span,
1783 }
1784 }
1785 }
1786 }
1787
1788 fn tuple_elem_to_rir_binding_or_capture(
1793 &mut self,
1794 elem: &TupleElemPattern,
1795 nested: &mut Vec<(Spur, Pattern)>,
1796 ) -> RirPatternBinding {
1797 match elem {
1798 TupleElemPattern::Pattern(Pattern::Wildcard(_)) => RirPatternBinding {
1799 is_wildcard: true,
1800 is_mut: false,
1801 name: None,
1802 sub_pattern: None,
1803 },
1804 TupleElemPattern::Pattern(Pattern::Ident { is_mut, name, .. }) => RirPatternBinding {
1805 is_wildcard: false,
1806 is_mut: *is_mut,
1807 name: Some(name.name),
1808 sub_pattern: None,
1809 },
1810 TupleElemPattern::Pattern(sub) => {
1811 let sub_rir = self.gen_match_arm_pattern(sub, nested);
1815 RirPatternBinding {
1816 is_wildcard: false,
1817 is_mut: false,
1818 name: None,
1819 sub_pattern: Some(Box::new(sub_rir)),
1820 }
1821 }
1822 TupleElemPattern::Rest(_) => {
1823 RirPatternBinding {
1828 is_wildcard: true,
1829 is_mut: false,
1830 name: Some(self.interner.get_or_intern_static("..")),
1831 sub_pattern: None,
1832 }
1833 }
1834 }
1835 }
1836
1837 fn field_pattern_to_rir_binding_or_capture(
1840 &mut self,
1841 fb: &FieldPattern,
1842 nested: &mut Vec<(Spur, Pattern)>,
1843 ) -> RirPatternBinding {
1844 let Some(name) = fb.field_name.as_ref() else {
1848 return RirPatternBinding {
1849 is_wildcard: true,
1850 is_mut: false,
1851 name: Some(self.interner.get_or_intern_static("..")),
1852 sub_pattern: None,
1853 };
1854 };
1855 match &fb.sub {
1856 None => RirPatternBinding {
1857 is_wildcard: false,
1859 is_mut: fb.is_mut,
1860 name: Some(name.name),
1861 sub_pattern: None,
1862 },
1863 Some(Pattern::Wildcard(_)) => RirPatternBinding {
1864 is_wildcard: true,
1865 is_mut: false,
1866 name: None,
1867 sub_pattern: None,
1868 },
1869 Some(Pattern::Ident {
1870 is_mut,
1871 name: bind_name,
1872 ..
1873 }) => RirPatternBinding {
1874 is_wildcard: false,
1875 is_mut: fb.is_mut || *is_mut,
1876 name: Some(bind_name.name),
1877 sub_pattern: None,
1878 },
1879 Some(sub) => {
1880 let sub_rir = self.gen_match_arm_pattern(sub, nested);
1881 RirPatternBinding {
1882 is_wildcard: false,
1883 is_mut: false,
1884 name: None,
1885 sub_pattern: Some(Box::new(sub_rir)),
1886 }
1887 }
1888 }
1889 }
1890
1891 fn gen_block(&mut self, block: &gruel_parser::BlockExpr) -> InstRef {
1892 if block.statements.is_empty() {
1893 self.gen_expr(&block.expr)
1895 } else {
1896 let mut inst_refs = Vec::with_capacity(block.statements.len() + 1);
1899
1900 for stmt in &block.statements {
1907 self.gen_statement_into(stmt, &mut inst_refs);
1908 }
1909
1910 let final_expr = self.gen_expr(&block.expr);
1912 inst_refs.push(final_expr.as_u32());
1913
1914 let extra_start = self.rir.add_extra(&inst_refs);
1916 let len = inst_refs.len() as u32;
1917
1918 self.rir.add_inst(Inst {
1919 data: InstData::Block { extra_start, len },
1920 span: block.span,
1921 })
1922 }
1923 }
1924
1925 fn emit_let_destructure_into(
1939 &mut self,
1940 pattern: &Pattern,
1941 init: InstRef,
1942 span: gruel_util::Span,
1943 out: &mut Vec<InstRef>,
1944 ) {
1945 let (type_name, rir_fields, child_destructures) = match pattern {
1948 Pattern::Struct {
1949 type_name, fields, ..
1950 } => {
1951 let mut rir_fields = Vec::with_capacity(fields.len());
1952 let mut children: Vec<(Spur, &Pattern)> = Vec::new();
1953 for fp in fields {
1954 let Some(field_name) = fp.field_name.as_ref() else {
1959 rir_fields.push(RirDestructureField {
1960 field_name: self.interner.get_or_intern_static(".."),
1961 binding_name: None,
1962 is_wildcard: true,
1963 is_mut: false,
1964 });
1965 continue;
1966 };
1967 match &fp.sub {
1968 None => rir_fields.push(RirDestructureField {
1969 field_name: field_name.name,
1970 binding_name: Some(field_name.name),
1971 is_wildcard: false,
1972 is_mut: fp.is_mut,
1973 }),
1974 Some(Pattern::Wildcard(_)) => rir_fields.push(RirDestructureField {
1975 field_name: field_name.name,
1976 binding_name: None,
1977 is_wildcard: true,
1978 is_mut: false,
1979 }),
1980 Some(Pattern::Ident {
1981 is_mut,
1982 name: bind_name,
1983 ..
1984 }) => rir_fields.push(RirDestructureField {
1985 field_name: field_name.name,
1986 binding_name: Some(bind_name.name),
1987 is_wildcard: false,
1988 is_mut: fp.is_mut || *is_mut,
1989 }),
1990 Some(sub @ (Pattern::Struct { .. } | Pattern::Tuple { .. })) => {
1991 let fresh = self.fresh_nested_pat_name();
1992 rir_fields.push(RirDestructureField {
1993 field_name: field_name.name,
1994 binding_name: Some(fresh),
1995 is_wildcard: false,
1996 is_mut: false,
1997 });
1998 children.push((fresh, sub));
1999 }
2000 Some(other) => panic!(
2001 "unexpected sub-pattern in let struct destructure: {:?}",
2002 other
2003 ),
2004 }
2005 }
2006 (type_name.name, rir_fields, children)
2007 }
2008 Pattern::Tuple { elems, .. } => {
2009 let rest_pos = elems
2017 .iter()
2018 .position(|e| matches!(e, TupleElemPattern::Rest(_)));
2019 let mut rir_fields = Vec::with_capacity(elems.len());
2020 let mut children: Vec<(Spur, &Pattern)> = Vec::new();
2021 for (i, elem) in elems.iter().enumerate() {
2022 if let TupleElemPattern::Rest(_) = elem {
2023 rir_fields.push(RirDestructureField {
2024 field_name: self.interner.get_or_intern_static(".."),
2025 binding_name: None,
2026 is_wildcard: true,
2027 is_mut: false,
2028 });
2029 continue;
2030 }
2031 let field_name = match rest_pos {
2032 Some(rp) if i > rp => {
2033 let from_end = elems.len() - 1 - i;
2035 self.interner.get_or_intern(format!("..end_{}", from_end))
2036 }
2037 _ => self.interner.get_or_intern(i.to_string()),
2038 };
2039 match elem {
2040 TupleElemPattern::Pattern(Pattern::Wildcard(_)) => {
2041 rir_fields.push(RirDestructureField {
2042 field_name,
2043 binding_name: None,
2044 is_wildcard: true,
2045 is_mut: false,
2046 });
2047 }
2048 TupleElemPattern::Pattern(Pattern::Ident { is_mut, name, .. }) => {
2049 rir_fields.push(RirDestructureField {
2050 field_name,
2051 binding_name: Some(name.name),
2052 is_wildcard: false,
2053 is_mut: *is_mut,
2054 });
2055 }
2056 TupleElemPattern::Pattern(
2057 sub @ (Pattern::Struct { .. } | Pattern::Tuple { .. }),
2058 ) => {
2059 let fresh = self.fresh_nested_pat_name();
2060 rir_fields.push(RirDestructureField {
2061 field_name,
2062 binding_name: Some(fresh),
2063 is_wildcard: false,
2064 is_mut: false,
2065 });
2066 children.push((fresh, sub));
2067 }
2068 TupleElemPattern::Pattern(other) => panic!(
2069 "unexpected sub-pattern in let tuple destructure: {:?}",
2070 other
2071 ),
2072 TupleElemPattern::Rest(_) => unreachable!("handled above"),
2073 }
2074 }
2075 let tuple_type_name = self.interner.get_or_intern_static("__tuple__");
2076 (tuple_type_name, rir_fields, children)
2077 }
2078 other => panic!(
2079 "emit_let_destructure called on non-destructure pattern: {:?}",
2080 other
2081 ),
2082 };
2083
2084 let (fields_start, fields_len) = self.rir.add_destructure_fields(&rir_fields);
2085 let outer_inst = self.rir.add_inst(Inst {
2086 data: InstData::StructDestructure {
2087 type_name,
2088 fields_start,
2089 fields_len,
2090 init,
2091 },
2092 span,
2093 });
2094 out.push(outer_inst);
2095
2096 for (binding_name, sub) in child_destructures {
2098 let var_ref = self.rir.add_inst(Inst {
2099 data: InstData::VarRef { name: binding_name },
2100 span: sub.span(),
2101 });
2102 self.emit_let_destructure_into(sub, var_ref, sub.span(), out);
2103 }
2104 }
2105
2106 fn gen_statement_into(&mut self, stmt: &Statement, out: &mut Vec<u32>) {
2110 if let Statement::Let(let_stmt) = stmt
2111 && matches!(
2112 &let_stmt.pattern,
2113 Pattern::Struct { .. } | Pattern::Tuple { .. }
2114 )
2115 {
2116 let init = self.gen_expr(&let_stmt.init);
2117 let mut emitted = Vec::new();
2118 self.emit_let_destructure_into(&let_stmt.pattern, init, let_stmt.span, &mut emitted);
2119 for r in emitted {
2120 out.push(r.as_u32());
2121 }
2122 return;
2123 }
2124 let single = self.gen_statement(stmt);
2125 out.push(single.as_u32());
2126 }
2127
2128 fn gen_statement(&mut self, stmt: &Statement) -> InstRef {
2129 match stmt {
2130 Statement::Let(let_stmt) => match &let_stmt.pattern {
2131 Pattern::Struct { .. } | Pattern::Tuple { .. } => {
2141 let init = self.gen_expr(&let_stmt.init);
2147 let mut emitted = Vec::new();
2148 self.emit_let_destructure_into(
2149 &let_stmt.pattern,
2150 init,
2151 let_stmt.span,
2152 &mut emitted,
2153 );
2154 *emitted
2156 .first()
2157 .expect("destructure must emit at least one instruction")
2158 }
2159 pattern => {
2160 let directives = self.convert_directives(&let_stmt.directives);
2161 let (directives_start, directives_len) = self.rir.add_directives(&directives);
2162 let is_mut = match pattern {
2163 Pattern::Ident { is_mut, .. } => *is_mut || let_stmt.is_mut,
2164 _ => let_stmt.is_mut,
2165 };
2166 let name = match pattern {
2167 Pattern::Ident { name, .. } => Some(name.name),
2168 Pattern::Wildcard(_) => None,
2169 _ => unreachable!(
2170 "Phase 1 let-statement parser only emits Ident/Wildcard/Struct/Tuple; got {:?}",
2171 pattern
2172 ),
2173 };
2174 let ty = let_stmt.ty.as_ref().map(|t| self.intern_type(t));
2175 let init = self.gen_expr(&let_stmt.init);
2176 self.rir.add_inst(Inst {
2177 data: InstData::Alloc {
2178 directives_start,
2179 directives_len,
2180 name,
2181 is_mut,
2182 ty,
2183 init,
2184 },
2185 span: let_stmt.span,
2186 })
2187 }
2188 },
2189 Statement::Assign(assign) => {
2190 let value = self.gen_expr(&assign.value);
2191 match &assign.target {
2192 AssignTarget::Var(ident) => {
2193 self.rir.add_inst(Inst {
2194 data: InstData::Assign {
2195 name: ident.name, value,
2197 },
2198 span: assign.span,
2199 })
2200 }
2201 AssignTarget::Field(field_expr) => {
2202 let base = self.gen_expr(&field_expr.base);
2203 self.rir.add_inst(Inst {
2204 data: InstData::FieldSet {
2205 base,
2206 field: field_expr.field.name, value,
2208 },
2209 span: assign.span,
2210 })
2211 }
2212 AssignTarget::Index(index_expr) => {
2213 let base = self.gen_expr(&index_expr.base);
2214 let index = self.gen_expr(&index_expr.index);
2215 self.rir.add_inst(Inst {
2216 data: InstData::IndexSet { base, index, value },
2217 span: assign.span,
2218 })
2219 }
2220 }
2221 }
2222 Statement::Expr(expr) => {
2223 self.gen_expr(expr)
2226 }
2227 }
2228 }
2229}
2230
2231fn is_irrefutable_destructure(pat: &Pattern) -> bool {
2238 match pat {
2239 Pattern::Wildcard(_) | Pattern::Ident { .. } => true,
2240 Pattern::Int(_) | Pattern::NegInt(_) | Pattern::Bool(_) => false,
2241 Pattern::Path(_) => false,
2242 Pattern::DataVariant { .. } | Pattern::StructVariant { .. } => false,
2243 Pattern::Struct { fields, .. } => fields.iter().all(|f| match &f.sub {
2244 None => true,
2245 Some(sub) => is_irrefutable_destructure(sub),
2246 }),
2247 Pattern::Tuple { elems, .. } => elems.iter().all(|e| match e {
2248 TupleElemPattern::Pattern(p) => is_irrefutable_destructure(p),
2249 TupleElemPattern::Rest(_) => true,
2250 }),
2251 Pattern::ComptimeUnrollArm { .. } => false,
2254 }
2255}
2256
2257#[cfg(test)]
2268mod tests {
2269 use super::*;
2270 use crate::print::RirPrinter;
2271 use gruel_lexer::Lexer;
2272 use gruel_parser::Parser;
2273
2274 fn gen_rir(source: &str) -> (Rir, ThreadedRodeo) {
2275 let lexer = Lexer::new(source);
2276 let (tokens, interner) = lexer.tokenize().unwrap();
2277 let parser = Parser::new(tokens, interner);
2278 let (ast, interner) = parser.parse().unwrap();
2279
2280 let astgen = AstGen::new(&ast, &interner);
2281 let rir = astgen.generate();
2282 (rir, interner)
2283 }
2284
2285 #[test]
2286 fn test_gen_simple_function() {
2287 let (rir, interner) = gen_rir("fn main() -> i32 { 42 }");
2288
2289 assert_eq!(rir.len(), 2);
2291
2292 let (_, fn_inst) = rir.iter().last().unwrap();
2294 match &fn_inst.data {
2295 InstData::FnDecl {
2296 name,
2297 params_start,
2298 params_len,
2299 return_type,
2300 body,
2301 has_self,
2302 ..
2303 } => {
2304 assert_eq!(interner.resolve(name), "main");
2305 let params = rir.get_params(*params_start, *params_len);
2306 assert!(params.is_empty());
2307 assert_eq!(interner.resolve(return_type), "i32");
2308 assert!(!has_self); let body_inst = rir.get(*body);
2311 assert!(matches!(body_inst.data, InstData::IntConst(42)));
2312 }
2313 _ => panic!("expected FnDecl"),
2314 }
2315 }
2316
2317 #[test]
2318 fn test_gen_addition() {
2319 let (rir, _) = gen_rir("fn main() -> i32 { 1 + 2 }");
2320
2321 assert_eq!(rir.len(), 4);
2323
2324 let add_inst = rir.get(InstRef::from_raw(2));
2326 match &add_inst.data {
2327 InstData::Bin {
2328 op: BinOp::Add,
2329 lhs,
2330 rhs,
2331 } => {
2332 assert!(matches!(rir.get(*lhs).data, InstData::IntConst(1)));
2333 assert!(matches!(rir.get(*rhs).data, InstData::IntConst(2)));
2334 }
2335 _ => panic!("expected Add"),
2336 }
2337 }
2338
2339 #[test]
2340 fn test_gen_precedence() {
2341 let (rir, _) = gen_rir("fn main() -> i32 { 1 + 2 * 3 }");
2342
2343 assert_eq!(rir.len(), 6);
2345
2346 let fn_inst = rir.iter().last().unwrap().1;
2348 match &fn_inst.data {
2349 InstData::FnDecl { body, .. } => {
2350 let body_inst = rir.get(*body);
2351 match &body_inst.data {
2352 InstData::Bin {
2353 op: BinOp::Add,
2354 lhs,
2355 rhs,
2356 } => {
2357 assert!(matches!(rir.get(*lhs).data, InstData::IntConst(1)));
2359 assert!(matches!(
2361 rir.get(*rhs).data,
2362 InstData::Bin { op: BinOp::Mul, .. }
2363 ));
2364 }
2365 _ => panic!("expected Add"),
2366 }
2367 }
2368 _ => panic!("expected FnDecl"),
2369 }
2370 }
2371
2372 #[test]
2373 fn test_gen_negation() {
2374 let (rir, _) = gen_rir("fn main() -> i32 { -42 }");
2375
2376 assert_eq!(rir.len(), 3);
2378
2379 let neg_inst = rir.get(InstRef::from_raw(1));
2381 match &neg_inst.data {
2382 InstData::Unary {
2383 op: UnaryOp::Neg,
2384 operand,
2385 } => {
2386 assert!(matches!(rir.get(*operand).data, InstData::IntConst(42)));
2387 }
2388 _ => panic!("expected Neg"),
2389 }
2390 }
2391
2392 #[test]
2393 fn test_gen_parens() {
2394 let (rir, _) = gen_rir("fn main() -> i32 { (1 + 2) * 3 }");
2395
2396 assert_eq!(rir.len(), 6);
2399
2400 let fn_inst = rir.iter().last().unwrap().1;
2402 match &fn_inst.data {
2403 InstData::FnDecl { body, .. } => {
2404 let body_inst = rir.get(*body);
2405 match &body_inst.data {
2406 InstData::Bin {
2407 op: BinOp::Mul,
2408 lhs,
2409 rhs,
2410 } => {
2411 assert!(matches!(
2413 rir.get(*lhs).data,
2414 InstData::Bin { op: BinOp::Add, .. }
2415 ));
2416 assert!(matches!(rir.get(*rhs).data, InstData::IntConst(3)));
2418 }
2419 _ => panic!("expected Mul"),
2420 }
2421 }
2422 _ => panic!("expected FnDecl"),
2423 }
2424 }
2425
2426 #[test]
2427 fn test_gen_all_binary_ops() {
2428 for (src, expected) in [
2429 ("fn main() -> i32 { 1 + 2 }", BinOp::Add),
2430 ("fn main() -> i32 { 1 - 2 }", BinOp::Sub),
2431 ("fn main() -> i32 { 1 * 2 }", BinOp::Mul),
2432 ("fn main() -> i32 { 1 / 2 }", BinOp::Div),
2433 ("fn main() -> i32 { 1 % 2 }", BinOp::Mod),
2434 ] {
2435 let (rir, _) = gen_rir(src);
2436 match rir.get(InstRef::from_raw(2)).data {
2437 InstData::Bin { op, .. } => assert_eq!(op, expected),
2438 _ => panic!("expected Bin for {}", src),
2439 }
2440 }
2441 }
2442
2443 #[test]
2444 fn test_gen_let_binding() {
2445 let (rir, interner) = gen_rir("fn main() -> i32 { let x = 42; x }");
2446
2447 let alloc_inst = rir
2449 .iter()
2450 .find(|(_, inst)| matches!(inst.data, InstData::Alloc { .. }));
2451 assert!(alloc_inst.is_some());
2452
2453 let (_, inst) = alloc_inst.unwrap();
2454 match &inst.data {
2455 InstData::Alloc {
2456 name,
2457 is_mut,
2458 ty,
2459 init,
2460 ..
2461 } => {
2462 assert_eq!(interner.resolve(&name.unwrap()), "x");
2463 assert!(!is_mut);
2464 assert!(ty.is_none());
2465 assert!(matches!(rir.get(*init).data, InstData::IntConst(42)));
2466 }
2467 _ => panic!("expected Alloc"),
2468 }
2469 }
2470
2471 #[test]
2472 fn test_gen_let_mut() {
2473 let (rir, interner) = gen_rir("fn main() -> i32 { let mut x = 10; x }");
2474
2475 let alloc_inst = rir
2476 .iter()
2477 .find(|(_, inst)| matches!(inst.data, InstData::Alloc { .. }));
2478 assert!(alloc_inst.is_some());
2479
2480 let (_, inst) = alloc_inst.unwrap();
2481 match &inst.data {
2482 InstData::Alloc { name, is_mut, .. } => {
2483 assert_eq!(interner.resolve(&name.unwrap()), "x");
2484 assert!(*is_mut);
2485 }
2486 _ => panic!("expected Alloc"),
2487 }
2488 }
2489
2490 #[test]
2491 fn test_gen_var_ref() {
2492 let (rir, interner) = gen_rir("fn main() -> i32 { let x = 42; x }");
2493
2494 let fn_inst = rir.iter().last().unwrap().1;
2496 match &fn_inst.data {
2497 InstData::FnDecl { body, .. } => {
2498 let body_inst = rir.get(*body);
2499 match &body_inst.data {
2500 InstData::Block { extra_start, len } => {
2501 assert_eq!(*len, 2);
2503 let inst_refs = rir.get_extra(*extra_start, *len);
2504 let var_ref_inst = rir.get(InstRef::from_raw(inst_refs[1]));
2506 match &var_ref_inst.data {
2507 InstData::VarRef { name } => {
2508 assert_eq!(interner.resolve(name), "x");
2509 }
2510 _ => panic!("expected VarRef"),
2511 }
2512 }
2513 _ => panic!("expected Block, got {:?}", body_inst.data),
2514 }
2515 }
2516 _ => panic!("expected FnDecl"),
2517 }
2518 }
2519
2520 #[test]
2521 fn test_gen_assignment() {
2522 let (rir, interner) = gen_rir("fn main() -> i32 { let mut x = 10; x = 20; x }");
2523
2524 let assign_inst = rir
2526 .iter()
2527 .find(|(_, inst)| matches!(inst.data, InstData::Assign { .. }));
2528 assert!(assign_inst.is_some());
2529
2530 let (_, inst) = assign_inst.unwrap();
2531 match &inst.data {
2532 InstData::Assign { name, value } => {
2533 assert_eq!(interner.resolve(name), "x");
2534 assert!(matches!(rir.get(*value).data, InstData::IntConst(20)));
2535 }
2536 _ => panic!("expected Assign"),
2537 }
2538 }
2539
2540 #[test]
2541 fn test_gen_multiple_statements() {
2542 let (rir, _interner) = gen_rir("fn main() -> i32 { let x = 1; let y = 2; x + y }");
2543
2544 let alloc_count = rir
2546 .iter()
2547 .filter(|(_, inst)| matches!(inst.data, InstData::Alloc { .. }))
2548 .count();
2549 assert_eq!(alloc_count, 2);
2550
2551 let fn_inst = rir.iter().last().unwrap().1;
2553 match &fn_inst.data {
2554 InstData::FnDecl { body, .. } => {
2555 let body_inst = rir.get(*body);
2556 match &body_inst.data {
2557 InstData::Block { extra_start, len } => {
2558 assert_eq!(*len, 3);
2560 let inst_refs = rir.get_extra(*extra_start, *len);
2561 let add_inst = rir.get(InstRef::from_raw(inst_refs[2]));
2563 assert!(matches!(
2564 add_inst.data,
2565 InstData::Bin { op: BinOp::Add, .. }
2566 ));
2567 }
2568 _ => panic!("expected Block"),
2569 }
2570 }
2571 _ => panic!("expected FnDecl"),
2572 }
2573 }
2574
2575 #[test]
2577 fn test_gen_struct_with_method() {
2578 let source = r#"
2579 struct Point {
2580 x: i32,
2581 y: i32,
2582 fn get_x(self) -> i32 {
2583 self.x
2584 }
2585 }
2586 fn main() -> i32 { 0 }
2587 "#;
2588 let (rir, interner) = gen_rir(source);
2589
2590 let struct_decl = rir
2592 .iter()
2593 .find(|(_, inst)| matches!(inst.data, InstData::StructDecl { .. }));
2594 assert!(struct_decl.is_some(), "Expected StructDecl instruction");
2595
2596 let (_, inst) = struct_decl.unwrap();
2597 match &inst.data {
2598 InstData::StructDecl {
2599 name,
2600 methods_start,
2601 methods_len,
2602 ..
2603 } => {
2604 assert_eq!(interner.resolve(name), "Point");
2605 let methods = rir.get_inst_refs(*methods_start, *methods_len);
2606 assert_eq!(methods.len(), 1);
2607
2608 let method_inst = rir.get(methods[0]);
2610 match &method_inst.data {
2611 InstData::FnDecl { name, has_self, .. } => {
2612 assert_eq!(interner.resolve(name), "get_x");
2613 assert!(*has_self);
2614 }
2615 _ => panic!("expected FnDecl"),
2616 }
2617 }
2618 _ => panic!("expected StructDecl"),
2619 }
2620 }
2621
2622 #[test]
2623 fn test_gen_struct_with_multiple_methods() {
2624 let source = r#"
2625 struct Point {
2626 x: i32,
2627 y: i32,
2628 fn get_x(self) -> i32 { self.x }
2629 fn get_y(self) -> i32 { self.y }
2630 fn origin() -> Point { Point { x: 0, y: 0 } }
2631 }
2632 fn main() -> i32 { 0 }
2633 "#;
2634 let (rir, interner) = gen_rir(source);
2635
2636 let struct_decl = rir
2637 .iter()
2638 .find(|(_, inst)| matches!(inst.data, InstData::StructDecl { .. }));
2639 assert!(struct_decl.is_some());
2640
2641 let (_, inst) = struct_decl.unwrap();
2642 match &inst.data {
2643 InstData::StructDecl {
2644 methods_start,
2645 methods_len,
2646 ..
2647 } => {
2648 let methods = rir.get_inst_refs(*methods_start, *methods_len);
2649 assert_eq!(methods.len(), 3);
2650
2651 for method_ref in methods {
2653 let method_inst = rir.get(method_ref);
2654 match &method_inst.data {
2655 InstData::FnDecl { name, has_self, .. } => {
2656 let method_name = interner.resolve(name);
2657 if method_name == "origin" {
2658 assert!(!has_self, "origin should not have self");
2659 } else {
2660 assert!(*has_self, "{} should have self", method_name);
2661 }
2662 }
2663 _ => panic!("expected FnDecl"),
2664 }
2665 }
2666 }
2667 _ => panic!("expected StructDecl"),
2668 }
2669 }
2670
2671 #[test]
2672 fn test_gen_method_call() {
2673 let source = r#"
2674 struct Point {
2675 x: i32,
2676 fn get_x(self) -> i32 { self.x }
2677 }
2678 fn main() -> i32 {
2679 let p = Point { x: 42 };
2680 p.get_x()
2681 }
2682 "#;
2683 let (rir, interner) = gen_rir(source);
2684
2685 let method_call = rir
2687 .iter()
2688 .find(|(_, inst)| matches!(inst.data, InstData::MethodCall { .. }));
2689 assert!(method_call.is_some(), "Expected MethodCall instruction");
2690
2691 let (_, inst) = method_call.unwrap();
2692 match &inst.data {
2693 InstData::MethodCall {
2694 receiver: _,
2695 method,
2696 args_start,
2697 args_len,
2698 } => {
2699 assert_eq!(interner.resolve(method), "get_x");
2700 let args = rir.get_call_args(*args_start, *args_len);
2701 assert!(args.is_empty()); }
2703 _ => panic!("expected MethodCall"),
2704 }
2705 }
2706
2707 #[test]
2708 fn test_gen_assoc_fn_call() {
2709 let source = r#"
2710 struct Point {
2711 x: i32,
2712 y: i32,
2713 fn origin() -> Point { Point { x: 0, y: 0 } }
2714 }
2715 fn main() -> i32 {
2716 let p = Point::origin();
2717 0
2718 }
2719 "#;
2720 let (rir, interner) = gen_rir(source);
2721
2722 let assoc_fn_call = rir
2724 .iter()
2725 .find(|(_, inst)| matches!(inst.data, InstData::AssocFnCall { .. }));
2726 assert!(assoc_fn_call.is_some(), "Expected AssocFnCall instruction");
2727
2728 let (_, inst) = assoc_fn_call.unwrap();
2729 match &inst.data {
2730 InstData::AssocFnCall {
2731 type_name,
2732 function,
2733 args_start,
2734 args_len,
2735 } => {
2736 assert_eq!(interner.resolve(type_name), "Point");
2737 assert_eq!(interner.resolve(function), "origin");
2738 let args = rir.get_call_args(*args_start, *args_len);
2739 assert!(args.is_empty());
2740 }
2741 _ => panic!("expected AssocFnCall"),
2742 }
2743 }
2744
2745 #[test]
2747 fn test_gen_match_wildcard_pattern() {
2748 let source = r#"
2749 fn main() -> i32 {
2750 let x = 5;
2751 match x {
2752 _ => 42,
2753 }
2754 }
2755 "#;
2756 let (rir, _interner) = gen_rir(source);
2757
2758 let match_inst = rir
2760 .iter()
2761 .find(|(_, inst)| matches!(inst.data, InstData::Match { .. }));
2762 assert!(match_inst.is_some(), "Expected Match instruction");
2763
2764 let (_, inst) = match_inst.unwrap();
2765 match &inst.data {
2766 InstData::Match {
2767 arms_start,
2768 arms_len,
2769 ..
2770 } => {
2771 let arms = rir.get_match_arms(*arms_start, *arms_len);
2772 assert_eq!(arms.len(), 1);
2773 assert!(matches!(arms[0].0, RirPattern::Wildcard(_)));
2774 }
2775 _ => panic!("expected Match"),
2776 }
2777 }
2778
2779 #[test]
2780 fn test_gen_match_int_patterns() {
2781 let source = r#"
2782 fn main() -> i32 {
2783 let x = 5;
2784 match x {
2785 1 => 10,
2786 2 => 20,
2787 _ => 0,
2788 }
2789 }
2790 "#;
2791 let (rir, _interner) = gen_rir(source);
2792
2793 let match_inst = rir
2794 .iter()
2795 .find(|(_, inst)| matches!(inst.data, InstData::Match { .. }));
2796 assert!(match_inst.is_some());
2797
2798 let (_, inst) = match_inst.unwrap();
2799 match &inst.data {
2800 InstData::Match {
2801 arms_start,
2802 arms_len,
2803 ..
2804 } => {
2805 let arms = rir.get_match_arms(*arms_start, *arms_len);
2806 assert_eq!(arms.len(), 3);
2807 assert!(matches!(arms[0].0, RirPattern::Int(1, _)));
2808 assert!(matches!(arms[1].0, RirPattern::Int(2, _)));
2809 assert!(matches!(arms[2].0, RirPattern::Wildcard(_)));
2810 }
2811 _ => panic!("expected Match"),
2812 }
2813 }
2814
2815 #[test]
2816 fn test_gen_match_negative_int_pattern() {
2817 let source = r#"
2818 fn main() -> i32 {
2819 let x: i32 = -5;
2820 match x {
2821 -5 => 1,
2822 -10 => 2,
2823 _ => 0,
2824 }
2825 }
2826 "#;
2827 let (rir, _interner) = gen_rir(source);
2828
2829 let match_inst = rir
2830 .iter()
2831 .find(|(_, inst)| matches!(inst.data, InstData::Match { .. }));
2832 assert!(match_inst.is_some());
2833
2834 let (_, inst) = match_inst.unwrap();
2835 match &inst.data {
2836 InstData::Match {
2837 arms_start,
2838 arms_len,
2839 ..
2840 } => {
2841 let arms = rir.get_match_arms(*arms_start, *arms_len);
2842 assert_eq!(arms.len(), 3);
2843 assert!(matches!(arms[0].0, RirPattern::Int(-5, _)));
2844 assert!(matches!(arms[1].0, RirPattern::Int(-10, _)));
2845 assert!(matches!(arms[2].0, RirPattern::Wildcard(_)));
2846 }
2847 _ => panic!("expected Match"),
2848 }
2849 }
2850
2851 #[test]
2852 fn test_gen_match_bool_patterns() {
2853 let source = r#"
2854 fn main() -> i32 {
2855 let b = true;
2856 match b {
2857 true => 1,
2858 false => 0,
2859 }
2860 }
2861 "#;
2862 let (rir, _interner) = gen_rir(source);
2863
2864 let match_inst = rir
2865 .iter()
2866 .find(|(_, inst)| matches!(inst.data, InstData::Match { .. }));
2867 assert!(match_inst.is_some());
2868
2869 let (_, inst) = match_inst.unwrap();
2870 match &inst.data {
2871 InstData::Match {
2872 arms_start,
2873 arms_len,
2874 ..
2875 } => {
2876 let arms = rir.get_match_arms(*arms_start, *arms_len);
2877 assert_eq!(arms.len(), 2);
2878 assert!(matches!(arms[0].0, RirPattern::Bool(true, _)));
2879 assert!(matches!(arms[1].0, RirPattern::Bool(false, _)));
2880 }
2881 _ => panic!("expected Match"),
2882 }
2883 }
2884
2885 #[test]
2886 fn test_gen_match_enum_patterns() {
2887 let source = r#"
2888 enum Color { Red, Green, Blue }
2889 fn main() -> i32 {
2890 let c = Color::Red;
2891 match c {
2892 Color::Red => 1,
2893 Color::Green => 2,
2894 Color::Blue => 3,
2895 }
2896 }
2897 "#;
2898 let (rir, interner) = gen_rir(source);
2899
2900 let match_inst = rir
2901 .iter()
2902 .find(|(_, inst)| matches!(inst.data, InstData::Match { .. }));
2903 assert!(match_inst.is_some());
2904
2905 let (_, inst) = match_inst.unwrap();
2906 match &inst.data {
2907 InstData::Match {
2908 arms_start,
2909 arms_len,
2910 ..
2911 } => {
2912 let arms = rir.get_match_arms(*arms_start, *arms_len);
2913 assert_eq!(arms.len(), 3);
2914
2915 match &arms[0].0 {
2917 RirPattern::Path {
2918 type_name, variant, ..
2919 } => {
2920 assert_eq!(interner.resolve(type_name), "Color");
2921 assert_eq!(interner.resolve(variant), "Red");
2922 }
2923 _ => panic!("expected Path pattern"),
2924 }
2925
2926 match &arms[1].0 {
2928 RirPattern::Path {
2929 type_name, variant, ..
2930 } => {
2931 assert_eq!(interner.resolve(type_name), "Color");
2932 assert_eq!(interner.resolve(variant), "Green");
2933 }
2934 _ => panic!("expected Path pattern"),
2935 }
2936
2937 match &arms[2].0 {
2939 RirPattern::Path {
2940 type_name, variant, ..
2941 } => {
2942 assert_eq!(interner.resolve(type_name), "Color");
2943 assert_eq!(interner.resolve(variant), "Blue");
2944 }
2945 _ => panic!("expected Path pattern"),
2946 }
2947 }
2948 _ => panic!("expected Match"),
2949 }
2950 }
2951
2952 #[test]
2953 fn test_gen_self_expr() {
2954 let source = r#"
2955 struct Point {
2956 x: i32,
2957 fn get_x(self) -> i32 { self.x }
2958 }
2959 fn main() -> i32 { 0 }
2960 "#;
2961 let (rir, interner) = gen_rir(source);
2962
2963 let self_ref = rir.iter().find(|(_, inst)| match &inst.data {
2965 InstData::VarRef { name } => interner.resolve(name) == "self",
2966 _ => false,
2967 });
2968 assert!(self_ref.is_some(), "Expected self VarRef instruction");
2969 }
2970
2971 #[test]
2972 fn test_gen_enum_variant() {
2973 let source = r#"
2974 enum Color { Red, Green, Blue }
2975 fn main() -> i32 {
2976 let c = Color::Red;
2977 0
2978 }
2979 "#;
2980 let (rir, interner) = gen_rir(source);
2981
2982 let enum_variant = rir
2984 .iter()
2985 .find(|(_, inst)| matches!(inst.data, InstData::EnumVariant { .. }));
2986 assert!(enum_variant.is_some(), "Expected EnumVariant instruction");
2987
2988 let (_, inst) = enum_variant.unwrap();
2989 match &inst.data {
2990 InstData::EnumVariant {
2991 type_name, variant, ..
2992 } => {
2993 assert_eq!(interner.resolve(type_name), "Color");
2994 assert_eq!(interner.resolve(variant), "Red");
2995 }
2996 _ => panic!("expected EnumVariant"),
2997 }
2998 }
2999
3000 #[test]
3001 fn test_gen_method_with_params() {
3002 let source = r#"
3003 struct Counter {
3004 value: i32,
3005 fn add(self, amount: i32) -> i32 { self.value + amount }
3006 }
3007 fn main() -> i32 { 0 }
3008 "#;
3009 let (rir, interner) = gen_rir(source);
3010
3011 let struct_decl = rir
3013 .iter()
3014 .find(|(_, inst)| matches!(inst.data, InstData::StructDecl { .. }));
3015 assert!(struct_decl.is_some());
3016
3017 let (_, inst) = struct_decl.unwrap();
3018 match &inst.data {
3019 InstData::StructDecl {
3020 methods_start,
3021 methods_len,
3022 ..
3023 } => {
3024 let methods = rir.get_inst_refs(*methods_start, *methods_len);
3025 let method_inst = rir.get(methods[0]);
3026 match &method_inst.data {
3027 InstData::FnDecl {
3028 name,
3029 params_start,
3030 params_len,
3031 has_self,
3032 ..
3033 } => {
3034 assert_eq!(interner.resolve(name), "add");
3035 assert!(*has_self);
3036 let params = rir.get_params(*params_start, *params_len);
3038 assert_eq!(params.len(), 1);
3039 assert_eq!(interner.resolve(¶ms[0].name), "amount");
3040 }
3041 _ => panic!("expected FnDecl"),
3042 }
3043 }
3044 _ => panic!("expected StructDecl"),
3045 }
3046 }
3047
3048 #[test]
3050 fn test_printer_integration() {
3051 let source = r#"
3052 struct Point {
3053 x: i32,
3054 y: i32,
3055 fn origin() -> Point { Point { x: 0, y: 0 } }
3056 }
3057 fn main() -> i32 {
3058 let p = Point::origin();
3059 p.x
3060 }
3061 "#;
3062 let (rir, interner) = gen_rir(source);
3063
3064 let printer = RirPrinter::new(&rir, &interner);
3065 let output = printer.to_string();
3066
3067 assert!(output.contains("struct Point"));
3069 assert!(output.contains("methods: ["));
3070 assert!(output.contains("fn origin"));
3071 assert!(output.contains("fn main"));
3072 assert!(output.contains("struct_init Point"));
3073 assert!(output.contains("assoc_fn_call Point::origin"));
3074 assert!(output.contains("field_get"));
3075 }
3076
3077 #[test]
3080 fn test_function_spans_simple() {
3081 let (rir, interner) = gen_rir("fn main() -> i32 { 42 }");
3082
3083 assert_eq!(rir.function_count(), 1);
3085
3086 let spans: Vec<_> = rir.functions().collect();
3087 assert_eq!(spans.len(), 1);
3088
3089 let span = &spans[0];
3090 assert_eq!(interner.resolve(&span.name), "main");
3091
3092 assert_eq!(span.instruction_count(), 2);
3094
3095 let fn_inst = rir.get(span.decl);
3097 assert!(matches!(fn_inst.data, InstData::FnDecl { .. }));
3098 }
3099
3100 #[test]
3101 fn test_function_spans_multiple_functions() {
3102 let source = r#"
3103 fn helper() -> i32 { 1 }
3104 fn main() -> i32 { 42 }
3105 "#;
3106 let (rir, interner) = gen_rir(source);
3107
3108 assert_eq!(rir.function_count(), 2);
3110
3111 let spans: Vec<_> = rir.functions().collect();
3112 assert_eq!(spans.len(), 2);
3113
3114 assert_eq!(interner.resolve(&spans[0].name), "helper");
3116 assert_eq!(spans[0].instruction_count(), 2);
3117
3118 assert_eq!(interner.resolve(&spans[1].name), "main");
3120 assert_eq!(spans[1].instruction_count(), 2);
3121
3122 assert!(
3124 spans[0].decl.as_u32() < spans[1].body_start.as_u32(),
3125 "helper should end before main starts"
3126 );
3127 }
3128
3129 #[test]
3130 fn test_function_spans_with_methods() {
3131 let source = r#"
3132 struct Point {
3133 x: i32,
3134 fn get_x(self) -> i32 { self.x }
3135 fn origin() -> Point { Point { x: 0 } }
3136 }
3137 fn main() -> i32 { 0 }
3138 "#;
3139 let (rir, interner) = gen_rir(source);
3140
3141 assert_eq!(rir.function_count(), 3);
3143
3144 let spans: Vec<_> = rir.functions().collect();
3145
3146 let names: Vec<_> = spans.iter().map(|s| interner.resolve(&s.name)).collect();
3148 assert!(names.contains(&"get_x"));
3149 assert!(names.contains(&"origin"));
3150 assert!(names.contains(&"main"));
3151 }
3152
3153 #[test]
3154 fn test_function_view() {
3155 let source = r#"
3156 fn helper(x: i32) -> i32 { x + 1 }
3157 fn main() -> i32 { helper(41) }
3158 "#;
3159 let (rir, interner) = gen_rir(source);
3160
3161 let main_span = rir.find_function(interner.get_or_intern("main")).unwrap();
3163
3164 let view = rir.function_view(main_span);
3166
3167 assert_eq!(view.len(), main_span.instruction_count() as usize);
3169
3170 let fn_decl = view.fn_decl();
3172 match &fn_decl.data {
3173 InstData::FnDecl { name, .. } => {
3174 assert_eq!(interner.resolve(name), "main");
3175 }
3176 _ => panic!("Expected FnDecl"),
3177 }
3178
3179 let mut found_call = false;
3181 for (_, inst) in view.iter() {
3182 if matches!(inst.data, InstData::Call { .. }) {
3183 found_call = true;
3184 }
3185 }
3186 assert!(found_call, "main should contain a call to helper");
3187 }
3188
3189 #[test]
3190 fn test_function_span_complex_body() {
3191 let source = r#"
3192 fn complex() -> i32 {
3193 let x = 1;
3194 let y = 2;
3195 if x < y {
3196 x + y
3197 } else {
3198 x - y
3199 }
3200 }
3201 "#;
3202 let (rir, interner) = gen_rir(source);
3203
3204 assert_eq!(rir.function_count(), 1);
3205
3206 let span = rir
3207 .find_function(interner.get_or_intern("complex"))
3208 .unwrap();
3209
3210 assert!(
3213 span.instruction_count() >= 8,
3214 "Complex function should have at least 8 instructions, got {}",
3215 span.instruction_count()
3216 );
3217
3218 let view = rir.function_view(span);
3220 let mut has_alloc = false;
3221 let mut has_branch = false;
3222
3223 for (_, inst) in view.iter() {
3224 if matches!(inst.data, InstData::Alloc { .. }) {
3225 has_alloc = true;
3226 }
3227 if matches!(inst.data, InstData::Branch { .. }) {
3228 has_branch = true;
3229 }
3230 }
3231
3232 assert!(has_alloc, "Function should have Alloc instructions");
3233 assert!(has_branch, "Function should have Branch instruction");
3234 }
3235
3236 #[test]
3237 fn test_find_function() {
3238 let source = r#"
3239 fn foo() -> i32 { 1 }
3240 fn bar() -> i32 { 2 }
3241 fn baz() -> i32 { 3 }
3242 "#;
3243 let (rir, interner) = gen_rir(source);
3244
3245 let foo_sym = interner.get_or_intern("foo");
3247 let bar_sym = interner.get_or_intern("bar");
3248 let baz_sym = interner.get_or_intern("baz");
3249 let nonexistent_sym = interner.get_or_intern("nonexistent");
3250
3251 assert!(rir.find_function(foo_sym).is_some());
3252 assert!(rir.find_function(bar_sym).is_some());
3253 assert!(rir.find_function(baz_sym).is_some());
3254 assert!(rir.find_function(nonexistent_sym).is_none());
3255 }
3256
3257 #[test]
3258 fn test_function_span_ordering() {
3259 let source = r#"
3260 fn a() -> i32 { 1 }
3261 fn b() -> i32 { 2 }
3262 fn c() -> i32 { 3 }
3263 "#;
3264 let (rir, _interner) = gen_rir(source);
3265
3266 let spans: Vec<_> = rir.functions().collect();
3267 assert_eq!(spans.len(), 3);
3268
3269 for i in 1..spans.len() {
3271 assert!(
3272 spans[i - 1].decl.as_u32() < spans[i].body_start.as_u32(),
3273 "Function {} should end before function {} starts",
3274 i - 1,
3275 i
3276 );
3277 }
3278 }
3279
3280 #[test]
3281 fn test_anon_struct_with_methods() {
3282 let source = r#"
3284 fn MakePoint(comptime T: type) -> type {
3285 struct {
3286 x: T,
3287 y: T,
3288
3289 fn get_x(self) -> T { self.x }
3290 fn origin() -> Self { Self { x: 0, y: 0 } }
3291 }
3292 }
3293 fn main() -> i32 { 0 }
3294 "#;
3295 let (rir, interner) = gen_rir(source);
3296
3297 let anon_struct = rir
3299 .iter()
3300 .find(|(_, inst)| matches!(inst.data, InstData::AnonStructType { .. }));
3301 assert!(
3302 anon_struct.is_some(),
3303 "Expected to find AnonStructType instruction"
3304 );
3305
3306 let (_, inst) = anon_struct.unwrap();
3307 match &inst.data {
3308 InstData::AnonStructType {
3309 fields_start,
3310 fields_len,
3311 methods_start,
3312 methods_len,
3313 ..
3314 } => {
3315 let fields = rir.get_field_decls(*fields_start, *fields_len);
3317 assert_eq!(fields.len(), 2);
3318 assert_eq!(interner.resolve(&fields[0].0), "x");
3319 assert_eq!(interner.resolve(&fields[1].0), "y");
3320
3321 assert_eq!(*methods_len, 2);
3323 let methods = rir.get_inst_refs(*methods_start, *methods_len);
3324 assert_eq!(methods.len(), 2);
3325
3326 for method_ref in methods {
3328 let method_inst = rir.get(method_ref);
3329 match &method_inst.data {
3330 InstData::FnDecl { name, has_self, .. } => {
3331 let name_str = interner.resolve(name);
3332 if name_str == "get_x" {
3334 assert!(*has_self, "get_x should have self parameter");
3335 } else if name_str == "origin" {
3336 assert!(!*has_self, "origin should not have self parameter");
3337 }
3338 }
3339 _ => panic!("Expected FnDecl for method"),
3340 }
3341 }
3342 }
3343 _ => panic!("Expected AnonStructType"),
3344 }
3345 }
3346
3347 #[test]
3348 fn test_anon_struct_without_methods() {
3349 let source = r#"
3351 fn MakePair(comptime T: type) -> type {
3352 struct { first: T, second: T }
3353 }
3354 fn main() -> i32 { 0 }
3355 "#;
3356 let (rir, _interner) = gen_rir(source);
3357
3358 let anon_struct = rir
3360 .iter()
3361 .find(|(_, inst)| matches!(inst.data, InstData::AnonStructType { .. }));
3362 assert!(
3363 anon_struct.is_some(),
3364 "Expected to find AnonStructType instruction"
3365 );
3366
3367 let (_, inst) = anon_struct.unwrap();
3368 match &inst.data {
3369 InstData::AnonStructType { methods_len, .. } => {
3370 assert_eq!(*methods_len, 0, "Expected no methods");
3371 }
3372 _ => panic!("Expected AnonStructType"),
3373 }
3374 }
3375
3376 #[test]
3377 fn test_anon_struct_method_function_spans() {
3378 let source = r#"
3380 fn Container(comptime T: type) -> type {
3381 struct {
3382 value: T,
3383 fn get(self) -> T { self.value }
3384 fn set(self, v: T) -> Self { Self { value: v } }
3385 }
3386 }
3387 fn main() -> i32 { 0 }
3388 "#;
3389 let (rir, interner) = gen_rir(source);
3390
3391 assert_eq!(
3393 rir.function_count(),
3394 4,
3395 "Expected 4 functions (Container, get, set, main)"
3396 );
3397
3398 let get_sym = interner.get_or_intern("get");
3400 let set_sym = interner.get_or_intern("set");
3401 assert!(
3402 rir.find_function(get_sym).is_some(),
3403 "Should find 'get' method"
3404 );
3405 assert!(
3406 rir.find_function(set_sym).is_some(),
3407 "Should find 'set' method"
3408 );
3409 }
3410
3411 #[test]
3416 fn test_anon_fn_lowers_to_call_method_and_value() {
3417 let (rir, interner) = gen_rir("fn main() -> i32 { fn(x: i32) -> i32 { x + 1 }; 0 }");
3420
3421 let call_sym = interner.get("__call").expect("__call should be interned");
3422
3423 let mut found_call = None;
3425 let mut found_anon_fn_value = None;
3426 for (i, inst) in rir.iter() {
3427 match &inst.data {
3428 InstData::FnDecl { name, has_self, .. } if *name == call_sym => {
3429 assert!(*has_self, "synthesized __call must have self receiver");
3430 found_call = Some(i);
3431 }
3432 InstData::AnonFnValue { method } => {
3433 found_anon_fn_value = Some((i, *method));
3434 }
3435 _ => {}
3436 }
3437 }
3438
3439 let call_ref = found_call.expect("expected a FnDecl named __call in RIR");
3440 let (_, value_method) = found_anon_fn_value.expect("expected an AnonFnValue in RIR");
3441 assert_eq!(
3442 value_method, call_ref,
3443 "AnonFnValue must point at the synthesized __call FnDecl"
3444 );
3445 }
3446
3447 #[test]
3448 fn test_anon_fn_two_sites_each_get_their_own_call_method() {
3449 let (rir, interner) = gen_rir(
3454 "fn main() -> i32 {
3455 fn(x: i32) -> i32 { x + 1 };
3456 fn(x: i32) -> i32 { x * 2 };
3457 0
3458 }",
3459 );
3460 let call_sym = interner.get("__call").expect("__call should be interned");
3461 let count = rir
3462 .iter()
3463 .filter(|(_, inst)| matches!(&inst.data, InstData::FnDecl { name, .. } if *name == call_sym))
3464 .count();
3465 assert_eq!(
3466 count, 2,
3467 "each fn(...) site should produce its own __call FnDecl"
3468 );
3469 }
3470
3471 #[test]
3472 fn test_anon_fn_zero_params_lowers() {
3473 let (rir, interner) = gen_rir("fn main() -> i32 { fn() -> i32 { 7 }; 0 }");
3474 let call_sym = interner.get("__call").expect("__call should be interned");
3475 let call_inst = rir.iter().find_map(|(_, inst)| {
3476 if let InstData::FnDecl {
3477 name,
3478 params_len,
3479 has_self,
3480 ..
3481 } = &inst.data
3482 && *name == call_sym
3483 {
3484 Some((*params_len, *has_self))
3485 } else {
3486 None
3487 }
3488 });
3489 let (params_len, has_self) = call_inst.expect("expected __call FnDecl");
3490 assert_eq!(params_len, 0);
3491 assert!(has_self);
3492 }
3493}