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

TyRoXx / NonlocalityOS / 15517850440

08 Jun 2025 11:12AM UTC coverage: 74.611% (+0.06%) from 74.555%
15517850440

Pull #284

github

web-flow
Merge eeaeb9932 into bda2893cf
Pull Request #284: GH-283: add Bool, true, and false

26 of 27 new or added lines in 1 file covered. (96.3%)

3 existing lines in 1 file now uncovered.

3791 of 5081 relevant lines covered (74.61%)

2073.26 hits per line

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

86.63
/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 serde::{Deserialize, Serialize};
15
use std::{collections::BTreeMap, sync::Arc};
16

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

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

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

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

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

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

145
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
146
pub struct TypedExpression {
147
    pub expression: DeepExpression,
148
    pub type_: DeepType,
149
}
150

151
impl TypedExpression {
152
    pub fn new(expression: DeepExpression, type_: DeepType) -> Self {
233✔
153
        Self { expression, type_ }
154
    }
155
}
156

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

188
#[derive(Debug, Clone, Copy)]
189
enum ParameterIndex {
190
    SingleParameter,
191
    GetChild(u16),
192
}
193

194
impl ParameterIndex {
195
    pub fn create_deep_expression(&self) -> lambda::expressions::DeepExpression {
39✔
196
        match self {
39✔
197
            ParameterIndex::SingleParameter => {
198
                lambda::expressions::DeepExpression(lambda::expressions::Expression::make_argument())
28✔
199
            }
200
            ParameterIndex::GetChild(index) => lambda::expressions::DeepExpression(
201
                lambda::expressions::Expression::make_get_child(
11✔
202
                    Arc::new(lambda::expressions::DeepExpression(
11✔
203
                        lambda::expressions::Expression::make_argument(),
11✔
204
                    )),
205
                    *index,
11✔
206
                ),
207
            ),
208
        }
209
    }
210
}
211

212
struct LocalVariable {
213
    parameter_index: ParameterIndex,
214
    type_: DeepType,
215
    compile_time_value: Option<DeepTree>,
216
}
217

218
impl LocalVariable {
219
    pub fn new(
203✔
220
        parameter_index: ParameterIndex,
221
        type_: DeepType,
222
        compile_time_value: Option<DeepTree>,
223
    ) -> Self {
224
        Self {
225
            parameter_index,
226
            type_,
227
            compile_time_value,
228
        }
229
    }
230
}
231

232
struct LambdaScope {
233
    names: BTreeMap<Name, LocalVariable>,
234
    captures: BTreeMap<TypedExpression, u16>,
235
}
236

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

268
    pub fn new_constant_scope(name: Name, type_: DeepType, compile_time_value: DeepTree) -> Self {
165✔
269
        let mut names = BTreeMap::new();
165✔
270
        names.insert(
165✔
271
            name,
165✔
272
            LocalVariable::new(
165✔
273
                ParameterIndex::SingleParameter,
165✔
274
                type_.clone(),
165✔
275
                Some(compile_time_value),
165✔
276
            ),
277
        );
278
        Self {
279
            names,
280
            captures: BTreeMap::new(),
165✔
281
        }
282
    }
283

284
    pub fn find_parameter_index(
141✔
285
        &self,
286
        parameter_name: &Name,
287
    ) -> Option<(ParameterIndex, DeepType, Option<DeepTree>)> {
288
        self.names.get(parameter_name).map(|variable| {
195✔
289
            (
290
                variable.parameter_index,
54✔
291
                variable.type_.clone(),
54✔
292
                variable.compile_time_value.clone(),
54✔
293
            )
294
        })
295
    }
296

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

327
    pub fn leave(self) -> Vec<TypedExpression> {
213✔
328
        let mut as_vec: Vec<(TypedExpression, u16)> = self.captures.into_iter().collect();
213✔
329
        as_vec.sort_by_key(|(_, index)| *index);
221✔
330
        // sanity check:
331
        for (expected_index, (_, actual_index)) in as_vec.iter().enumerate() {
227✔
332
            assert_eq!(expected_index, *actual_index as usize);
333
        }
334
        as_vec
213✔
335
            .into_iter()
336
            .map(|(expression, _)| expression)
227✔
337
            .collect()
338
    }
339
}
340

341
pub struct EnvironmentBuilder {
342
    lambda_layers: Vec<LambdaScope>,
343
}
344

345
impl Default for EnvironmentBuilder {
346
    fn default() -> Self {
×
347
        Self::new()
×
348
    }
349
}
350

351
impl EnvironmentBuilder {
352
    pub fn new() -> Self {
33✔
353
        Self {
354
            lambda_layers: Vec::new(),
33✔
355
        }
356
    }
357

358
    pub fn is_empty(&self) -> bool {
33✔
359
        self.lambda_layers.is_empty()
33✔
360
    }
361

362
    pub fn enter_lambda_body(&mut self, parameters: &[TypeCheckedLambdaParameter]) {
48✔
363
        self.lambda_layers
48✔
364
            .push(LambdaScope::new_lambda_scope(parameters));
48✔
365
    }
366

367
    pub fn leave_lambda_body(&mut self) -> Vec<TypedExpression> {
213✔
368
        let top_scope = self.lambda_layers.pop().unwrap();
213✔
369
        top_scope.leave()
213✔
370
    }
371

372
    pub fn define_constant(&mut self, name: Name, type_: DeepType, compile_time_value: DeepTree) {
165✔
373
        self.lambda_layers.push(LambdaScope::new_constant_scope(
165✔
374
            name,
165✔
375
            type_,
165✔
376
            compile_time_value,
165✔
377
        ));
378
    }
379

380
    pub fn undefine_constant(&mut self) {
165✔
381
        let captures = self.leave_lambda_body();
165✔
382
        if !captures.is_empty() {
165✔
383
            todo!()
384
        }
385
    }
386

387
    pub fn read(
58✔
388
        &mut self,
389
        identifier: &Name,
390
        location: &SourceLocation,
391
    ) -> (CompilerOutput, Option<DeepTree>) {
392
        Self::read_down(&mut self.lambda_layers, identifier, location)
58✔
393
    }
394

395
    fn read_down(
141✔
396
        layers: &mut [LambdaScope],
397
        identifier: &Name,
398
        location: &SourceLocation,
399
    ) -> (CompilerOutput, Option<DeepTree>) {
400
        let layer_count = layers.len();
141✔
401
        if let Some(last) = layers.last_mut() {
282✔
402
            if let Some((parameter_index, parameter_type, compile_time_value)) =
54✔
403
                last.find_parameter_index(identifier)
404
            {
405
                return match compile_time_value {
406
                    Some(value) => (
15✔
407
                        CompilerOutput::new(
15✔
408
                            Some(TypedExpression::new(
15✔
409
                                DeepExpression(lambda::expressions::Expression::make_literal(
15✔
410
                                    value.clone(),
15✔
411
                                )),
412
                                parameter_type,
15✔
413
                            )),
414
                            Vec::new(),
15✔
415
                        ),
416
                        Some(value),
15✔
417
                    ),
418
                    None => (
39✔
419
                        CompilerOutput::new(
39✔
420
                            Some(TypedExpression::new(
39✔
421
                                parameter_index.create_deep_expression(),
39✔
422
                                parameter_type,
39✔
423
                            )),
424
                            Vec::new(),
39✔
425
                        ),
426
                        None,
39✔
427
                    ),
428
                };
429
            } else if layer_count > 1 {
87✔
430
                let result = Self::read_down(&mut layers[..layer_count - 1], identifier, location);
83✔
431
                return match result.0.entry_point {
83✔
432
                    Some(success) => match result.1 {
67✔
433
                        Some(compile_time_value) => (
43✔
434
                            CompilerOutput::new(
43✔
435
                                Some(TypedExpression::new(
43✔
436
                                    DeepExpression(Expression::Literal(compile_time_value.clone())),
43✔
437
                                    success.type_,
43✔
438
                                )),
439
                                result.0.errors,
43✔
440
                            ),
441
                            Some(compile_time_value),
43✔
442
                        ),
443
                        None => {
444
                            let mut errors = result.0.errors;
24✔
445
                            let captured = layers.last_mut().unwrap().capture(success);
24✔
446
                            errors.extend(captured.errors);
24✔
447
                            (CompilerOutput::new(captured.entry_point, errors), None)
24✔
448
                        }
449
                    },
450
                    None => result,
16✔
451
                };
452
            }
453
        }
454
        (
455
            CompilerOutput::new(
4✔
456
                None,
4✔
457
                vec![crate::compilation::CompilerError::new(
4✔
458
                    format!("Identifier {identifier} not found"),
4✔
459
                    *location,
4✔
460
                )],
461
            ),
462
            None,
4✔
463
        )
464
    }
465
}
466

467
pub struct TypeCheckedLambdaParameter {
468
    pub name: Name,
469
    pub source_location: SourceLocation,
470
    pub type_: DeepType,
471
    pub compile_time_value: Option<DeepTree>,
472
}
473

474
impl TypeCheckedLambdaParameter {
475
    pub fn new(
6✔
476
        name: Name,
477
        source_location: SourceLocation,
478
        type_: DeepType,
479
        compile_time_value: Option<DeepTree>,
480
    ) -> Self {
481
        Self {
482
            name,
483
            source_location,
484
            type_,
485
            compile_time_value,
486
        }
487
    }
488
}
489

490
fn is_type(type_of_value: &DeepType) -> bool {
12✔
491
    match &type_of_value.0 {
12✔
492
        GenericType::Any => false,
×
493
        GenericType::String => false,
×
494
        GenericType::TreeWithKnownChildTypes(_items) => false,
1✔
495
        GenericType::Function {
496
            parameters: _,
497
            return_type: _,
498
        } => false,
×
499
        GenericType::Type => true,
11✔
NEW
500
        GenericType::Named(_name) => false,
×
501
    }
502
}
503

504
struct WithCompilerErrors<T> {
505
    output: T,
506
    errors: Vec<CompilerError>,
507
}
508

509
impl<T> WithCompilerErrors<T> {
510
    pub fn new(output: T, errors: Vec<CompilerError>) -> Self {
42✔
511
        Self { output, errors }
512
    }
513
}
514

515
async fn check_lambda_parameters(
42✔
516
    parameters: &[LambdaParameter],
517
    environment_builder: &mut EnvironmentBuilder,
518
) -> Result<WithCompilerErrors<Vec<TypeCheckedLambdaParameter>>, StoreError> {
519
    let mut checked_parameters = Vec::new();
42✔
520
    let mut errors: Vec<CompilerError> = Vec::new();
42✔
521
    for parameter in parameters {
106✔
522
        let parameter_type: DeepType = match &parameter.type_annotation {
64✔
523
            Some(type_annotation) => {
13✔
524
                let checked_type = check_types(type_annotation, environment_builder).await?;
26✔
525
                errors.extend(checked_type.0.errors);
526
                if let Some(checked) = checked_type.0.entry_point {
12✔
527
                    if is_type(&checked.type_) {
528
                        match checked_type.1 {
11✔
529
                            Some(compile_time_value) => type_from_deep_tree(&compile_time_value),
10✔
530
                            None => {
531
                                errors.push(CompilerError::new(
1✔
532
                                    "Type annotation must be a compile time constant".to_string(),
1✔
533
                                    parameter.source_location,
1✔
534
                                ));
535
                                // Fallback to Any if the type is not valid.
536
                                DeepType(GenericType::Any)
1✔
537
                            }
538
                        }
539
                    } else {
540
                        errors.push(CompilerError::new(
1✔
541
                            "Type annotation must be a type".to_string(),
1✔
542
                            parameter.source_location,
1✔
543
                        ));
544
                        // Fallback to Any if the type is not valid.
545
                        DeepType(GenericType::Any)
1✔
546
                    }
547
                } else {
548
                    // Fallback to Any if the type is not valid.
549
                    DeepType(GenericType::Any)
1✔
550
                }
551
            }
552
            None => {
553
                // If no type annotation is provided, we assume the type is `Any`.
554
                DeepType(GenericType::Any)
19✔
555
            }
556
        };
557
        checked_parameters.push(TypeCheckedLambdaParameter {
558
            name: parameter.name.clone(),
559
            source_location: parameter.source_location,
560
            type_: parameter_type,
561
            compile_time_value: None, // TODO?
562
        });
563
    }
564
    Ok(WithCompilerErrors::new(checked_parameters, errors))
42✔
565
}
566

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

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

657
pub async fn check_types(
153✔
658
    syntax_tree: &ast::Expression,
659
    environment_builder: &mut EnvironmentBuilder,
660
) -> Result<(CompilerOutput, Option<DeepTree>), StoreError> {
661
    Box::pin(async move {
306✔
662
        match syntax_tree {
153✔
663
            ast::Expression::Identifier(name, location) => {
58✔
664
                Ok(environment_builder.read(name, location))
58✔
665
            }
666
            ast::Expression::StringLiteral(value, source_location) => {
15✔
667
                let compile_time_value = match DeepTree::try_from_string(value) {
29✔
668
                    Some(tree) => tree,
14✔
669
                    None => {
670
                        return Ok((
1✔
671
                            CompilerOutput::new(
1✔
672
                                None,
1✔
673
                                vec![CompilerError::new(
1✔
674
                                    "String literal is too long".to_string(),
1✔
675
                                    *source_location,
1✔
676
                                )],
677
                            ),
678
                            None,
1✔
679
                        ))
680
                    }
681
                };
682
                Ok((
14✔
683
                    CompilerOutput::new(
14✔
684
                        Some(TypedExpression::new(
14✔
685
                            lambda::expressions::DeepExpression(
14✔
686
                                lambda::expressions::Expression::Literal(
14✔
687
                                    compile_time_value.clone(),
14✔
688
                                ),
689
                            ),
690
                            DeepType(GenericType::String),
14✔
691
                        )),
692
                        Vec::new(),
14✔
693
                    ),
694
                    Some(compile_time_value),
14✔
695
                ))
696
            }
697
            ast::Expression::Apply { callee, arguments } => {
8✔
698
                let callee_output = check_types(callee, environment_builder).await?;
16✔
699
                let argument_output = if arguments.len() == 1 {
8✔
700
                    // For N=1 we don't need an indirection.
701
                    check_types(&arguments[0], environment_builder).await?
3✔
702
                } else {
703
                    check_tree_construction_or_argument_list(&arguments[..], environment_builder)
5✔
704
                        .await?
5✔
705
                };
706
                let errors = callee_output
707
                    .0
708
                    .errors
709
                    .into_iter()
710
                    .chain(argument_output.0.errors)
711
                    .collect();
712
                match (callee_output.0.entry_point, argument_output.0.entry_point) {
713
                    (Some(callee_checked), Some(argument_checked)) => {
7✔
714
                        let return_type = match &callee_checked.type_.0 {
13✔
715
                            GenericType::Function { return_type, .. } => {
716
                                return_type.as_ref().clone()
717
                            }
718
                            _ => {
719
                                return Ok((
1✔
720
                                    CompilerOutput::new(
1✔
721
                                        None,
1✔
722
                                        vec![crate::compilation::CompilerError::new(
1✔
723
                                            "Callee is not a function".to_string(),
1✔
724
                                            callee.source_location(),
1✔
725
                                        )],
726
                                    ),
727
                                    None,
1✔
728
                                ))
729
                            }
730
                        };
731
                        // TODO: check argument types against callee parameter types
732
                        Ok((
733
                            CompilerOutput {
734
                                entry_point: Some(TypedExpression::new(
735
                                    lambda::expressions::DeepExpression(
736
                                        lambda::expressions::Expression::Apply {
737
                                            callee: Arc::new(callee_checked.expression),
738
                                            argument: Arc::new(argument_checked.expression),
739
                                        },
740
                                    ),
741
                                    return_type,
742
                                )),
743
                                errors,
744
                            },
745
                            /*TODO: compile time function calls*/ None,
746
                        ))
747
                    }
748
                    (None, _) | (_, None) => Ok((CompilerOutput::new(None, errors), None)),
1✔
749
                }
750
            }
751
            ast::Expression::Lambda { parameters, body } => {
42✔
752
                check_lambda(&parameters[..], body, environment_builder)
42✔
753
                    .await
42✔
754
                    .map(|output| (output, /*TODO: compile time function calls*/ None))
84✔
755
            }
756
            ast::Expression::ConstructTree(arguments) => {
16✔
757
                check_tree_construction_or_argument_list(&arguments[..], environment_builder).await
16✔
758
            }
759
            ast::Expression::Braces(expression) => {
6✔
760
                check_types(expression, environment_builder).await
6✔
761
            }
762
            ast::Expression::Let {
763
                name,
8✔
764
                location,
8✔
765
                value,
8✔
766
                body,
8✔
767
            } => check_let(name, location, value, body, environment_builder)
8✔
768
                .await
8✔
769
                .map(|output| {
16✔
770
                    (
771
                        output, /*TODO: compile time let or a const keyword*/ None,
8✔
772
                    )
773
                }),
774
        }
775
    })
776
    .await
153✔
777
}
778

779
pub async fn check_types_with_default_globals(
33✔
780
    syntax_tree: &ast::Expression,
781
    default_global_namespace: NamespaceId,
782
) -> Result<CompilerOutput, StoreError> {
783
    let mut environment_builder = EnvironmentBuilder::new();
33✔
784
    environment_builder.define_constant(
33✔
785
        Name::new(default_global_namespace, "Type".to_string()),
33✔
786
        DeepType(GenericType::Type),
33✔
787
        type_to_deep_tree(&DeepType(GenericType::Type)),
33✔
788
    );
789
    environment_builder.define_constant(
33✔
790
        Name::new(default_global_namespace, "String".to_string()),
33✔
791
        DeepType(GenericType::Type),
33✔
792
        type_to_deep_tree(&DeepType(GenericType::String)),
33✔
793
    );
794
    let bool_type = DeepType(GenericType::Named(Name::new(
33✔
795
        default_global_namespace,
33✔
796
        "Bool".to_string(),
33✔
797
    )));
798
    environment_builder.define_constant(
33✔
799
        Name::new(default_global_namespace, "Bool".to_string()),
33✔
800
        DeepType(GenericType::Type),
33✔
801
        type_to_deep_tree(&bool_type),
33✔
802
    );
803
    environment_builder.define_constant(
33✔
804
        Name::new(default_global_namespace, "true".to_string()),
33✔
805
        bool_type.clone(),
33✔
806
        DeepTree::new(
33✔
807
            TreeBlob::try_from(bytes::Bytes::from_static(&[1u8]))
33✔
808
                .expect("one byte will always fit"),
33✔
809
            Vec::new(),
33✔
810
        ),
811
    );
812
    environment_builder.define_constant(
33✔
813
        Name::new(default_global_namespace, "false".to_string()),
33✔
814
        bool_type,
33✔
815
        DeepTree::new(
33✔
816
            TreeBlob::try_from(bytes::Bytes::from_static(&[0u8]))
33✔
817
                .expect("one byte will always fit"),
33✔
818
            Vec::new(),
33✔
819
        ),
820
    );
821
    let output = check_types(syntax_tree, &mut environment_builder).await;
66✔
822
    environment_builder.undefine_constant();
33✔
823
    environment_builder.undefine_constant();
33✔
824
    environment_builder.undefine_constant();
33✔
825
    environment_builder.undefine_constant();
33✔
826
    environment_builder.undefine_constant();
33✔
827
    assert!(environment_builder.is_empty());
828
    output.map(|output| /*TODO: return compile time values*/ output.0)
66✔
829
}
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