···105105pub enum AllocKind {
106106 // this should always be a ComptimeInt by the time we get to MIR lowering
107107 Array(Box<TypeKind>, Box<ComptimeValue>),
108108- DynArray(Box<TypeKind>),
109108 Record(Vec<RecordField>),
110109 Str(String),
111110 Tuple(Vec<TypeKind>),
···116115 pub fn fill_type(&mut self, ty: TypeKind) {
117116 match self {
118117 AllocKind::Array(ty_, _) => *ty_ = Box::new(ty),
119119- AllocKind::DynArray(ty_) => *ty_ = Box::new(ty),
120118 _ => {}
121119 }
122120 }
···145143 kind: AllocKind,
146144 // some allocations may not have elements, we just leave this empty
147145 elements: Vec<Expr>,
146146+ // for [expr; n] syntax - the default element to repeat n times
147147+ default_elem: Option<Box<Expr>>,
148148 // without a region, this is allocated in the function's implicit contextual region
149149 region: Option<Region>,
150150 },
+447
frontend/src/ast_typecheck/tests.rs
···11+#![cfg(test)]
22+33+use super::*;
44+55+use std::collections::VecDeque;
66+77+use crate::{ast::TypeKind, ctx::Ctx, lex, parse, span::Spanned};
88+99+fn tokenify(s: &str) -> (Ctx, VecDeque<Spanned<crate::lex::Token>>) {
1010+ let mut ctx = Ctx::default();
1111+ let tokens = lex::tokenize(&mut ctx, s).map(|t| t.unwrap()).collect();
1212+ (ctx, tokens)
1313+}
1414+1515+fn parseify(ctx: &mut Ctx, tokens: VecDeque<Spanned<crate::lex::Token>>) -> Module {
1616+ parse::parse(ctx, tokens).unwrap()
1717+}
1818+1919+fn typecheck_src(src: &str) -> (Ctx, TypecheckResult<Module>) {
2020+ let (mut ctx, tokens) = tokenify(src);
2121+ let mut module = parseify(&mut ctx, tokens);
2222+ let result = typecheck(&mut ctx, &mut module);
2323+ (ctx, result)
2424+}
2525+2626+#[test]
2727+fn test_typecheck_simple_procedure() {
2828+ let src = "foo :: (x: int): int { y : int = x }";
2929+ let (_, result) = typecheck_src(src);
3030+ assert!(result.is_ok());
3131+}
3232+3333+#[test]
3434+fn test_typecheck_infers_val_type() {
3535+ let src = "foo :: (x: int): int { y := x }";
3636+ let (_, result) = typecheck_src(src);
3737+ assert!(result.is_ok());
3838+3939+ let module = result.unwrap();
4040+ let DeclKind::Procedure { block, .. } = &module.declarations[0].node else {
4141+ panic!("expected procedure");
4242+ };
4343+4444+ let StmtKind::ValDec { ty, .. } = &block.node.stmts[0].node else {
4545+ panic!("expected val dec");
4646+ };
4747+4848+ assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int));
4949+}
5050+5151+#[test]
5252+fn test_typecheck_binop_expression() {
5353+ let src = "foo :: (x: int, y: int): int { z : int = x + y }";
5454+ let (_ctx, result) = typecheck_src(src);
5555+ assert!(result.is_ok());
5656+}
5757+5858+#[test]
5959+fn test_typecheck_assignment() {
6060+ let src = "foo :: (x: int): int { y : int = x \n y = x + 1 }";
6161+ let (_ctx, result) = typecheck_src(src);
6262+ assert!(result.is_ok());
6363+}
6464+6565+#[test]
6666+fn test_typecheck_if_else() {
6767+ let src = "foo :: (x: int): int { if x { y : int = 1 } else { z : int = 2 } }";
6868+ let (_ctx, result) = typecheck_src(src);
6969+ assert!(result.is_ok());
7070+}
7171+7272+#[test]
7373+fn test_typecheck_constant() {
7474+ let src = "MY_CONST :: 42";
7575+ let (_ctx, result) = typecheck_src(src);
7676+ assert!(result.is_ok());
7777+7878+ let module = result.unwrap();
7979+ let DeclKind::Constant { ty, .. } = &module.declarations[0].node else {
8080+ panic!("expected constant");
8181+ };
8282+8383+ assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int));
8484+}
8585+8686+#[test]
8787+fn test_typecheck_function_call() {
8888+ let src = "bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { bar(1) }";
8989+ let (_ctx, result) = typecheck_src(src);
9090+ assert!(result.is_ok());
9191+}
9292+9393+#[test]
9494+fn test_typecheck_function_call_with_return() {
9595+ let src =
9696+ "bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { result : int = bar(1) }";
9797+ let (_ctx, result) = typecheck_src(src);
9898+ assert!(result.is_ok());
9999+}
100100+101101+#[test]
102102+fn test_typecheck_error_unknown_symbol_in_ident() {
103103+ let src = "foo :: (): int { y : int = unknown }";
104104+ let (_ctx, result) = typecheck_src(src);
105105+ assert!(result.is_err());
106106+ let err = result.unwrap_err();
107107+ assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_)));
108108+}
109109+110110+#[test]
111111+fn test_typecheck_error_unknown_symbol_in_assignment() {
112112+ let src = "foo :: (): int { y : int = 1 \n y = unknown }";
113113+ let (_ctx, result) = typecheck_src(src);
114114+ assert!(result.is_err());
115115+ let err = result.unwrap_err();
116116+ assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_)));
117117+}
118118+119119+#[test]
120120+fn test_typecheck_error_unknown_function() {
121121+ let src = "foo :: (): int { unknown_func(1) }";
122122+ let (_ctx, result) = typecheck_src(src);
123123+ assert!(result.is_err());
124124+125125+ let err = result.unwrap_err();
126126+ assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_)));
127127+}
128128+129129+#[test]
130130+fn test_typecheck_nested_if() {
131131+ let src = "foo :: (x: int): int { if 1 { if 1 { y : int = 1 } } }";
132132+ let (_ctx, result) = typecheck_src(src);
133133+ assert!(result.is_ok());
134134+}
135135+136136+#[test]
137137+fn test_typecheck_multiple_params() {
138138+ let src = "foo :: (a: int, b: int, c: int): int { sum : int = 1 + 2 + 3 }";
139139+ let (_ctx, result) = typecheck_src(src);
140140+ assert!(result.is_ok());
141141+}
142142+143143+#[test]
144144+fn test_typecheck_procedure_infers_fn_type() {
145145+ let src = "foo :: (x: int): int { y : int = 1 }";
146146+ let (_ctx, result) = typecheck_src(src);
147147+ assert!(result.is_ok());
148148+149149+ let module = result.unwrap();
150150+ let DeclKind::Procedure { fn_ty, sig, .. } = &module.declarations[0].node else {
151151+ panic!("expected procedure");
152152+ };
153153+154154+ assert!(fn_ty.is_some());
155155+ let TypeKind::Fn(fn_sig) = &fn_ty.as_ref().unwrap().node else {
156156+ panic!("expected fn type");
157157+ };
158158+ assert_eq!(**fn_sig, sig.node);
159159+}
160160+161161+#[test]
162162+fn test_typecheck_multiple_declarations() {
163163+ let src =
164164+ "CONST :: 10 \n bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { bar(1) }";
165165+ let (_ctx, result) = typecheck_src(src);
166166+ assert!(result.is_ok());
167167+168168+ let module = result.unwrap();
169169+ assert_eq!(module.declarations.len(), 3);
170170+}
171171+172172+#[test]
173173+fn test_typecheck_constant_with_type_annotation() {
174174+ let src = "MY_CONST : int : 42";
175175+ let (_ctx, result) = typecheck_src(src);
176176+ assert!(result.is_ok());
177177+178178+ let module = result.unwrap();
179179+ let DeclKind::Constant { ty, .. } = &module.declarations[0].node else {
180180+ panic!("expected constant");
181181+ };
182182+183183+ assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int));
184184+}
185185+186186+#[test]
187187+fn test_typecheck_constant_with_binop() {
188188+ let src = "MY_CONST :: 1 + 2 * 3";
189189+ let (_ctx, result) = typecheck_src(src);
190190+ assert!(result.is_ok());
191191+192192+ let module = result.unwrap();
193193+ let DeclKind::Constant { ty, .. } = &module.declarations[0].node else {
194194+ panic!("expected constant");
195195+ };
196196+197197+ assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int));
198198+}
199199+200200+#[test]
201201+fn test_typecheck_empty_procedure() {
202202+ let src = "foo :: () {}";
203203+ let (_ctx, result) = typecheck_src(src);
204204+ assert!(result.is_ok());
205205+}
206206+207207+#[test]
208208+fn test_typecheck_procedure_with_return_type() {
209209+ let src = "foo :: (): int {}";
210210+ let (_ctx, result) = typecheck_src(src);
211211+ assert!(result.is_ok());
212212+213213+ let module = result.unwrap();
214214+ let DeclKind::Procedure { sig, .. } = &module.declarations[0].node else {
215215+ panic!("expected procedure");
216216+ };
217217+218218+ assert_eq!(
219219+ sig.node.return_ty.as_ref().map(|t| &t.node),
220220+ Some(&TypeKind::Int)
221221+ );
222222+}
223223+224224+#[test]
225225+fn test_typecheck_val_dec_infers_int_from_literal() {
226226+ let src = "foo :: (): int { y := 42 }";
227227+ let (_ctx, result) = typecheck_src(src);
228228+ assert!(result.is_ok());
229229+230230+ let module = result.unwrap();
231231+ let DeclKind::Procedure { block, .. } = &module.declarations[0].node else {
232232+ panic!("expected procedure");
233233+ };
234234+235235+ let StmtKind::ValDec { ty, .. } = &block.node.stmts[0].node else {
236236+ panic!("expected val dec");
237237+ };
238238+239239+ assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int));
240240+}
241241+242242+#[test]
243243+fn test_typecheck_multiple_val_decs() {
244244+ let src = "foo :: (): int { a : int = 1 \n b : int = 2 \n c : int = 3 }";
245245+ let (_ctx, result) = typecheck_src(src);
246246+ assert!(result.is_ok());
247247+}
248248+249249+#[test]
250250+fn test_typecheck_val_dec_uses_previous_val() {
251251+ let src = "foo :: (): int { a : int = 1 \n b : int = a }";
252252+ let (_ctx, result) = typecheck_src(src);
253253+ assert!(result.is_ok());
254254+}
255255+256256+#[test]
257257+fn test_typecheck_assignment_to_declared_var() {
258258+ let src = "foo :: (): int { a : int = 1 \n a = 2 }";
259259+ let (_ctx, result) = typecheck_src(src);
260260+ assert!(result.is_ok());
261261+}
262262+263263+#[test]
264264+fn test_typecheck_error_assignment_to_undeclared_var() {
265265+ let src = "foo :: (): int { a = 1 }";
266266+ let (_ctx, result) = typecheck_src(src);
267267+ assert!(result.is_err());
268268+269269+ let err = result.unwrap_err();
270270+ assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_)));
271271+}
272272+273273+#[test]
274274+fn test_typecheck_variant_type() {
275275+ let src = "foo :: (): int { x := .None }";
276276+ let (_ctx, result) = typecheck_src(src);
277277+ assert!(result.is_ok());
278278+279279+ let module = result.unwrap();
280280+ let DeclKind::Procedure { block, .. } = &module.declarations[0].node else {
281281+ panic!("expected procedure");
282282+ };
283283+284284+ let StmtKind::ValDec { expr, .. } = &block.node.stmts[0].node else {
285285+ panic!("expected val dec");
286286+ };
287287+288288+ assert!(matches!(
289289+ &expr.node,
290290+ ExprKind::Allocation {
291291+ kind: AllocKind::Variant(variant_name),
292292+ elements,..
293293+294294+ } if *variant_name == Symbol(2) && elements.is_empty()
295295+ ));
296296+}
297297+298298+#[test]
299299+fn test_typecheck_variant_type_with_args() {
300300+ let src = "foo :: (): int { x : .Some(int) | .None = .Some(1) }";
301301+ let (_ctx, result) = typecheck_src(src);
302302+ assert!(result.is_ok());
303303+304304+ let module = result.unwrap();
305305+ let DeclKind::Procedure { block, .. } = &module.declarations[0].node else {
306306+ panic!("expected procedure");
307307+ };
308308+309309+ let StmtKind::ValDec { expr, .. } = &block.node.stmts[0].node else {
310310+ panic!("expected val dec");
311311+ };
312312+313313+ assert!(matches!(
314314+ &expr.node,
315315+ ExprKind::Allocation {
316316+ kind: AllocKind::Variant(variant_name),
317317+ elements,..
318318+319319+ } if *variant_name == Symbol(2) && elements.len() == 1 && elements[0].node == ExprKind::Value(ValueKind::Int(1))
320320+ ));
321321+}
322322+323323+#[test]
324324+fn test_typecheck_subtyping_record() {
325325+ let src = "foo :: () { x : { a: int } = { a := 1, b := 2 } }";
326326+ let (_ctx, result) = typecheck_src(src);
327327+ assert!(result.is_ok());
328328+}
329329+330330+#[test]
331331+fn test_comptime_constant_evaluation() {
332332+ let src = "MY_CONST :: 1 + 2 * 3";
333333+ let (_ctx, result) = typecheck_src(src);
334334+ assert!(result.is_ok());
335335+}
336336+337337+#[test]
338338+fn test_comptime_bool_evaluation() {
339339+ let src = "TRUE_CONST :: true and false";
340340+ let (_ctx, result) = typecheck_src(src);
341341+ assert!(result.is_ok());
342342+}
343343+344344+#[test]
345345+fn test_monomorphization_basic_comptime_type() {
346346+ let src = "identity :: (comptime T: type, x: T): T { return x }";
347347+ let (_ctx, result) = typecheck_src(src);
348348+ assert!(result.is_ok());
349349+ let module = result.unwrap();
350350+351351+ let proc = module
352352+ .declarations
353353+ .iter()
354354+ .find(|d| matches!(&d.node, DeclKind::Procedure { .. }))
355355+ .expect("generic function not found");
356356+357357+ if let DeclKind::Procedure {
358358+ sig, monomorph_of, ..
359359+ } = &proc.node
360360+ {
361361+ assert!(
362362+ monomorph_of.is_none(),
363363+ "Original should not have monomorph_of"
364364+ );
365365+ let params = &sig.node.params.params;
366366+ assert_eq!(params.len(), 2);
367367+ assert!(params[0].is_comptime);
368368+ assert!(matches!(params[0].ty.node, TypeKind::Type));
369369+ }
370370+}
371371+372372+#[test]
373373+fn test_monomorphization_multiple_comptime_params() {
374374+ let src = "first :: (comptime T: type, comptime U: type, a: T, b: U): T { return a }";
375375+ let (_ctx, result) = typecheck_src(src);
376376+ assert!(result.is_ok());
377377+ let module = result.unwrap();
378378+379379+ let proc = module
380380+ .declarations
381381+ .iter()
382382+ .find(|d| matches!(&d.node, DeclKind::Procedure { .. }))
383383+ .expect("generic function not found");
384384+385385+ if let DeclKind::Procedure { sig, .. } = &proc.node {
386386+ let params = &sig.node.params.params;
387387+ assert_eq!(params.len(), 4);
388388+ assert!(params[0].is_comptime);
389389+ assert!(params[1].is_comptime);
390390+ assert!(!params[2].is_comptime);
391391+ assert!(!params[3].is_comptime);
392392+ }
393393+}
394394+395395+#[test]
396396+fn test_monomorphization_mixed_params() {
397397+ let src = "wrap :: (comptime T: type, x: T, y: int): T { return x }";
398398+ let (_ctx, result) = typecheck_src(src);
399399+ assert!(result.is_ok());
400400+ let module = result.unwrap();
401401+402402+ let proc = module
403403+ .declarations
404404+ .iter()
405405+ .find(|d| matches!(&d.node, DeclKind::Procedure { .. }))
406406+ .expect("generic function not found");
407407+408408+ if let DeclKind::Procedure { sig, .. } = &proc.node {
409409+ let params = &sig.node.params.params;
410410+ assert_eq!(params.len(), 3);
411411+ assert!(params[0].is_comptime);
412412+ assert!(!params[1].is_comptime);
413413+ assert!(!params[2].is_comptime);
414414+ }
415415+}
416416+417417+#[test]
418418+fn test_monomorphization_basic() {
419419+ let src = "identity :: (comptime T: type, x: T): T { return x } \n main :: () { y : int = identity(int, 42) }";
420420+ let (ctx, result) = typecheck_src(src);
421421+ assert!(result.is_ok(), "typechecking failed: {:?}", result);
422422+ let module = result.unwrap();
423423+424424+ let monomorph_decl = module.declarations.iter().find(|d| {
425425+ if let DeclKind::Procedure { name, .. } = &d.node {
426426+ ctx.resolve(name.node).starts_with("identity_TInt")
427427+ } else {
428428+ false
429429+ }
430430+ });
431431+ assert!(
432432+ monomorph_decl.is_some(),
433433+ "monomorphized identity_TInt not found"
434434+ );
435435+436436+ let monomorph = monomorph_decl.unwrap();
437437+ if let DeclKind::Procedure {
438438+ sig, monomorph_of, ..
439439+ } = &monomorph.node
440440+ {
441441+ assert!(monomorph_of.is_some(), "monomorph_of should be set");
442442+ let params = &sig.node.params.params;
443443+ assert_eq!(params.len(), 1);
444444+ assert!(!params[0].is_comptime, "x param should remain runtime");
445445+ assert_eq!(params[0].ty.node, TypeKind::Int);
446446+ }
447447+}