rue_compiler/compile/expr/
function_call.rs

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