rukalang/elab/
elaborate_intrinsics.rs1use super::prelude::*;
2
3impl Elaborator {
4 pub(super) fn elaborate_intrinsic_call_expr(
6 &mut self,
7 name: &str,
8 args: &mut [CallArg],
9 locals: &mut Vec<(String, Ty)>,
10 ) -> Result<Ty, ElabError> {
11 let intrinsic = IntrinsicId::parse(name);
12 if let Some(signature) = intrinsic.signature()
13 && (args.len() != signature.type_args + signature.value_args)
14 {
15 return Err(ElabError::ArityMismatch {
16 function: format!("@{}", intrinsic.name()),
17 expected: signature.type_args + signature.value_args,
18 actual: args.len(),
19 });
20 }
21
22 match intrinsic {
23 IntrinsicId::Box => {
24 let CallArg::Expr(value) = &mut args[0] else {
25 return Err(ElabError::UnsupportedTypeExpr);
26 };
27 let inner_ty = self.elaborate_expr(value, None, locals)?;
28 Ok(Ty::Pointer(Box::new(inner_ty)))
29 }
30 IntrinsicId::Array => {
31 let CallArg::Expr(init_expr) = &mut args[0] else {
32 return Err(ElabError::UnsupportedTypeExpr);
33 };
34 let item_ty = self.elaborate_expr(init_expr, None, locals)?;
35 let CallArg::Expr(len_expr) = &mut args[1] else {
36 return Err(ElabError::UnsupportedTypeExpr);
37 };
38 let len_ty = self.elaborate_expr(len_expr, None, locals)?;
39 if !len_ty.is_integer() {
40 return Err(ElabError::TypeMismatch {
41 expected: Ty::I64,
42 actual: len_ty,
43 });
44 }
45 Ok(Ty::Slice(Box::new(item_ty)))
46 }
47 IntrinsicId::As
48 | IntrinsicId::IntCast
49 | IntrinsicId::IntToFloat
50 | IntrinsicId::Trunc => {
51 let CallArg::Type(target_ty_expr) = &args[0] else {
52 return Err(ElabError::UnsupportedTypeExpr);
53 };
54 let target_ty = self.resolve_type_expr(
55 target_ty_expr,
56 &BTreeMap::new(),
57 &BTreeSet::new(),
58 None,
59 )?;
60 let CallArg::Expr(value_expr) = &mut args[1] else {
61 return Err(ElabError::UnsupportedTypeExpr);
62 };
63 let source_ty = self.elaborate_expr(value_expr, None, locals)?;
64 match intrinsic {
65 IntrinsicId::As => {
66 if !can_safely_coerce_numeric(&source_ty, &target_ty) {
67 return Err(ElabError::TypeMismatch {
68 expected: target_ty,
69 actual: source_ty,
70 });
71 }
72 }
73 IntrinsicId::IntCast => {
74 if !(source_ty.is_integer() && target_ty.is_integer()) {
75 return Err(ElabError::TypeMismatch {
76 expected: target_ty,
77 actual: source_ty,
78 });
79 }
80 }
81 IntrinsicId::IntToFloat => {
82 if !(source_ty.is_integer() && target_ty.is_float()) {
83 return Err(ElabError::TypeMismatch {
84 expected: target_ty,
85 actual: source_ty,
86 });
87 }
88 }
89 IntrinsicId::Trunc => {
90 if !is_truncation_cast(&source_ty, &target_ty) {
91 return Err(ElabError::TypeMismatch {
92 expected: target_ty,
93 actual: source_ty,
94 });
95 }
96 }
97 _ => unreachable!("non-cast intrinsic matched cast branch"),
98 }
99 Ok(target_ty)
100 }
101 IntrinsicId::Unknown(name) => Err(ElabError::UnknownFunction {
102 name: format!("@{name}"),
103 }),
104 }
105 }
106}