• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TyRoXx / NonlocalityOS / 16847634528

09 Aug 2025 08:54AM UTC coverage: 76.756% (-0.02%) from 76.779%
16847634528

push

github

TyRoXx
GH-306: cargo update

4131 of 5382 relevant lines covered (76.76%)

2249.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.79
/lambda_compiler/src/type_checking.rs
1
use crate::{
2
    ast::{self, LambdaParameter},
3
    compilation::{CompilerError, CompilerOutput, SourceLocation},
4
};
5
use astraea::{
6
    deep_tree::DeepTree,
7
    storage::StoreError,
8
    tree::{ReferenceIndex, TreeBlob},
9
};
10
use lambda::{
11
    expressions::{DeepExpression, Expression},
12
    name::{Name, NamespaceId},
13
};
14
use pretty_assertions::assert_eq;
15
use serde::{Deserialize, Serialize};
16
use std::{collections::BTreeMap, sync::Arc};
17

18
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
19
pub enum GenericType<T>
20
where
21
    T: Clone,
22
{
23
    Any,
24
    String,
25
    TreeWithKnownChildTypes(Vec<T>),
26
    Function {
27
        parameters: Vec<T>,
28
        return_type: Box<T>,
29
    },
30
    Type,
31
    Named(Name),
32
    Integer,
33
}
34

35
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone)]
36
pub struct DeepType(pub GenericType<DeepType>);
37

38
pub fn to_reference_type(deep_type: &DeepType) -> (GenericType<ReferenceIndex>, Vec<DeepType>) {
206✔
39
    match deep_type.0 {
206✔
40
        GenericType::Any => (GenericType::Any, Vec::new()),
3✔
41
        GenericType::String => (GenericType::String, Vec::new()),
57✔
42
        GenericType::TreeWithKnownChildTypes(ref children) => (
1✔
43
            GenericType::TreeWithKnownChildTypes(
1✔
44
                (0u64..(children.len() as u64))
1✔
45
                    .map(ReferenceIndex)
1✔
46
                    .collect(),
1✔
47
            ),
48
            children.clone(),
1✔
49
        ),
50
        GenericType::Function {
51
            ref parameters,
1✔
52
            ref return_type,
1✔
53
        } => {
1✔
54
            let mut parameters_references = Vec::new();
1✔
55
            let mut children = Vec::new();
1✔
56
            for (index, parameter) in parameters.iter().enumerate() {
3✔
57
                parameters_references.push(ReferenceIndex(index as u64));
58
                children.push(parameter.clone());
59
            }
60
            let return_type_reference = ReferenceIndex(children.len() as u64);
1✔
61
            children.push(return_type.as_ref().clone());
1✔
62
            (
63
                GenericType::Function {
1✔
64
                    parameters: parameters_references,
1✔
65
                    return_type: Box::new(return_type_reference),
1✔
66
                },
67
                children,
1✔
68
            )
69
        }
70
        GenericType::Type => (GenericType::Type, Vec::new()),
48✔
71
        GenericType::Named(ref name) => (GenericType::Named(name.clone()), Vec::new()),
48✔
72
        GenericType::Integer => (GenericType::Integer, Vec::new()),
48✔
73
    }
74
}
75

76
pub fn type_to_deep_tree(deep_type: &DeepType) -> DeepTree {
206✔
77
    let (body, children) = to_reference_type(deep_type);
206✔
78
    let body_serialized = postcard::to_allocvec(&body).unwrap(/*TODO*/);
206✔
79
    DeepTree::new(
80
        TreeBlob::try_from(bytes::Bytes::from( body_serialized)).unwrap(/*TODO*/),
206✔
81
        children.iter().map(type_to_deep_tree).collect(),
206✔
82
    )
83
}
84

85
pub fn from_reference_type(body: &GenericType<ReferenceIndex>, children: &[DeepType]) -> DeepType {
27✔
86
    match body {
27✔
87
        GenericType::Any => DeepType(GenericType::Any),
×
88
        GenericType::String => DeepType(GenericType::String),
21✔
89
        GenericType::TreeWithKnownChildTypes(ref children_references) => {
1✔
90
            let mut resulting_children = Vec::new();
1✔
91
            for reference in children_references {
5✔
92
                let index = reference.0 as usize;
2✔
93
                if index < children.len() {
4✔
94
                    resulting_children.push(children[index].clone());
2✔
95
                } else {
96
                    // TODO error handling
97
                    // This should not happen if the tree is well-formed.
98
                    panic!("Reference index out of bounds: {index}");
99
                }
100
            }
101
            DeepType(GenericType::TreeWithKnownChildTypes(resulting_children))
1✔
102
        }
103
        GenericType::Function {
104
            ref parameters,
1✔
105
            ref return_type,
1✔
106
        } => {
1✔
107
            let mut resulting_parameters = Vec::new();
1✔
108
            for reference in parameters {
5✔
109
                let index: usize = reference.0.try_into().expect("TODO");
2✔
110
                if index < children.len() {
4✔
111
                    resulting_parameters.push(children[index].clone());
2✔
112
                } else {
113
                    // TODO error handling
114
                    // This should not happen if the tree is well-formed.
115
                    panic!("Reference index out of bounds: {index}");
116
                }
117
            }
118
            let resulting_return_type = {
1✔
119
                let index: usize = return_type.0.try_into().expect("TODO");
1✔
120
                if index < children.len() {
1✔
121
                    children[index].clone()
1✔
122
                } else {
123
                    // TODO error handling
124
                    panic!("Reference index out of bounds: {index}");
125
                }
126
            };
127
            DeepType(GenericType::Function {
1✔
128
                parameters: resulting_parameters,
1✔
129
                return_type: Box::new(resulting_return_type),
1✔
130
            })
131
        }
132
        GenericType::Type => DeepType(GenericType::Type),
1✔
133
        GenericType::Named(ref name) => DeepType(GenericType::Named(name.clone())),
2✔
134
        GenericType::Integer => DeepType(GenericType::Integer),
1✔
135
    }
136
}
137

138
pub fn type_from_deep_tree(deep_tree: &DeepTree) -> DeepType {
27✔
139
    let body: GenericType<ReferenceIndex> =
27✔
140
        postcard::from_bytes(deep_tree.blob().as_slice()).unwrap(/*TODO*/);
27✔
141
    let children: Vec<_> = deep_tree
27✔
142
        .references()
143
        .iter()
144
        .map(type_from_deep_tree)
27✔
145
        .collect();
146
    from_reference_type(&body, &children)
27✔
147
}
148

149
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
150
pub struct TypedExpression {
151
    pub expression: DeepExpression,
152
    pub type_: DeepType,
153
}
154

155
impl TypedExpression {
156
    pub fn new(expression: DeepExpression, type_: DeepType) -> Self {
420✔
157
        Self { expression, type_ }
158
    }
159
}
160

161
async fn check_tree_construction_or_argument_list(
29✔
162
    arguments: &[ast::Expression],
163
    environment_builder: &mut EnvironmentBuilder,
164
) -> Result<(CompilerOutput, Option<DeepTree>), StoreError> {
165
    let mut errors = Vec::new();
29✔
166
    let mut checked_arguments = Vec::new();
29✔
167
    let mut argument_types = Vec::new();
29✔
168
    for argument in arguments {
121✔
169
        let output = check_types(argument, environment_builder).await?;
92✔
170
        errors.extend(output.0.errors);
171
        if let Some(checked) = output.0.entry_point {
46✔
172
            checked_arguments.push(Arc::new(checked.expression));
173
            argument_types.push(checked.type_);
174
        } else {
175
            return Ok((CompilerOutput::new(None, errors), None));
×
176
        }
177
    }
178
    Ok((
29✔
179
        CompilerOutput {
29✔
180
            entry_point: Some(TypedExpression::new(
29✔
181
                lambda::expressions::DeepExpression(
29✔
182
                    lambda::expressions::Expression::ConstructTree(checked_arguments),
29✔
183
                ),
184
                DeepType(GenericType::TreeWithKnownChildTypes(argument_types)),
29✔
185
            )),
186
            errors,
29✔
187
        },
188
        /*TODO: support compile time tree construction*/ None,
29✔
189
    ))
190
}
191

192
#[derive(Debug, Clone, Copy)]
193
enum ParameterIndex {
194
    SingleParameter,
195
    GetChild(u16),
196
}
197

198
impl ParameterIndex {
199
    pub fn create_deep_expression(&self) -> lambda::expressions::DeepExpression {
63✔
200
        match self {
63✔
201
            ParameterIndex::SingleParameter => {
202
                lambda::expressions::DeepExpression(lambda::expressions::Expression::make_argument())
45✔
203
            }
204
            ParameterIndex::GetChild(index) => lambda::expressions::DeepExpression(
205
                lambda::expressions::Expression::make_get_child(
18✔
206
                    Arc::new(lambda::expressions::DeepExpression(
18✔
207
                        lambda::expressions::Expression::make_argument(),
18✔
208
                    )),
209
                    *index,
18✔
210
                ),
211
            ),
212
        }
213
    }
214
}
215

216
#[derive(Debug, Clone)]
217
struct LocalVariable {
218
    parameter_index: ParameterIndex,
219
    type_: DeepType,
220
    compile_time_value: Option<DeepTree>,
221
}
222

223
impl LocalVariable {
224
    pub fn new(
359✔
225
        parameter_index: ParameterIndex,
226
        type_: DeepType,
227
        compile_time_value: Option<DeepTree>,
228
    ) -> Self {
229
        Self {
230
            parameter_index,
231
            type_,
232
            compile_time_value,
233
        }
234
    }
235
}
236

237
#[derive(Debug, Clone)]
238
struct LambdaScope {
239
    names: BTreeMap<Name, LocalVariable>,
240
    captures: BTreeMap<TypedExpression, u16>,
241
}
242

243
impl LambdaScope {
244
    pub fn new_lambda_scope(parameters: &[TypeCheckedLambdaParameter]) -> Self {
80✔
245
        let mut names = BTreeMap::new();
80✔
246
        if parameters.len() == 1 {
128✔
247
            names.insert(
48✔
248
                parameters[0].name.clone(),
48✔
249
                LocalVariable::new(
48✔
250
                    ParameterIndex::SingleParameter,
48✔
251
                    parameters[0].type_.clone(),
48✔
252
                    parameters[0].compile_time_value.clone(),
48✔
253
                ),
254
            );
255
        } else {
256
            for (index, parameter) in parameters.iter().enumerate() {
55✔
257
                let checked_index: u16 = index.try_into().expect("TODO handle too many parameters");
258
                names.insert(
259
                    parameter.name.clone(),
260
                    LocalVariable::new(
261
                        ParameterIndex::GetChild(checked_index),
262
                        parameter.type_.clone(),
263
                        parameter.compile_time_value.clone(),
264
                    ),
265
                );
266
            }
267
        }
268
        Self {
269
            names,
270
            captures: BTreeMap::new(),
80✔
271
        }
272
    }
273

274
    pub fn new_constant_scope(name: Name, type_: DeepType, compile_time_value: DeepTree) -> Self {
288✔
275
        let mut names = BTreeMap::new();
288✔
276
        names.insert(
288✔
277
            name,
288✔
278
            LocalVariable::new(
288✔
279
                ParameterIndex::SingleParameter,
288✔
280
                type_.clone(),
288✔
281
                Some(compile_time_value),
288✔
282
            ),
283
        );
284
        Self {
285
            names,
286
            captures: BTreeMap::new(),
288✔
287
        }
288
    }
289

290
    pub fn find_parameter_index(
281✔
291
        &self,
292
        parameter_name: &Name,
293
    ) -> Option<(ParameterIndex, DeepType, Option<DeepTree>)> {
294
        self.names.get(parameter_name).map(|variable| {
376✔
295
            (
296
                variable.parameter_index,
95✔
297
                variable.type_.clone(),
95✔
298
                variable.compile_time_value.clone(),
95✔
299
            )
300
        })
301
    }
302

303
    pub fn capture(&mut self, expression: TypedExpression) -> CompilerOutput {
30✔
304
        let type_ = expression.type_.clone();
30✔
305
        let index = match self.captures.get(&expression) {
60✔
306
            Some(&already_exists) => already_exists,
10✔
307
            None => {
308
                let new_index = self
20✔
309
                    .captures
20✔
310
                    .len()
311
                    .try_into()
312
                    .expect("TODO handle too many captures");
313
                self.captures.insert(expression, new_index);
20✔
314
                new_index
20✔
315
            }
316
        };
317
        CompilerOutput::new(
318
            Some(TypedExpression::new(
30✔
319
                lambda::expressions::DeepExpression(
30✔
320
                    lambda::expressions::Expression::make_get_child(
30✔
321
                        Arc::new(DeepExpression(
30✔
322
                            lambda::expressions::Expression::make_environment(),
30✔
323
                        )),
324
                        index,
30✔
325
                    ),
326
                ),
327
                type_,
30✔
328
            )),
329
            Vec::new(),
30✔
330
        )
331
    }
332

333
    pub fn leave(self) -> Vec<TypedExpression> {
368✔
334
        let mut as_vec: Vec<(TypedExpression, u16)> = self.captures.into_iter().collect();
368✔
335
        as_vec.sort_by_key(|(_, index)| *index);
376✔
336
        // sanity check:
337
        for (expected_index, (_, actual_index)) in as_vec.iter().enumerate() {
386✔
338
            assert_eq!(expected_index, *actual_index as usize);
339
        }
340
        as_vec
368✔
341
            .into_iter()
342
            .map(|(expression, _)| expression)
386✔
343
            .collect()
344
    }
345
}
346

347
#[derive(Debug, Clone)]
348
pub struct EnvironmentBuilder {
349
    lambda_layers: Vec<LambdaScope>,
350
}
351

352
impl Default for EnvironmentBuilder {
353
    fn default() -> Self {
×
354
        Self::new()
×
355
    }
356
}
357

358
impl EnvironmentBuilder {
359
    pub fn new() -> Self {
48✔
360
        Self {
361
            lambda_layers: Vec::new(),
48✔
362
        }
363
    }
364

365
    pub fn is_empty(&self) -> bool {
48✔
366
        self.lambda_layers.is_empty()
48✔
367
    }
368

369
    pub fn enter_lambda_body(&mut self, parameters: &[TypeCheckedLambdaParameter]) {
80✔
370
        self.lambda_layers
80✔
371
            .push(LambdaScope::new_lambda_scope(parameters));
80✔
372
    }
373

374
    pub fn leave_lambda_body(&mut self) -> Vec<TypedExpression> {
368✔
375
        let top_scope = self.lambda_layers.pop().unwrap();
368✔
376
        top_scope.leave()
368✔
377
    }
378

379
    pub fn define_constant(&mut self, name: Name, type_: DeepType, compile_time_value: DeepTree) {
288✔
380
        self.lambda_layers.push(LambdaScope::new_constant_scope(
288✔
381
            name,
288✔
382
            type_,
288✔
383
            compile_time_value,
288✔
384
        ));
385
    }
386

387
    pub fn undefine_constant(&mut self) {
288✔
388
        let captures = self.leave_lambda_body();
288✔
389
        if !captures.is_empty() {
288✔
390
            todo!()
391
        }
392
    }
393

394
    pub fn read(
102✔
395
        &mut self,
396
        identifier: &Name,
397
        location: &SourceLocation,
398
    ) -> (CompilerOutput, Option<DeepTree>) {
399
        Self::read_down(&mut self.lambda_layers, identifier, location)
102✔
400
    }
401

402
    fn read_down(
281✔
403
        layers: &mut [LambdaScope],
404
        identifier: &Name,
405
        location: &SourceLocation,
406
    ) -> (CompilerOutput, Option<DeepTree>) {
407
        let layer_count = layers.len();
281✔
408
        if let Some(last) = layers.last_mut() {
562✔
409
            if let Some((parameter_index, parameter_type, compile_time_value)) =
95✔
410
                last.find_parameter_index(identifier)
411
            {
412
                return match compile_time_value {
413
                    Some(value) => (
32✔
414
                        CompilerOutput::new(
32✔
415
                            Some(TypedExpression::new(
32✔
416
                                DeepExpression(lambda::expressions::Expression::make_literal(
32✔
417
                                    value.clone(),
32✔
418
                                )),
419
                                parameter_type,
32✔
420
                            )),
421
                            Vec::new(),
32✔
422
                        ),
423
                        Some(value),
32✔
424
                    ),
425
                    None => (
63✔
426
                        CompilerOutput::new(
63✔
427
                            Some(TypedExpression::new(
63✔
428
                                parameter_index.create_deep_expression(),
63✔
429
                                parameter_type,
63✔
430
                            )),
431
                            Vec::new(),
63✔
432
                        ),
433
                        None,
63✔
434
                    ),
435
                };
436
            } else if layer_count > 1 {
186✔
437
                let result = Self::read_down(&mut layers[..layer_count - 1], identifier, location);
179✔
438
                return match result.0.entry_point {
179✔
439
                    Some(success) => match result.1 {
143✔
440
                        Some(compile_time_value) => (
113✔
441
                            CompilerOutput::new(
113✔
442
                                Some(TypedExpression::new(
113✔
443
                                    DeepExpression(Expression::Literal(compile_time_value.clone())),
113✔
444
                                    success.type_,
113✔
445
                                )),
446
                                result.0.errors,
113✔
447
                            ),
448
                            Some(compile_time_value),
113✔
449
                        ),
450
                        None => {
451
                            let mut errors = result.0.errors;
30✔
452
                            let captured = layers.last_mut().unwrap().capture(success);
30✔
453
                            errors.extend(captured.errors);
30✔
454
                            (CompilerOutput::new(captured.entry_point, errors), None)
30✔
455
                        }
456
                    },
457
                    None => result,
36✔
458
                };
459
            }
460
        }
461
        (
462
            CompilerOutput::new(
7✔
463
                None,
7✔
464
                vec![crate::compilation::CompilerError::new(
7✔
465
                    format!("Identifier {identifier} not found"),
7✔
466
                    *location,
7✔
467
                )],
468
            ),
469
            None,
7✔
470
        )
471
    }
472
}
473

474
pub struct TypeCheckedLambdaParameter {
475
    pub name: Name,
476
    pub source_location: SourceLocation,
477
    pub type_: DeepType,
478
    pub compile_time_value: Option<DeepTree>,
479
}
480

481
impl TypeCheckedLambdaParameter {
482
    pub fn new(
19✔
483
        name: Name,
484
        source_location: SourceLocation,
485
        type_: DeepType,
486
        compile_time_value: Option<DeepTree>,
487
    ) -> Self {
488
        Self {
489
            name,
490
            source_location,
491
            type_,
492
            compile_time_value,
493
        }
494
    }
495
}
496

497
fn is_type(type_of_value: &DeepType) -> bool {
28✔
498
    match &type_of_value.0 {
28✔
499
        GenericType::Any => false,
1✔
500
        GenericType::String => false,
1✔
501
        GenericType::TreeWithKnownChildTypes(_items) => false,
1✔
502
        GenericType::Function {
503
            parameters: _,
504
            return_type: _,
505
        } => false,
1✔
506
        GenericType::Type => true,
23✔
507
        GenericType::Named(_name) => false,
1✔
508
        GenericType::Integer => false,
×
509
    }
510
}
511

512
struct WithCompilerErrors<T> {
513
    output: T,
514
    errors: Vec<CompilerError>,
515
}
516

517
impl<T> WithCompilerErrors<T> {
518
    pub fn new(output: T, errors: Vec<CompilerError>) -> Self {
61✔
519
        Self { output, errors }
520
    }
521
}
522

523
async fn check_lambda_parameters(
61✔
524
    parameters: &[LambdaParameter],
525
    environment_builder: &mut EnvironmentBuilder,
526
) -> Result<WithCompilerErrors<Vec<TypeCheckedLambdaParameter>>, StoreError> {
527
    let mut checked_parameters = Vec::new();
61✔
528
    let mut errors: Vec<CompilerError> = Vec::new();
61✔
529
    for parameter in parameters {
165✔
530
        let parameter_type: DeepType = match &parameter.type_annotation {
104✔
531
            Some(type_annotation) => {
29✔
532
                let checked_type = check_types(type_annotation, environment_builder).await?;
58✔
533
                errors.extend(checked_type.0.errors);
534
                if let Some(checked) = checked_type.0.entry_point {
28✔
535
                    if is_type(&checked.type_) {
536
                        match checked_type.1 {
23✔
537
                            Some(compile_time_value) => type_from_deep_tree(&compile_time_value),
22✔
538
                            None => {
539
                                errors.push(CompilerError::new(
1✔
540
                                    "Type annotation must be a compile time constant".to_string(),
1✔
541
                                    parameter.source_location,
1✔
542
                                ));
543
                                // Fallback to Any if the type is not valid.
544
                                DeepType(GenericType::Any)
1✔
545
                            }
546
                        }
547
                    } else {
548
                        errors.push(CompilerError::new(
5✔
549
                            "Type annotation must be a type".to_string(),
5✔
550
                            parameter.source_location,
5✔
551
                        ));
552
                        // Fallback to Any if the type is not valid.
553
                        DeepType(GenericType::Any)
5✔
554
                    }
555
                } else {
556
                    // Fallback to Any if the type is not valid.
557
                    DeepType(GenericType::Any)
1✔
558
                }
559
            }
560
            None => {
561
                // If no type annotation is provided, we assume the type is `Any`.
562
                DeepType(GenericType::Any)
23✔
563
            }
564
        };
565
        checked_parameters.push(TypeCheckedLambdaParameter {
566
            name: parameter.name.clone(),
567
            source_location: parameter.source_location,
568
            type_: parameter_type,
569
            compile_time_value: None, // TODO?
570
        });
571
    }
572
    Ok(WithCompilerErrors::new(checked_parameters, errors))
61✔
573
}
574

575
pub async fn check_lambda(
61✔
576
    parameters: &[LambdaParameter],
577
    body: &ast::Expression,
578
    environment_builder: &mut EnvironmentBuilder,
579
) -> Result<CompilerOutput, StoreError> {
580
    let checked_parameters = check_lambda_parameters(parameters, environment_builder).await?;
122✔
581
    let mut errors = checked_parameters.errors;
582
    environment_builder.enter_lambda_body(&checked_parameters.output[..]);
583
    let body_result = check_types(body, environment_builder).await;
61✔
584
    // TODO: use RAII or something?
585
    let environment = environment_builder.leave_lambda_body();
61✔
586
    let environment_expressions = environment
61✔
587
        .into_iter()
588
        .map(|typed_expression| Arc::new(typed_expression.expression))
73✔
589
        .collect();
590
    let body_output = body_result?;
122✔
591
    errors.extend(body_output.0.errors);
592
    match body_output.0.entry_point {
593
        Some(body_checked) => Ok(CompilerOutput {
60✔
594
            entry_point: Some(TypedExpression::new(
60✔
595
                lambda::expressions::DeepExpression(lambda::expressions::Expression::Lambda {
60✔
596
                    environment: Arc::new(DeepExpression(Expression::make_construct_tree(
60✔
597
                        environment_expressions,
60✔
598
                    ))),
599
                    body: Arc::new(body_checked.expression),
60✔
600
                }),
601
                DeepType(GenericType::Function {
60✔
602
                    parameters: checked_parameters
60✔
603
                        .output
60✔
604
                        .into_iter()
60✔
605
                        .map(|parameter| parameter.type_)
111✔
606
                        .collect(),
60✔
607
                    return_type: Box::new(body_checked.type_),
60✔
608
                }),
609
            )),
610
            errors,
60✔
611
        }),
612
        None => Ok(CompilerOutput::new(None, errors)),
1✔
613
    }
614
}
615

616
pub async fn check_let(
21✔
617
    name: &Name,
618
    location: &SourceLocation,
619
    value: &ast::Expression,
620
    body: &ast::Expression,
621
    environment_builder: &mut EnvironmentBuilder,
622
) -> Result<CompilerOutput, StoreError> {
623
    let value_checked = check_types(value, environment_builder).await?;
42✔
624
    let value_checked_unwrapped = match value_checked.0.entry_point {
19✔
625
        Some(success) => success,
19✔
626
        None => return Ok(value_checked.0),
2✔
627
    };
628
    let checked_parameters = [TypeCheckedLambdaParameter::new(
19✔
629
        name.clone(),
19✔
630
        *location,
19✔
631
        value_checked_unwrapped.type_.clone(),
19✔
632
        value_checked.1,
19✔
633
    )];
634
    environment_builder.enter_lambda_body(&checked_parameters[..]);
19✔
635
    let body_result = check_types(body, environment_builder).await;
38✔
636
    // TODO: use RAII or something?
637
    let environment = environment_builder.leave_lambda_body();
19✔
638
    let environment_expressions = environment
19✔
639
        .into_iter()
640
        .map(|typed_expression| Arc::new(typed_expression.expression))
25✔
641
        .collect();
642
    let body_output = body_result?;
38✔
643
    match body_output.0.entry_point {
644
        Some(body_checked) => Ok(CompilerOutput {
18✔
645
            entry_point: Some(TypedExpression::new(
18✔
646
                lambda::expressions::DeepExpression(lambda::expressions::Expression::make_apply(
18✔
647
                    Arc::new(lambda::expressions::DeepExpression(
18✔
648
                        lambda::expressions::Expression::Lambda {
18✔
649
                            environment: Arc::new(DeepExpression(Expression::make_construct_tree(
18✔
650
                                environment_expressions,
18✔
651
                            ))),
652
                            body: Arc::new(body_checked.expression),
18✔
653
                        },
654
                    )),
655
                    Arc::new(value_checked_unwrapped.expression),
18✔
656
                )),
657
                body_checked.type_,
18✔
658
            )),
659
            errors: body_output.0.errors,
18✔
660
        }),
661
        None => Ok(CompilerOutput::new(None, body_output.0.errors)),
1✔
662
    }
663
}
664

665
async fn check_type_of(
7✔
666
    expression: &ast::Expression,
667
    environment_builder: &mut EnvironmentBuilder,
668
) -> Result<(CompilerOutput, Option<DeepTree>), StoreError> {
669
    // Copy environment builder to prevent captures by unevaluated expressions.
670
    // TODO: make this more efficient (clone could be expensive).
671
    let mut unevaluated_context = environment_builder.clone();
7✔
672
    let checked_expression = check_types(expression, &mut unevaluated_context).await?;
14✔
673
    drop(unevaluated_context);
674

675
    let type_ = match checked_expression.0.entry_point {
6✔
676
        Some(success) => success.type_,
6✔
677
        None => {
678
            assert!(!checked_expression.0.errors.is_empty());
679
            return Ok((CompilerOutput::new(None, checked_expression.0.errors), None));
1✔
680
        }
681
    };
682
    let errors = checked_expression.0.errors;
6✔
683
    let type_as_tree = type_to_deep_tree(&type_);
6✔
684
    Ok((
6✔
685
        CompilerOutput::new(
6✔
686
            Some(TypedExpression::new(
6✔
687
                lambda::expressions::DeepExpression(lambda::expressions::Expression::Literal(
6✔
688
                    type_as_tree.clone(),
6✔
689
                )),
690
                DeepType(GenericType::Type),
6✔
691
            )),
692
            errors,
6✔
693
        ),
694
        Some(type_as_tree),
6✔
695
    ))
696
}
697

698
pub fn convert_implicitly(from: &DeepType, to: &DeepType) -> bool {
47✔
699
    match (&from.0, &to.0) {
47✔
700
        (_, GenericType::Any) => true,
12✔
701
        (GenericType::String, GenericType::String) => true,
15✔
702
        (
703
            GenericType::TreeWithKnownChildTypes(from_children),
3✔
704
            GenericType::TreeWithKnownChildTypes(to_children),
3✔
705
        ) => {
3✔
706
            if from_children.len() != to_children.len() {
3✔
707
                return false;
1✔
708
            }
709
            from_children
2✔
710
                .iter()
711
                .zip(to_children.iter())
2✔
712
                .all(|(from_child, to_child)| convert_implicitly(from_child, to_child))
5✔
713
        }
714
        (
715
            GenericType::Function {
716
                parameters: from_params,
7✔
717
                return_type: from_return,
7✔
718
            },
719
            GenericType::Function {
7✔
720
                parameters: to_params,
7✔
721
                return_type: to_return,
7✔
722
            },
723
        ) => {
7✔
724
            if from_params.len() != to_params.len() {
7✔
725
                return false;
1✔
726
            }
727
            from_params
6✔
728
                .iter()
6✔
729
                .zip(to_params.iter())
6✔
730
                .all(|(from_param, to_param)| convert_implicitly(to_param, from_param))
11✔
731
                && convert_implicitly(from_return.as_ref(), to_return.as_ref())
5✔
732
        }
733
        (GenericType::Type, GenericType::Type) => true,
1✔
734
        (GenericType::Named(from_name), GenericType::Named(to_name)) => from_name == to_name,
2✔
735
        (GenericType::Integer, GenericType::Integer) => true,
1✔
736
        _ => false,
6✔
737
    }
738
}
739

740
async fn check_integer_literal(
3✔
741
    value: i64,
742
) -> Result<(CompilerOutput, Option<DeepTree>), StoreError> {
743
    let serialized = postcard::to_allocvec(&value).unwrap(/*TODO*/);
3✔
744
    let tree = DeepTree::new(
745
        TreeBlob::try_from(bytes::Bytes::from(serialized)).expect("an integer will always fit"),
3✔
746
        vec![],
3✔
747
    );
748
    Ok((
3✔
749
        CompilerOutput::new(
3✔
750
            Some(TypedExpression::new(
3✔
751
                DeepExpression(lambda::expressions::Expression::Literal(tree.clone())),
3✔
752
                DeepType(GenericType::Integer),
3✔
753
            )),
754
            vec![],
3✔
755
        ),
756
        Some(tree),
3✔
757
    ))
758
}
759

760
pub async fn check_types(
270✔
761
    syntax_tree: &ast::Expression,
762
    environment_builder: &mut EnvironmentBuilder,
763
) -> Result<(CompilerOutput, Option<DeepTree>), StoreError> {
764
    Box::pin(async move {
540✔
765
        match syntax_tree {
270✔
766
            ast::Expression::Identifier(name, location) => {
102✔
767
                Ok(environment_builder.read(name, location))
102✔
768
            }
769
            ast::Expression::StringLiteral(value, source_location) => {
25✔
770
                let compile_time_value = match DeepTree::try_from_string(value) {
49✔
771
                    Some(tree) => tree,
24✔
772
                    None => {
773
                        return Ok((
1✔
774
                            CompilerOutput::new(
1✔
775
                                None,
1✔
776
                                vec![CompilerError::new(
1✔
777
                                    "String literal is too long".to_string(),
1✔
778
                                    *source_location,
1✔
779
                                )],
780
                            ),
781
                            None,
1✔
782
                        ))
783
                    }
784
                };
785
                Ok((
24✔
786
                    CompilerOutput::new(
24✔
787
                        Some(TypedExpression::new(
24✔
788
                            lambda::expressions::DeepExpression(
24✔
789
                                lambda::expressions::Expression::Literal(
24✔
790
                                    compile_time_value.clone(),
24✔
791
                                ),
792
                            ),
793
                            DeepType(GenericType::String),
24✔
794
                        )),
795
                        Vec::new(),
24✔
796
                    ),
797
                    Some(compile_time_value),
24✔
798
                ))
799
            }
800
            ast::Expression::Apply { callee, arguments } => {
17✔
801
                let callee_output = check_types(callee, environment_builder).await?;
34✔
802
                let argument_output = if arguments.len() == 1 {
17✔
803
                    // For N=1 we don't need an indirection.
804
                    check_types(&arguments[0], environment_builder).await?
9✔
805
                } else {
806
                    check_tree_construction_or_argument_list(&arguments[..], environment_builder)
8✔
807
                        .await?
8✔
808
                };
809
                let errors = callee_output
810
                    .0
811
                    .errors
812
                    .into_iter()
813
                    .chain(argument_output.0.errors)
814
                    .collect();
815
                match (callee_output.0.entry_point, argument_output.0.entry_point) {
816
                    (Some(callee_checked), Some(argument_checked)) => {
15✔
817
                        let (return_type, parameter_types) = match &callee_checked.type_.0 {
29✔
818
                            GenericType::Function {
819
                                return_type,
820
                                parameters,
821
                            } => (return_type.as_ref().clone(), parameters),
822
                            _ => {
823
                                return Ok((
1✔
824
                                    CompilerOutput::new(
1✔
825
                                        None,
1✔
826
                                        vec![crate::compilation::CompilerError::new(
1✔
827
                                            "Callee is not a function".to_string(),
1✔
828
                                            callee.source_location(),
1✔
829
                                        )],
830
                                    ),
831
                                    None,
1✔
832
                                ))
833
                            }
834
                        };
835
                        if parameter_types.len() != arguments.len() {
836
                            return Ok((
1✔
837
                                CompilerOutput::new(
1✔
838
                                    None,
1✔
839
                                    vec![CompilerError::new(
1✔
840
                                        format!(
1✔
841
                                            "Expected {} arguments, but got {}",
1✔
842
                                            parameter_types.len(),
1✔
843
                                            arguments.len()
1✔
844
                                        ),
845
                                        callee.source_location(),
1✔
846
                                    )],
847
                                ),
848
                                None,
1✔
849
                            ));
850
                        }
851
                        if parameter_types.len() == 1 {
13✔
852
                            if !convert_implicitly(&argument_checked.type_, &parameter_types[0]) {
5✔
853
                                return Ok((
1✔
854
                                    CompilerOutput::new(
1✔
855
                                        None,
1✔
856
                                        vec![CompilerError::new(
1✔
857
                                            format!(
1✔
858
                                                "Argument type '{:?}' is not convertible into parameter type '{:?}'",
1✔
859
                                                argument_checked.type_, parameter_types[0]
1✔
860
                                            ),
861
                                            arguments[0].source_location(),
1✔
862
                                        )],
863
                                    ),
864
                                    None,
1✔
865
                                ));
866
                            }
867
                        } else {
868
                            match argument_checked.type_.0 {
8✔
869
                                GenericType::TreeWithKnownChildTypes(argument_types) => {
8✔
870
                                    assert_eq!(
8✔
871
                                        argument_types.len(),
8✔
872
                                        parameter_types.len(),
8✔
873
                                        "Argument count mismatch"
874
                                    );
875
                                    for (index, (argument_type, parameter_type)) in argument_types
23✔
876
                                        .iter()
8✔
877
                                        .zip(parameter_types.iter())
8✔
878
                                        .enumerate()
8✔
879
                                    {
880
                                        if !convert_implicitly(argument_type, parameter_type) {
15✔
881
                                            return Ok((
1✔
882
                                                CompilerOutput::new(
1✔
883
                                                    None,
1✔
884
                                                    vec![CompilerError::new(
1✔
885
                                                        format!(
1✔
886
                                                            "Argument {} type '{:?}' is not convertible into parameter type '{:?}'",
1✔
887
                                                            index + 1, argument_type, parameter_type
1✔
888
                                                        ),
889
                                                        arguments[index].source_location(),
1✔
890
                                                    )],
891
                                                ),
892
                                                None,
1✔
893
                                            ));
894
                                        }
895
                                    }
896
                                }
897
                                _ => unreachable!()
×
898
                            }
899
                        }
900
                        Ok((
11✔
901
                            CompilerOutput {
11✔
902
                                entry_point: Some(TypedExpression::new(
11✔
903
                                    lambda::expressions::DeepExpression(
11✔
904
                                        lambda::expressions::Expression::Apply {
11✔
905
                                            callee: Arc::new(callee_checked.expression),
11✔
906
                                            argument: Arc::new(argument_checked.expression),
11✔
907
                                        },
908
                                    ),
909
                                    return_type,
11✔
910
                                )),
911
                                errors,
11✔
912
                            },
913
                            /*TODO: compile time function calls*/ None,
11✔
914
                        ))
915
                    }
916
                    (None, _) | (_, None) => Ok((CompilerOutput::new(None, errors), None)),
2✔
917
                }
918
            }
919
            ast::Expression::Lambda { parameters, body } => {
61✔
920
                check_lambda(&parameters[..], body, environment_builder)
61✔
921
                    .await
61✔
922
                    .map(|output| (output, /*TODO: compile time function calls*/ None))
122✔
923
            }
924
            ast::Expression::ConstructTree(arguments, _) => {
21✔
925
                check_tree_construction_or_argument_list(&arguments[..], environment_builder).await
21✔
926
            }
927
            ast::Expression::Braces(expression) => {
10✔
928
                check_types(expression, environment_builder).await
10✔
929
            }
930
            ast::Expression::Let {
931
                name,
21✔
932
                location,
21✔
933
                value,
21✔
934
                body,
21✔
935
            } => check_let(name, location, value, body, environment_builder)
21✔
936
                .await
21✔
937
                .map(|output| {
42✔
938
                    (
939
                        output, /*TODO: compile time let or a const keyword*/ None,
21✔
940
                    )
941
                }),
942
            ast::Expression::TypeOf(expression) => {
7✔
943
                check_type_of(expression, environment_builder).await
7✔
944
            }
945
            ast::Expression::Comment(_, expression, _) => {
3✔
946
                check_types(expression, environment_builder).await
3✔
947
            }
948
            ast::Expression::IntegerLiteral(value, _base, _source_location) => {
3✔
949
                check_integer_literal(*value)                    .await
3✔
950
            }
951
        }
952
    })
953
    .await
270✔
954
}
955

956
pub async fn check_types_with_default_globals(
48✔
957
    syntax_tree: &ast::Expression,
958
    default_global_namespace: NamespaceId,
959
) -> Result<CompilerOutput, StoreError> {
960
    let mut environment_builder = EnvironmentBuilder::new();
48✔
961
    environment_builder.define_constant(
48✔
962
        Name::new(default_global_namespace, "Type".to_string()),
48✔
963
        DeepType(GenericType::Type),
48✔
964
        type_to_deep_tree(&DeepType(GenericType::Type)),
48✔
965
    );
966
    environment_builder.define_constant(
48✔
967
        Name::new(default_global_namespace, "String".to_string()),
48✔
968
        DeepType(GenericType::Type),
48✔
969
        type_to_deep_tree(&DeepType(GenericType::String)),
48✔
970
    );
971
    let bool_type = DeepType(GenericType::Named(Name::new(
48✔
972
        default_global_namespace,
48✔
973
        "Bool".to_string(),
48✔
974
    )));
975
    environment_builder.define_constant(
48✔
976
        Name::new(default_global_namespace, "Bool".to_string()),
48✔
977
        DeepType(GenericType::Type),
48✔
978
        type_to_deep_tree(&bool_type),
48✔
979
    );
980
    environment_builder.define_constant(
48✔
981
        Name::new(default_global_namespace, "true".to_string()),
48✔
982
        bool_type.clone(),
48✔
983
        DeepTree::new(
48✔
984
            TreeBlob::try_from(bytes::Bytes::from_static(&[1u8]))
48✔
985
                .expect("one byte will always fit"),
48✔
986
            Vec::new(),
48✔
987
        ),
988
    );
989
    environment_builder.define_constant(
48✔
990
        Name::new(default_global_namespace, "false".to_string()),
48✔
991
        bool_type,
48✔
992
        DeepTree::new(
48✔
993
            TreeBlob::try_from(bytes::Bytes::from_static(&[0u8]))
48✔
994
                .expect("one byte will always fit"),
48✔
995
            Vec::new(),
48✔
996
        ),
997
    );
998
    environment_builder.define_constant(
48✔
999
        Name::new(default_global_namespace, "Int".to_string()),
48✔
1000
        DeepType(GenericType::Type),
48✔
1001
        type_to_deep_tree(&DeepType(GenericType::Integer)),
48✔
1002
    );
1003
    let output = check_types(syntax_tree, &mut environment_builder).await;
96✔
1004
    environment_builder.undefine_constant();
48✔
1005
    environment_builder.undefine_constant();
48✔
1006
    environment_builder.undefine_constant();
48✔
1007
    environment_builder.undefine_constant();
48✔
1008
    environment_builder.undefine_constant();
48✔
1009
    environment_builder.undefine_constant();
48✔
1010
    assert!(environment_builder.is_empty());
1011
    output.map(|output| /*TODO: return compile time values*/ output.0)
96✔
1012
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc