fix: bug hunt
This commit is contained in:
+155
-6
@@ -4570,6 +4570,75 @@ main func() i32 {
|
||||
testing.expect(t, undefined_found)
|
||||
}
|
||||
|
||||
@(test)
|
||||
zero_runtime_fold_tracks_mutated_locals_in_dependent_array_types :: proc(t: ^testing.T) {
|
||||
text := `FoldedMap func($V type) type {
|
||||
return struct {
|
||||
keys [][]u8
|
||||
values []V
|
||||
indexes []u32
|
||||
}
|
||||
}
|
||||
Pair func($V type) type { return struct { []u8, V } }
|
||||
build_map func($V type, $N usize, $entries [N]Pair(V)) FoldedMap(V) {
|
||||
keys [N]mut []u8 = undefined
|
||||
values [N]mut V = undefined
|
||||
for entries |entry, i| {
|
||||
keys[i] = entry.0
|
||||
values[i] = entry.1
|
||||
}
|
||||
for 1..N |i| {
|
||||
key :: keys[i]
|
||||
value :: values[i]
|
||||
j usize = i
|
||||
while j > 0 and keys[j - 1].len > key.len : j -= 1 {
|
||||
keys[j] = keys[j - 1]
|
||||
values[j] = values[j - 1]
|
||||
}
|
||||
keys[j] = key
|
||||
values[j] = value
|
||||
}
|
||||
max_len usize :: keys[N - 1].len
|
||||
indexes [max_len + 1]mut u32 = undefined
|
||||
for 0..=max_len |length| {
|
||||
indexes[length] = 0
|
||||
}
|
||||
return FoldedMap(V){
|
||||
keys = keys[..],
|
||||
values = values[..],
|
||||
indexes = indexes[..],
|
||||
}
|
||||
}
|
||||
Kind :: enum { short, long }
|
||||
MAP FoldedMap(Kind) :: build_map([
|
||||
{"four", .long},
|
||||
{"a", .short},
|
||||
])
|
||||
main func() i32 {
|
||||
if MAP.keys.len != 2 or MAP.indexes.len != 5 { return 1 }
|
||||
return 0
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
build_map_found := false
|
||||
for function in hir_module.functions {
|
||||
build_map_found = build_map_found || symbol.resolve(&symbols, function.name) == "build_map"
|
||||
}
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, !build_map_found)
|
||||
}
|
||||
|
||||
@(test)
|
||||
zero_runtime_fold_preserves_reached_compile_error :: proc(t: ^testing.T) {
|
||||
text := `fail func() i32 {
|
||||
@@ -6536,6 +6605,7 @@ AError :: enum { a }
|
||||
BError :: enum { b }
|
||||
CError :: enum { c }
|
||||
DetailError :: union(enum) { out_of_memory i32 }
|
||||
Code :: alias i32
|
||||
|
||||
key_or_alloc func(code i32) void ! (KeyError | AllocError) {
|
||||
if code == 1 { return .key_exists }
|
||||
@@ -6557,7 +6627,7 @@ via_else func() i32 ! AllocError {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
via_group func() i32 ! (AError | BError) {
|
||||
via_group func() Code ! (AError | BError) {
|
||||
abc(2) catch |err| {
|
||||
match err {
|
||||
.a, .b: return err
|
||||
@@ -9843,6 +9913,8 @@ answer :: alias dep.answer
|
||||
hide local_answer_alias :: alias dep.answer
|
||||
local_answer func() i32 { return local_answer_alias() }
|
||||
Scalar :: alias i32
|
||||
ScalarChain :: alias Scalar
|
||||
static_scalar Scalar :: Scalar(usize(6))
|
||||
MaybePoint :: alias ?@dep.Point
|
||||
Concrete :: alias dep.Box(i32)
|
||||
`
|
||||
@@ -9862,10 +9934,11 @@ main func() i32 {
|
||||
box top.Box(i32) :: top.Box(i32) { value = 2 }
|
||||
point top.Point :: top.Point { value = 3 }
|
||||
maybe facade.MaybePoint :: null
|
||||
scalar facade.Scalar :: 5
|
||||
scalar facade.Scalar :: facade.Scalar(usize(5))
|
||||
chained facade.ScalarChain :: facade.ScalarChain(usize(6))
|
||||
top.counter = 7
|
||||
if box.value != 2 or point.value != 3 { return 1 }
|
||||
if scalar != 5 or top.answer() != 40 or facade.local_answer() != 40 or dep.counter != 7 { return 2 }
|
||||
if scalar != 5 or chained != 6 or facade.static_scalar != 6 or top.answer() != 40 or facade.local_answer() != 40 or dep.counter != 7 { return 2 }
|
||||
if apply(top.answer) != 40 or apply(facade.answer) != 40 { return 3 }
|
||||
_ = maybe
|
||||
return 0
|
||||
@@ -9882,6 +9955,75 @@ main func() i32 {
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
scalar_alias_casts_reject_bad_arity_and_operands :: proc(t: ^testing.T) {
|
||||
text := `StringId :: alias u32
|
||||
main func() void {
|
||||
_ = StringId()
|
||||
_ = StringId(1, 2)
|
||||
_ = StringId(true)
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
arity := 0
|
||||
bad_operand := false
|
||||
for diagnostic in diagnostics.items {
|
||||
arity += 1 if strings.contains(diagnostic.message, "type alias 'StringId' expects 1 argument") else 0
|
||||
bad_operand = bad_operand || strings.contains(diagnostic.message, "scalar cast requires numeric scalar types")
|
||||
}
|
||||
testing.expect_value(t, arity, 2)
|
||||
testing.expect(t, bad_operand)
|
||||
}
|
||||
|
||||
@(test)
|
||||
optional_contextual_enum_literals_compile_at_runtime_and_comptime :: proc(t: ^testing.T) {
|
||||
text := `Kind :: enum { first, second }
|
||||
Choice :: union(enum) { empty void, payload i32 }
|
||||
STATIC ?Kind :: .second
|
||||
STATIC_CHOICE ?Choice :: .payload{4}
|
||||
choose func(first bool) ?Kind {
|
||||
if first { return .first }
|
||||
return .second
|
||||
}
|
||||
choose_choice func() ?Choice { return .empty }
|
||||
main func() i32 {
|
||||
if choose(true) |value| {
|
||||
if value != Kind.first { return 1 }
|
||||
} else { return 2 }
|
||||
if STATIC |value| {
|
||||
if value != Kind.second { return 3 }
|
||||
} else { return 4 }
|
||||
if choose_choice() |_| {} else { return 5 }
|
||||
if STATIC_CHOICE |_| {} else { return 6 }
|
||||
return 0
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
declaration_aliases_diagnose_invalid_targets :: proc(t: ^testing.T) {
|
||||
root :: "/tmp/brolang-test-declaration-alias-errors"
|
||||
@@ -11095,7 +11237,8 @@ main func() i32 {
|
||||
|
||||
@(test)
|
||||
range_bound_parenthesization_is_enforced :: proc(t: ^testing.T) {
|
||||
text := `main func() void {
|
||||
text := `limit_func func() usize { return 3 }
|
||||
main func() void {
|
||||
limit :: 3
|
||||
for 0..limit + 1 |bad| {
|
||||
_ = bad
|
||||
@@ -11103,6 +11246,12 @@ range_bound_parenthesization_is_enforced :: proc(t: ^testing.T) {
|
||||
for 0..(limit + 1) |good| {
|
||||
_ = good
|
||||
}
|
||||
for 0..=usize(limit) |cast_bound| {
|
||||
_ = cast_bound
|
||||
}
|
||||
for 0..limit_func() |call_bound| {
|
||||
_ = call_bound
|
||||
}
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
@@ -14934,7 +15083,7 @@ TokenKind :: enum {
|
||||
keyword_while
|
||||
}
|
||||
|
||||
keywords std.StaticStringMap(TokenKind) = static_string_map.init([
|
||||
keywords std.StaticStringMap(TokenKind) :: static_string_map.init([
|
||||
{"if", .keyword_if},
|
||||
{"else", .keyword_else},
|
||||
{"for", .keyword_for},
|
||||
@@ -14943,7 +15092,7 @@ keywords std.StaticStringMap(TokenKind) = static_string_map.init([
|
||||
fallback :: static_string_map.init(TokenKind, [
|
||||
{"while", .keyword_while},
|
||||
])
|
||||
empty std.StaticStringMap(TokenKind) = static_string_map.init([])
|
||||
empty std.StaticStringMap(TokenKind) :: static_string_map.init([])
|
||||
numbers []i32 = ${
|
||||
values [3]mut i32 = [7, 8, 9]
|
||||
yield values[..]
|
||||
|
||||
Reference in New Issue
Block a user