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::{FunctionCall, Hir, Value};
7use rue_types::{Type, Union, substitute_with_mappings};
8
9use crate::{Compiler, compile_expr};
10
11pub fn compile_function_call_expr(ctx: &mut Compiler, call: &AstFunctionCallExpr) -> Value {
12    let Some(expr) = call.expr() else {
13        debug!("Unresolved function call expr");
14        return ctx.builtins().unresolved.clone();
15    };
16
17    let expr = compile_expr(ctx, &expr, None);
18
19    let expected_functions = rue_types::extract_functions(ctx.types_mut(), expr.ty);
20
21    if expected_functions.len() > 1 {
22        let name = ctx.type_name(expr.ty);
23        ctx.diagnostic(
24            call.syntax(),
25            DiagnosticKind::CannotDisambiguateFunctionTypes(name),
26        );
27    }
28
29    if expected_functions.is_empty() {
30        let name = ctx.type_name(expr.ty);
31        ctx.diagnostic(call.syntax(), DiagnosticKind::InvalidFunctionCall(name));
32    }
33
34    let expected_function = expected_functions.first();
35
36    let mut args = Vec::new();
37    let mut nil_terminated = true;
38    let mut next_spreadable_type = None;
39    let mut mappings = HashMap::new();
40
41    let len = call.args().count();
42
43    for (i, arg) in call.args().enumerate() {
44        let is_spread = if let Some(spread) = arg.spread() {
45            if i == len - 1 {
46                if let Some(function) = expected_function {
47                    if function.nil_terminated {
48                        ctx.diagnostic(&spread, DiagnosticKind::InvalidSpread);
49                    } else {
50                        nil_terminated = false;
51                    }
52                }
53                true
54            } else {
55                ctx.diagnostic(&spread, DiagnosticKind::NonFinalSpread);
56                false
57            }
58        } else {
59            false
60        };
61
62        let expected_type = if let Some(function) = expected_function {
63            if function.nil_terminated || i < function.params.len() - 1 {
64                function.params.get(i).copied()
65            } else {
66                if next_spreadable_type.is_none() {
67                    next_spreadable_type = Some(function.params.last().copied());
68                }
69
70                match next_spreadable_type {
71                    None => unreachable!(),
72                    Some(Some(ty)) if is_spread => {
73                        next_spreadable_type = None;
74                        Some(ty)
75                    }
76                    Some(Some(ty)) => {
77                        let pairs = rue_types::extract_pairs(ctx.types_mut(), ty);
78
79                        if pairs.is_empty() {
80                            next_spreadable_type = None;
81                            None
82                        } else if pairs.len() == 1 {
83                            next_spreadable_type = Some(Some(pairs[0].rest));
84
85                            Some(pairs[0].first)
86                        } else {
87                            next_spreadable_type = Some(Some(ctx.alloc_type(Type::Union(
88                                Union::new(pairs.iter().map(|pair| pair.rest).collect()),
89                            ))));
90
91                            Some(ctx.alloc_type(Type::Union(Union::new(
92                                pairs.iter().map(|pair| pair.first).collect(),
93                            ))))
94                        }
95                    }
96                    Some(None) => None,
97                }
98            }
99        } else {
100            None
101        };
102
103        let expected_type = expected_type.map(|expected_type| {
104            substitute_with_mappings(ctx.types_mut(), expected_type, &mappings)
105        });
106
107        let value = if let Some(expr) = arg.expr() {
108            let value = compile_expr(ctx, &expr, expected_type);
109
110            if let Some(expected_type) = expected_type {
111                ctx.infer_type(arg.syntax(), value.ty, expected_type, &mut mappings);
112            }
113
114            value
115        } else {
116            debug!("Unresolved function call arg");
117            ctx.builtins().unresolved.clone()
118        };
119
120        args.push(value.hir);
121    }
122
123    let ty = if expected_functions.is_empty() {
124        debug!("Unresolved function call return type due to unresolved function type");
125        ctx.builtins().unresolved.ty
126    } else if expected_functions.len() == 1 {
127        let function = expected_functions[0].clone();
128
129        if !function.nil_terminated {
130            if args.len() < function.params.len().saturating_sub(1) {
131                ctx.diagnostic(
132                    call.syntax(),
133                    DiagnosticKind::ExpectedArgumentsBeforeSpread(
134                        function.params.len(),
135                        args.len(),
136                    ),
137                );
138            }
139        } else if args.len() != function.params.len() {
140            ctx.diagnostic(
141                call.syntax(),
142                DiagnosticKind::ExpectedArgumentsExact(function.params.len(), args.len()),
143            );
144        }
145
146        function.ret
147    } else {
148        ctx.alloc_type(Type::Union(Union::new(
149            expected_functions
150                .iter()
151                .map(|function| function.ret)
152                .collect(),
153        )))
154    };
155
156    let ty = substitute_with_mappings(ctx.types_mut(), ty, &mappings);
157
158    let hir = ctx.alloc_hir(Hir::FunctionCall(FunctionCall {
159        function: expr.hir,
160        args,
161        nil_terminated,
162    }));
163
164    Value::new(hir, ty)
165}