rue_compiler/compile/expr/
lambda.rs1use log::debug;
2use rue_ast::{AstLambdaExpr, AstNode};
3use rue_diagnostic::DiagnosticKind;
4use rue_hir::{FunctionSymbol, Hir, ParameterSymbol, Scope, Symbol, Value};
5use rue_types::{FunctionType, Type, TypeId, Union};
6
7use crate::{Compiler, compile_expr, compile_type};
8
9pub fn compile_lambda_expr(
10 ctx: &mut Compiler,
11 expr: &AstLambdaExpr,
12 expected_type: Option<TypeId>,
13) -> Value {
14 let expected_functions = if let Some(ty) = expected_type {
15 rue_types::extract_functions(ctx.types_mut(), ty)
16 } else {
17 vec![]
18 };
19
20 let scope = ctx.alloc_scope(Scope::new());
21
22 ctx.push_scope(scope);
23
24 let mut parameters = Vec::new();
25 let mut params = Vec::new();
26 let mut nil_terminated = true;
27
28 let len = expr.parameters().count();
29
30 for (i, param) in expr.parameters().enumerate() {
31 let is_spread = if let Some(spread) = param.spread() {
32 if i == len - 1 {
33 true
34 } else {
35 ctx.diagnostic(&spread, DiagnosticKind::NonFinalSpread);
36 false
37 }
38 } else {
39 false
40 };
41
42 if is_spread {
43 nil_terminated = false;
44 }
45
46 let ty = if let Some(ty) = param.ty() {
47 compile_type(ctx, &ty)
48 } else if !expected_functions.is_empty()
49 && let params = expected_functions
50 .iter()
51 .filter_map(|function| function.params.get(i).copied())
52 .collect::<Vec<_>>()
53 && !params.is_empty()
54 {
55 if params.len() == 1 {
56 params[0]
57 } else {
58 ctx.alloc_type(Type::Union(Union::new(params)))
59 }
60 } else {
61 debug!("Unresolved lambda parameter type due to missing inference");
62 ctx.diagnostic(
63 param.syntax(),
64 DiagnosticKind::CannotInferParameterType(param.name().unwrap().text().to_string()),
65 );
66 ctx.builtins().unresolved.ty
67 };
68
69 let symbol = ctx.alloc_symbol(Symbol::Parameter(ParameterSymbol {
70 name: param.name(),
71 ty,
72 }));
73
74 if let Some(name) = param.name() {
75 if ctx.last_scope().symbol(name.text()).is_some() {
76 ctx.diagnostic(
77 &name,
78 DiagnosticKind::DuplicateSymbol(name.text().to_string()),
79 );
80 }
81
82 ctx.last_scope_mut()
83 .insert_symbol(name.text().to_string(), symbol, false);
84 }
85
86 parameters.push(symbol);
87 params.push(ty);
88 }
89
90 let return_type = expr.ty().map(|ty| compile_type(ctx, &ty));
91
92 let body = if let Some(body) = expr.body() {
93 let result = compile_expr(ctx, &body, return_type);
94 if let Some(return_type) = return_type {
95 ctx.assign_type(expr.syntax(), result.ty, return_type);
96 }
97 result
98 } else {
99 debug!("Unresolved lambda body");
100 ctx.builtins().unresolved.clone()
101 };
102
103 let return_type = return_type.unwrap_or(body.ty);
104
105 let ty = ctx.alloc_type(Type::Function(FunctionType {
106 params,
107 nil_terminated,
108 ret: return_type,
109 }));
110
111 ctx.pop_scope();
112
113 let symbol = ctx.alloc_symbol(Symbol::Function(FunctionSymbol {
114 name: None,
115 ty,
116 scope,
117 vars: vec![],
118 parameters,
119 nil_terminated,
120 return_type,
121 body: body.hir,
122 inline: false,
123 }));
124
125 let hir = ctx.alloc_hir(Hir::Lambda(symbol));
126
127 Value::new(hir, ty)
128}