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, ¶m) 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}