disambiguate enum blocks and complete distinct type operations
This commit is contained in:
+199
-20
@@ -313,7 +313,9 @@ main func() i32 {
|
||||
|
||||
@(test)
|
||||
typed_bitwise_constants_fold_in_runtime_expressions :: proc(t: ^testing.T) {
|
||||
text := `main func() void {
|
||||
text := `D :: distinct u8
|
||||
main func() void {
|
||||
_ = ~D(1)
|
||||
_ = ~u8(0)
|
||||
_ = (u8(240) & u8(204)) xor u8(15)
|
||||
_ = u8(129) << 1
|
||||
@@ -332,12 +334,17 @@ typed_bitwise_constants_fold_in_runtime_expressions :: proc(t: ^testing.T) {
|
||||
defer ast.destroy_module(&ast_module)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
for statement_id in hir_module.functions[0].body {
|
||||
d_type := types.find_named(&ast_module.type_store, 0, u32(symbol.intern(&symbols, "D")))
|
||||
for statement_id, index in hir_module.functions[0].body {
|
||||
statement := hir_module.statements[statement_id]
|
||||
testing.expect(t, statement.expr != hir.INVALID_EXPR)
|
||||
testing.expect_value(t, hir_module.exprs[statement.expr].kind, hir.Expr_Kind.Integer)
|
||||
if index == 0 {
|
||||
testing.expect_value(t, hir_module.exprs[statement.expr].kind, hir.Expr_Kind.Bit_Not)
|
||||
testing.expect_value(t, hir_module.exprs[statement.expr].type, d_type)
|
||||
} else {
|
||||
testing.expect_value(t, hir_module.exprs[statement.expr].kind, hir.Expr_Kind.Integer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +360,7 @@ main func() void {
|
||||
_ = true & false
|
||||
_ = 1.0 | 2.0
|
||||
_ = ~p
|
||||
_ = ~d
|
||||
_ = d
|
||||
_ = ~e
|
||||
_ = u8(1) & i8(1)
|
||||
_ = u8(1) << signed_count
|
||||
@@ -410,6 +417,32 @@ main func() i32 {
|
||||
testing.expect(t, state.exit_code != 0)
|
||||
testing.expect(t, strings.contains(string(stderr), "shift count exceeds integer width"))
|
||||
}
|
||||
@(test)
|
||||
runtime_distinct_ordinary_overshift_traps :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-distinct-bitwise-overshift"
|
||||
main_path := "/tmp/brolang-test-distinct-bitwise-overshift/main.bro"
|
||||
output := "/tmp/brolang-test-distinct-bitwise-overshift-output"
|
||||
text := `D :: distinct u8
|
||||
shift func(value D, count u8) D { return value << count }
|
||||
main func() i32 {
|
||||
_ = shift(D(1), 8)
|
||||
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, stdout, stderr, err := os2.process_exec(os2.Process_Desc{command=[]string{output}}, context.allocator)
|
||||
defer delete(stdout)
|
||||
defer delete(stderr)
|
||||
testing.expect(t, err == nil)
|
||||
testing.expect(t, state.exit_code != 0)
|
||||
testing.expect(t, strings.contains(string(stderr), "shift count exceeds integer width"))
|
||||
}
|
||||
|
||||
|
||||
@(test)
|
||||
parser_accepts_grouped_params_and_multiline_statements :: proc(t: ^testing.T) {
|
||||
@@ -1704,6 +1737,11 @@ integer_bound_builtins_compile_and_run :: proc(t: ^testing.T) {
|
||||
main_path := "/tmp/brolang-test-integer-bounds/main.bro"
|
||||
output := "/tmp/brolang-test-integer-bounds-output"
|
||||
text := `MAX_U64 u64 :: maxval!(u64)
|
||||
Signed :: distinct i16
|
||||
Unsigned :: distinct u16
|
||||
Inner :: distinct u8
|
||||
Outer :: distinct Inner
|
||||
|
||||
|
||||
maximum func($T type) T {
|
||||
return maxval!(T)
|
||||
@@ -1720,6 +1758,16 @@ main func() i32 {
|
||||
if (maximum(u16) != 65535) return 8
|
||||
if (minval!(c_int) != -2147483648) return 9
|
||||
if (maxval!(c_ulong) != 18446744073709551615) return 10
|
||||
signed_min Signed = minval!(Signed)
|
||||
unsigned_max Unsigned = maxval!(Unsigned)
|
||||
nested_max Outer = maxval!(Outer)
|
||||
generic_min Signed = maximum(Signed)
|
||||
generic_nested Outer = maximum(Outer)
|
||||
if i16(signed_min) != -32768 { return 11 }
|
||||
if u16(unsigned_max) != 65535 { return 12 }
|
||||
if u8(nested_max) != 255 { return 13 }
|
||||
if i16(generic_min) != 32767 { return 14 }
|
||||
if u8(generic_nested) != 255 { return 15 }
|
||||
return 0
|
||||
}
|
||||
`
|
||||
@@ -1736,7 +1784,9 @@ main func() i32 {
|
||||
|
||||
@(test)
|
||||
integer_bound_builtins_reject_invalid_targets :: proc(t: ^testing.T) {
|
||||
text := `Named :: distinct u8
|
||||
text := `BadFloat :: distinct f32
|
||||
BadBool :: distinct bool
|
||||
BadAggregate :: distinct [2]u8
|
||||
Choice :: enum { one }
|
||||
|
||||
main func() void {
|
||||
@@ -1747,7 +1797,9 @@ main func() void {
|
||||
_ = maxval!(uint)
|
||||
_ = maxval!(f32)
|
||||
_ = maxval!(bool)
|
||||
_ = maxval!(Named)
|
||||
_ = maxval!(BadFloat)
|
||||
_ = maxval!(BadBool)
|
||||
_ = maxval!(BadAggregate)
|
||||
_ = maxval!(Choice)
|
||||
}
|
||||
`
|
||||
@@ -1773,7 +1825,7 @@ main func() void {
|
||||
}
|
||||
testing.expect_value(t, bad_arity, 2)
|
||||
testing.expect(t, bad_type)
|
||||
testing.expect_value(t, bad_target, 6)
|
||||
testing.expect_value(t, bad_target, 8)
|
||||
}
|
||||
|
||||
@(test)
|
||||
@@ -3284,6 +3336,8 @@ milestone_37_format_errors_are_reported_at_comptime :: proc(t: ^testing.T) {
|
||||
main_path := "/tmp/brolang-test-format-errors/main.bro"
|
||||
text := `io :: import "@std/io"
|
||||
process :: import "@std/process"
|
||||
Aggregate :: distinct [2]u8
|
||||
|
||||
|
||||
main func(init process.Init) void {
|
||||
writer io.Writer :: io.stdout(init.io)
|
||||
@@ -3299,6 +3353,7 @@ main func(init process.Init) void {
|
||||
io.print(writer, "{e}", {1,}) catch |_| {}
|
||||
io.print(writer, "{c}", {i16(65),}) catch |_| {}
|
||||
io.print(writer, "}", {}) catch |_| {}
|
||||
io.print(writer, "{}", {Aggregate([1, 2]),}) catch |_| {}
|
||||
}
|
||||
`
|
||||
_ = os2.remove_all(directory)
|
||||
@@ -3317,7 +3372,7 @@ main func(init process.Init) void {
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
|
||||
found := [10]bool{}
|
||||
found := [11]bool{}
|
||||
for diagnostic in diagnostics.items {
|
||||
message := diagnostic.message
|
||||
found[0] = found[0] || strings.contains(message, "arguments must be a tuple")
|
||||
@@ -3330,6 +3385,7 @@ main func(init process.Init) void {
|
||||
found[7] = found[7] || strings.contains(message, "integer format requires an integer argument")
|
||||
found[8] = found[8] || strings.contains(message, "float format requires a float argument")
|
||||
found[9] = found[9] || strings.contains(message, "'{c}' requires an unsigned integer that fits in u8")
|
||||
found[10] = found[10] || strings.contains(message, "io.print '{}' does not support this argument type")
|
||||
}
|
||||
testing.expect(t, loaded)
|
||||
for present in found {
|
||||
@@ -3402,7 +3458,7 @@ milestone_39_stable_values_and_richer_formatting_compile_and_run :: proc(t: ^tes
|
||||
testing.expect_value(
|
||||
t,
|
||||
string(stdout),
|
||||
"true -42 1.5 .running bro 2.5 1010 12 ff FF A 1.5000000000000000e+00 {} -9223372036854775808 0 inf nan 1.50000000e+00\n",
|
||||
"true -42 1.5 .running bro 2.5 1010 12 ff FF A 1.5000000000000000e+00 {} -9223372036854775808 0 inf nan 1.50000000e+00\n-42 -42 1010 12 ff FF A 1.50000000e+00 7\n",
|
||||
)
|
||||
testing.expect_value(t, string(stderr), "debug=.idle 2a\n")
|
||||
}
|
||||
@@ -7927,6 +7983,28 @@ checked_addition_traps_on_overflow :: proc(t: ^testing.T) {
|
||||
state := run_executable(output)
|
||||
testing.expect(t, !state.success)
|
||||
}
|
||||
@(test)
|
||||
checked_distinct_addition_traps_on_backing_overflow :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-distinct-overflow"
|
||||
main_path := "/tmp/brolang-test-distinct-overflow/main.bro"
|
||||
output := "/tmp/brolang-test-distinct-overflow-output"
|
||||
text := `D :: distinct i8
|
||||
add func(left, right D) D { return left + right }
|
||||
main func() i32 {
|
||||
_ = add(D(127), D(1))
|
||||
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(t, !state.success)
|
||||
}
|
||||
|
||||
|
||||
@(test)
|
||||
checked_runtime_negation_traps_for_every_signed_width :: proc(t: ^testing.T) {
|
||||
@@ -10708,6 +10786,32 @@ parser_diagnoses_braceless_if_without_parens_or_call :: proc(t: ^testing.T) {
|
||||
testing.expect(t, strings.contains(diagnostics.items[0].message, "parenthesized"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
parser_separates_contextual_enum_literal_from_if_block :: proc(t: ^testing.T) {
|
||||
text := `Kind :: enum {
|
||||
newline
|
||||
other
|
||||
}
|
||||
main func() void {
|
||||
kind Kind = .other
|
||||
if kind != .newline {
|
||||
}
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect_value(t, module.statements[module.functions[0].body[1]].kind, ast.Stmt_Kind.If)
|
||||
}
|
||||
|
||||
@(test)
|
||||
parser_accepts_braceless_while_bodies :: proc(t: ^testing.T) {
|
||||
text := `ready func() bool { return false }
|
||||
@@ -13125,6 +13229,7 @@ OtherID :: distinct u32
|
||||
PointID :: distinct Point
|
||||
Bytes :: distinct [2]u8
|
||||
WrappedID :: distinct UserID
|
||||
Flag :: distinct bool
|
||||
static_id UserID :: UserID(42)
|
||||
take func(value UserID) UserID {
|
||||
return value
|
||||
@@ -13137,11 +13242,27 @@ main func() i32 {
|
||||
point PointID :: PointID(Point { x = 1, y = 2 })
|
||||
bytes Bytes :: Bytes([3, 4])
|
||||
wrapped WrappedID :: WrappedID(id)
|
||||
sum UserID = id + 1
|
||||
matches bool = id == 7
|
||||
raw u32 = u32(id)
|
||||
wide usize = usize(id)
|
||||
real f64 = f64(id)
|
||||
inner UserID = UserID(wrapped)
|
||||
terminal u32 = u32(wrapped)
|
||||
flag_matches bool = Flag(true) == Flag(true)
|
||||
_ = maybe
|
||||
_ = pointer
|
||||
_ = point
|
||||
_ = bytes
|
||||
_ = wrapped
|
||||
_ = sum
|
||||
_ = matches
|
||||
_ = raw
|
||||
_ = wide
|
||||
_ = real
|
||||
_ = inner
|
||||
_ = terminal
|
||||
_ = flag_matches
|
||||
return 0
|
||||
}
|
||||
`
|
||||
@@ -13177,17 +13298,33 @@ main func() i32 {
|
||||
testing.expect(t, strings.contains(llvm_text, "@bro.g.0 = internal constant i32 42"))
|
||||
testing.expect(t, strings.contains(llvm_text, "select i1 true, i32"))
|
||||
|
||||
nominal_hir_add := false
|
||||
for hir_expr in hir_module.exprs {
|
||||
nominal_hir_add = nominal_hir_add || hir_expr.kind == .Add && hir_expr.type == user_id
|
||||
}
|
||||
testing.expect(t, nominal_hir_add)
|
||||
|
||||
retype_count := 0
|
||||
nominal_ir_add := false
|
||||
u32_cast, usize_cast, f64_cast := false, false, false
|
||||
for function in ir_module.functions {
|
||||
for instruction in function.instructions {
|
||||
retype_count += 1 if instruction.op == .Retype else 0
|
||||
nominal_ir_add = nominal_ir_add || instruction.op == .Add_Checked && instruction.type == user_id
|
||||
if instruction.op == .Scalar_Cast {
|
||||
u32_cast = u32_cast || instruction.type == types.U32
|
||||
usize_cast = usize_cast || instruction.type == types.USIZE
|
||||
f64_cast = f64_cast || instruction.type == types.F64
|
||||
}
|
||||
}
|
||||
}
|
||||
testing.expect_value(t, retype_count, 4)
|
||||
testing.expect(t, nominal_ir_add)
|
||||
testing.expect(t, u32_cast && usize_cast && f64_cast)
|
||||
testing.expect(t, retype_count >= 5)
|
||||
}
|
||||
|
||||
@(test)
|
||||
distinct_types_reject_implicit_conversions_operators_and_invalid_backings :: proc(t: ^testing.T) {
|
||||
distinct_types_reject_implicit_conversions_and_invalid_backings :: proc(t: ^testing.T) {
|
||||
text := `Opaque :: opaque
|
||||
UserID :: distinct u32
|
||||
OtherID :: distinct u32
|
||||
@@ -13207,9 +13344,14 @@ main func() void {
|
||||
_ = UserID()
|
||||
_ = UserID(1, 2)
|
||||
left UserID :: UserID(5)
|
||||
right UserID :: UserID(6)
|
||||
_ = left + right
|
||||
_ = left == right
|
||||
raw_operand u32 :: u32(6)
|
||||
other_operand OtherID :: OtherID(6)
|
||||
_ = left + raw_operand
|
||||
_ = raw_operand + left
|
||||
_ = left + other_operand
|
||||
_ = left == raw_operand
|
||||
_ = raw_operand == left
|
||||
_ = left == other_operand
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
@@ -14616,12 +14758,12 @@ dependency_passes test {
|
||||
defer delete(stderr)
|
||||
output := string(stderr)
|
||||
testing.expect_value(t, state.exit_code, 1)
|
||||
testing.expect(t, strings.contains(output, "root.root_passes [ok]"))
|
||||
testing.expect(t, strings.contains(output, "root.root_fails [failed]"))
|
||||
testing.expect(t, strings.contains(output, "root.root_passes...[ok]"))
|
||||
testing.expect(t, strings.contains(output, "root.root_fails...[failed]"))
|
||||
testing.expect(t, strings.contains(output, "expected 42, found 41"))
|
||||
testing.expect(t, strings.contains(output, "root.root_continues [ok]"))
|
||||
testing.expect(t, strings.contains(output, "root.root_errors [failed]"))
|
||||
testing.expect(t, strings.contains(output, "dependency.dependency_passes [ok]"))
|
||||
testing.expect(t, strings.contains(output, "root.root_continues...[ok]"))
|
||||
testing.expect(t, strings.contains(output, "root.root_errors...[failed]"))
|
||||
testing.expect(t, strings.contains(output, "dependency.dependency_passes...[ok]"))
|
||||
testing.expect(t, strings.contains(output, root_path))
|
||||
testing.expect(t, strings.contains(output, "3 passed, 2 failed"))
|
||||
}
|
||||
@@ -15233,6 +15375,43 @@ main func() i32 {
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
@(test)
|
||||
distinct_reflection_reports_immediate_backing :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-distinct-reflection"
|
||||
main_path := "/tmp/brolang-test-distinct-reflection/main.bro"
|
||||
output := "/tmp/brolang-test-distinct-reflection-output"
|
||||
text := `meta :: import "@std/meta"
|
||||
|
||||
Inner :: distinct u16
|
||||
Outer :: distinct Inner
|
||||
OuterAlias :: alias Outer
|
||||
|
||||
matches func($Distinct, $Backing type) bool {
|
||||
match typeinfo!(Distinct) {
|
||||
.distinct |backing|: return backing == Backing
|
||||
else: return false
|
||||
}
|
||||
}
|
||||
|
||||
main func() i32 {
|
||||
if !$(matches(Inner, u16)) { return 1 }
|
||||
if !$(matches(Outer, Inner)) { return 2 }
|
||||
if !$(matches(OuterAlias, Inner)) { return 3 }
|
||||
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, nil, target.DEFAULT, cimport.Options{}, ".",
|
||||
), 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
|
||||
@(test)
|
||||
static_string_map_infers_array_size_and_preserves_promoted_backing :: proc(t: ^testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user