1use super::*;
18
19use leo_ast::{
20 ArrayAccess,
21 ArrayExpression,
22 AssociatedConstantExpression,
23 AssociatedFunctionExpression,
24 AsyncExpression,
25 BinaryExpression,
26 BinaryOperation,
27 CallExpression,
28 CastExpression,
29 ErrExpression,
30 Expression,
31 Identifier,
32 Literal,
33 LiteralVariant,
34 Location,
35 LocatorExpression,
36 MemberAccess,
37 Node,
38 Path,
39 ProgramId,
40 RepeatExpression,
41 StructExpression,
42 TernaryExpression,
43 TupleExpression,
44 Type,
45 UnaryExpression,
46 UnaryOperation,
47 UnitExpression,
48 Variant,
49};
50use leo_span::sym;
51
52use std::{borrow::Borrow, fmt::Write as _};
53
54impl CodeGeneratingVisitor<'_> {
56 pub fn visit_expression(&mut self, input: &Expression) -> (String, String) {
57 match input {
58 Expression::Array(expr) => self.visit_array(expr),
59 Expression::ArrayAccess(expr) => self.visit_array_access(expr),
60 Expression::AssociatedConstant(expr) => self.visit_associated_constant(expr),
61 Expression::AssociatedFunction(expr) => self.visit_associated_function(expr),
62 Expression::Async(expr) => self.visit_async(expr),
63 Expression::Binary(expr) => self.visit_binary(expr),
64 Expression::Call(expr) => self.visit_call(expr),
65 Expression::Cast(expr) => self.visit_cast(expr),
66 Expression::Struct(expr) => self.visit_struct_init(expr),
67 Expression::Err(expr) => self.visit_err(expr),
68 Expression::Path(expr) => self.visit_path(expr),
69 Expression::Literal(expr) => self.visit_value(expr),
70 Expression::Locator(expr) => self.visit_locator(expr),
71 Expression::MemberAccess(expr) => self.visit_member_access(expr),
72 Expression::Repeat(expr) => self.visit_repeat(expr),
73 Expression::Ternary(expr) => self.visit_ternary(expr),
74 Expression::Tuple(expr) => self.visit_tuple(expr),
75 Expression::TupleAccess(_) => panic!("Tuple accesses should not appear in the AST at this point."),
76 Expression::Unary(expr) => self.visit_unary(expr),
77 Expression::Unit(expr) => self.visit_unit(expr),
78 }
79 }
80
81 fn visit_path(&mut self, input: &Path) -> (String, String) {
82 let var_name = input.identifier().name;
85 (
86 self.variable_mapping.get(&var_name).or_else(|| self.global_mapping.get(&var_name)).unwrap().clone(),
87 String::new(),
88 )
89 }
90
91 fn visit_err(&mut self, _input: &ErrExpression) -> (String, String) {
92 panic!("`ErrExpression`s should not be in the AST at this phase of compilation.")
93 }
94
95 fn visit_value(&mut self, input: &Literal) -> (String, String) {
96 let literal = if let LiteralVariant::Unsuffixed(value) = &input.variant {
98 match self.state.type_table.get(&input.id) {
101 Some(Type::Integer(int_ty)) => Literal {
102 variant: LiteralVariant::Integer(int_ty, value.clone()),
103 id: self.state.node_builder.next_id(),
104 span: input.span,
105 },
106 Some(Type::Field) => Literal {
107 variant: LiteralVariant::Field(value.clone()),
108 id: self.state.node_builder.next_id(),
109 span: input.span,
110 },
111 Some(Type::Group) => Literal {
112 variant: LiteralVariant::Group(value.clone()),
113 id: self.state.node_builder.next_id(),
114 span: input.span,
115 },
116 Some(Type::Scalar) => Literal {
117 variant: LiteralVariant::Scalar(value.clone()),
118 id: self.state.node_builder.next_id(),
119 span: input.span,
120 },
121 _ => panic!(
122 "Unexpected type for unsuffixed integer literal. This should have been caught by the type checker"
123 ),
124 }
125 } else {
126 input.clone()
127 };
128 (format!("{}", literal.display_decimal()), String::new())
129 }
130
131 fn visit_locator(&mut self, input: &LocatorExpression) -> (String, String) {
132 if input.program.name.name == self.program_id.expect("Locators only appear within programs.").name.name {
133 (format!("{}", input.name), String::new())
135 } else {
136 (format!("{input}"), String::new())
137 }
138 }
139
140 fn visit_binary(&mut self, input: &BinaryExpression) -> (String, String) {
141 let (left_operand, left_instructions) = self.visit_expression(&input.left);
142 let (right_operand, right_instructions) = self.visit_expression(&input.right);
143
144 let opcode = match input.op {
145 BinaryOperation::Add => String::from("add"),
146 BinaryOperation::AddWrapped => String::from("add.w"),
147 BinaryOperation::And => String::from("and"),
148 BinaryOperation::BitwiseAnd => String::from("and"),
149 BinaryOperation::Div => String::from("div"),
150 BinaryOperation::DivWrapped => String::from("div.w"),
151 BinaryOperation::Eq => String::from("is.eq"),
152 BinaryOperation::Gte => String::from("gte"),
153 BinaryOperation::Gt => String::from("gt"),
154 BinaryOperation::Lte => String::from("lte"),
155 BinaryOperation::Lt => String::from("lt"),
156 BinaryOperation::Mod => String::from("mod"),
157 BinaryOperation::Mul => String::from("mul"),
158 BinaryOperation::MulWrapped => String::from("mul.w"),
159 BinaryOperation::Nand => String::from("nand"),
160 BinaryOperation::Neq => String::from("is.neq"),
161 BinaryOperation::Nor => String::from("nor"),
162 BinaryOperation::Or => String::from("or"),
163 BinaryOperation::BitwiseOr => String::from("or"),
164 BinaryOperation::Pow => String::from("pow"),
165 BinaryOperation::PowWrapped => String::from("pow.w"),
166 BinaryOperation::Rem => String::from("rem"),
167 BinaryOperation::RemWrapped => String::from("rem.w"),
168 BinaryOperation::Shl => String::from("shl"),
169 BinaryOperation::ShlWrapped => String::from("shl.w"),
170 BinaryOperation::Shr => String::from("shr"),
171 BinaryOperation::ShrWrapped => String::from("shr.w"),
172 BinaryOperation::Sub => String::from("sub"),
173 BinaryOperation::SubWrapped => String::from("sub.w"),
174 BinaryOperation::Xor => String::from("xor"),
175 };
176
177 let destination_register = self.next_register();
178 let binary_instruction = format!(" {opcode} {left_operand} {right_operand} into {destination_register};\n",);
179
180 let mut instructions = left_instructions;
182 instructions.push_str(&right_instructions);
183 instructions.push_str(&binary_instruction);
184
185 (destination_register, instructions)
186 }
187
188 fn visit_cast(&mut self, input: &CastExpression) -> (String, String) {
189 let (expression_operand, mut instructions) = self.visit_expression(&input.expression);
190
191 let destination_register = self.next_register();
193
194 let cast_instruction = format!(
195 " cast {expression_operand} into {destination_register} as {};\n",
196 Self::visit_type(&input.type_)
197 );
198
199 instructions.push_str(&cast_instruction);
201
202 (destination_register, instructions)
203 }
204
205 fn visit_array(&mut self, input: &ArrayExpression) -> (String, String) {
206 let mut expression_operands = String::new();
207 let mut instructions = String::new();
208 for (operand, operand_instructions) in input.elements.iter().map(|expr| self.visit_expression(expr)) {
209 let space = if expression_operands.is_empty() { "" } else { " " };
210 write!(&mut expression_operands, "{space}{operand}").unwrap();
211 instructions.push_str(&operand_instructions);
212 }
213
214 let destination_register = self.next_register();
216
217 let Some(array_type @ Type::Array(..)) = self.state.type_table.get(&input.id) else {
219 panic!("All types should be known at this phase of compilation");
220 };
221 let array_type: String = Self::visit_type(&array_type);
222
223 let array_instruction =
224 format!(" cast {expression_operands} into {destination_register} as {array_type};\n");
225
226 instructions.push_str(&array_instruction);
228
229 (destination_register, instructions)
230 }
231
232 fn visit_unary(&mut self, input: &UnaryExpression) -> (String, String) {
233 let (expression_operand, expression_instructions) = self.visit_expression(&input.receiver);
234
235 let (opcode, suffix) = match input.op {
237 UnaryOperation::Abs => ("abs", ""),
238 UnaryOperation::AbsWrapped => ("abs.w", ""),
239 UnaryOperation::Double => ("double", ""),
240 UnaryOperation::Inverse => ("inv", ""),
241 UnaryOperation::Not => ("not", ""),
242 UnaryOperation::Negate => ("neg", ""),
243 UnaryOperation::Square => ("square", ""),
244 UnaryOperation::SquareRoot => ("sqrt", ""),
245 UnaryOperation::ToXCoordinate => ("cast", " as group.x"),
246 UnaryOperation::ToYCoordinate => ("cast", " as group.y"),
247 };
248
249 let destination_register = self.next_register();
250 let unary_instruction = format!(" {opcode} {expression_operand} into {destination_register}{suffix};\n");
251
252 let mut instructions = expression_instructions;
254 instructions.push_str(&unary_instruction);
255
256 (destination_register, instructions)
257 }
258
259 fn visit_ternary(&mut self, input: &TernaryExpression) -> (String, String) {
260 let (condition_operand, condition_instructions) = self.visit_expression(&input.condition);
261 let (if_true_operand, if_true_instructions) = self.visit_expression(&input.if_true);
262 let (if_false_operand, if_false_instructions) = self.visit_expression(&input.if_false);
263
264 let destination_register = self.next_register();
265 let ternary_instruction = format!(
266 " ternary {condition_operand} {if_true_operand} {if_false_operand} into {destination_register};\n",
267 );
268
269 let mut instructions = condition_instructions;
271 instructions.push_str(&if_true_instructions);
272 instructions.push_str(&if_false_instructions);
273 instructions.push_str(&ternary_instruction);
274
275 (destination_register, instructions)
276 }
277
278 fn visit_struct_init(&mut self, input: &StructExpression) -> (String, String) {
279 let name = if let Some((is_record, type_)) = self.composite_mapping.get(&input.path.absolute_path()) {
281 if *is_record {
282 let [record_name] = &input.path.absolute_path()[..] else {
284 panic!("Absolute paths to records can only have a single segment at this stage.")
285 };
286 format!("{record_name}.{type_}")
287 } else {
288 Self::legalize_path(&input.path.absolute_path()).expect("path format cannot be legalized at this point")
290 }
291 } else {
292 panic!("All composite types should be known at this phase of compilation")
293 };
294
295 let mut instructions = String::new();
297 let mut struct_init_instruction = String::from(" cast ");
298
299 for member in input.members.iter() {
301 let operand = if let Some(expr) = member.expression.as_ref() {
302 let (variable_operand, variable_instructions) = self.visit_expression(expr);
304 instructions.push_str(&variable_instructions);
305
306 variable_operand
307 } else {
308 let (ident_operand, ident_instructions) =
310 self.visit_path(&Path::from(member.identifier).into_absolute());
311 instructions.push_str(&ident_instructions);
312
313 ident_operand
314 };
315
316 write!(struct_init_instruction, "{operand} ").expect("failed to write to string");
318 }
319
320 let destination_register = self.next_register();
322 writeln!(struct_init_instruction, "into {destination_register} as {name};",)
323 .expect("failed to write to string");
324
325 instructions.push_str(&struct_init_instruction);
326
327 (destination_register, instructions)
328 }
329
330 fn visit_array_access(&mut self, input: &ArrayAccess) -> (String, String) {
331 let (array_operand, _) = self.visit_expression(&input.array);
332
333 assert!(
334 matches!(self.state.type_table.get(&input.index.id()), Some(Type::Integer(_))),
335 "unexpected type for for array index. This should have been caught by the type checker."
336 );
337
338 let index_operand = match &input.index {
339 Expression::Literal(Literal {
340 variant: LiteralVariant::Integer(_, s) | LiteralVariant::Unsuffixed(s),
341 ..
342 }) => format!("{s}u32"),
343 _ => panic!("Array indices must be integer literals"),
344 };
345
346 (format!("{array_operand}[{index_operand}]"), String::new())
347 }
348
349 fn visit_member_access(&mut self, input: &MemberAccess) -> (String, String) {
350 if let Expression::Path(path) = input.inner.borrow()
352 && matches!(path.try_absolute_path().as_deref(), Some([sym::SelfLower]))
353 {
354 let program_id = self.program_id.expect("Program ID should be set before traversing the program");
356
357 match input.name.name {
358 sym::address | sym::id => {
360 return (program_id.to_string(), String::new());
361 }
362 name @ (sym::checksum | sym::edition | sym::program_owner) => {
364 return (name.to_string(), String::new());
365 }
366 _ => {} }
368 }
369
370 let (inner_expr, _) = self.visit_expression(&input.inner);
371 let member_access = format!("{}.{}", inner_expr, input.name);
372
373 (member_access, String::new())
374 }
375
376 fn visit_repeat(&mut self, input: &RepeatExpression) -> (String, String) {
377 let (operand, mut operand_instructions) = self.visit_expression(&input.expr);
378 let count = input.count.as_u32().expect("repeat count should be known at this point");
379
380 let expression_operands = std::iter::repeat_n(operand, count as usize).collect::<Vec<_>>().join(" ");
381
382 let destination_register = self.next_register();
384
385 let Some(array_type @ Type::Array(..)) = self.state.type_table.get(&input.id) else {
387 panic!("All types should be known at this phase of compilation");
388 };
389 let array_type: String = Self::visit_type(&array_type);
390
391 let array_instruction =
392 format!(" cast {expression_operands} into {destination_register} as {array_type};\n");
393
394 operand_instructions.push_str(&array_instruction);
396
397 (destination_register, operand_instructions)
398 }
399
400 fn visit_associated_constant(&mut self, input: &AssociatedConstantExpression) -> (String, String) {
402 (format!("{input}"), String::new())
403 }
404
405 fn visit_associated_function(&mut self, input: &AssociatedFunctionExpression) -> (String, String) {
407 let mut instructions = String::new();
408
409 let arguments = input
411 .arguments
412 .iter()
413 .map(|argument| {
414 let (arg_string, arg_instructions) = self.visit_expression(argument);
415 instructions.push_str(&arg_instructions);
416 arg_string
417 })
418 .collect::<Vec<_>>();
419
420 let mut construct_simple_function_call = |function: &Identifier, variant: &str, arguments: Vec<String>| {
423 let function_name = function.name.to_string();
425 let mut names = function_name.split("_to_");
426 let opcode = names.next().expect("failed to get opcode");
427 let return_type = names.next().expect("failed to get type");
428
429 let mut instruction = format!(" {opcode}.{variant}");
430 for argument in arguments {
431 write!(instruction, " {argument}").expect("failed to write to string");
432 }
433 let destination_register = self.next_register();
434 writeln!(instruction, " into {destination_register} as {return_type};").expect("failed to write to string");
435 (destination_register, instruction)
436 };
437
438 let (destination, instruction) = match input.variant.name {
440 sym::BHP256 => construct_simple_function_call(&input.name, "bhp256", arguments),
441 sym::BHP512 => construct_simple_function_call(&input.name, "bhp512", arguments),
442 sym::BHP768 => construct_simple_function_call(&input.name, "bhp768", arguments),
443 sym::BHP1024 => construct_simple_function_call(&input.name, "bhp1024", arguments),
444 sym::Keccak256 => construct_simple_function_call(&input.name, "keccak256", arguments),
445 sym::Keccak384 => construct_simple_function_call(&input.name, "keccak384", arguments),
446 sym::Keccak512 => construct_simple_function_call(&input.name, "keccak512", arguments),
447 sym::Pedersen64 => construct_simple_function_call(&input.name, "ped64", arguments),
448 sym::Pedersen128 => construct_simple_function_call(&input.name, "ped128", arguments),
449 sym::Poseidon2 => construct_simple_function_call(&input.name, "psd2", arguments),
450 sym::Poseidon4 => construct_simple_function_call(&input.name, "psd4", arguments),
451 sym::Poseidon8 => construct_simple_function_call(&input.name, "psd8", arguments),
452 sym::SHA3_256 => construct_simple_function_call(&input.name, "sha3_256", arguments),
453 sym::SHA3_384 => construct_simple_function_call(&input.name, "sha3_384", arguments),
454 sym::SHA3_512 => construct_simple_function_call(&input.name, "sha3_512", arguments),
455 sym::Mapping => match input.name.name {
456 sym::get => {
457 let mut instruction = " get".to_string();
458 let destination_register = self.next_register();
459 writeln!(instruction, " {}[{}] into {destination_register};", arguments[0], arguments[1])
461 .expect("failed to write to string");
462 (destination_register, instruction)
463 }
464 sym::get_or_use => {
465 let mut instruction = " get.or_use".to_string();
466 let destination_register = self.next_register();
467 writeln!(
469 instruction,
470 " {}[{}] {} into {destination_register};",
471 arguments[0], arguments[1], arguments[2]
472 )
473 .expect("failed to write to string");
474 (destination_register, instruction)
475 }
476 sym::set => {
477 let mut instruction = " set".to_string();
478 writeln!(instruction, " {} into {}[{}];", arguments[2], arguments[0], arguments[1])
480 .expect("failed to write to string");
481 (String::new(), instruction)
482 }
483 sym::remove => {
484 let mut instruction = " remove".to_string();
485 writeln!(instruction, " {}[{}];", arguments[0], arguments[1]).expect("failed to write to string");
487 (String::new(), instruction)
488 }
489 sym::contains => {
490 let mut instruction = " contains".to_string();
491 let destination_register = self.next_register();
492 writeln!(instruction, " {}[{}] into {destination_register};", arguments[0], arguments[1])
494 .expect("failed to write to string");
495 (destination_register, instruction)
496 }
497 _ => panic!("The only variants of Mapping are get, get_or, and set"),
498 },
499 sym::Optional => panic!("Functions for optional types should have been lowered by now."),
500 sym::group => {
501 match input.name {
502 Identifier { name: sym::to_x_coordinate, .. } => {
503 let mut instruction = " cast".to_string();
504 let destination_register = self.next_register();
505 writeln!(instruction, " {} into {destination_register} as group.x;", arguments[0],)
507 .expect("failed to write to string");
508 (destination_register, instruction)
509 }
510 Identifier { name: sym::to_y_coordinate, .. } => {
511 let mut instruction = " cast".to_string();
512 let destination_register = self.next_register();
513 writeln!(instruction, " {} into {destination_register} as group.y;", arguments[0],)
515 .expect("failed to write to string");
516 (destination_register, instruction)
517 }
518 _ => panic!("The only associated methods of `group` are `to_x_coordinate` and `to_y_coordinate`"),
519 }
520 }
521 sym::ChaCha => {
522 let destination_register = self.next_register();
524 let mut instruction = format!(" rand.chacha into {destination_register} as ");
526 match input.name {
528 Identifier { name: sym::rand_address, .. } => writeln!(instruction, "address;"),
529 Identifier { name: sym::rand_bool, .. } => writeln!(instruction, "boolean;"),
530 Identifier { name: sym::rand_field, .. } => writeln!(instruction, "field;"),
531 Identifier { name: sym::rand_group, .. } => writeln!(instruction, "group;"),
532 Identifier { name: sym::rand_i8, .. } => writeln!(instruction, "i8;"),
533 Identifier { name: sym::rand_i16, .. } => writeln!(instruction, "i16;"),
534 Identifier { name: sym::rand_i32, .. } => writeln!(instruction, "i32;"),
535 Identifier { name: sym::rand_i64, .. } => writeln!(instruction, "i64;"),
536 Identifier { name: sym::rand_i128, .. } => writeln!(instruction, "i128;"),
537 Identifier { name: sym::rand_scalar, .. } => writeln!(instruction, "scalar;"),
538 Identifier { name: sym::rand_u8, .. } => writeln!(instruction, "u8;"),
539 Identifier { name: sym::rand_u16, .. } => writeln!(instruction, "u16;"),
540 Identifier { name: sym::rand_u32, .. } => writeln!(instruction, "u32;"),
541 Identifier { name: sym::rand_u64, .. } => writeln!(instruction, "u64;"),
542 Identifier { name: sym::rand_u128, .. } => writeln!(instruction, "u128;"),
543 _ => panic!("The only associated methods of ChaCha are `rand_*`"),
544 }
545 .expect("failed to write to string");
546 (destination_register, instruction)
547 }
548 sym::signature => {
549 let mut instruction = " sign.verify".to_string();
550 let destination_register = self.next_register();
551 writeln!(
553 instruction,
554 " {} {} {} into {destination_register};",
555 arguments[0], arguments[1], arguments[2]
556 )
557 .expect("failed to write to string");
558 (destination_register, instruction)
559 }
560 sym::Future => {
561 let mut instruction = " await".to_string();
562 writeln!(instruction, " {};", arguments[0]).expect("failed to write to string");
563 (String::new(), instruction)
564 }
565 sym::ProgramCore => {
566 match input.name.name {
567 name @ (sym::checksum | sym::edition | sym::program_owner) => {
569 let program_id =
571 ProgramId::from_str_with_network(&arguments[0].replace("\"", ""), self.state.network)
572 .expect("Type checking guarantees that the program name is valid");
573 let operand = match program_id.to_string()
575 == self.program_id.expect("The program ID is set before traversing the program").to_string()
576 {
577 true => name.to_string(),
578 false => format!("{program_id}/{name}"),
579 };
580 (operand, String::new())
581 }
582 _ => panic!(
584 "The only associated methods of `Program` are `checksum`, `edition`, and `program_owner`"
585 ),
586 }
587 }
588 sym::CheatCode => {
589 (String::new(), String::new())
590 }
592 _ => {
593 panic!("All core functions should be known at this phase of compilation")
594 }
595 };
596 instructions.push_str(&instruction);
598
599 (destination, instructions)
600 }
601
602 fn visit_async(&mut self, _input: &AsyncExpression) -> (String, String) {
603 panic!("`AsyncExpression`s should not be in the AST at this phase of compilation.")
604 }
605
606 fn visit_call(&mut self, input: &CallExpression) -> (String, String) {
607 let caller_program = self.program_id.expect("Calls only appear within programs.").name.name;
608 let callee_program = input.program.unwrap_or(caller_program);
609 let func_symbol = self
610 .state
611 .symbol_table
612 .lookup_function(&Location::new(callee_program, input.function.absolute_path().to_vec()))
613 .expect("Type checking guarantees functions exist");
614
615 let mut call_instruction = if caller_program != callee_program {
617 assert!(
619 self.program.stubs.get(&callee_program).is_some(),
620 "Type checking guarantees that imported and stub programs are present."
621 );
622 format!(" call {}.aleo/{}", callee_program, input.function)
623 } else if func_symbol.function.variant.is_async() {
624 format!(" async {}", self.current_function.unwrap().identifier)
625 } else {
626 format!(" call {}", input.function)
627 };
628
629 let mut instructions = String::new();
630
631 for argument in input.arguments.iter() {
632 let (argument, argument_instructions) = self.visit_expression(argument);
633 write!(call_instruction, " {argument}").expect("failed to write to string");
634 instructions.push_str(&argument_instructions);
635 }
636
637 let mut destinations = Vec::new();
639
640 match func_symbol.function.output_type.clone() {
642 Type::Unit => {} Type::Tuple(tuple) => match tuple.length() {
644 0 | 1 => panic!("Parsing guarantees that a tuple type has at least two elements"),
645 len => {
646 for _ in 0..len {
647 destinations.push(self.next_register());
648 }
649 }
650 },
651 _ => {
652 destinations.push(self.next_register());
653 }
654 }
655
656 if func_symbol.function.variant == Variant::AsyncFunction {
658 destinations.push(self.next_register());
659 }
660
661 let output_operands = destinations.join(" ");
663
664 if !destinations.is_empty() {
666 write!(call_instruction, " into").expect("failed to write to string");
667 for destination in &destinations {
668 write!(call_instruction, " {destination}").expect("failed to write to string");
669 }
670 }
671
672 writeln!(call_instruction, ";").expect("failed to write to string");
674
675 instructions.push_str(&call_instruction);
677
678 (output_operands, instructions)
680 }
681
682 fn visit_tuple(&mut self, input: &TupleExpression) -> (String, String) {
683 let mut tuple_elements = Vec::with_capacity(input.elements.len());
686 let mut instructions = String::new();
687
688 for element in input.elements.iter() {
690 let (element, element_instructions) = self.visit_expression(element);
691 tuple_elements.push(element);
692 instructions.push_str(&element_instructions);
693 }
694
695 (tuple_elements.join(" "), instructions)
697 }
698
699 fn visit_unit(&mut self, _input: &UnitExpression) -> (String, String) {
700 panic!("`UnitExpression`s should not be visited during code generation.")
701 }
702
703 pub fn clone_register(&mut self, register: &str, typ: &Type) -> (String, String) {
704 let new_reg = self.next_register();
705 match typ {
706 Type::Address
707 | Type::Boolean
708 | Type::Field
709 | Type::Group
710 | Type::Scalar
711 | Type::Signature
712 | Type::Integer(_) => {
713 let instruction = format!(" cast {register} into {new_reg} as {typ};\n");
715 (new_reg, instruction)
716 }
717
718 Type::Array(array_type) => {
719 let mut instruction = " cast ".to_string();
721 for i in 0..array_type.length.as_u32().expect("length should be known at this point") as usize {
722 write!(&mut instruction, "{register}[{i}u32] ").unwrap();
723 }
724 writeln!(&mut instruction, "into {new_reg} as {};", Self::visit_type(typ)).unwrap();
725 (new_reg, instruction)
726 }
727
728 Type::Composite(comp_ty) => {
729 let program = comp_ty.program.unwrap_or(self.program_id.unwrap().name.name);
731 let location = Location::new(program, comp_ty.path.absolute_path().to_vec());
732 let comp = self
733 .state
734 .symbol_table
735 .lookup_record(&location)
736 .or_else(|| self.state.symbol_table.lookup_struct(&comp_ty.path.absolute_path()))
737 .unwrap();
738 let mut instruction = " cast ".to_string();
739 for member in &comp.members {
740 write!(&mut instruction, "{register}.{} ", member.identifier.name).unwrap();
741 }
742 writeln!(
743 &mut instruction,
744 "into {new_reg} as {};",
745 self.visit_type_with_visibility(typ, leo_ast::Mode::None)
747 )
748 .unwrap();
749 (new_reg, instruction)
750 }
751
752 Type::Optional(_) => panic!("All optional types should have been lowered by now."),
753
754 Type::Mapping(..)
755 | Type::Future(..)
756 | Type::Tuple(..)
757 | Type::Identifier(..)
758 | Type::String
759 | Type::Unit
760 | Type::Numeric
761 | Type::Err => panic!("Objects of type {typ} cannot be cloned."),
762 }
763 }
764}