Skip to content

Commit 4099083

Browse files
committed
so long nerds
1 parent 2127147 commit 4099083

43 files changed

Lines changed: 1316 additions & 163 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cargo/config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[env]
2+
LLVM_SYS_181_PREFIX = "/usr/lib/llvm18"

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ main.aelys
1414
main.ll
1515
torture/
1616
audit/**
17-
audit_tmp/**
17+
audit_tmp/**
18+
.vs/**
19+
.idea/**
20+
tests_e2e/**

aelys/tests/air_validation_tests.rs

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ fn caller() -> i32 {
334334

335335
let mut program = air;
336336
compute_layouts(&mut program);
337-
let program = monomorphize(program);
337+
let program = monomorphize(program).unwrap();
338338

339339
let mono_fn = program
340340
.functions
@@ -418,7 +418,7 @@ fn main() {
418418
"#,
419419
);
420420
compute_layouts(&mut air);
421-
let mut air = monomorphize(air);
421+
let mut air = monomorphize(air).unwrap();
422422
passes::copy_elim::eliminate_copies(&mut air);
423423
passes::dead_locals::eliminate_dead_locals(&mut air);
424424

@@ -501,7 +501,7 @@ fn align_probe(x: i64, y: i32, z: i16, w: i8, b: bool, f: f32, d: f64, p: string
501501
"#,
502502
);
503503
compute_layouts(&mut air);
504-
let mut air = monomorphize(air);
504+
let mut air = monomorphize(air).unwrap();
505505
passes::copy_elim::eliminate_copies(&mut air);
506506

507507
let f = func(&air, "align_probe");
@@ -536,7 +536,7 @@ fn keep_copy(x: i64) -> i64 {
536536
"#,
537537
);
538538
compute_layouts(&mut air);
539-
let mut air = monomorphize(air);
539+
let mut air = monomorphize(air).unwrap();
540540
aelys_air::passes::copy_elim::eliminate_copies(&mut air);
541541

542542
let f = func(&air, "keep_copy");
@@ -626,7 +626,7 @@ fn align_probe(x: i64, y: i32, z: i16, w: i8, b: bool, f: f32, d: f64, p: string
626626
"#,
627627
);
628628
compute_layouts(&mut air);
629-
let mut air = monomorphize(air);
629+
let mut air = monomorphize(air).unwrap();
630630
passes::copy_elim::eliminate_copies(&mut air);
631631
passes::dead_locals::eliminate_dead_locals(&mut air);
632632

@@ -658,7 +658,7 @@ fn caller() -> i64 {
658658

659659
let mut program = air;
660660
compute_layouts(&mut program);
661-
let program = monomorphize(program);
661+
let program = monomorphize(program).unwrap();
662662

663663
// Both instantiations should exist
664664
let mono_i32 = program
@@ -998,20 +998,20 @@ fn main() -> i64 {
998998
"#,
999999
);
10001000
let f = func(&air, "main");
1001-
let has_fnref = f.blocks.iter().any(|b| {
1001+
let has_closure_create = f.blocks.iter().any(|b| {
10021002
b.stmts.iter().any(|s| {
10031003
matches!(
10041004
&s.kind,
10051005
AirStmtKind::Assign {
1006-
rvalue: Rvalue::Use(Operand::Const(AirConst::FnRef(name))),
1006+
rvalue: Rvalue::ClosureCreate { fn_name, .. },
10071007
..
1008-
} if name == "inc"
1008+
} if fn_name == "inc"
10091009
)
10101010
})
10111011
});
10121012
assert!(
1013-
has_fnref,
1014-
"expected function identifier value to materialize from FnRef(\"inc\")"
1013+
has_closure_create,
1014+
"expected function identifier value to materialize from ClosureCreate(\"inc\")"
10151015
);
10161016
}
10171017

@@ -1156,7 +1156,7 @@ fn caller() -> i32 {
11561156
"#,
11571157
);
11581158
compute_layouts(&mut air);
1159-
let mut air = monomorphize(air);
1159+
let mut air = monomorphize(air).unwrap();
11601160
passes::copy_elim::eliminate_copies(&mut air);
11611161
passes::dead_locals::eliminate_dead_locals(&mut air);
11621162

@@ -1423,7 +1423,7 @@ fn caller() -> i64 {
14231423
"#,
14241424
);
14251425
compute_layouts(&mut air);
1426-
let mut air = monomorphize(air);
1426+
let mut air = monomorphize(air).unwrap();
14271427
passes::copy_elim::eliminate_copies(&mut air);
14281428
passes::dead_locals::eliminate_dead_locals(&mut air);
14291429

@@ -1448,7 +1448,7 @@ fn main() {
14481448
&["print", "println"],
14491449
);
14501450
compute_layouts(&mut air);
1451-
let mut air = monomorphize(air);
1451+
let mut air = monomorphize(air).unwrap();
14521452
passes::copy_elim::eliminate_copies(&mut air);
14531453
passes::dead_locals::eliminate_dead_locals(&mut air);
14541454

@@ -1710,31 +1710,13 @@ fn validate_rejects_ambiguous_generic_unit_variant_after_mono() {
17101710
struct_sizes: std::collections::HashMap::new(),
17111711
};
17121712

1713-
let air = monomorphize(program);
1714-
let result = validate_air(&air);
1715-
assert!(
1716-
result.is_err(),
1717-
"ambiguous generic unit variant should be rejected after monomorphization"
1718-
);
1719-
let errors = result.unwrap_err();
1720-
assert!(
1721-
errors.iter().any(|e| matches!(
1722-
&e.detail,
1723-
AirValidationDetail::UnknownEnumType {
1724-
local_name: Some(name),
1725-
enum_name,
1726-
..
1727-
} if name == "ambiguous" && enum_name == "Option"
1728-
)),
1729-
"expected unknown enum type error for unresolved local, got: {:?}",
1730-
errors
1731-
);
1713+
let errors = match monomorphize(program) {
1714+
Err(e) => e,
1715+
Ok(_) => panic!("ambiguous generic unit variant should be rejected during monomorphization"),
1716+
};
17321717
assert!(
1733-
errors.iter().any(|e| matches!(
1734-
&e.detail,
1735-
AirValidationDetail::UnknownEnumReference { enum_name, .. } if enum_name == "Option"
1736-
)),
1737-
"expected unknown enum reference error for unresolved enum_init, got: {:?}",
1718+
errors.iter().any(|e| e.contains("ambiguous unit variant")),
1719+
"expected ambiguous unit variant error, got: {:?}",
17381720
errors
17391721
);
17401722
}
@@ -1894,7 +1876,7 @@ fn monomorphize_distinguishes_fnptr_calling_conventions_in_enum_type_args() {
18941876
struct_sizes: std::collections::HashMap::new(),
18951877
};
18961878

1897-
let air = monomorphize(program);
1879+
let air = monomorphize(program).unwrap();
18981880
let holder_defs: Vec<_> = air
18991881
.enums
19001882
.iter()

aelys/tests/enum_parse_tests.rs

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use aelys::api::compile_to_typed_ast;
2+
use aelys_air::AirType;
23
use aelys_air::lower::lower;
34
use aelys_air::print::print_program;
45
use aelys_frontend::lexer::Lexer;
@@ -14,6 +15,11 @@ fn lower_source(code: &str) -> aelys_air::AirProgram {
1415
lower(&typed)
1516
}
1617

18+
fn lower_and_monomorphize(code: &str) -> aelys_air::AirProgram {
19+
let air = lower_source(code);
20+
aelys_air::mono::monomorphize(air).unwrap()
21+
}
22+
1723
#[test]
1824
fn parse_basic_enum_declaration() {
1925
let src = r#"
@@ -296,7 +302,9 @@ enum Message {
296302
Move(i64, i64),
297303
Write(string),
298304
}
299-
let msg = Message::Write("hello")
305+
fn use_write() -> Message {
306+
return Message::Write("hello")
307+
}
300308
"#;
301309
let air = lower_source(src);
302310
// Verify the enum def exists in the AIR program
@@ -477,6 +485,27 @@ fn name(c: Color) -> i64 {
477485
);
478486
}
479487

488+
#[test]
489+
fn match_wildcard_must_be_last() {
490+
let src = r#"
491+
enum Color { Red, Green, Blue }
492+
493+
fn name(c: Color) -> i64 {
494+
return match c {
495+
_ => 0,
496+
Color::Red => 1,
497+
}
498+
}
499+
"#;
500+
let result = compile_to_typed_ast(src);
501+
let errors = result.expect_err("wildcard before specific arms should fail");
502+
let rendered = format!("{:?}", errors);
503+
assert!(
504+
rendered.contains("wildcard pattern must be the last match arm"),
505+
"unexpected diagnostics: {rendered}"
506+
);
507+
}
508+
480509
#[test]
481510
fn match_non_exhaustive_error() {
482511
let src = r#"
@@ -1305,6 +1334,115 @@ fn handle(r: Result<i64, string>) -> i64 {
13051334
);
13061335
}
13071336

1337+
#[test]
1338+
fn nested_generic_enum_unit_variant_monomorphizes_nested_enum_def() {
1339+
let src = r#"
1340+
enum Pair<A, B> {
1341+
Both(A, B),
1342+
Neither,
1343+
}
1344+
1345+
enum Boxed<T> {
1346+
Value(T),
1347+
Empty,
1348+
}
1349+
1350+
fn get_empty() -> Boxed<Pair<i64, string>> {
1351+
return Boxed::Empty
1352+
}
1353+
1354+
fn main() {
1355+
let e = get_empty()
1356+
}
1357+
"#;
1358+
let air = lower_and_monomorphize(src);
1359+
let pair = air
1360+
.enums
1361+
.iter()
1362+
.find(|e| e.name == "__mono_Pair_i64$str")
1363+
.expect("nested Pair mono enum should exist");
1364+
assert_eq!(pair.variants[0].payload.len(), 2);
1365+
1366+
let boxed = air
1367+
.enums
1368+
.iter()
1369+
.find(|e| e.name == "__mono_Boxed_enum___mono_Pair_i64$str")
1370+
.expect("Boxed<Pair<...>> mono enum should exist");
1371+
let value_variant = boxed
1372+
.variants
1373+
.iter()
1374+
.find(|v| v.name == "Value")
1375+
.expect("Value variant should exist");
1376+
assert_eq!(
1377+
value_variant.payload,
1378+
vec![AirType::Enum("__mono_Pair_i64$str".to_string())]
1379+
);
1380+
}
1381+
1382+
#[test]
1383+
fn generic_enum_unit_variant_with_fnptr_type_arg_monomorphizes() {
1384+
let src = r#"
1385+
enum Holder<T> {
1386+
Value(T),
1387+
Empty,
1388+
}
1389+
1390+
fn apply_default() -> Holder<fn(i64) -> i64> {
1391+
return Holder::Empty
1392+
}
1393+
"#;
1394+
let air = lower_and_monomorphize(src);
1395+
let air_text = print_program(&air);
1396+
1397+
let holder = air
1398+
.enums
1399+
.iter()
1400+
.find(|e| e.name == "__mono_Holder_fnptr$i64$Ri64")
1401+
.expect("fnptr-instantiated Holder enum should exist");
1402+
assert_eq!(holder.variants.len(), 2);
1403+
assert!(
1404+
!air_text.contains("enum_init Holder::"),
1405+
"fnptr generic unit variant should be rewritten to mono enum:\n{air_text}"
1406+
);
1407+
}
1408+
1409+
#[test]
1410+
fn generic_enum_named_fn_payload_uses_fnptr_monomorphization() {
1411+
let src = r#"
1412+
enum Holder<T> {
1413+
Value(T),
1414+
Empty,
1415+
}
1416+
1417+
fn inc(x: i64) -> i64 {
1418+
return x + 1
1419+
}
1420+
1421+
fn call_holder(h: Holder<fn(i64) -> i64>) -> i64 {
1422+
return match h {
1423+
Holder::Value(f) => f(41)
1424+
Holder::Empty => 0
1425+
}
1426+
}
1427+
1428+
fn main() {
1429+
let h: Holder<fn(i64) -> i64> = Holder::Value(inc)
1430+
call_holder(h)
1431+
}
1432+
"#;
1433+
let air = lower_and_monomorphize(src);
1434+
let air_text = print_program(&air);
1435+
1436+
assert!(
1437+
air_text.contains("enum_init __mono_Holder_fnptr$i64$Ri64::Value"),
1438+
"named function payload should monomorphize to fnptr enum, got:\n{air_text}"
1439+
);
1440+
assert!(
1441+
!air_text.contains("__mono_Holder_ptr_void"),
1442+
"named function payload must not degrade to ptr_void mono, got:\n{air_text}"
1443+
);
1444+
}
1445+
13081446
#[test]
13091447
fn generic_enum_result_air_lowering() {
13101448
let src = r#"
@@ -1375,7 +1513,7 @@ fn make_none_int() -> Option<i64> {
13751513
}
13761514
"#;
13771515
let air = lower_source(src);
1378-
let air = aelys_air::mono::monomorphize(air);
1516+
let air = aelys_air::mono::monomorphize(air).unwrap();
13791517
let air_text = print_program(&air);
13801518

13811519
// After monomorphization, no generic enum definitions should remain

aelys/tests/fatal_error_filter_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ fn while_with_early_return() {
231231
assert!(
232232
sema_ok(
233233
r#"
234-
fn find(arr: Array<i64>, n: i64, target: i64) -> i64 {
234+
fn find(arr: [i64; 10], n: i64, target: i64) -> i64 {
235235
let mut i: i64 = 0
236236
while i < n {
237237
if arr[i] == target {

aelys/tests/llvm_air_abi_tests.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,19 @@ fn air_and_llvm_string_layout_match_x86_64_abi() {
136136

137137
let ir = compile_air_to_verified_ir(&program);
138138
assert!(ir.contains("%__aelys_string = type { ptr, i64 }"), "{ir}");
139+
// Aelys-convention functions prepend an implicit env ptr; the string follows.
140+
let sink_decl = ir
141+
.lines()
142+
.find(|l| l.contains("define fastcc i64 @sink"))
143+
.expect("sink function must be defined");
139144
assert!(
140-
ir.contains("define fastcc i64 @sink(%__aelys_string"),
141-
"{ir}"
145+
sink_decl.contains("%__aelys_string"),
146+
"string param must lower to %__aelys_string struct, not a bare ptr:\n{sink_decl}"
147+
);
148+
assert!(
149+
!sink_decl.contains("ptr, i64"),
150+
"string must not be flattened to (ptr, i64) scalars:\n{sink_decl}"
142151
);
143-
assert!(!ir.contains("define fastcc i64 @sink(ptr"), "{ir}");
144152

145153
let context = Context::create();
146154
let mut nul_terminated_ir = ir.into_bytes();

0 commit comments

Comments
 (0)