130 lines
5.0 KiB
Plaintext
130 lines
5.0 KiB
Plaintext
import "@std/mem"
|
|
import "@source/ast"
|
|
import "@source/diagnostics"
|
|
import "@source/strpool"
|
|
sema :: import "@source/sema"
|
|
typecheck :: import "@source/sema/check"
|
|
import "@std/testing"
|
|
import "@source/lexer"
|
|
import "@source/parser"
|
|
|
|
@hide:file
|
|
expect_specialization proc(
|
|
source []u8, expected diagnostics.Code, expected_count usize,
|
|
) void ! (mem.AllocError | diagnostics.CapacityError | strpool.InternError | testing.Error) {
|
|
strings := strpool.init(mem.c_allocator)
|
|
defer strpool.deinit(&strings)
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
scan_state := lexer.init(mem.c_allocator)
|
|
defer lexer.deinit(&scan_state)
|
|
try lexer.scan(&scan_state, source, &strings, &diagnostic_store)
|
|
builder := ast.init_builder(mem.c_allocator, source)
|
|
defer ast.deinit_builder(&builder)
|
|
root :: try parser.parse_source(&builder, scan_state.tokens.items, &diagnostic_store)
|
|
tree := ast.view(&builder, root)
|
|
resolution := try sema.resolve(mem.c_allocator, &tree, &strings, &diagnostic_store)
|
|
defer sema.deinit(&resolution)
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
elaborated := try elaborate(mem.c_allocator, &builder, root, &resolution, &strings, &diagnostic_store)
|
|
defer deinit(&elaborated)
|
|
tree = ast.view(&builder, root)
|
|
checked := try typecheck.check_elaborated(mem.c_allocator, &tree, &resolution, elaborated.constraints.items, &diagnostic_store)
|
|
defer typecheck.deinit(&checked)
|
|
if (expected_count == 0) {
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..ast.package_decl_count(&tree)) |i| {
|
|
declaration :: ast.package_decl(&tree, i)
|
|
if (ast.node_class(&tree, declaration) != .function) continue
|
|
try testing.expect(!ast.function_generic(&tree, declaration))
|
|
for (0..ast.function_param_count(&tree, declaration)) |j|
|
|
try testing.expect(!ast.param(&tree, ast.function_param(&tree, declaration, j)).comptime)
|
|
}
|
|
} else {
|
|
count := usize(0)
|
|
for (diagnostic_store.list.items) |diagnostic| {
|
|
if (diagnostic.code == expected) count += 1
|
|
}
|
|
try testing.expect_equal(expected_count, count)
|
|
}
|
|
}
|
|
|
|
infers_nested_nominal_pointer_parameters_and_readonly_slice_views test {
|
|
try expect_specialization(
|
|
`Storage proc($T type) type { return struct { items []mut T, capacity usize } }
|
|
`make proc($T type, values []mut T) Storage(T) {
|
|
` return Storage(T) { items = values, capacity = values.len }
|
|
`}
|
|
`observe proc($T type, values []T) usize { return values.len }
|
|
`reserve proc($T type, storage @mut Storage(T), count usize) void {
|
|
` _ = observe(storage.items.ptr[..count])
|
|
`}
|
|
`append proc($T type, storage @mut Storage(T), value T) void {
|
|
` reserve(storage, storage.items.len)
|
|
` storage.items[0] = value
|
|
`}
|
|
`release proc($T type, storage @mut Storage(T)) void {
|
|
` allocation :: storage.items.ptr[..storage.capacity]
|
|
` _ = observe(allocation)
|
|
`}
|
|
`forward proc(storage @mut Storage(i16)) void {
|
|
` append(storage, 7)
|
|
` release(storage)
|
|
`}
|
|
`main proc() i16 {
|
|
` values [2]mut i16 := [1, 2]
|
|
` storage := make(i16, values[..])
|
|
` forward(&storage)
|
|
` append(&storage, 9)
|
|
` release(&storage)
|
|
` return storage.items[0]
|
|
`}
|
|
, .cannot_infer_generic, 0,
|
|
)
|
|
}
|
|
|
|
rejects_conflicting_rigid_types_and_unrelated_nominal_generators test {
|
|
try expect_specialization(
|
|
`same proc($T type, left, right T) void {}
|
|
`main proc() void { same(i16(1), u8(2)) }
|
|
, .cannot_infer_generic, 1,
|
|
)
|
|
try expect_specialization(
|
|
`Box proc($T type) type { return struct { value T } }
|
|
`Other proc($T type) type { return struct { value T } }
|
|
`read proc($T type, value @Box(T)) void {}
|
|
`main proc() void {
|
|
` value Other(i16) :: { value = 1 }
|
|
` read(&value)
|
|
`}
|
|
, .cannot_infer_generic, 1,
|
|
)
|
|
try expect_specialization(
|
|
`unknown proc($T type, value usize) void {}
|
|
`main proc() void { unknown(1) }
|
|
, .cannot_infer_generic, 1,
|
|
)
|
|
}
|
|
|
|
preserves_rigid_inference_before_contextual_literals test {
|
|
try expect_specialization(
|
|
`same proc($T type, left, right T) T { return right }
|
|
`main proc() i16 { return same(i16(1), 2) }
|
|
, .cannot_infer_generic, 0,
|
|
)
|
|
}
|
|
|
|
infers_integer_builtin_results_from_their_type_or_rigid_operand test {
|
|
try expect_specialization(
|
|
`same proc($T type, left, right T) T { return right }
|
|
`main proc() i16 {
|
|
` upper :: same(maxval!(i16), i16(1))
|
|
` lower :: same(minval!(i16), i16(2))
|
|
` left :: same(divtrunc!(i16(8), 2), i16(3))
|
|
` right :: same(divtrunc!(8, i16(2)), i16(4))
|
|
` return upper + lower + left + right
|
|
`}
|
|
, .cannot_infer_generic, 0,
|
|
)
|
|
}
|