unsigned integer constraint (uint)
This commit is contained in:
+188
-1
@@ -1485,6 +1485,7 @@ main func() void {
|
||||
_ = maxval!(u8, u16)
|
||||
_ = minval!(1)
|
||||
_ = maxval!(int)
|
||||
_ = maxval!(uint)
|
||||
_ = maxval!(f32)
|
||||
_ = maxval!(bool)
|
||||
_ = maxval!(Named)
|
||||
@@ -1513,7 +1514,7 @@ main func() void {
|
||||
}
|
||||
testing.expect_value(t, bad_arity, 2)
|
||||
testing.expect(t, bad_type)
|
||||
testing.expect_value(t, bad_target, 5)
|
||||
testing.expect_value(t, bad_target, 6)
|
||||
}
|
||||
|
||||
@(test)
|
||||
@@ -12876,3 +12877,189 @@ dependency_passes test {
|
||||
testing.expect(t, strings.contains(output, root_path))
|
||||
testing.expect(t, strings.contains(output, "3 passed, 1 failed"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
uint_constraint_parses_as_type_and_comptime_value :: proc(t: ^testing.T) {
|
||||
text := `value uint :: 1
|
||||
Constraint :: uint
|
||||
`
|
||||
source_file := source.Source{path="uint.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)
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect_value(t, len(module.globals), 2)
|
||||
testing.expect_value(t, module.globals[0].type, types.UINT)
|
||||
testing.expect_value(t, module.exprs[module.globals[1].expr].kind, ast.Expr_Kind.Type)
|
||||
testing.expect_value(t, module.exprs[module.globals[1].expr].type, types.UINT)
|
||||
}
|
||||
|
||||
@(test)
|
||||
uint_constraint_uses_smallest_unsigned_types_and_widens :: proc(t: ^testing.T) {
|
||||
text := `Zero uint :: 0
|
||||
Byte uint :: 255
|
||||
Word uint :: 256
|
||||
Dword uint :: 65536
|
||||
Maximum uint :: 18446744073709551615
|
||||
Counter uint = 1
|
||||
|
||||
widen func() uint {
|
||||
value uint = 1
|
||||
value = 1000
|
||||
return value
|
||||
}
|
||||
|
||||
widen_global func() void { Counter = 1000 }
|
||||
|
||||
main func() void {
|
||||
_ = Zero
|
||||
_ = Byte
|
||||
_ = Word
|
||||
_ = Dword
|
||||
_ = Maximum
|
||||
_ = widen()
|
||||
widen_global()
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="uint_types.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)
|
||||
|
||||
expected := []types.Type{types.U8, types.U8, types.U16, types.U32, types.U64, types.U16}
|
||||
for value_type, index in expected {
|
||||
testing.expect_value(t, hir_module.globals[index].type, value_type)
|
||||
}
|
||||
widen_symbol := symbol.intern(&symbols, "widen")
|
||||
found_widen := false
|
||||
for function in hir_module.functions {
|
||||
if function.name != widen_symbol {
|
||||
continue
|
||||
}
|
||||
found_widen = true
|
||||
testing.expect_value(t, function.result, types.U16)
|
||||
testing.expect_value(t, function.locals[0].type, types.U16)
|
||||
}
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, found_widen)
|
||||
}
|
||||
|
||||
@(test)
|
||||
uint_constraint_infers_boundaries_calls_and_records :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-uint-constraint"
|
||||
main_path := "/tmp/brolang-test-uint-constraint/main.bro"
|
||||
output := "/tmp/brolang-test-uint-constraint-output"
|
||||
text := `Box :: struct { value uint }
|
||||
|
||||
identity func(value uint) uint { return value }
|
||||
whole func(value int) int { return value }
|
||||
max_value func() uint { return 18446744073709551615 }
|
||||
|
||||
make_box func(value usize) Box { return Box{value = value} }
|
||||
|
||||
main func() i32 {
|
||||
zero uint :: 0
|
||||
byte uint :: 255
|
||||
word uint :: 256
|
||||
word_max uint :: 65535
|
||||
dword uint :: 65536
|
||||
maximum uint :: 18446744073709551615
|
||||
platform usize = 7
|
||||
c_value c_uint = c_uint(9)
|
||||
box Box = make_box(7)
|
||||
signed isize = -1
|
||||
if (identity(zero) != 0) return 1
|
||||
if (identity(byte) != 255) return 2
|
||||
if (identity(word) != 256) return 3
|
||||
if (identity(word_max) != 65535) return 4
|
||||
if (identity(dword) != 65536) return 5
|
||||
if (identity(maximum) != 18446744073709551615) return 6
|
||||
if (box.value != 7) return 7
|
||||
if (signed != -1) return 8
|
||||
if (identity(platform) != 7) return 9
|
||||
if (identity(c_value) != c_value) return 10
|
||||
if (whole(word) != 256) return 11
|
||||
if (max_value() != 18446744073709551615) return 12
|
||||
return 0
|
||||
}
|
||||
`
|
||||
_ = os2.remove_all(directory)
|
||||
defer _ = os2.remove_all(directory)
|
||||
defer _ = os.remove(output)
|
||||
testing.expect(t, os.make_directory(directory) == nil)
|
||||
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
|
||||
testing.expect_value(t, compiler_core.compile_package(directory, output), 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
uint_constraint_rejects_other_families_and_recovers_records_as_u64 :: proc(t: ^testing.T) {
|
||||
text := `Unresolved :: struct { value uint }
|
||||
Conflict :: struct { value uint }
|
||||
|
||||
take func(value uint) uint { return value }
|
||||
bad_result func() uint { return -1 }
|
||||
|
||||
bad func(signed i32, decimal f64) void {
|
||||
_ = take(signed)
|
||||
_ = take(decimal)
|
||||
negative uint :: -1
|
||||
a Conflict = Conflict{value = signed}
|
||||
_ = negative
|
||||
_ = a
|
||||
}
|
||||
|
||||
Overflow uint :: 18446744073709551616
|
||||
NegativeGlobal uint :: -1
|
||||
main func() void {
|
||||
bad(1, 1.0)
|
||||
_ = bad_result()
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="bad_uint.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)
|
||||
|
||||
signed_error := false
|
||||
float_error := false
|
||||
negative_error := false
|
||||
field_error := false
|
||||
overflow_error := false
|
||||
global_error := false
|
||||
result_error := false
|
||||
for diagnostic in diagnostics.items {
|
||||
signed_error = signed_error || strings.contains(diagnostic.message, "cannot pass i32 to 'uint' parameter 'value'")
|
||||
float_error = float_error || strings.contains(diagnostic.message, "cannot pass f64 to 'uint' parameter 'value'")
|
||||
negative_error = negative_error || strings.contains(diagnostic.message, "could not resolve the 'uint' constraint for local 'negative'")
|
||||
field_error = field_error || strings.contains(diagnostic.message, "type i32 does not satisfy the 'uint' constraint for field 'Conflict.value'")
|
||||
overflow_error = overflow_error || strings.contains(diagnostic.message, "magnitude does not fit in u64")
|
||||
global_error = global_error || strings.contains(diagnostic.message, "could not resolve the 'uint' constraint for global 'NegativeGlobal'")
|
||||
result_error = result_error || strings.contains(diagnostic.message, "could not resolve a concrete result type for 'bad_result'")
|
||||
}
|
||||
unresolved, unresolved_ok := named_record_field_type(&hir_module, &symbols, "Unresolved", "value")
|
||||
testing.expect(t, signed_error && float_error && negative_error && field_error && overflow_error && global_error && result_error)
|
||||
testing.expect(t, unresolved_ok)
|
||||
testing.expect_value(t, unresolved, types.U64)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user