comptime value-params
This commit is contained in:
@@ -175,6 +175,35 @@ main func() void {}
|
||||
testing.expect_value(t, len(module.functions[0].params), 2)
|
||||
}
|
||||
|
||||
@(test)
|
||||
parser_accepts_comptime_value_params :: proc(t: ^testing.T) {
|
||||
text := `make func($N usize, value i32) i32 {
|
||||
return value
|
||||
}
|
||||
main func() void {}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
defer delete(stream.items)
|
||||
module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
defer ast.destroy_module(&module)
|
||||
|
||||
found_dollar := false
|
||||
for tok in stream.items {
|
||||
found_dollar = found_dollar || tok.kind == token.Kind.Dollar
|
||||
}
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, found_dollar)
|
||||
testing.expect_value(t, len(module.functions[0].params), 2)
|
||||
testing.expect(t, module.functions[0].params[0].comptime_value)
|
||||
testing.expect(t, !module.functions[0].params[1].comptime_value)
|
||||
}
|
||||
|
||||
@(test)
|
||||
parser_accepts_sentinel_many_item_pointer_types :: proc(t: ^testing.T) {
|
||||
text := `zero func(value [*;0]u8) void {}
|
||||
@@ -1945,6 +1974,116 @@ main func() i32 {
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
comptime_value_params_specialize_by_value_and_omit_runtime_args :: proc(t: ^testing.T) {
|
||||
text := `make_array func($N usize) [N]u8 {
|
||||
data [N]u8 = undefined
|
||||
return data
|
||||
}
|
||||
main func() void {
|
||||
four [4]u8 :: make_array(4)
|
||||
eight [8]u8 :: make_array(8)
|
||||
again [4]u8 :: make_array(4)
|
||||
_ = four
|
||||
_ = eight
|
||||
_ = again
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
defer delete(stream.items)
|
||||
ast_module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
defer ast.destroy_module(&ast_module)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
ir_module := lower.lower(&hir_module)
|
||||
defer ir.destroy_module(&ir_module)
|
||||
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
|
||||
defer delete(llvm_text)
|
||||
|
||||
make_specs := 0
|
||||
for function in hir_module.functions {
|
||||
if symbol.resolve(&symbols, function.name) == "make_array" {
|
||||
make_specs += 1
|
||||
testing.expect_value(t, len(function.params), 0)
|
||||
}
|
||||
}
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect_value(t, make_specs, 2)
|
||||
testing.expect(t, strings.contains(llvm_text, "@bro__p0__make_array__cv4"))
|
||||
testing.expect(t, strings.contains(llvm_text, "@bro__p0__make_array__cv8"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
comptime_value_params_diagnose_invalid_uses :: proc(t: ^testing.T) {
|
||||
text := `make func($N usize) i32 {
|
||||
return N
|
||||
}
|
||||
tiny func($N u8) i32 {
|
||||
return N
|
||||
}
|
||||
bad_type func($T bool) void {}
|
||||
bad_use func($N usize) void {
|
||||
N = 1
|
||||
_ = &N
|
||||
}
|
||||
main func() void {
|
||||
x usize = 4
|
||||
_ = make(x)
|
||||
_ = make()
|
||||
_ = make(1, 2)
|
||||
_ = make(-1)
|
||||
_ = tiny(300)
|
||||
bad_use(4)
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
defer delete(stream.items)
|
||||
ast_module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
defer ast.destroy_module(&ast_module)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
|
||||
found_runtime_arg := false
|
||||
found_missing := false
|
||||
found_extra := false
|
||||
found_negative := false
|
||||
found_range := false
|
||||
found_bad_type := false
|
||||
found_assignment := false
|
||||
found_address := false
|
||||
for diagnostic in diagnostics.items {
|
||||
message := diagnostic.message
|
||||
found_runtime_arg = found_runtime_arg || strings.contains(message, "must be a compile-time integer expression")
|
||||
found_missing = found_missing || strings.contains(message, "expects 1 arguments, got 0")
|
||||
found_extra = found_extra || strings.contains(message, "expects 1 arguments, got 2")
|
||||
found_negative = found_negative || strings.contains(message, "integer constant -1 does not fit in usize")
|
||||
found_range = found_range || strings.contains(message, "integer constant 300 does not fit in u8")
|
||||
found_bad_type = found_bad_type || strings.contains(message, "requires a concrete integer type")
|
||||
found_assignment = found_assignment || strings.contains(message, "cannot assign comptime parameter 'N'")
|
||||
found_address = found_address || strings.contains(message, "'&' requires an addressable location")
|
||||
}
|
||||
|
||||
testing.expect(t, found_runtime_arg)
|
||||
testing.expect(t, found_missing)
|
||||
testing.expect(t, found_extra)
|
||||
testing.expect(t, found_negative)
|
||||
testing.expect(t, found_range)
|
||||
testing.expect(t, found_bad_type)
|
||||
testing.expect(t, found_assignment)
|
||||
testing.expect(t, found_address)
|
||||
}
|
||||
|
||||
@(test)
|
||||
unused_function_signatures_are_validated_eagerly :: proc(t: ^testing.T) {
|
||||
text := `broken func(value, value i8, nope void) void {}
|
||||
@@ -5305,6 +5444,16 @@ cross_package_generic_specializes_from_folded_argument :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, state.exit_code, 128)
|
||||
}
|
||||
|
||||
@(test)
|
||||
comptime_value_params_compile_and_run :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-comptime-value-params"
|
||||
defer _ = os.remove(output)
|
||||
status := compiler_core.compile_package("examples/programs/comptime_value_params", output)
|
||||
testing.expect_value(t, status, 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
lazy_function_body_marks_import_as_used_without_resolving_it :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-package-lazy-import"
|
||||
|
||||
Reference in New Issue
Block a user