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