Skip to main content

ssf/analysis/type_check/
mod.rs

1mod error;
2mod type_checker;
3
4use crate::ir::*;
5pub use error::*;
6use type_checker::*;
7
8pub fn check_types(module: &Module) -> Result<(), TypeCheckError> {
9    TypeChecker::new().check(module)
10}
11
12#[cfg(test)]
13mod tests {
14    use super::check_types;
15    use super::error::*;
16    use crate::ir::*;
17    use crate::types;
18
19    #[test]
20    fn check_types_with_empty_modules() {
21        assert_eq!(
22            check_types(&Module::without_validation(vec![], vec![], vec![])),
23            Ok(())
24        );
25    }
26
27    #[test]
28    fn check_types_of_variables() {
29        let module = Module::without_validation(
30            vec![],
31            vec![ValueDefinition::new("x", 42.0, types::Primitive::Float64).into()],
32            vec![],
33        );
34        assert_eq!(check_types(&module), Ok(()));
35    }
36
37    #[test]
38    fn fail_to_check_types_of_variables() {
39        let module = Module::without_validation(
40            vec![],
41            vec![
42                FunctionDefinition::new(
43                    "f",
44                    vec![Argument::new("x", types::Primitive::Float64)],
45                    42.0,
46                    types::Primitive::Float64,
47                )
48                .into(),
49                ValueDefinition::new("x", Variable::new("f"), types::Primitive::Float64).into(),
50            ],
51            vec![],
52        );
53
54        assert_eq!(check_types(&module), Err(TypeCheckError));
55    }
56
57    #[test]
58    fn check_types_of_functions() {
59        let module = Module::without_validation(
60            vec![],
61            vec![FunctionDefinition::new(
62                "f",
63                vec![Argument::new("x", types::Primitive::Float64)],
64                42.0,
65                types::Primitive::Float64,
66            )
67            .into()],
68            vec![],
69        );
70
71        assert_eq!(check_types(&module), Ok(()));
72    }
73
74    #[test]
75    fn fail_to_check_types_of_functions() {
76        let module = Module::without_validation(
77            vec![],
78            vec![
79                FunctionDefinition::new(
80                    "f",
81                    vec![Argument::new("x", types::Primitive::Float64)],
82                    42.0,
83                    types::Primitive::Float64,
84                )
85                .into(),
86                FunctionDefinition::new(
87                    "g",
88                    vec![Argument::new("x", types::Primitive::Float64)],
89                    Variable::new("f"),
90                    types::Primitive::Float64,
91                )
92                .into(),
93            ],
94            vec![],
95        );
96
97        assert_eq!(check_types(&module), Err(TypeCheckError));
98    }
99
100    #[test]
101    fn check_types_of_function_applications() {
102        let module = Module::without_validation(
103            vec![],
104            vec![
105                FunctionDefinition::new(
106                    "f",
107                    vec![Argument::new("x", types::Primitive::Float64)],
108                    42.0,
109                    types::Primitive::Float64,
110                )
111                .into(),
112                ValueDefinition::new(
113                    "x",
114                    FunctionApplication::new(Variable::new("f"), vec![42.0.into()]),
115                    types::Primitive::Float64,
116                )
117                .into(),
118            ],
119            vec![],
120        );
121
122        assert_eq!(check_types(&module), Ok(()));
123    }
124
125    #[test]
126    fn fail_to_check_types_of_function_applications() {
127        let module = Module::without_validation(
128            vec![],
129            vec![
130                FunctionDefinition::new(
131                    "f",
132                    vec![Argument::new("x", types::Primitive::Float64)],
133                    42.0,
134                    types::Primitive::Float64,
135                )
136                .into(),
137                ValueDefinition::new(
138                    "x",
139                    FunctionApplication::new(Variable::new("f"), vec![42.0.into(), 42.0.into()]),
140                    types::Primitive::Float64,
141                )
142                .into(),
143            ],
144            vec![],
145        );
146
147        assert_eq!(check_types(&module), Err(TypeCheckError));
148    }
149
150    #[test]
151    fn fail_to_check_types_because_of_missing_variables() {
152        let module = Module::without_validation(
153            vec![],
154            vec![ValueDefinition::new("x", Variable::new("y"), types::Primitive::Float64).into()],
155            vec![],
156        );
157
158        assert_eq!(check_types(&module), Err(TypeCheckError));
159    }
160
161    #[test]
162    fn check_types_of_let_values() {
163        let module = Module::without_validation(
164            vec![],
165            vec![ValueDefinition::new(
166                "x",
167                LetValues::new(
168                    vec![
169                        ValueDefinition::new("y", 42.0, types::Primitive::Float64),
170                        ValueDefinition::new("z", Variable::new("y"), types::Primitive::Float64),
171                    ],
172                    Variable::new("z"),
173                ),
174                types::Primitive::Float64,
175            )
176            .into()],
177            vec![],
178        );
179
180        assert_eq!(check_types(&module), Ok(()));
181    }
182
183    #[test]
184    fn fail_to_check_types_of_let_values() {
185        let module = Module::without_validation(
186            vec![],
187            vec![
188                FunctionDefinition::new(
189                    "f",
190                    vec![Argument::new("x", types::Primitive::Float64)],
191                    42.0,
192                    types::Primitive::Float64,
193                )
194                .into(),
195                ValueDefinition::new(
196                    "x",
197                    LetValues::new(
198                        vec![ValueDefinition::new(
199                            "y",
200                            Variable::new("f"),
201                            types::Primitive::Float64,
202                        )],
203                        Variable::new("y"),
204                    ),
205                    types::Primitive::Float64,
206                )
207                .into(),
208            ],
209            vec![],
210        );
211
212        assert_eq!(check_types(&module), Err(TypeCheckError));
213    }
214
215    #[test]
216    fn check_types_of_declarations() {
217        let module = Module::without_validation(
218            vec![Declaration::new("x", types::Primitive::Float64)],
219            vec![ValueDefinition::new("y", Variable::new("x"), types::Primitive::Float64).into()],
220            vec![],
221        );
222        assert_eq!(check_types(&module), Ok(()));
223    }
224
225    #[test]
226    fn fail_to_check_types_of_declarations() {
227        let module = Module::without_validation(
228            vec![Declaration::new(
229                "x",
230                types::Function::new(
231                    vec![types::Primitive::Float64.into()],
232                    types::Primitive::Float64,
233                ),
234            )],
235            vec![ValueDefinition::new("y", Variable::new("x"), types::Primitive::Float64).into()],
236            vec![],
237        );
238        assert_eq!(check_types(&module), Err(TypeCheckError));
239    }
240
241    mod case_expressions {
242        use super::*;
243
244        mod algebraic {
245            use super::*;
246
247            #[test]
248            fn check_case_expressions_only_with_default_alternative() {
249                assert_eq!(
250                    check_types(&Module::without_validation(
251                        vec![],
252                        vec![FunctionDefinition::new(
253                            "f",
254                            vec![Argument::new(
255                                "x",
256                                types::Algebraic::new(vec![types::Constructor::new(vec![])]),
257                            )],
258                            AlgebraicCase::new(
259                                Variable::new("x"),
260                                vec![],
261                                Some(DefaultAlternative::new("x", 42.0)),
262                            ),
263                            types::Primitive::Float64,
264                        )
265                        .into()],
266                        vec![],
267                    )),
268                    Ok(())
269                );
270            }
271
272            #[test]
273            fn check_case_expressions_only_with_default_alternative_and_bound_variable() {
274                let algebraic_type = types::Algebraic::new(vec![types::Constructor::new(vec![])]);
275
276                assert_eq!(
277                    check_types(&Module::without_validation(
278                        vec![],
279                        vec![FunctionDefinition::new(
280                            "f",
281                            vec![Argument::new("x", algebraic_type.clone())],
282                            AlgebraicCase::new(
283                                Variable::new("x"),
284                                vec![],
285                                Some(DefaultAlternative::new("y", Variable::new("y"))),
286                            ),
287                            algebraic_type,
288                        )
289                        .into()],
290                        vec![],
291                    )),
292                    Ok(())
293                );
294            }
295
296            #[test]
297            fn check_case_expressions_with_one_alternative() {
298                let algebraic_type = types::Algebraic::new(vec![types::Constructor::new(vec![])]);
299
300                assert_eq!(
301                    check_types(&Module::without_validation(
302                        vec![],
303                        vec![FunctionDefinition::new(
304                            "f",
305                            vec![Argument::new("x", algebraic_type.clone())],
306                            AlgebraicCase::new(
307                                Variable::new("x"),
308                                vec![AlgebraicAlternative::new(
309                                    Constructor::new(algebraic_type, 0),
310                                    vec![],
311                                    42.0
312                                )],
313                                None
314                            ),
315                            types::Primitive::Float64,
316                        )
317                        .into()],
318                        vec![],
319                    )),
320                    Ok(())
321                );
322            }
323
324            #[test]
325            fn check_case_expressions_with_deconstruction() {
326                let algebraic_type = types::Algebraic::new(vec![types::Constructor::new(vec![
327                    types::Primitive::Float64.into(),
328                ])]);
329
330                assert_eq!(
331                    check_types(&Module::without_validation(
332                        vec![],
333                        vec![FunctionDefinition::new(
334                            "f",
335                            vec![Argument::new("x", algebraic_type.clone())],
336                            AlgebraicCase::new(
337                                Variable::new("x"),
338                                vec![AlgebraicAlternative::new(
339                                    Constructor::new(algebraic_type, 0),
340                                    vec!["y".into()],
341                                    Variable::new("y")
342                                )],
343                                None
344                            ),
345                            types::Primitive::Float64,
346                        )
347                        .into()],
348                        vec![],
349                    )),
350                    Ok(())
351                );
352            }
353
354            #[test]
355            fn fail_to_check_case_expressions_without_alternatives() {
356                assert_eq!(
357                    check_types(&Module::without_validation(
358                        vec![],
359                        vec![FunctionDefinition::new(
360                            "f",
361                            vec![Argument::new(
362                                "x",
363                                types::Algebraic::new(vec![types::Constructor::new(vec![])]),
364                            )],
365                            AlgebraicCase::new(Variable::new("x"), vec![], None),
366                            types::Primitive::Float64,
367                        )
368                        .into()],
369                        vec![],
370                    )),
371                    Err(TypeCheckError)
372                );
373            }
374
375            #[test]
376            fn fail_to_check_case_expressions_with_inconsistent_alternative_types() {
377                let algebraic_type = types::Algebraic::new(vec![types::Constructor::new(vec![])]);
378
379                assert_eq!(
380                    check_types(&Module::without_validation(
381                        vec![],
382                        vec![FunctionDefinition::new(
383                            "f",
384                            vec![Argument::new(
385                                "x",
386                                types::Algebraic::new(vec![types::Constructor::new(vec![])]),
387                            )],
388                            AlgebraicCase::new(
389                                Variable::new("x"),
390                                vec![
391                                    AlgebraicAlternative::new(
392                                        Constructor::new(algebraic_type.clone(), 0),
393                                        vec![],
394                                        Variable::new("x")
395                                    ),
396                                    AlgebraicAlternative::new(
397                                        Constructor::new(algebraic_type, 0),
398                                        vec![],
399                                        42.0
400                                    )
401                                ],
402                                None
403                            ),
404                            types::Primitive::Float64,
405                        )
406                        .into()],
407                        vec![],
408                    )),
409                    Err(TypeCheckError)
410                );
411            }
412        }
413
414        mod primitive {
415            use super::*;
416
417            #[test]
418            fn check_case_expressions_only_with_default_alternative() {
419                assert_eq!(
420                    check_types(&Module::without_validation(
421                        vec![],
422                        vec![ValueDefinition::new(
423                            "x",
424                            PrimitiveCase::new(
425                                42.0,
426                                vec![],
427                                Some(DefaultAlternative::new("x", 42.0)),
428                            ),
429                            types::Primitive::Float64,
430                        )
431                        .into()],
432                        vec![],
433                    )),
434                    Ok(())
435                );
436            }
437
438            #[test]
439            fn check_case_expressions_with_one_alternative() {
440                assert_eq!(
441                    check_types(&Module::without_validation(
442                        vec![],
443                        vec![ValueDefinition::new(
444                            "x",
445                            PrimitiveCase::new(
446                                42.0,
447                                vec![PrimitiveAlternative::new(42.0, 42.0)],
448                                None
449                            ),
450                            types::Primitive::Float64,
451                        )
452                        .into()],
453                        vec![],
454                    )),
455                    Ok(())
456                );
457            }
458
459            #[test]
460            fn check_case_expressions_with_one_alternative_and_default_alternative() {
461                assert_eq!(
462                    check_types(&Module::without_validation(
463                        vec![],
464                        vec![ValueDefinition::new(
465                            "x",
466                            PrimitiveCase::new(
467                                42.0,
468                                vec![PrimitiveAlternative::new(42.0, 42.0)],
469                                Some(DefaultAlternative::new("x", 42.0))
470                            ),
471                            types::Primitive::Float64,
472                        )
473                        .into()],
474                        vec![],
475                    )),
476                    Ok(())
477                );
478            }
479        }
480    }
481
482    mod constructor_applications {
483        use super::*;
484
485        #[test]
486        fn check_constructor_applications_with_no_arguments() {
487            let algebraic_type = types::Algebraic::new(vec![types::Constructor::new(vec![])]);
488
489            assert_eq!(
490                check_types(&Module::without_validation(
491                    vec![],
492                    vec![ValueDefinition::new(
493                        "x",
494                        ConstructorApplication::new(
495                            Constructor::new(algebraic_type.clone(), 0),
496                            vec![],
497                        ),
498                        algebraic_type,
499                    )
500                    .into()],
501                    vec![],
502                )),
503                Ok(())
504            );
505        }
506
507        #[test]
508        fn check_constructor_applications_with_arguments() {
509            let algebraic_type = types::Algebraic::new(vec![types::Constructor::new(vec![
510                types::Primitive::Float64.into(),
511            ])]);
512
513            assert_eq!(
514                check_types(&Module::without_validation(
515                    vec![],
516                    vec![ValueDefinition::new(
517                        "x",
518                        ConstructorApplication::new(
519                            Constructor::new(algebraic_type.clone(), 0),
520                            vec![42.0.into()],
521                        ),
522                        algebraic_type,
523                    )
524                    .into()],
525                    vec![],
526                )),
527                Ok(())
528            );
529        }
530
531        #[test]
532        fn fail_to_check_constructor_applications_with_wrong_number_of_arguments() {
533            let algebraic_type = types::Algebraic::new(vec![types::Constructor::new(vec![
534                types::Primitive::Float64.into(),
535            ])]);
536
537            assert_eq!(
538                check_types(&Module::without_validation(
539                    vec![],
540                    vec![ValueDefinition::new(
541                        "x",
542                        ConstructorApplication::new(
543                            Constructor::new(algebraic_type.clone(), 0),
544                            vec![42.0.into(), 42.0.into()],
545                        ),
546                        algebraic_type,
547                    )
548                    .into()],
549                    vec![],
550                )),
551                Err(TypeCheckError)
552            );
553        }
554
555        #[test]
556        fn fail_to_check_constructor_applications_with_wrong_argument_type() {
557            let algebraic_type = types::Algebraic::new(vec![types::Constructor::new(vec![
558                types::Primitive::Float64.into(),
559            ])]);
560
561            assert_eq!(
562                check_types(&Module::without_validation(
563                    vec![],
564                    vec![ValueDefinition::new(
565                        "x",
566                        ConstructorApplication::new(
567                            Constructor::new(algebraic_type.clone(), 0),
568                            vec![ConstructorApplication::new(
569                                Constructor::new(algebraic_type.clone(), 0),
570                                vec![42.0.into()],
571                            )
572                            .into()],
573                        ),
574                        algebraic_type,
575                    )
576                    .into()],
577                    vec![],
578                )),
579                Err(TypeCheckError)
580            );
581        }
582    }
583}