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}