region-based memory management in a c-like form
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

adopt rust's array syntax

+759 -567
+2 -2
frontend/src/ast.rs
··· 105 105 pub enum AllocKind { 106 106 // this should always be a ComptimeInt by the time we get to MIR lowering 107 107 Array(Box<TypeKind>, Box<ComptimeValue>), 108 - DynArray(Box<TypeKind>), 109 108 Record(Vec<RecordField>), 110 109 Str(String), 111 110 Tuple(Vec<TypeKind>), ··· 116 115 pub fn fill_type(&mut self, ty: TypeKind) { 117 116 match self { 118 117 AllocKind::Array(ty_, _) => *ty_ = Box::new(ty), 119 - AllocKind::DynArray(ty_) => *ty_ = Box::new(ty), 120 118 _ => {} 121 119 } 122 120 } ··· 145 143 kind: AllocKind, 146 144 // some allocations may not have elements, we just leave this empty 147 145 elements: Vec<Expr>, 146 + // for [expr; n] syntax - the default element to repeat n times 147 + default_elem: Option<Box<Expr>>, 148 148 // without a region, this is allocated in the function's implicit contextual region 149 149 region: Option<Region>, 150 150 },
+447
frontend/src/ast_typecheck/tests.rs
··· 1 + #![cfg(test)] 2 + 3 + use super::*; 4 + 5 + use std::collections::VecDeque; 6 + 7 + use crate::{ast::TypeKind, ctx::Ctx, lex, parse, span::Spanned}; 8 + 9 + fn tokenify(s: &str) -> (Ctx, VecDeque<Spanned<crate::lex::Token>>) { 10 + let mut ctx = Ctx::default(); 11 + let tokens = lex::tokenize(&mut ctx, s).map(|t| t.unwrap()).collect(); 12 + (ctx, tokens) 13 + } 14 + 15 + fn parseify(ctx: &mut Ctx, tokens: VecDeque<Spanned<crate::lex::Token>>) -> Module { 16 + parse::parse(ctx, tokens).unwrap() 17 + } 18 + 19 + fn typecheck_src(src: &str) -> (Ctx, TypecheckResult<Module>) { 20 + let (mut ctx, tokens) = tokenify(src); 21 + let mut module = parseify(&mut ctx, tokens); 22 + let result = typecheck(&mut ctx, &mut module); 23 + (ctx, result) 24 + } 25 + 26 + #[test] 27 + fn test_typecheck_simple_procedure() { 28 + let src = "foo :: (x: int): int { y : int = x }"; 29 + let (_, result) = typecheck_src(src); 30 + assert!(result.is_ok()); 31 + } 32 + 33 + #[test] 34 + fn test_typecheck_infers_val_type() { 35 + let src = "foo :: (x: int): int { y := x }"; 36 + let (_, result) = typecheck_src(src); 37 + assert!(result.is_ok()); 38 + 39 + let module = result.unwrap(); 40 + let DeclKind::Procedure { block, .. } = &module.declarations[0].node else { 41 + panic!("expected procedure"); 42 + }; 43 + 44 + let StmtKind::ValDec { ty, .. } = &block.node.stmts[0].node else { 45 + panic!("expected val dec"); 46 + }; 47 + 48 + assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 49 + } 50 + 51 + #[test] 52 + fn test_typecheck_binop_expression() { 53 + let src = "foo :: (x: int, y: int): int { z : int = x + y }"; 54 + let (_ctx, result) = typecheck_src(src); 55 + assert!(result.is_ok()); 56 + } 57 + 58 + #[test] 59 + fn test_typecheck_assignment() { 60 + let src = "foo :: (x: int): int { y : int = x \n y = x + 1 }"; 61 + let (_ctx, result) = typecheck_src(src); 62 + assert!(result.is_ok()); 63 + } 64 + 65 + #[test] 66 + fn test_typecheck_if_else() { 67 + let src = "foo :: (x: int): int { if x { y : int = 1 } else { z : int = 2 } }"; 68 + let (_ctx, result) = typecheck_src(src); 69 + assert!(result.is_ok()); 70 + } 71 + 72 + #[test] 73 + fn test_typecheck_constant() { 74 + let src = "MY_CONST :: 42"; 75 + let (_ctx, result) = typecheck_src(src); 76 + assert!(result.is_ok()); 77 + 78 + let module = result.unwrap(); 79 + let DeclKind::Constant { ty, .. } = &module.declarations[0].node else { 80 + panic!("expected constant"); 81 + }; 82 + 83 + assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 84 + } 85 + 86 + #[test] 87 + fn test_typecheck_function_call() { 88 + let src = "bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { bar(1) }"; 89 + let (_ctx, result) = typecheck_src(src); 90 + assert!(result.is_ok()); 91 + } 92 + 93 + #[test] 94 + fn test_typecheck_function_call_with_return() { 95 + let src = 96 + "bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { result : int = bar(1) }"; 97 + let (_ctx, result) = typecheck_src(src); 98 + assert!(result.is_ok()); 99 + } 100 + 101 + #[test] 102 + fn test_typecheck_error_unknown_symbol_in_ident() { 103 + let src = "foo :: (): int { y : int = unknown }"; 104 + let (_ctx, result) = typecheck_src(src); 105 + assert!(result.is_err()); 106 + let err = result.unwrap_err(); 107 + assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_))); 108 + } 109 + 110 + #[test] 111 + fn test_typecheck_error_unknown_symbol_in_assignment() { 112 + let src = "foo :: (): int { y : int = 1 \n y = unknown }"; 113 + let (_ctx, result) = typecheck_src(src); 114 + assert!(result.is_err()); 115 + let err = result.unwrap_err(); 116 + assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_))); 117 + } 118 + 119 + #[test] 120 + fn test_typecheck_error_unknown_function() { 121 + let src = "foo :: (): int { unknown_func(1) }"; 122 + let (_ctx, result) = typecheck_src(src); 123 + assert!(result.is_err()); 124 + 125 + let err = result.unwrap_err(); 126 + assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_))); 127 + } 128 + 129 + #[test] 130 + fn test_typecheck_nested_if() { 131 + let src = "foo :: (x: int): int { if 1 { if 1 { y : int = 1 } } }"; 132 + let (_ctx, result) = typecheck_src(src); 133 + assert!(result.is_ok()); 134 + } 135 + 136 + #[test] 137 + fn test_typecheck_multiple_params() { 138 + let src = "foo :: (a: int, b: int, c: int): int { sum : int = 1 + 2 + 3 }"; 139 + let (_ctx, result) = typecheck_src(src); 140 + assert!(result.is_ok()); 141 + } 142 + 143 + #[test] 144 + fn test_typecheck_procedure_infers_fn_type() { 145 + let src = "foo :: (x: int): int { y : int = 1 }"; 146 + let (_ctx, result) = typecheck_src(src); 147 + assert!(result.is_ok()); 148 + 149 + let module = result.unwrap(); 150 + let DeclKind::Procedure { fn_ty, sig, .. } = &module.declarations[0].node else { 151 + panic!("expected procedure"); 152 + }; 153 + 154 + assert!(fn_ty.is_some()); 155 + let TypeKind::Fn(fn_sig) = &fn_ty.as_ref().unwrap().node else { 156 + panic!("expected fn type"); 157 + }; 158 + assert_eq!(**fn_sig, sig.node); 159 + } 160 + 161 + #[test] 162 + fn test_typecheck_multiple_declarations() { 163 + let src = 164 + "CONST :: 10 \n bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { bar(1) }"; 165 + let (_ctx, result) = typecheck_src(src); 166 + assert!(result.is_ok()); 167 + 168 + let module = result.unwrap(); 169 + assert_eq!(module.declarations.len(), 3); 170 + } 171 + 172 + #[test] 173 + fn test_typecheck_constant_with_type_annotation() { 174 + let src = "MY_CONST : int : 42"; 175 + let (_ctx, result) = typecheck_src(src); 176 + assert!(result.is_ok()); 177 + 178 + let module = result.unwrap(); 179 + let DeclKind::Constant { ty, .. } = &module.declarations[0].node else { 180 + panic!("expected constant"); 181 + }; 182 + 183 + assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 184 + } 185 + 186 + #[test] 187 + fn test_typecheck_constant_with_binop() { 188 + let src = "MY_CONST :: 1 + 2 * 3"; 189 + let (_ctx, result) = typecheck_src(src); 190 + assert!(result.is_ok()); 191 + 192 + let module = result.unwrap(); 193 + let DeclKind::Constant { ty, .. } = &module.declarations[0].node else { 194 + panic!("expected constant"); 195 + }; 196 + 197 + assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 198 + } 199 + 200 + #[test] 201 + fn test_typecheck_empty_procedure() { 202 + let src = "foo :: () {}"; 203 + let (_ctx, result) = typecheck_src(src); 204 + assert!(result.is_ok()); 205 + } 206 + 207 + #[test] 208 + fn test_typecheck_procedure_with_return_type() { 209 + let src = "foo :: (): int {}"; 210 + let (_ctx, result) = typecheck_src(src); 211 + assert!(result.is_ok()); 212 + 213 + let module = result.unwrap(); 214 + let DeclKind::Procedure { sig, .. } = &module.declarations[0].node else { 215 + panic!("expected procedure"); 216 + }; 217 + 218 + assert_eq!( 219 + sig.node.return_ty.as_ref().map(|t| &t.node), 220 + Some(&TypeKind::Int) 221 + ); 222 + } 223 + 224 + #[test] 225 + fn test_typecheck_val_dec_infers_int_from_literal() { 226 + let src = "foo :: (): int { y := 42 }"; 227 + let (_ctx, result) = typecheck_src(src); 228 + assert!(result.is_ok()); 229 + 230 + let module = result.unwrap(); 231 + let DeclKind::Procedure { block, .. } = &module.declarations[0].node else { 232 + panic!("expected procedure"); 233 + }; 234 + 235 + let StmtKind::ValDec { ty, .. } = &block.node.stmts[0].node else { 236 + panic!("expected val dec"); 237 + }; 238 + 239 + assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 240 + } 241 + 242 + #[test] 243 + fn test_typecheck_multiple_val_decs() { 244 + let src = "foo :: (): int { a : int = 1 \n b : int = 2 \n c : int = 3 }"; 245 + let (_ctx, result) = typecheck_src(src); 246 + assert!(result.is_ok()); 247 + } 248 + 249 + #[test] 250 + fn test_typecheck_val_dec_uses_previous_val() { 251 + let src = "foo :: (): int { a : int = 1 \n b : int = a }"; 252 + let (_ctx, result) = typecheck_src(src); 253 + assert!(result.is_ok()); 254 + } 255 + 256 + #[test] 257 + fn test_typecheck_assignment_to_declared_var() { 258 + let src = "foo :: (): int { a : int = 1 \n a = 2 }"; 259 + let (_ctx, result) = typecheck_src(src); 260 + assert!(result.is_ok()); 261 + } 262 + 263 + #[test] 264 + fn test_typecheck_error_assignment_to_undeclared_var() { 265 + let src = "foo :: (): int { a = 1 }"; 266 + let (_ctx, result) = typecheck_src(src); 267 + assert!(result.is_err()); 268 + 269 + let err = result.unwrap_err(); 270 + assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_))); 271 + } 272 + 273 + #[test] 274 + fn test_typecheck_variant_type() { 275 + let src = "foo :: (): int { x := .None }"; 276 + let (_ctx, result) = typecheck_src(src); 277 + assert!(result.is_ok()); 278 + 279 + let module = result.unwrap(); 280 + let DeclKind::Procedure { block, .. } = &module.declarations[0].node else { 281 + panic!("expected procedure"); 282 + }; 283 + 284 + let StmtKind::ValDec { expr, .. } = &block.node.stmts[0].node else { 285 + panic!("expected val dec"); 286 + }; 287 + 288 + assert!(matches!( 289 + &expr.node, 290 + ExprKind::Allocation { 291 + kind: AllocKind::Variant(variant_name), 292 + elements,.. 293 + 294 + } if *variant_name == Symbol(2) && elements.is_empty() 295 + )); 296 + } 297 + 298 + #[test] 299 + fn test_typecheck_variant_type_with_args() { 300 + let src = "foo :: (): int { x : .Some(int) | .None = .Some(1) }"; 301 + let (_ctx, result) = typecheck_src(src); 302 + assert!(result.is_ok()); 303 + 304 + let module = result.unwrap(); 305 + let DeclKind::Procedure { block, .. } = &module.declarations[0].node else { 306 + panic!("expected procedure"); 307 + }; 308 + 309 + let StmtKind::ValDec { expr, .. } = &block.node.stmts[0].node else { 310 + panic!("expected val dec"); 311 + }; 312 + 313 + assert!(matches!( 314 + &expr.node, 315 + ExprKind::Allocation { 316 + kind: AllocKind::Variant(variant_name), 317 + elements,.. 318 + 319 + } if *variant_name == Symbol(2) && elements.len() == 1 && elements[0].node == ExprKind::Value(ValueKind::Int(1)) 320 + )); 321 + } 322 + 323 + #[test] 324 + fn test_typecheck_subtyping_record() { 325 + let src = "foo :: () { x : { a: int } = { a := 1, b := 2 } }"; 326 + let (_ctx, result) = typecheck_src(src); 327 + assert!(result.is_ok()); 328 + } 329 + 330 + #[test] 331 + fn test_comptime_constant_evaluation() { 332 + let src = "MY_CONST :: 1 + 2 * 3"; 333 + let (_ctx, result) = typecheck_src(src); 334 + assert!(result.is_ok()); 335 + } 336 + 337 + #[test] 338 + fn test_comptime_bool_evaluation() { 339 + let src = "TRUE_CONST :: true and false"; 340 + let (_ctx, result) = typecheck_src(src); 341 + assert!(result.is_ok()); 342 + } 343 + 344 + #[test] 345 + fn test_monomorphization_basic_comptime_type() { 346 + let src = "identity :: (comptime T: type, x: T): T { return x }"; 347 + let (_ctx, result) = typecheck_src(src); 348 + assert!(result.is_ok()); 349 + let module = result.unwrap(); 350 + 351 + let proc = module 352 + .declarations 353 + .iter() 354 + .find(|d| matches!(&d.node, DeclKind::Procedure { .. })) 355 + .expect("generic function not found"); 356 + 357 + if let DeclKind::Procedure { 358 + sig, monomorph_of, .. 359 + } = &proc.node 360 + { 361 + assert!( 362 + monomorph_of.is_none(), 363 + "Original should not have monomorph_of" 364 + ); 365 + let params = &sig.node.params.params; 366 + assert_eq!(params.len(), 2); 367 + assert!(params[0].is_comptime); 368 + assert!(matches!(params[0].ty.node, TypeKind::Type)); 369 + } 370 + } 371 + 372 + #[test] 373 + fn test_monomorphization_multiple_comptime_params() { 374 + let src = "first :: (comptime T: type, comptime U: type, a: T, b: U): T { return a }"; 375 + let (_ctx, result) = typecheck_src(src); 376 + assert!(result.is_ok()); 377 + let module = result.unwrap(); 378 + 379 + let proc = module 380 + .declarations 381 + .iter() 382 + .find(|d| matches!(&d.node, DeclKind::Procedure { .. })) 383 + .expect("generic function not found"); 384 + 385 + if let DeclKind::Procedure { sig, .. } = &proc.node { 386 + let params = &sig.node.params.params; 387 + assert_eq!(params.len(), 4); 388 + assert!(params[0].is_comptime); 389 + assert!(params[1].is_comptime); 390 + assert!(!params[2].is_comptime); 391 + assert!(!params[3].is_comptime); 392 + } 393 + } 394 + 395 + #[test] 396 + fn test_monomorphization_mixed_params() { 397 + let src = "wrap :: (comptime T: type, x: T, y: int): T { return x }"; 398 + let (_ctx, result) = typecheck_src(src); 399 + assert!(result.is_ok()); 400 + let module = result.unwrap(); 401 + 402 + let proc = module 403 + .declarations 404 + .iter() 405 + .find(|d| matches!(&d.node, DeclKind::Procedure { .. })) 406 + .expect("generic function not found"); 407 + 408 + if let DeclKind::Procedure { sig, .. } = &proc.node { 409 + let params = &sig.node.params.params; 410 + assert_eq!(params.len(), 3); 411 + assert!(params[0].is_comptime); 412 + assert!(!params[1].is_comptime); 413 + assert!(!params[2].is_comptime); 414 + } 415 + } 416 + 417 + #[test] 418 + fn test_monomorphization_basic() { 419 + let src = "identity :: (comptime T: type, x: T): T { return x } \n main :: () { y : int = identity(int, 42) }"; 420 + let (ctx, result) = typecheck_src(src); 421 + assert!(result.is_ok(), "typechecking failed: {:?}", result); 422 + let module = result.unwrap(); 423 + 424 + let monomorph_decl = module.declarations.iter().find(|d| { 425 + if let DeclKind::Procedure { name, .. } = &d.node { 426 + ctx.resolve(name.node).starts_with("identity_TInt") 427 + } else { 428 + false 429 + } 430 + }); 431 + assert!( 432 + monomorph_decl.is_some(), 433 + "monomorphized identity_TInt not found" 434 + ); 435 + 436 + let monomorph = monomorph_decl.unwrap(); 437 + if let DeclKind::Procedure { 438 + sig, monomorph_of, .. 439 + } = &monomorph.node 440 + { 441 + assert!(monomorph_of.is_some(), "monomorph_of should be set"); 442 + let params = &sig.node.params.params; 443 + assert_eq!(params.len(), 1); 444 + assert!(!params[0].is_comptime, "x param should remain runtime"); 445 + assert_eq!(params[0].ty.node, TypeKind::Int); 446 + } 447 + }
+4 -4
frontend/src/lib.rs
··· 1 1 mod ast; 2 - mod to_mir; 2 + mod ast_typecheck; 3 3 mod ast_visitor; 4 4 mod ctx; 5 5 mod lex; ··· 7 7 pub mod mir; 8 8 mod parse; 9 9 mod span; 10 - mod typecheck; 10 + mod to_mir; 11 11 12 12 pub use ctx::{Ctx, Symbol}; 13 13 pub use lex::BinOp; 14 14 pub use mir::{Function, visualize}; 15 15 pub use span::{Diagnostic, SourceMap, Span, SpanExt, Spanned}; 16 16 17 - use to_mir::AstToMIR; 18 17 use ast_visitor::AstVisitor; 18 + use to_mir::AstToMIR; 19 19 20 20 use std::collections::VecDeque; 21 21 use std::fs::File; ··· 41 41 42 42 let mut module = parse::parse(&mut ctx, tokens).map_err(|e| e.format(&source_map))?; 43 43 44 - typecheck::typecheck(&mut ctx, &mut module).map_err(|e| e.format(&source_map))?; 44 + ast_typecheck::typecheck(&mut ctx, &mut module).map_err(|e| e.format(&source_map))?; 45 45 46 46 let mut ast_visitor = AstToMIR::new(&ctx); 47 47 ast_visitor.visit_module(module);
+188 -50
frontend/src/parse/mod.rs
··· 103 103 if let ExprKind::Allocation { 104 104 kind: _, 105 105 elements: _, 106 + default_elem: _, 106 107 region, 107 108 } = &mut expr.node 108 109 { ··· 431 432 ExprKind::Allocation { 432 433 kind: AllocKind::Variant(variant_name), 433 434 elements: args, 435 + default_elem: None, 434 436 region: None, 435 437 }, 436 438 span, ··· 440 442 ExprKind::Allocation { 441 443 kind: AllocKind::Variant(variant_name), 442 444 elements: vec![], 445 + default_elem: None, 443 446 region: None, 444 447 }, 445 448 span, ··· 482 485 ExprKind::Allocation { 483 486 kind: AllocKind::Str(s), 484 487 elements: vec![], 488 + default_elem: None, 485 489 region: None, 486 490 }, 487 491 token.span, ··· 513 517 parse_variant_expr(ctx, variant_name, span, tokens) 514 518 } 515 519 520 + // array expr 516 521 Token::LBracket => { 517 522 let start_span = token.span; 518 - let next_tok = tokens.pop_front().ok_or_else(ParseError::eof)?; 519 523 520 - let mut alloc_kind = match next_tok.node { 521 - Token::RBracket => AllocKind::DynArray(TypeKind::Int.into()), 522 - Token::Int(i) => { 523 - expect_next(tokens, Token::RBracket)?; 524 - AllocKind::Array(TypeKind::Any.into(), ComptimeValue::Int(i as i128).into()) 525 - } 526 - Token::Identifier(name) => { 527 - expect_next(tokens, Token::RBracket)?; 528 - // assuming comptime identifier that will be resolved during typechecking 529 - AllocKind::Array(TypeKind::Any.into(), ComptimeValue::Ident(name).into()) 530 - } 531 - _ => { 532 - return Err(ParseError::new( 533 - ParseErrorKind::ExpectedExpression, 534 - next_tok.span, 535 - )); 536 - } 537 - }; 538 - 539 - let Some(array_ty) = parse_type(ctx, tokens)? else { 540 - return Err(ParseError::new( 541 - ParseErrorKind::ExpectedType, 542 - peek_span(tokens).unwrap_or(start_span), 524 + // Handle empty list [] 525 + if let Some(Token::RBracket) = peek_token(tokens) { 526 + let end_span = expect_next(tokens, Token::RBracket)?; 527 + return Ok(Spanned::new( 528 + ExprKind::Allocation { 529 + kind: AllocKind::Array(TypeKind::Any.into(), ComptimeValue::Int(0).into()), 530 + elements: vec![], 531 + default_elem: None, 532 + region: None, 533 + }, 534 + start_span.merge(&end_span), 543 535 )); 544 - }; 536 + } 545 537 546 - alloc_kind.fill_type(array_ty.node); 538 + // Parse first expression 539 + let first_expr = parse_expr(ctx, tokens)?; 547 540 548 - expect_next(tokens, Token::LBrace)?; 549 - 550 - let mut exprs = Vec::new(); 541 + match peek_token(tokens) { 542 + // [expr; size] - default array syntax 543 + Some(Token::SemiColon) => { 544 + tokens.pop_front(); // consume ; 545 + let size_expr = parse_expr(ctx, tokens)?; 546 + let size_cv = match &size_expr.node { 547 + ExprKind::Value(ValueKind::Int(i)) => ComptimeValue::Int(*i as i128), 548 + ExprKind::Value(ValueKind::Ident(name)) => ComptimeValue::Ident(*name), 549 + _ => { 550 + return Err(ParseError::new( 551 + ParseErrorKind::ExpectedExpression, 552 + size_expr.span, 553 + )); 554 + } 555 + }; 556 + expect_next(tokens, Token::RBracket)?; 557 + let region = check_region_type_annotation(ctx, tokens)?; 558 + let span = start_span.merge(&size_expr.span); 551 559 552 - loop { 553 - if let Some(Token::RBrace) = peek_token(tokens) { 554 - break; 560 + Ok(Spanned::new( 561 + ExprKind::Allocation { 562 + kind: AllocKind::Array(TypeKind::Any.into(), size_cv.into()), 563 + elements: vec![], 564 + default_elem: Some(Box::new(first_expr)), 565 + region, 566 + }, 567 + span, 568 + )) 555 569 } 556 570 557 - exprs.push(parse_expr(ctx, tokens)?); 571 + // [expr, expr, ...] or [expr] - list literal syntax 572 + Some(Token::Comma) | Some(Token::RBracket) => { 573 + let mut exprs = vec![first_expr]; 574 + 575 + while let Some(Token::Comma) = peek_token(tokens) { 576 + tokens.pop_front(); // consume , 577 + if let Some(Token::RBracket) = peek_token(tokens) { 578 + break; // trailing comma 579 + } 580 + exprs.push(parse_expr(ctx, tokens)?); 581 + } 582 + 583 + let end_span = expect_next(tokens, Token::RBracket)?; 584 + let span = start_span.merge(&end_span); 558 585 559 - if let Some(Token::Comma) = peek_token(tokens) { 560 - tokens.pop_front(); 586 + Ok(Spanned::new( 587 + ExprKind::Allocation { 588 + kind: AllocKind::Array( 589 + TypeKind::Any.into(), 590 + ComptimeValue::Int(exprs.len() as i128).into(), 591 + ), 592 + elements: exprs, 593 + default_elem: None, 594 + region: None, 595 + }, 596 + span, 597 + )) 561 598 } 562 - } 563 599 564 - let end_span = expect_next(tokens, Token::RBrace)?; 565 - let span = start_span.merge(&end_span); 566 - 567 - Ok(Spanned::new( 568 - ExprKind::Allocation { 569 - kind: alloc_kind, 570 - elements: exprs, 571 - region: None, 572 - }, 573 - span, 574 - )) 600 + _ => Err(ParseError::new( 601 + ParseErrorKind::ExpectedExpression, 602 + peek_span(tokens).unwrap_or(start_span), 603 + )), 604 + } 575 605 } 576 606 607 + // Token::LBracket => { 608 + // let start_span = token.span; 609 + // 610 + // let is_default_array = match peek_token(tokens) { 611 + // Some(Token::SemiColon) => true, 612 + // Some(Token::Int(_) | Token::Identifier(_) | Token::Keyword(_)) => { 613 + // let mut temp_tokens = tokens.clone(); 614 + // let _ = parse_expr(ctx, &mut temp_tokens); 615 + // matches!(peek_token(&temp_tokens), Some(Token::SemiColon)) 616 + // } 617 + // _ => false, 618 + // }; 619 + // 620 + // if is_default_array { 621 + // let expr = parse_expr(ctx, tokens)?; 622 + // let _ = expect_next(tokens, Token::SemiColon)?; 623 + // let default_elem = Box::new(expr); 624 + // 625 + // let size_expr = parse_expr(ctx, tokens)?; 626 + // let size_cv = match &size_expr.node { 627 + // ExprKind::Value(ValueKind::Int(i)) => ComptimeValue::Int(*i as i128), 628 + // ExprKind::Value(ValueKind::Ident(name)) => ComptimeValue::Ident(*name), 629 + // _ => { 630 + // return Err(ParseError::new( 631 + // ParseErrorKind::ExpectedExpression, 632 + // size_expr.span, 633 + // )); 634 + // } 635 + // }; 636 + // expect_next(tokens, Token::RBracket)?; 637 + // 638 + // let region = check_region_type_annotation(ctx, tokens)?; 639 + // 640 + // let span = start_span.merge(&size_expr.span); 641 + // 642 + // Ok(Spanned::new( 643 + // ExprKind::Allocation { 644 + // kind: AllocKind::Array(TypeKind::Any.into(), size_cv.into()), 645 + // elements: vec![], 646 + // default_elem: Some(default_elem), 647 + // region, 648 + // }, 649 + // span, 650 + // )) 651 + // } else { 652 + // let next_tok = tokens.pop_front().ok_or_else(ParseError::eof)?; 653 + // 654 + // let mut alloc_kind = match next_tok.node { 655 + // Token::RBracket => AllocKind::DynArray(TypeKind::Int.into()), 656 + // Token::Int(i) => { 657 + // expect_next(tokens, Token::RBracket)?; 658 + // AllocKind::Array(TypeKind::Any.into(), ComptimeValue::Int(i as i128).into()) 659 + // } 660 + // Token::Identifier(name) => { 661 + // expect_next(tokens, Token::RBracket)?; 662 + // AllocKind::Array(TypeKind::Any.into(), ComptimeValue::Ident(name).into()) 663 + // } 664 + // _ => { 665 + // return Err(ParseError::new( 666 + // ParseErrorKind::ExpectedExpression, 667 + // next_tok.span, 668 + // )); 669 + // } 670 + // }; 671 + // 672 + // let Some(array_ty) = parse_type(ctx, tokens)? else { 673 + // return Err(ParseError::new( 674 + // ParseErrorKind::ExpectedType, 675 + // peek_span(tokens).unwrap_or(start_span), 676 + // )); 677 + // }; 678 + // 679 + // alloc_kind.fill_type(array_ty.node); 680 + // 681 + // expect_next(tokens, Token::LBrace)?; 682 + // 683 + // let mut exprs = Vec::new(); 684 + // 685 + // loop { 686 + // if let Some(Token::RBrace) = peek_token(tokens) { 687 + // break; 688 + // } 689 + // 690 + // exprs.push(parse_expr(ctx, tokens)?); 691 + // 692 + // if let Some(Token::Comma) = peek_token(tokens) { 693 + // tokens.pop_front(); 694 + // } 695 + // } 696 + // 697 + // let end_span = expect_next(tokens, Token::RBrace)?; 698 + // let span = start_span.merge(&end_span); 699 + // 700 + // Ok(Spanned::new( 701 + // ExprKind::Allocation { 702 + // kind: alloc_kind, 703 + // elements: exprs, 704 + // default_elem: None, 705 + // region: None, 706 + // }, 707 + // span, 708 + // )) 709 + // } 710 + // } 577 711 Token::LParen => { 578 712 let start_span = token.span; 579 713 let expr = parse_expr(ctx, tokens)?; ··· 602 736 // filled in during typechecking 603 737 kind: AllocKind::Tuple(vec![]), 604 738 elements: exprs, 739 + default_elem: None, 605 740 region: None, 606 741 }, 607 742 span, ··· 645 780 ExprKind::Allocation { 646 781 kind: AllocKind::Record(fields), 647 782 elements: exprs, 783 + default_elem: None, 648 784 region: None, 649 785 }, 650 786 span, ··· 904 1040 } 905 1041 Some(Token::LBracket) => { 906 1042 let start_span = tokens.pop_front().unwrap().span; 907 - let next_tok = tokens.pop_front().ok_or_else(ParseError::eof)?; 908 - 909 - expect_next(tokens, Token::RBracket)?; 910 1043 911 1044 let arr_ty = match parse_type(ctx, tokens)? { 912 1045 Some(ty) => ty, ··· 918 1051 } 919 1052 }; 920 1053 1054 + expect_next(tokens, Token::SemiColon)?; 1055 + 1056 + let next_tok = tokens.pop_front().ok_or_else(ParseError::eof)?; 921 1057 let alloc_kind = match next_tok.node { 922 1058 Token::Int(i) => { 923 1059 AllocKind::Array(arr_ty.node.into(), ComptimeValue::Int(i as i128).into()) ··· 933 1069 )); 934 1070 } 935 1071 }; 1072 + 1073 + expect_next(tokens, Token::RBracket)?; 936 1074 937 1075 let span = start_span.merge(&arr_ty.span); 938 1076
+5 -17
frontend/src/parse/tests.rs
··· 297 297 } 298 298 299 299 #[test] 300 - fn parse_array_and_dyn_array() { 300 + fn parse_array() { 301 301 let decs = expect_parse_ok( 302 302 "foo :: () { 303 - x := [3]int{1, 2, 3} 304 - y := []int{1, 2, 3} 303 + x := [1, 2, 3] 305 304 }", 306 305 1, 307 306 ); ··· 310 309 let DeclKind::Procedure { block, .. } = &decs[0].node else { 311 310 unreachable!() 312 311 }; 313 - assert_eq!(block.node.stmts.len(), 2); 312 + assert_eq!(block.node.stmts.len(), 1); 314 313 315 314 // Verify first is Array, second is DynArray 316 315 let StmtKind::ValDec { expr: expr1, .. } = &block.node.stmts[0].node else { ··· 321 320 &expr1.node, 322 321 ExprKind::Allocation { 323 322 kind: AllocKind::Array(_, _), 324 - .. 325 - } 326 - )); 327 - 328 - let StmtKind::ValDec { expr: expr2, .. } = &block.node.stmts[1].node else { 329 - unreachable!() 330 - }; 331 - assert!(matches!( 332 - &expr2.node, 333 - ExprKind::Allocation { 334 - kind: AllocKind::DynArray(_), 335 323 .. 336 324 } 337 325 )); ··· 715 703 fn parse_region_alloc() { 716 704 let decs = expect_parse_ok( 717 705 "foo :: (comptime R: region) { 718 - x := [2]int{ 1, 2 } @ local 706 + x := [ 1, 2 ] @ local 719 707 y := (1, false) @ R 720 708 }", 721 709 1, ··· 736 724 737 725 assert_eq!( 738 726 *kind, 739 - AllocKind::Array(TypeKind::Int.into(), ComptimeValue::Int(2).into()) 727 + AllocKind::Array(TypeKind::Any.into(), ComptimeValue::Int(2).into()) 740 728 ); 741 729 assert_eq!(*region, Some(Region::Local)); 742 730
+55 -16
frontend/src/to_mir/mod.rs
··· 351 351 monomorph_of: _, 352 352 is_comptime, 353 353 } => { 354 - let name_ = self.ctx.resolve(name.node).to_string(); 355 354 if *is_comptime { 356 - println!("skipping {name_}"); 357 355 return; 358 356 } 359 - println!("compiling {name_}"); 360 357 361 358 let name_sym = name.node; 362 359 // TODO: we do not use function types yet ··· 365 362 self.function_sigs.insert(name_sym, sig.clone()); 366 363 367 364 let sig_inner = &sig.node; 368 - eprintln!("\t{sig_inner:?}"); 369 365 let return_ty = sig_inner 370 366 .return_ty 371 367 .as_ref() ··· 489 485 ExprKind::Allocation { 490 486 kind, 491 487 elements, 488 + default_elem, 492 489 region: _, 493 490 } => { 494 491 let mut ops = Vec::new(); 495 492 let mut elem_types = Vec::new(); 496 - for elem in elements { 497 - let elem = self.visit_expr(elem); 498 - let (op, ty) = match elem { 493 + 494 + if let Some(default_elem) = default_elem { 495 + let default_mir = self.visit_expr(*default_elem); 496 + let (op, ty) = match default_mir { 499 497 mir::RValue::Use(mir::Operand::Copy(place)) => { 500 498 let local_ty = self.local_types.get(&place.local).unwrap().clone(); 501 499 (mir::Operand::Copy(place), local_ty) ··· 508 506 let elem_local = self.new_local(&TypeKind::Int); 509 507 self.get_current_block() 510 508 .stmts 511 - .push(mir::Statement::Assign(elem_local, elem)); 509 + .push(mir::Statement::Assign(elem_local, default_mir)); 512 510 513 511 let place = mir::Place::new(elem_local, mir::PlaceKind::Deref); 514 512 let local_ty = self.local_types.get(&elem_local).unwrap().clone(); 515 513 (mir::Operand::Copy(place), local_ty) 516 514 } 517 515 }; 518 - ops.push(op); 519 - elem_types.push(ty); 516 + 517 + let array_size = match kind { 518 + AllocKind::Array(_, ref size) => match size.as_ref() { 519 + ComptimeValue::Int(i) => *i as usize, 520 + ComptimeValue::Ident(_) => { 521 + panic!("comptime identifier should be resolved by typechecker") 522 + } 523 + _ => panic!("unexpected comptime value for array size"), 524 + }, 525 + _ => panic!("expected array allocation"), 526 + }; 527 + 528 + for _ in 0..array_size { 529 + ops.push(op.clone()); 530 + elem_types.push(ty.clone()); 531 + } 532 + } else { 533 + for elem in elements { 534 + let elem = self.visit_expr(elem); 535 + let (op, ty) = match elem { 536 + mir::RValue::Use(mir::Operand::Copy(place)) => { 537 + let local_ty = self.local_types.get(&place.local).unwrap().clone(); 538 + (mir::Operand::Copy(place), local_ty) 539 + } 540 + mir::RValue::Use(mir::Operand::Constant(c)) => { 541 + let local_ty = Self::type_of_constant(&c); 542 + (mir::Operand::Constant(c), local_ty) 543 + } 544 + _ => { 545 + let elem_local = self.new_local(&TypeKind::Int); 546 + self.get_current_block() 547 + .stmts 548 + .push(mir::Statement::Assign(elem_local, elem)); 549 + 550 + let place = mir::Place::new(elem_local, mir::PlaceKind::Deref); 551 + let local_ty = self.local_types.get(&elem_local).unwrap().clone(); 552 + (mir::Operand::Copy(place), local_ty) 553 + } 554 + }; 555 + ops.push(op); 556 + elem_types.push(ty); 557 + } 520 558 } 521 559 522 560 match kind { ··· 528 566 let tys = tys.into_iter().map(|t| ast_type_to_mir_type(&t)).collect(); 529 567 530 568 mir::RValue::Alloc(mir::AllocKind::Tuple(tys), ops) 531 - } 532 - 533 - AllocKind::DynArray(ty) => { 534 - let ty = ast_type_to_mir_type(&ty); 535 - mir::RValue::Alloc(mir::AllocKind::DynArray(ty), ops) 536 569 } 537 570 AllocKind::Record(_fields) => { 538 571 let tys = elem_types ··· 621 654 let local_id = self.new_local(&ty.node); 622 655 623 656 self.symbol_table.insert(name.node, local_id); 657 + 658 + // println!( 659 + // "assigning to {}: {:?}\n\t{:?}", 660 + // self.ctx.resolve(name.node), 661 + // ty, 662 + // expr.node 663 + // ); 624 664 625 665 self.in_assign_expr = true; 626 666 let rvalue = self.visit_expr(expr); ··· 921 961 mir::Ty::Tuple(tys) 922 962 } 923 963 924 - AllocKind::DynArray(ty) => mir::Ty::DynArray(Box::new(ast_type_to_mir_type(ty))), 925 964 AllocKind::Array(ty, len) => { 926 965 if let ComptimeValue::Int(len) = **len { 927 966 mir::Ty::Array(Box::new(ast_type_to_mir_type(ty)), len as usize)
+58 -478
frontend/src/typecheck.rs frontend/src/ast_typecheck/mod.rs
··· 1 - #![allow(unused)] 1 + mod tests; 2 2 3 - use std::collections::{HashMap, HashSet}; 3 + use std::collections::HashMap; 4 4 5 5 use crate::{ 6 6 Ctx, ··· 42 42 } 43 43 44 44 #[derive(Debug)] 45 + #[allow(unused)] 45 46 pub enum TypeErrorKind { 46 47 ArraySizeMismatch { 47 48 expected: ComptimeValue, ··· 134 135 .map(|cv| self.type_of_comptime_value(cv)) 135 136 .collect(); 136 137 if tys.is_empty() { 137 - TypeKind::Alloc(AllocKind::DynArray(Box::new(TypeKind::Unit)), Region::Stack) 138 + TypeKind::Alloc( 139 + AllocKind::Array(Box::new(TypeKind::Unit), ComptimeValue::Int(0).into()), 140 + Region::Stack, 141 + ) 138 142 } else { 139 143 let ty = tys.first().unwrap(); 140 144 assert!(tys.iter().all(|t| t == ty)); 141 - TypeKind::Alloc(AllocKind::DynArray(Box::new(ty.clone())), Region::Stack) 145 + TypeKind::Alloc( 146 + AllocKind::Array( 147 + Box::new(ty.clone()), 148 + ComptimeValue::Int(tys.len() as i128).into(), 149 + ), 150 + Region::Stack, 151 + ) 142 152 } 143 153 } 144 154 ComptimeValue::Bool(_) => TypeKind::Bool, ··· 260 270 AllocKind::Array(ty, size) => AllocKind::Array( 261 271 self.substitute_type(ty, subs).into(), 262 272 match **size { 263 - ComptimeValue::Int(i) => size.clone(), 273 + ComptimeValue::Int(_) => size.clone(), 264 274 ComptimeValue::Ident(sym) => { 265 275 let cv = subs.get(&sym).cloned().unwrap().cv; 266 276 assert!(matches!(cv, ComptimeValue::Int(_))); ··· 286 296 .iter() 287 297 .map(|a| self.substitute_expr(a, subs)) 288 298 .collect(), 289 - returned_ty: call.returned_ty.clone(), 299 + returned_ty: call 300 + .returned_ty 301 + .as_ref() 302 + .map(|t| Spanned::new(self.substitute_type(&t.node, subs), t.span.clone())), 290 303 }), 291 304 expr.span.clone(), 292 305 ), ··· 318 331 ExprKind::Value(ValueKind::Int(*i as i32)), 319 332 expr.span.clone(), 320 333 ), 321 - ComptimeValue::Ident(ident) => { 334 + ComptimeValue::Ident(_ident) => { 322 335 todo!() 323 336 } 324 337 _ => todo!(), ··· 326 339 ExprKind::Allocation { 327 340 kind, 328 341 elements, 342 + default_elem, 329 343 region, 330 344 } => { 331 345 let sub_kind = self.substitute_alloc_kind(kind, subs); 346 + let sub_default_elem = default_elem 347 + .as_ref() 348 + .map(|e| self.substitute_expr(e, subs).into()); 332 349 Spanned::new( 333 350 ExprKind::Allocation { 334 351 kind: sub_kind, ··· 336 353 .iter() 337 354 .map(|e| self.substitute_expr(e, subs)) 338 355 .collect(), 356 + default_elem: sub_default_elem, 339 357 region: *region, 340 358 }, 341 359 expr.span.clone(), ··· 630 648 kind, 631 649 region, 632 650 elements, 651 + default_elem, 633 652 } => { 634 653 let mut elem_vals = Vec::new(); 635 - for elem in elements { 636 - elem_vals.push(self.analyze_expr(elem)?); 654 + 655 + if let Some(default_elem) = default_elem { 656 + let default_val = self.analyze_expr(default_elem)?; 657 + elem_vals.push(default_val); 658 + } else { 659 + for elem in elements { 660 + elem_vals.push(self.analyze_expr(elem)?); 661 + } 637 662 } 638 663 639 664 let region_handle = region.unwrap_or(Region::Stack); ··· 679 704 expr.span.clone(), 680 705 )); 681 706 } 707 + 682 708 Box::new(elem_vals[0].ty.clone()) 683 709 } 684 710 _ => { ··· 711 737 } 712 738 _ => kind.clone(), 713 739 }; 740 + 741 + *kind = resolved_kind.clone(); 714 742 Ok(TypedValue::runtime(TypeKind::Alloc( 715 743 resolved_kind, 716 744 region_handle, ··· 791 819 .map(|arg| self.analyze_expr(arg)) 792 820 .collect::<Result<_, _>>()?; 793 821 794 - let (callee_sig, span) = self.resolve_callee_signature(&call.callee)?; 822 + let (callee_sig, _) = self.resolve_callee_signature(&call.callee)?; 795 823 796 824 let params = &callee_sig.node.params.params; 797 825 let expected_count = params.len(); ··· 862 890 if !comptime_args.is_empty() 863 891 && let ExprKind::Value(ValueKind::Ident(fn_name)) = &call.callee.node 864 892 { 865 - println!("here: {comptime_args:?}"); 866 893 let monomorphized_decl = self.monomorphize(*fn_name, comptime_args)?; 867 894 if let DeclKind::Procedure { name, sig, .. } = monomorphized_decl.node { 868 895 return_ty = sig ··· 931 958 }; 932 959 Ok((sig.clone(), callee.span.clone())) 933 960 } 934 - ExprKind::FieldAccess(receiver, method_name) => { 961 + ExprKind::FieldAccess(_receiver, method_name) => { 935 962 let Some(sig) = self.function_sigs.get(method_name) else { 936 963 return Err(TypeError::new( 937 964 TypeErrorKind::UnknownMethod(*method_name), ··· 1041 1068 )); 1042 1069 } 1043 1070 } 1071 + (TypeKind::Alloc(AllocKind::Str(_), _), TypeKind::Alloc(AllocKind::Str(_), _)) => {} 1044 1072 (TypeKind::Alloc(AllocKind::Str(_), _), TypeKind::Ptr(c)) 1045 1073 if (**c) == TypeKind::Char => {} 1046 1074 _ => { ··· 1081 1109 self.check_entry_point() 1082 1110 } 1083 1111 1112 + #[allow(unused)] 1113 + // found_main is used but rust analyzer complains 1084 1114 fn check_entry_point(&mut self) -> Result<(), TypeError> { 1085 1115 let mut found_main = false; 1086 1116 for function in self.function_sigs.keys() { ··· 1179 1209 } 1180 1210 1181 1211 if param.is_comptime { 1182 - println!("{}", self.front_ctx.resolve(name.node)); 1183 1212 *is_comptime = true; 1184 1213 } 1185 1214 } ··· 1192 1221 let expr_val = self.analyze_expr(expr)?; 1193 1222 self.structural_typecheck(&expr_val.ty, &ret_ty.node, expr.span.clone())?; 1194 1223 } 1224 + 1225 + // we must reinsert the decl here after mutation 1226 + // this is critical for type inference, otherwise, when functions are monomorphized, 1227 + // they monomorphize the uninferred statements 1228 + self.module_decls.insert(name.node, decl.node.clone()); 1195 1229 Ok(()) 1196 1230 } 1197 1231 } ··· 1236 1270 )); 1237 1271 } 1238 1272 } 1273 + 1274 + let name_ = self.front_ctx.resolve(name.node).to_string(); 1275 + println!( 1276 + "inferred type for {}: {:?}\n\t{:?}", 1277 + name_, inferred_ty, expr.node 1278 + ); 1239 1279 *ty = Some(inferred_ty.clone()); 1240 1280 self.type_map.insert(name.node, inferred_ty); 1241 1281 Ok(()) ··· 1251 1291 1252 1292 let val = self.analyze_expr(expr)?; 1253 1293 1254 - if location_val.ty != val.ty { 1255 - return Err(TypeError::new( 1256 - TypeErrorKind::ExpectedType { 1257 - expected: location_val.ty.clone(), 1258 - found: val.ty, 1259 - }, 1260 - expr.span.clone(), 1261 - )); 1262 - } 1294 + self.structural_typecheck(&location_val.ty, &val.ty, expr.span.clone())?; 1263 1295 Ok(()) 1264 1296 } 1265 1297 StmtKind::IfElse(if_else) => { ··· 1278 1310 let scrutinee_val = self.analyze_expr(scrutinee)?; 1279 1311 for arm in arms { 1280 1312 match &arm.pat.node { 1281 - PatKind::Symbol(name) => { 1313 + PatKind::Symbol(_) => { 1282 1314 self.bind_pattern(&arm.pat, &Type::synthetic(scrutinee_val.ty.clone())); 1283 1315 } 1284 1316 PatKind::Variant { name, bindings } => { ··· 1306 1338 } 1307 1339 } 1308 1340 PatKind::Record(fields) => { 1309 - let TypeKind::Record(scru_fields) = &scrutinee_val.ty else { 1341 + let TypeKind::Record(_scru_fields) = &scrutinee_val.ty else { 1310 1342 return Err(TypeError::new( 1311 1343 TypeErrorKind::ExpectedRecord, 1312 1344 scrutinee.span.clone(), ··· 1353 1385 } 1354 1386 } 1355 1387 1356 - pub fn typecheck(ctx: &mut Ctx, module: &mut Module) -> TypecheckResult<Module> { 1388 + pub fn typecheck(ctx: &mut Ctx, module: &mut Module) -> TypecheckResult<()> { 1357 1389 let mut analyzer = Analyzer::new(ctx); 1358 1390 analyzer.typecheck_module(module)?; 1359 - Ok(module.clone()) 1360 - } 1361 - 1362 - #[cfg(test)] 1363 - mod tests { 1364 - use std::collections::VecDeque; 1365 - 1366 - use crate::{ 1367 - ast::{Pat, PatKind, TypeKind}, 1368 - ctx::Ctx, 1369 - lex, parse, 1370 - span::Spanned, 1371 - }; 1372 - 1373 - use super::*; 1374 - 1375 - fn tokenify(s: &str) -> (Ctx, VecDeque<Spanned<crate::lex::Token>>) { 1376 - let mut ctx = Ctx::default(); 1377 - let tokens = lex::tokenize(&mut ctx, s).map(|t| t.unwrap()).collect(); 1378 - (ctx, tokens) 1379 - } 1380 - 1381 - fn parseify(ctx: &mut Ctx, tokens: VecDeque<Spanned<crate::lex::Token>>) -> Module { 1382 - parse::parse(ctx, tokens).unwrap() 1383 - } 1384 - 1385 - fn typecheck_src(src: &str) -> (Ctx, TypecheckResult<Module>) { 1386 - let (mut ctx, tokens) = tokenify(src); 1387 - let mut module = parseify(&mut ctx, tokens); 1388 - let result = typecheck(&mut ctx, &mut module); 1389 - (ctx, result) 1390 - } 1391 - 1392 - #[test] 1393 - fn test_typecheck_simple_procedure() { 1394 - let src = "foo :: (x: int): int { y : int = x }"; 1395 - let (_, result) = typecheck_src(src); 1396 - assert!(result.is_ok()); 1397 - } 1398 - 1399 - #[test] 1400 - fn test_typecheck_infers_val_type() { 1401 - let src = "foo :: (x: int): int { y := x }"; 1402 - let (_, result) = typecheck_src(src); 1403 - assert!(result.is_ok()); 1404 - 1405 - let module = result.unwrap(); 1406 - let DeclKind::Procedure { block, .. } = &module.declarations[0].node else { 1407 - panic!("expected procedure"); 1408 - }; 1409 - 1410 - let StmtKind::ValDec { ty, .. } = &block.node.stmts[0].node else { 1411 - panic!("expected val dec"); 1412 - }; 1413 - 1414 - assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 1415 - } 1416 - 1417 - #[test] 1418 - fn test_typecheck_binop_expression() { 1419 - let src = "foo :: (x: int, y: int): int { z : int = x + y }"; 1420 - let (ctx, result) = typecheck_src(src); 1421 - assert!(result.is_ok()); 1422 - } 1423 - 1424 - #[test] 1425 - fn test_typecheck_assignment() { 1426 - let src = "foo :: (x: int): int { y : int = x \n y = x + 1 }"; 1427 - let (ctx, result) = typecheck_src(src); 1428 - assert!(result.is_ok()); 1429 - } 1430 - 1431 - #[test] 1432 - fn test_typecheck_if_else() { 1433 - let src = "foo :: (x: int): int { if x { y : int = 1 } else { z : int = 2 } }"; 1434 - let (ctx, result) = typecheck_src(src); 1435 - assert!(result.is_ok()); 1436 - } 1437 - 1438 - #[test] 1439 - fn test_typecheck_constant() { 1440 - let src = "MY_CONST :: 42"; 1441 - let (ctx, result) = typecheck_src(src); 1442 - assert!(result.is_ok()); 1443 - 1444 - let module = result.unwrap(); 1445 - let DeclKind::Constant { ty, .. } = &module.declarations[0].node else { 1446 - panic!("expected constant"); 1447 - }; 1448 - 1449 - assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 1450 - } 1451 - 1452 - #[test] 1453 - fn test_typecheck_function_call() { 1454 - let src = "bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { bar(1) }"; 1455 - let (ctx, result) = typecheck_src(src); 1456 - assert!(result.is_ok()); 1457 - } 1458 - 1459 - #[test] 1460 - fn test_typecheck_function_call_with_return() { 1461 - let src = "bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { result : int = bar(1) }"; 1462 - let (ctx, result) = typecheck_src(src); 1463 - assert!(result.is_ok()); 1464 - } 1465 - 1466 - #[test] 1467 - fn test_typecheck_error_unknown_symbol_in_ident() { 1468 - let src = "foo :: (): int { y : int = unknown }"; 1469 - let (ctx, result) = typecheck_src(src); 1470 - assert!(result.is_err()); 1471 - let err = result.unwrap_err(); 1472 - assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_))); 1473 - } 1474 - 1475 - #[test] 1476 - fn test_typecheck_error_unknown_symbol_in_assignment() { 1477 - let src = "foo :: (): int { y : int = 1 \n y = unknown }"; 1478 - let (ctx, result) = typecheck_src(src); 1479 - assert!(result.is_err()); 1480 - let err = result.unwrap_err(); 1481 - assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_))); 1482 - } 1483 - 1484 - #[test] 1485 - fn test_typecheck_error_unknown_function() { 1486 - let src = "foo :: (): int { unknown_func(1) }"; 1487 - let (ctx, result) = typecheck_src(src); 1488 - assert!(result.is_err()); 1489 - 1490 - let err = result.unwrap_err(); 1491 - assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_))); 1492 - } 1493 - 1494 - #[test] 1495 - fn test_typecheck_nested_if() { 1496 - let src = "foo :: (x: int): int { if 1 { if 1 { y : int = 1 } } }"; 1497 - let (ctx, result) = typecheck_src(src); 1498 - assert!(result.is_ok()); 1499 - } 1500 - 1501 - #[test] 1502 - fn test_typecheck_multiple_params() { 1503 - let src = "foo :: (a: int, b: int, c: int): int { sum : int = 1 + 2 + 3 }"; 1504 - let (ctx, result) = typecheck_src(src); 1505 - assert!(result.is_ok()); 1506 - } 1507 - 1508 - #[test] 1509 - fn test_typecheck_procedure_infers_fn_type() { 1510 - let src = "foo :: (x: int): int { y : int = 1 }"; 1511 - let (ctx, result) = typecheck_src(src); 1512 - assert!(result.is_ok()); 1513 - 1514 - let module = result.unwrap(); 1515 - let DeclKind::Procedure { fn_ty, sig, .. } = &module.declarations[0].node else { 1516 - panic!("expected procedure"); 1517 - }; 1518 - 1519 - assert!(fn_ty.is_some()); 1520 - let TypeKind::Fn(fn_sig) = &fn_ty.as_ref().unwrap().node else { 1521 - panic!("expected fn type"); 1522 - }; 1523 - assert_eq!(**fn_sig, sig.node); 1524 - } 1525 - 1526 - #[test] 1527 - fn test_typecheck_multiple_declarations() { 1528 - let src = "CONST :: 10 \n bar :: (x: int): int { y : int = 1 } \n foo :: (a: int): int { bar(1) }"; 1529 - let (ctx, result) = typecheck_src(src); 1530 - assert!(result.is_ok()); 1531 - 1532 - let module = result.unwrap(); 1533 - assert_eq!(module.declarations.len(), 3); 1534 - } 1535 - 1536 - #[test] 1537 - fn test_typecheck_constant_with_type_annotation() { 1538 - let src = "MY_CONST : int : 42"; 1539 - let (ctx, result) = typecheck_src(src); 1540 - assert!(result.is_ok()); 1541 - 1542 - let module = result.unwrap(); 1543 - let DeclKind::Constant { ty, .. } = &module.declarations[0].node else { 1544 - panic!("expected constant"); 1545 - }; 1546 - 1547 - assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 1548 - } 1549 - 1550 - #[test] 1551 - fn test_typecheck_constant_with_binop() { 1552 - let src = "MY_CONST :: 1 + 2 * 3"; 1553 - let (ctx, result) = typecheck_src(src); 1554 - assert!(result.is_ok()); 1555 - 1556 - let module = result.unwrap(); 1557 - let DeclKind::Constant { ty, .. } = &module.declarations[0].node else { 1558 - panic!("expected constant"); 1559 - }; 1560 - 1561 - assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 1562 - } 1563 - 1564 - #[test] 1565 - fn test_typecheck_empty_procedure() { 1566 - let src = "foo :: () {}"; 1567 - let (ctx, result) = typecheck_src(src); 1568 - assert!(result.is_ok()); 1569 - } 1570 - 1571 - #[test] 1572 - fn test_typecheck_procedure_with_return_type() { 1573 - let src = "foo :: (): int {}"; 1574 - let (ctx, result) = typecheck_src(src); 1575 - assert!(result.is_ok()); 1576 - 1577 - let module = result.unwrap(); 1578 - let DeclKind::Procedure { sig, .. } = &module.declarations[0].node else { 1579 - panic!("expected procedure"); 1580 - }; 1581 - 1582 - assert_eq!( 1583 - sig.node.return_ty.as_ref().map(|t| &t.node), 1584 - Some(&TypeKind::Int) 1585 - ); 1586 - } 1587 - 1588 - #[test] 1589 - fn test_typecheck_val_dec_infers_int_from_literal() { 1590 - let src = "foo :: (): int { y := 42 }"; 1591 - let (ctx, result) = typecheck_src(src); 1592 - assert!(result.is_ok()); 1593 - 1594 - let module = result.unwrap(); 1595 - let DeclKind::Procedure { block, .. } = &module.declarations[0].node else { 1596 - panic!("expected procedure"); 1597 - }; 1598 - 1599 - let StmtKind::ValDec { ty, .. } = &block.node.stmts[0].node else { 1600 - panic!("expected val dec"); 1601 - }; 1602 - 1603 - assert_eq!(ty.as_ref().map(|t| &t.node), Some(&TypeKind::Int)); 1604 - } 1605 - 1606 - #[test] 1607 - fn test_typecheck_multiple_val_decs() { 1608 - let src = "foo :: (): int { a : int = 1 \n b : int = 2 \n c : int = 3 }"; 1609 - let (ctx, result) = typecheck_src(src); 1610 - assert!(result.is_ok()); 1611 - } 1612 - 1613 - #[test] 1614 - fn test_typecheck_val_dec_uses_previous_val() { 1615 - let src = "foo :: (): int { a : int = 1 \n b : int = a }"; 1616 - let (ctx, result) = typecheck_src(src); 1617 - assert!(result.is_ok()); 1618 - } 1619 - 1620 - #[test] 1621 - fn test_typecheck_assignment_to_declared_var() { 1622 - let src = "foo :: (): int { a : int = 1 \n a = 2 }"; 1623 - let (ctx, result) = typecheck_src(src); 1624 - assert!(result.is_ok()); 1625 - } 1626 - 1627 - #[test] 1628 - fn test_typecheck_error_assignment_to_undeclared_var() { 1629 - let src = "foo :: (): int { a = 1 }"; 1630 - let (ctx, result) = typecheck_src(src); 1631 - assert!(result.is_err()); 1632 - 1633 - let err = result.unwrap_err(); 1634 - assert!(matches!(err.kind, TypeErrorKind::UnknownSymbol(_))); 1635 - } 1636 - 1637 - #[test] 1638 - fn test_typecheck_variant_type() { 1639 - let src = "foo :: (): int { x := .None }"; 1640 - let (ctx, result) = typecheck_src(src); 1641 - assert!(result.is_ok()); 1642 - 1643 - let module = result.unwrap(); 1644 - let DeclKind::Procedure { block, .. } = &module.declarations[0].node else { 1645 - panic!("expected procedure"); 1646 - }; 1647 - 1648 - let StmtKind::ValDec { expr, .. } = &block.node.stmts[0].node else { 1649 - panic!("expected val dec"); 1650 - }; 1651 - 1652 - assert!(matches!( 1653 - &expr.node, 1654 - ExprKind::Allocation { 1655 - kind: AllocKind::Variant(variant_name), 1656 - elements,.. 1657 - 1658 - } if *variant_name == Symbol(2) && elements.is_empty() 1659 - )); 1660 - } 1661 - 1662 - #[test] 1663 - fn test_typecheck_variant_type_with_args() { 1664 - let src = "foo :: (): int { x : .Some(int) | .None = .Some(1) }"; 1665 - let (ctx, result) = typecheck_src(src); 1666 - assert!(result.is_ok()); 1667 - 1668 - let module = result.unwrap(); 1669 - let DeclKind::Procedure { block, .. } = &module.declarations[0].node else { 1670 - panic!("expected procedure"); 1671 - }; 1672 - 1673 - let StmtKind::ValDec { expr, .. } = &block.node.stmts[0].node else { 1674 - panic!("expected val dec"); 1675 - }; 1676 - 1677 - assert!(matches!( 1678 - &expr.node, 1679 - ExprKind::Allocation { 1680 - kind: AllocKind::Variant(variant_name), 1681 - elements,.. 1682 - 1683 - } if *variant_name == Symbol(2) && elements.len() == 1 && elements[0].node == ExprKind::Value(ValueKind::Int(1)) 1684 - )); 1685 - } 1686 - 1687 - #[test] 1688 - fn test_typecheck_subtyping_record() { 1689 - let src = "foo :: () { x : { a: int } = { a := 1, b := 2 } }"; 1690 - let (ctx, result) = typecheck_src(src); 1691 - assert!(result.is_ok()); 1692 - } 1693 - 1694 - #[test] 1695 - fn test_comptime_constant_evaluation() { 1696 - let src = "MY_CONST :: 1 + 2 * 3"; 1697 - let (ctx, result) = typecheck_src(src); 1698 - assert!(result.is_ok()); 1699 - } 1700 - 1701 - #[test] 1702 - fn test_comptime_bool_evaluation() { 1703 - let src = "TRUE_CONST :: true and false"; 1704 - let (ctx, result) = typecheck_src(src); 1705 - assert!(result.is_ok()); 1706 - } 1707 - 1708 - #[test] 1709 - fn test_monomorphization_basic_comptime_type() { 1710 - let src = "identity :: (comptime T: type, x: T): T { return x }"; 1711 - let (ctx, result) = typecheck_src(src); 1712 - assert!(result.is_ok()); 1713 - let module = result.unwrap(); 1714 - 1715 - let proc = module 1716 - .declarations 1717 - .iter() 1718 - .find(|d| matches!(&d.node, DeclKind::Procedure { .. })) 1719 - .expect("generic function not found"); 1720 - 1721 - if let DeclKind::Procedure { 1722 - sig, monomorph_of, .. 1723 - } = &proc.node 1724 - { 1725 - assert!( 1726 - monomorph_of.is_none(), 1727 - "Original should not have monomorph_of" 1728 - ); 1729 - let params = &sig.node.params.params; 1730 - assert_eq!(params.len(), 2); 1731 - assert!(params[0].is_comptime); 1732 - assert!(matches!(params[0].ty.node, TypeKind::Type)); 1733 - } 1734 - } 1735 - 1736 - #[test] 1737 - fn test_monomorphization_multiple_comptime_params() { 1738 - let src = "first :: (comptime T: type, comptime U: type, a: T, b: U): T { return a }"; 1739 - let (ctx, result) = typecheck_src(src); 1740 - assert!(result.is_ok()); 1741 - let module = result.unwrap(); 1742 - 1743 - let proc = module 1744 - .declarations 1745 - .iter() 1746 - .find(|d| matches!(&d.node, DeclKind::Procedure { .. })) 1747 - .expect("generic function not found"); 1748 - 1749 - if let DeclKind::Procedure { sig, .. } = &proc.node { 1750 - let params = &sig.node.params.params; 1751 - assert_eq!(params.len(), 4); 1752 - assert!(params[0].is_comptime); 1753 - assert!(params[1].is_comptime); 1754 - assert!(!params[2].is_comptime); 1755 - assert!(!params[3].is_comptime); 1756 - } 1757 - } 1758 - 1759 - #[test] 1760 - fn test_monomorphization_mixed_params() { 1761 - let src = "wrap :: (comptime T: type, x: T, y: int): T { return x }"; 1762 - let (ctx, result) = typecheck_src(src); 1763 - assert!(result.is_ok()); 1764 - let module = result.unwrap(); 1765 - 1766 - let proc = module 1767 - .declarations 1768 - .iter() 1769 - .find(|d| matches!(&d.node, DeclKind::Procedure { .. })) 1770 - .expect("generic function not found"); 1771 - 1772 - if let DeclKind::Procedure { sig, .. } = &proc.node { 1773 - let params = &sig.node.params.params; 1774 - assert_eq!(params.len(), 3); 1775 - assert!(params[0].is_comptime); 1776 - assert!(!params[1].is_comptime); 1777 - assert!(!params[2].is_comptime); 1778 - } 1779 - } 1780 - 1781 - #[test] 1782 - fn test_monomorphization_basic() { 1783 - let src = "identity :: (comptime T: type, x: T): T { return x } \n main :: () { y : int = identity(int, 42) }"; 1784 - let (ctx, result) = typecheck_src(src); 1785 - assert!(result.is_ok(), "typechecking failed: {:?}", result); 1786 - let module = result.unwrap(); 1787 - 1788 - let monomorph_decl = module.declarations.iter().find(|d| { 1789 - if let DeclKind::Procedure { name, .. } = &d.node { 1790 - ctx.resolve(name.node).starts_with("identity_TInt") 1791 - } else { 1792 - false 1793 - } 1794 - }); 1795 - assert!( 1796 - monomorph_decl.is_some(), 1797 - "monomorphized identity_TInt not found" 1798 - ); 1799 - 1800 - let monomorph = monomorph_decl.unwrap(); 1801 - if let DeclKind::Procedure { 1802 - sig, monomorph_of, .. 1803 - } = &monomorph.node 1804 - { 1805 - assert!(monomorph_of.is_some(), "monomorph_of should be set"); 1806 - let params = &sig.node.params.params; 1807 - assert_eq!(params.len(), 1); 1808 - assert!(!params[0].is_comptime, "x param should remain runtime"); 1809 - assert_eq!(params[0].ty.node, TypeKind::Int); 1810 - } 1811 - } 1391 + Ok(()) 1812 1392 }