From d4e4b58dfdc11e1cf6ef271f3deb6610244f4ec8 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 21 Nov 2025 11:20:41 -0500 Subject: [PATCH] Update some tests, delete obsolete ones --- .../let_polymorphism_integration_test.zig | 86 +------------------ src/compile/test/module_env_test.zig | 4 +- src/eval/test/eval_test.zig | 47 ---------- src/eval/test/helpers.zig | 38 ++++++++ 4 files changed, 42 insertions(+), 133 deletions(-) diff --git a/src/check/test/let_polymorphism_integration_test.zig b/src/check/test/let_polymorphism_integration_test.zig index 7aecf04abf..102bcc1ba9 100644 --- a/src/check/test/let_polymorphism_integration_test.zig +++ b/src/check/test/let_polymorphism_integration_test.zig @@ -66,44 +66,15 @@ test "polymorphic empty list" { } test "polymorphic cons function" { - // This test is skipped because these features are missing: - // - Spread operator `..` in list literals [fails at parse stage - syntax not recognized] - // TODO: Enable when spread operator is implemented in the parser - const source = \\{ - \\ cons = |x, xs| [x, ..xs] + \\ cons = |x, xs| List.concat([x], xs) \\ list1 = cons(1, [2, 3]) \\ list2 = cons("a", ["b", "c"]) \\ { list1, list2 } \\} ; - try typeCheck(source, "TODO"); -} - -test "polymorphic map function" { - // This test is skipped because these features are missing: - // - If-then-else expressions [fails at parse stage - syntax not recognized] - // - Recursive function calls [would fail at canonicalize stage - self-references not resolved] - // - List slicing `xs[1..]` [fails at parse stage - range syntax not recognized] - // - Spread operator `[x, ..xs]` [fails at parse stage - syntax not recognized] - // - List equality comparison `xs == []` [may fail at type-check stage] - // Note: List indexing `xs[0]` does parse and canonicalize but may have type issues - // TODO: Enable when conditional expressions, recursion, and list operations are implemented - - const source = - \\{ - \\ map = |f, xs| - \\ if xs == [] then - \\ [] - \\ else - \\ [f(xs[0]), ..map(f, xs[1..])] - \\ double = |x| x * 2 - \\ nums = map(double, [1, 2, 3]) - \\ { nums } - \\} - ; - try typeCheck(source, "TODO"); + try typeCheck(source, "{ list1: List(item), list2: List(Str) } where [_a.from_num_literal : _arg -> _ret]"); } test "polymorphic record constructor" { @@ -174,32 +145,6 @@ test "polymorphic swap function" { try typeCheck(source, "{ swapped1: { first: Str, second: _field }, swapped2: { first: _field2, second: [True]_others } } where [_a.from_num_literal : _arg -> _ret, _b.from_num_literal : _arg2 -> _ret2]"); } -test "polymorphic fold function" { - // This test is skipped because these features are missing: - // - If-then-else expressions [fails at parse stage - syntax not recognized] - // - Recursive function calls [would fail at canonicalize stage - self-references not resolved] - // - List equality comparison `xs == []` [may fail at type-check stage] - // - String concatenation operator `++` [fails at parse or canonicalize stage] - // - List slicing `xs[1..]` [fails at parse stage - range syntax not recognized] - // Even if parsing succeeded, the canonicalizer doesn't support recursive - // let-bindings, and the type checker doesn't handle recursive polymorphic functions. - // TODO: Enable when conditional expressions, recursion, and list/string operations are implemented - - const source = - \\{ - \\ fold = |f, acc, xs| - \\ if xs == [] then - \\ acc - \\ else - \\ fold(f, f(acc, xs[0]), xs[1..]) - \\ sum = fold(|a, b| a + b, 0, [1, 2, 3]) - \\ concat = fold(|a, b| a ++ b, "", ["a", "b", "c"]) - \\ { sum, concat } - \\} - ; - try typeCheck(source, "TODO"); -} - test "polymorphic option type simulation" { const source = \\{ @@ -228,33 +173,6 @@ test "polymorphic const function" { try typeCheck(source, "{ num: _field, str: Str } where [_a.from_num_literal : _arg -> _ret]"); } -test "shadowing of polymorphic values" { - // This test is skipped because these features are missing: - // - Type checking for nested block expressions that return values - // [parses and canonicalizes successfully, fails at type-check stage] - // The inner block `{ id = ...; b = ...; b }` should return `b` as its value. - // The type checker fails to properly handle the combination of: - // 1. A nested block that shadows a polymorphic identifier - // 2. The block returning a value (the final `b` expression) - // 3. Continuing to use the original polymorphic `id` after the block - // TODO: Enable when nested block expressions with value returns are fully supported - - const source = - \\{ - \\ id = |x| x - \\ a = id(1) - \\ inner = { - \\ id = |x| x + 1 // shadows outer id, now monomorphic - \\ b = id(2) - \\ b - \\ } - \\ c = id("test") // uses outer polymorphic id - \\ { a, inner, c } - \\} - ; - try typeCheck(source, "TODO"); -} - test "polymorphic pipe function" { const source = \\{ diff --git a/src/compile/test/module_env_test.zig b/src/compile/test/module_env_test.zig index ac0a5daaec..3690816235 100644 --- a/src/compile/test/module_env_test.zig +++ b/src/compile/test/module_env_test.zig @@ -138,8 +138,8 @@ test "ModuleEnv.Serialized roundtrip" { try testing.expectEqual(@as(usize, 2), original.imports.imports.len()); // Should have 2 unique imports // First verify that the CommonEnv data was preserved after deserialization - // Should have same 10 identifiers as original: hello, world, TestModule + 7 well-known identifiers from ModuleEnv.init() - try testing.expectEqual(@as(u32, 10), env.common.idents.interner.entry_count); + // Should have same 21 identifiers as original: hello, world, TestModule + 18 well-known identifiers from ModuleEnv.init() + try testing.expectEqual(@as(u32, 21), env.common.idents.interner.entry_count); try testing.expectEqual(@as(usize, 1), env.common.exposed_items.count()); try testing.expectEqual(@as(?u16, 42), env.common.exposed_items.getNodeIndexById(gpa, @as(u32, @bitCast(hello_idx)))); diff --git a/src/eval/test/eval_test.zig b/src/eval/test/eval_test.zig index e500bf92a2..6bd1a7cc7d 100644 --- a/src/eval/test/eval_test.zig +++ b/src/eval/test/eval_test.zig @@ -45,42 +45,6 @@ test "eval simple number" { try runExpectInt("-1234", -1234, .no_trace); } -test "eval boolean literals" { - try runExpectBool("True", true, .no_trace); - try runExpectBool("False", false, .no_trace); - // Note: Qualified tags like Bool.True and Bool.False don't work yet - // See QUALIFIED_TAGS.md for details -} - -test "eval unary not operator" { - try runExpectBool("!True", false, .no_trace); - try runExpectBool("!False", true, .no_trace); -} - -test "eval double negation" { - try runExpectBool("!!True", true, .no_trace); - try runExpectBool("!!False", false, .no_trace); - try runExpectBool("!!!True", false, .no_trace); - try runExpectBool("!!!False", true, .no_trace); -} - -test "eval boolean in lambda expressions" { - try runExpectBool("(|x| !x)(True)", false, .no_trace); - try runExpectBool("(|x| !x)(False)", true, .no_trace); - // Not implemented yet -- the closure return type is still flex var - // try runExpectBool("(|x, y| x and y)(True, False)", false, .no_trace); - // try runExpectBool("(|x, y| x or y)(False, True)", true, .no_trace); - // try runExpectBool("(|x| x and !x)(True)", false, .no_trace); - // try runExpectBool("(|x| x or !x)(False)", true, .no_trace); -} - -test "eval unary not in conditional expressions" { - try runExpectInt("if !True 42 else 99", 99, .no_trace); - try runExpectInt("if !False 42 else 99", 42, .no_trace); - try runExpectInt("if !!True 42 else 99", 42, .no_trace); - try runExpectInt("if !!False 42 else 99", 99, .no_trace); -} - test "if-else" { try runExpectInt("if (1 == 1) 42 else 99", 42, .no_trace); try runExpectInt("if (1 == 2) 42 else 99", 99, .no_trace); @@ -142,17 +106,6 @@ test "comparison binops" { try runExpectInt("if 5 != 5 100 else 200", 200, .no_trace); } -test "logical binops" { - try runExpectInt("if True and True 1 else 0", 1, .no_trace); - try runExpectInt("if True and False 1 else 0", 0, .no_trace); - try runExpectInt("if False and True 1 else 0", 0, .no_trace); - try runExpectInt("if False and False 1 else 0", 0, .no_trace); - try runExpectInt("if True or True 1 else 0", 1, .no_trace); - try runExpectInt("if True or False 1 else 0", 1, .no_trace); - try runExpectInt("if False or True 1 else 0", 1, .no_trace); - try runExpectInt("if False or False 1 else 0", 0, .no_trace); -} - test "unary minus" { try runExpectInt("-5", -5, .no_trace); try runExpectInt("-(-10)", 10, .no_trace); diff --git a/src/eval/test/helpers.zig b/src/eval/test/helpers.zig index 82a951998a..4c23c1eeb5 100644 --- a/src/eval/test/helpers.zig +++ b/src/eval/test/helpers.zig @@ -107,6 +107,44 @@ pub fn runExpectInt(src: []const u8, expected_int: i128, should_trace: enum { tr try std.testing.expectEqual(expected_int, int_value); } +/// Helper function to run an expression and expect a boolean result. +pub fn runExpectBool(src: []const u8, expected_bool: bool, should_trace: enum { trace, no_trace }) !void { + const resources = try parseAndCanonicalizeExpr(test_allocator, src); + defer cleanupParseAndCanonical(test_allocator, resources); + + var test_env_instance = TestEnv.init(test_allocator); + defer test_env_instance.deinit(); + + const builtin_types = BuiltinTypes.init(resources.builtin_indices, resources.builtin_module.env, resources.builtin_module.env, resources.builtin_module.env); + var interpreter = try Interpreter.init(test_allocator, resources.module_env, builtin_types, resources.builtin_module.env, &[_]*const can.ModuleEnv{}); + defer interpreter.deinit(); + + const enable_trace = should_trace == .trace; + if (enable_trace) { + interpreter.startTrace(); + } + defer if (enable_trace) interpreter.endTrace(); + + const ops = test_env_instance.get_ops(); + const result = try interpreter.evalMinimal(resources.expr_idx, ops); + const layout_cache = &interpreter.runtime_layout_store; + defer result.decref(layout_cache, ops); + + // For boolean results, read the underlying byte value + if (result.layout.tag == .scalar and result.layout.data.scalar.tag == .int) { + // Boolean represented as integer (discriminant) + const int_val = result.asI128(); + const bool_val = int_val != 0; + try std.testing.expectEqual(expected_bool, bool_val); + } else { + // Try reading as raw byte (for boolean tag values) + std.debug.assert(result.ptr != null); + const bool_ptr: *const u8 = @ptrCast(@alignCast(result.ptr.?)); + const bool_val = bool_ptr.* != 0; + try std.testing.expectEqual(expected_bool, bool_val); + } +} + /// Helper function to run an expression and expect an f32 result (with epsilon tolerance). pub fn runExpectF32(src: []const u8, expected_f32: f32, should_trace: enum { trace, no_trace }) !void { const resources = try parseAndCanonicalizeExpr(test_allocator, src);