1use std::collections::HashMap;
2
3use log::debug;
4use rue_ast::{AstFunctionCallExpr, AstNode};
5use rue_diagnostic::DiagnosticKind;
6use rue_hir::{BinaryOp, Builtin, FunctionCall, Hir, Symbol, UnaryOp, Value};
7use rue_lir::ClvmOp;
8use rue_types::{Pair, Type, TypeId, Union, substitute_with_mappings};
9
10use crate::{Compiler, compile_expr};
11
12pub fn compile_function_call_expr(ctx: &mut Compiler, call: &AstFunctionCallExpr) -> Value {
13 let Some(expr) = call.expr() else {
14 debug!("Unresolved function call expr");
15 return ctx.builtins().unresolved.clone();
16 };
17
18 let expr = compile_expr(ctx, &expr, None);
19
20 if let Hir::Reference(symbol) = ctx.hir(expr.hir).clone()
21 && let Symbol::Builtin(builtin) = ctx.symbol(symbol).clone()
22 {
23 return compile_builtin(ctx, call, builtin);
24 }
25
26 let is_unresolved = ctx.is_unresolved(expr.ty);
27
28 let expected_functions = rue_types::extract_functions(ctx.types_mut(), expr.ty);
29
30 if expected_functions.len() > 1 {
31 let name = ctx.type_name(expr.ty);
32 ctx.diagnostic(
33 call.syntax(),
34 DiagnosticKind::CannotDisambiguateFunctionTypes(name),
35 );
36 } else if expected_functions.is_empty() && !is_unresolved {
37 let name = ctx.type_name(expr.ty);
38 ctx.diagnostic(call.syntax(), DiagnosticKind::InvalidFunctionCall(name));
39 }
40
41 let expected_function = expected_functions.first();
42
43 let len = call.args().count();
44
45 let mut nil_terminated = true;
46 let mut args = Vec::new();
47
48 for (i, arg) in call.args().enumerate() {
49 if let Some(spread) = arg.spread() {
50 if i == len - 1 {
51 nil_terminated = false;
52 } else {
53 ctx.diagnostic(&spread, DiagnosticKind::NonFinalSpread);
54 }
55 }
56
57 args.extend(arg.expr());
58 }
59
60 let (args, mappings) = if let Some(function) = expected_function {
61 if function.nil_terminated != nil_terminated {
62 ctx.diagnostic(call.syntax(), DiagnosticKind::InvalidSpread);
63 }
64
65 if function.params.len() != args.len() {
66 ctx.diagnostic(
67 call.syntax(),
68 DiagnosticKind::ExpectedArguments(function.params.len(), args.len()),
69 );
70 }
71
72 let mut mappings: HashMap<TypeId, Vec<TypeId>> = HashMap::new();
73 let mut results = Vec::new();
74
75 for (i, (_, param)) in function.params.iter().enumerate() {
76 let substitute_mappings = mappings
77 .iter()
78 .map(|(k, v)| {
79 (
80 *k,
81 if v.is_empty() {
82 ctx.builtins().types.never
83 } else if v.len() == 1 {
84 v[0]
85 } else {
86 ctx.alloc_type(Type::Union(Union::new(v.clone())))
87 },
88 )
89 })
90 .collect();
91
92 let param = substitute_with_mappings(ctx.types_mut(), *param, &substitute_mappings);
93
94 if let Some(expr) = args.get(i) {
95 let value = compile_expr(ctx, expr, Some(param));
96 results.push(value.hir);
97 ctx.infer_type(expr.syntax(), value.ty, param, &mut mappings);
98 } else {
99 debug!("Unresolved function call argument");
100 results.push(ctx.builtins().unresolved.hir);
101 }
102 }
103
104 (results, mappings)
105 } else {
106 (vec![], HashMap::new())
107 };
108
109 let ty = if expected_functions.is_empty() {
110 debug!("Unresolved function call return type due to unresolved function type");
111 ctx.alloc_type(Type::Unresolved)
112 } else if expected_functions.len() == 1 {
113 expected_functions[0].ret
114 } else {
115 ctx.alloc_type(Type::Union(Union::new(
116 expected_functions
117 .iter()
118 .map(|function| function.ret)
119 .collect(),
120 )))
121 };
122
123 let mappings = mappings
124 .into_iter()
125 .map(|(k, v)| {
126 (
127 k,
128 if v.is_empty() {
129 ctx.builtins().types.never
130 } else if v.len() == 1 {
131 v[0]
132 } else {
133 ctx.alloc_type(Type::Union(Union::new(v)))
134 },
135 )
136 })
137 .collect();
138
139 let ty = substitute_with_mappings(ctx.types_mut(), ty, &mappings);
140
141 let hir = ctx.alloc_hir(Hir::FunctionCall(FunctionCall {
142 function: expr.hir,
143 args,
144 nil_terminated,
145 }));
146
147 Value::new(hir, ty)
148}
149
150fn compile_builtin(ctx: &mut Compiler, call: &AstFunctionCallExpr, builtin: Builtin) -> Value {
151 let mut args = Vec::new();
152 let mut spread = None;
153
154 let len = call.args().count();
155
156 for (i, arg) in call.args().enumerate() {
157 let Some(expr) = arg.expr() else {
158 debug!("Unresolved clvm op argument");
159 continue;
160 };
161
162 if let Some(op) = arg.spread() {
163 if i == len - 1 {
164 spread = Some(op);
165 } else {
166 ctx.diagnostic(arg.syntax(), DiagnosticKind::NonFinalSpread);
167 }
168 }
169
170 let value = compile_expr(ctx, &expr, None);
171
172 args.push((value, expr));
173 }
174
175 match builtin {
176 Builtin::Sha256 { inline } | Builtin::Keccak256 { inline } => {
177 if args.len() != 1 {
178 ctx.diagnostic(
179 call.syntax(),
180 DiagnosticKind::ExpectedArguments(1, args.len()),
181 );
182 }
183
184 let value = if let Some((value, expr)) = args.first() {
185 let ty = if let Some(spread) = &spread {
186 if inline {
187 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
188 }
189
190 let list = ctx.builtins().types.list;
191
192 let mappings = HashMap::from_iter([(
193 ctx.builtins().types.list_generic,
194 ctx.builtins().types.bytes,
195 )]);
196
197 rue_types::substitute_with_mappings(ctx.types_mut(), list, &mappings)
198 } else {
199 ctx.builtins().types.bytes
200 };
201 ctx.assign_type(expr.syntax(), value.ty, ty);
202 value.hir
203 } else {
204 ctx.builtins().unresolved.hir
205 };
206
207 let hir = match (builtin, spread) {
208 (Builtin::Sha256 { inline }, None) => {
209 if inline {
210 ctx.alloc_hir(Hir::Unary(UnaryOp::Sha256Inline, value))
211 } else {
212 ctx.alloc_hir(Hir::Unary(UnaryOp::Sha256, value))
213 }
214 }
215 (Builtin::Keccak256 { inline }, None) => {
216 if inline {
217 ctx.alloc_hir(Hir::Unary(UnaryOp::Keccak256Inline, value))
218 } else {
219 ctx.alloc_hir(Hir::Unary(UnaryOp::Keccak256, value))
220 }
221 }
222 (Builtin::Sha256 { .. }, Some(_)) => {
223 ctx.alloc_hir(Hir::ClvmOp(ClvmOp::Sha256, value))
224 }
225 (Builtin::Keccak256 { .. }, Some(_)) => {
226 ctx.alloc_hir(Hir::ClvmOp(ClvmOp::Keccak256, value))
227 }
228 _ => unreachable!(),
229 };
230
231 Value::new(hir, ctx.builtins().types.bytes32)
232 }
233 Builtin::Concat => {
234 if args.len() != 1 {
235 ctx.diagnostic(
236 call.syntax(),
237 DiagnosticKind::ExpectedArguments(1, args.len()),
238 );
239 }
240
241 if let Some(spread) = &spread {
242 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
243 }
244
245 let value = if let Some((value, expr)) = args.first() {
246 let list = ctx.builtins().types.list;
247
248 let mappings = HashMap::from_iter([(
249 ctx.builtins().types.list_generic,
250 ctx.builtins().types.bytes,
251 )]);
252
253 let ty = rue_types::substitute_with_mappings(ctx.types_mut(), list, &mappings);
254 ctx.assign_type(expr.syntax(), value.ty, ty);
255 value.hir
256 } else {
257 ctx.builtins().unresolved.hir
258 };
259
260 let hir = ctx.alloc_hir(Hir::ClvmOp(ClvmOp::Concat, value));
261
262 Value::new(hir, ctx.builtins().types.bytes)
263 }
264 Builtin::CoinId => {
265 if args.len() != 3 {
266 ctx.diagnostic(
267 call.syntax(),
268 DiagnosticKind::ExpectedArguments(3, args.len()),
269 );
270 }
271
272 if let Some(spread) = &spread {
273 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
274 }
275
276 let hir = if args.len() == 3 {
277 ctx.assign_type(args[0].1.syntax(), args[0].0.ty, ctx.builtins().types.bytes);
278 ctx.assign_type(args[1].1.syntax(), args[1].0.ty, ctx.builtins().types.bytes);
279 ctx.assign_type(args[2].1.syntax(), args[2].0.ty, ctx.builtins().types.int);
280 ctx.alloc_hir(Hir::CoinId(args[0].0.hir, args[1].0.hir, args[2].0.hir))
281 } else {
282 ctx.builtins().unresolved.hir
283 };
284
285 Value::new(hir, ctx.builtins().types.bytes32)
286 }
287 Builtin::Substr => {
288 if args.len() != 2 && args.len() != 3 {
289 ctx.diagnostic(
290 call.syntax(),
291 DiagnosticKind::ExpectedArgumentsBetween(2, 3, args.len()),
292 );
293 }
294
295 if let Some(spread) = &spread {
296 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
297 }
298
299 let hir = if args.len() >= 2 {
300 ctx.assign_type(args[0].1.syntax(), args[0].0.ty, ctx.builtins().types.bytes);
301 ctx.assign_type(args[1].1.syntax(), args[1].0.ty, ctx.builtins().types.int);
302
303 if args.len() == 3 {
304 ctx.assign_type(args[2].1.syntax(), args[2].0.ty, ctx.builtins().types.int);
305 }
306
307 ctx.alloc_hir(Hir::Substr(
308 args[0].0.hir,
309 args[1].0.hir,
310 args.get(2).map(|arg| arg.0.hir),
311 ))
312 } else {
313 ctx.builtins().unresolved.hir
314 };
315
316 Value::new(hir, ctx.builtins().types.bytes)
317 }
318 Builtin::Sum | Builtin::Difference | Builtin::Product => {
319 if args.len() != 1 {
320 ctx.diagnostic(
321 call.syntax(),
322 DiagnosticKind::ExpectedArguments(1, args.len()),
323 );
324 }
325
326 if let Some(spread) = &spread {
327 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
328 }
329
330 let value = if let Some((value, expr)) = args.first() {
331 let list = ctx.builtins().types.list;
332
333 let mappings = HashMap::from_iter([(
334 ctx.builtins().types.list_generic,
335 ctx.builtins().types.int,
336 )]);
337
338 let ty = rue_types::substitute_with_mappings(ctx.types_mut(), list, &mappings);
339 ctx.assign_type(expr.syntax(), value.ty, ty);
340 value.hir
341 } else {
342 ctx.builtins().unresolved.hir
343 };
344
345 let hir = ctx.alloc_hir(Hir::ClvmOp(
346 match builtin {
347 Builtin::Sum => ClvmOp::Add,
348 Builtin::Difference => ClvmOp::Sub,
349 Builtin::Product => ClvmOp::Mul,
350 _ => unreachable!(),
351 },
352 value,
353 ));
354
355 Value::new(hir, ctx.builtins().types.int)
356 }
357 Builtin::Divmod => {
358 if args.len() != 2 {
359 ctx.diagnostic(
360 call.syntax(),
361 DiagnosticKind::ExpectedArguments(2, args.len()),
362 );
363 }
364
365 if let Some(spread) = &spread {
366 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
367 }
368
369 let hir = if args.len() == 2 {
370 ctx.assign_type(args[0].1.syntax(), args[0].0.ty, ctx.builtins().types.int);
371 ctx.assign_type(args[1].1.syntax(), args[1].0.ty, ctx.builtins().types.int);
372 ctx.alloc_hir(Hir::Binary(BinaryOp::Divmod, args[0].0.hir, args[1].0.hir))
373 } else {
374 ctx.builtins().unresolved.hir
375 };
376
377 let int = ctx.builtins().types.int;
378 let pair = ctx.alloc_type(Type::Pair(Pair::new(int, int)));
379
380 Value::new(hir, pair)
381 }
382 Builtin::Modpow => {
383 if args.len() != 3 {
384 ctx.diagnostic(
385 call.syntax(),
386 DiagnosticKind::ExpectedArguments(3, args.len()),
387 );
388 }
389
390 if let Some(spread) = &spread {
391 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
392 }
393
394 let hir = if args.len() == 3 {
395 ctx.assign_type(args[0].1.syntax(), args[0].0.ty, ctx.builtins().types.int);
396 ctx.assign_type(args[1].1.syntax(), args[1].0.ty, ctx.builtins().types.int);
397 ctx.assign_type(args[2].1.syntax(), args[2].0.ty, ctx.builtins().types.int);
398 ctx.alloc_hir(Hir::Modpow(args[0].0.hir, args[1].0.hir, args[2].0.hir))
399 } else {
400 ctx.builtins().unresolved.hir
401 };
402
403 Value::new(hir, ctx.builtins().types.int)
404 }
405 Builtin::Any | Builtin::All => {
406 if args.len() != 1 {
407 ctx.diagnostic(
408 call.syntax(),
409 DiagnosticKind::ExpectedArguments(1, args.len()),
410 );
411 }
412
413 if let Some(spread) = &spread {
414 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
415 }
416
417 let value = if let Some((value, expr)) = args.first() {
418 let list = ctx.builtins().types.list;
419
420 let mappings = HashMap::from_iter([(
421 ctx.builtins().types.list_generic,
422 ctx.builtins().types.bool,
423 )]);
424
425 let ty = rue_types::substitute_with_mappings(ctx.types_mut(), list, &mappings);
426 ctx.assign_type(expr.syntax(), value.ty, ty);
427 value.hir
428 } else {
429 ctx.builtins().unresolved.hir
430 };
431
432 let hir = ctx.alloc_hir(Hir::ClvmOp(
433 match builtin {
434 Builtin::Any => ClvmOp::Any,
435 Builtin::All => ClvmOp::All,
436 _ => unreachable!(),
437 },
438 value,
439 ));
440
441 Value::new(hir, ctx.builtins().types.bool)
442 }
443 Builtin::PubkeyForExp => {
444 if args.len() != 1 {
445 ctx.diagnostic(
446 call.syntax(),
447 DiagnosticKind::ExpectedArguments(1, args.len()),
448 );
449 }
450
451 if let Some(spread) = &spread {
452 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
453 }
454
455 let hir = if args.len() == 1 {
456 ctx.assign_type(
457 args[0].1.syntax(),
458 args[0].0.ty,
459 ctx.builtins().types.bytes32,
460 );
461 ctx.alloc_hir(Hir::Unary(UnaryOp::PubkeyForExp, args[0].0.hir))
462 } else {
463 ctx.builtins().unresolved.hir
464 };
465
466 Value::new(hir, ctx.builtins().types.public_key)
467 }
468 Builtin::G1Sum | Builtin::G1Difference => {
469 if args.len() != 1 {
470 ctx.diagnostic(
471 call.syntax(),
472 DiagnosticKind::ExpectedArguments(1, args.len()),
473 );
474 }
475
476 if let Some(spread) = &spread {
477 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
478 }
479
480 let value = if let Some((value, expr)) = args.first() {
481 let list = ctx.builtins().types.list;
482
483 let mappings = HashMap::from_iter([(
484 ctx.builtins().types.list_generic,
485 ctx.builtins().types.public_key,
486 )]);
487
488 let ty = rue_types::substitute_with_mappings(ctx.types_mut(), list, &mappings);
489 ctx.assign_type(expr.syntax(), value.ty, ty);
490 value.hir
491 } else {
492 ctx.builtins().unresolved.hir
493 };
494
495 let hir = ctx.alloc_hir(Hir::ClvmOp(
496 match builtin {
497 Builtin::G1Sum => ClvmOp::G1Add,
498 Builtin::G1Difference => ClvmOp::G1Subtract,
499 _ => unreachable!(),
500 },
501 value,
502 ));
503
504 Value::new(hir, ctx.builtins().types.public_key)
505 }
506 Builtin::G2Sum | Builtin::G2Difference => {
507 if args.len() != 1 {
508 ctx.diagnostic(
509 call.syntax(),
510 DiagnosticKind::ExpectedArguments(1, args.len()),
511 );
512 }
513
514 if let Some(spread) = &spread {
515 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
516 }
517
518 let value = if let Some((value, expr)) = args.first() {
519 let list = ctx.builtins().types.list;
520
521 let mappings = HashMap::from_iter([(
522 ctx.builtins().types.list_generic,
523 ctx.builtins().types.signature,
524 )]);
525
526 let ty = rue_types::substitute_with_mappings(ctx.types_mut(), list, &mappings);
527 ctx.assign_type(expr.syntax(), value.ty, ty);
528 value.hir
529 } else {
530 ctx.builtins().unresolved.hir
531 };
532
533 let hir = ctx.alloc_hir(Hir::ClvmOp(
534 match builtin {
535 Builtin::G2Sum => ClvmOp::G2Add,
536 Builtin::G2Difference => ClvmOp::G2Subtract,
537 _ => unreachable!(),
538 },
539 value,
540 ));
541
542 Value::new(hir, ctx.builtins().types.signature)
543 }
544 Builtin::G1Map | Builtin::G2Map => {
545 if args.len() != 1 && args.len() != 2 {
546 ctx.diagnostic(
547 call.syntax(),
548 DiagnosticKind::ExpectedArgumentsBetween(1, 2, args.len()),
549 );
550 }
551
552 if let Some(spread) = &spread {
553 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
554 }
555
556 let data = if let Some((value, expr)) = args.first() {
557 ctx.assign_type(expr.syntax(), value.ty, ctx.builtins().types.bytes);
558 value.hir
559 } else {
560 ctx.builtins().unresolved.hir
561 };
562
563 let dst = args.get(1).map(|(value, expr)| {
564 ctx.assign_type(expr.syntax(), value.ty, ctx.builtins().types.bytes);
565 value.hir
566 });
567
568 let hir = match builtin {
569 Builtin::G1Map => ctx.alloc_hir(Hir::G1Map(data, dst)),
570 Builtin::G2Map => ctx.alloc_hir(Hir::G2Map(data, dst)),
571 _ => unreachable!(),
572 };
573
574 Value::new(
575 hir,
576 match builtin {
577 Builtin::G1Map => ctx.builtins().types.public_key,
578 Builtin::G2Map => ctx.builtins().types.signature,
579 _ => unreachable!(),
580 },
581 )
582 }
583 Builtin::BlsPairingIdentity => {
584 let hir = if spread.is_some() {
585 if args.len() != 1 {
586 ctx.diagnostic(
587 call.syntax(),
588 DiagnosticKind::ExpectedArguments(1, args.len()),
589 );
590 }
591
592 let list = ctx.builtins().types.alternating_list;
593
594 let mappings = HashMap::from_iter([
595 (
596 ctx.builtins().types.alternating_list_generic_a,
597 ctx.builtins().types.public_key,
598 ),
599 (
600 ctx.builtins().types.alternating_list_generic_b,
601 ctx.builtins().types.signature,
602 ),
603 ]);
604
605 let ty = rue_types::substitute_with_mappings(ctx.types_mut(), list, &mappings);
606
607 if let Some((value, expr)) = args.first() {
608 ctx.assign_type(expr.syntax(), value.ty, ty);
609 ctx.alloc_hir(Hir::ClvmOp(ClvmOp::BlsPairingIdentity, value.hir))
610 } else {
611 ctx.builtins().unresolved.hir
612 }
613 } else {
614 if args.len() % 2 != 0 {
615 ctx.diagnostic(call.syntax(), DiagnosticKind::ExpectedEvenArguments);
616 }
617
618 for (i, (value, expr)) in args.iter().enumerate() {
619 if i % 2 == 0 {
620 ctx.assign_type(expr.syntax(), value.ty, ctx.builtins().types.public_key);
621 } else {
622 ctx.assign_type(expr.syntax(), value.ty, ctx.builtins().types.signature);
623 }
624 }
625
626 ctx.alloc_hir(Hir::BlsPairingIdentity(
627 args.iter().map(|arg| arg.0.hir).collect(),
628 ))
629 };
630
631 Value::new(hir, ctx.builtins().types.nil)
632 }
633 Builtin::BlsVerify => {
634 let hir = if spread.is_some() {
635 if args.len() != 2 {
636 ctx.diagnostic(
637 call.syntax(),
638 DiagnosticKind::ExpectedArguments(2, args.len()),
639 );
640 }
641
642 let list = ctx.builtins().types.alternating_list;
643
644 let mappings = HashMap::from_iter([
645 (
646 ctx.builtins().types.alternating_list_generic_a,
647 ctx.builtins().types.public_key,
648 ),
649 (
650 ctx.builtins().types.alternating_list_generic_b,
651 ctx.builtins().types.bytes,
652 ),
653 ]);
654
655 let ty = rue_types::substitute_with_mappings(ctx.types_mut(), list, &mappings);
656
657 if args.len() == 2 {
658 ctx.assign_type(
659 args[0].1.syntax(),
660 args[0].0.ty,
661 ctx.builtins().types.signature,
662 );
663 ctx.assign_type(args[1].1.syntax(), args[1].0.ty, ty);
664
665 let pair = ctx.alloc_hir(Hir::Pair(args[0].0.hir, args[1].0.hir));
666 ctx.alloc_hir(Hir::ClvmOp(ClvmOp::BlsVerify, pair))
667 } else {
668 ctx.builtins().unresolved.hir
669 }
670 } else {
671 if args.is_empty() || args.len() % 2 != 1 {
672 ctx.diagnostic(
673 call.syntax(),
674 DiagnosticKind::ExpectedOneArgumentEvenAdditional,
675 );
676 }
677
678 for (i, (value, expr)) in args.iter().enumerate() {
679 if i == 0 {
680 ctx.assign_type(expr.syntax(), value.ty, ctx.builtins().types.signature);
681 } else if i % 2 == 1 {
682 ctx.assign_type(expr.syntax(), value.ty, ctx.builtins().types.public_key);
683 } else {
684 ctx.assign_type(expr.syntax(), value.ty, ctx.builtins().types.bytes);
685 }
686 }
687
688 if args.is_empty() {
689 ctx.builtins().unresolved.hir
690 } else {
691 ctx.alloc_hir(Hir::BlsVerify(
692 args[0].0.hir,
693 args.iter().skip(1).map(|arg| arg.0.hir).collect(),
694 ))
695 }
696 };
697
698 Value::new(hir, ctx.builtins().types.nil)
699 }
700 Builtin::Secp256K1Verify | Builtin::Secp256R1Verify => {
701 if args.len() != 3 {
702 ctx.diagnostic(
703 call.syntax(),
704 DiagnosticKind::ExpectedArguments(3, args.len()),
705 );
706 }
707
708 if let Some(spread) = &spread {
709 ctx.diagnostic(spread, DiagnosticKind::InvalidSpreadBuiltin);
710 }
711
712 let hir = if args.len() == 3 {
713 ctx.assign_type(
714 args[0].1.syntax(),
715 args[0].0.ty,
716 match builtin {
717 Builtin::Secp256K1Verify => ctx.builtins().types.k1_public_key,
718 Builtin::Secp256R1Verify => ctx.builtins().types.r1_public_key,
719 _ => unreachable!(),
720 },
721 );
722 ctx.assign_type(
723 args[1].1.syntax(),
724 args[1].0.ty,
725 ctx.builtins().types.bytes32,
726 );
727 ctx.assign_type(
728 args[2].1.syntax(),
729 args[2].0.ty,
730 match builtin {
731 Builtin::Secp256K1Verify => ctx.builtins().types.k1_signature,
732 Builtin::Secp256R1Verify => ctx.builtins().types.r1_signature,
733 _ => unreachable!(),
734 },
735 );
736
737 match builtin {
738 Builtin::Secp256K1Verify => ctx.alloc_hir(Hir::Secp256K1Verify(
739 args[0].0.hir,
740 args[1].0.hir,
741 args[2].0.hir,
742 )),
743 Builtin::Secp256R1Verify => ctx.alloc_hir(Hir::Secp256R1Verify(
744 args[0].0.hir,
745 args[1].0.hir,
746 args[2].0.hir,
747 )),
748 _ => unreachable!(),
749 }
750 } else {
751 ctx.builtins().unresolved.hir
752 };
753
754 Value::new(hir, ctx.builtins().types.nil)
755 }
756 }
757}