add range constraint type
This commit is contained in:
+125
-3
@@ -4841,7 +4841,7 @@ main :: func() i32 {
|
||||
|
||||
@(test)
|
||||
equal_range_returns_infer_a_usable_result_type :: proc(t: ^testing.T) {
|
||||
text := `choose :: func(first bool) int {
|
||||
text := `choose :: func(first bool) range {
|
||||
if first {
|
||||
return 0..1
|
||||
}
|
||||
@@ -4886,10 +4886,10 @@ main :: func() i32 {
|
||||
|
||||
@(test)
|
||||
for_loop_lowering_evaluates_once_and_avoids_index_bounds_checks :: proc(t: ^testing.T) {
|
||||
text := `make_range :: func() int {
|
||||
text := `make_range :: func() range {
|
||||
return 0..2
|
||||
}
|
||||
make_array :: func() int {
|
||||
make_array :: func() [2]i32 {
|
||||
return [1, 2]
|
||||
}
|
||||
main :: func() i32 {
|
||||
@@ -5339,6 +5339,128 @@ main :: func() void {
|
||||
testing.expect(t, found_convert_error)
|
||||
}
|
||||
|
||||
@(test)
|
||||
range_constraint_local_resolves_to_inferred_range :: proc(t: ^testing.T) {
|
||||
text := `make :: func() range {
|
||||
r range :: 0..10
|
||||
return r
|
||||
}
|
||||
main :: func() void {
|
||||
_ = make()
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
r_type, found := float_local_type(&hir_module, &symbols, "make", "r")
|
||||
result_type, _ := float_result_type(&hir_module, &symbols, "make")
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, found)
|
||||
testing.expect(t, types.is_range(r_type, &hir_module.types))
|
||||
testing.expect_value(t, types.child_type(r_type, &hir_module.types), types.I8)
|
||||
testing.expect(t, types.is_range(result_type, &hir_module.types))
|
||||
}
|
||||
|
||||
@(test)
|
||||
range_constraint_param_and_result_monomorphize :: proc(t: ^testing.T) {
|
||||
text := `pass :: func(r range) range {
|
||||
return r
|
||||
}
|
||||
main :: func() void {
|
||||
once :: 0..5
|
||||
for pass(once) |v| {
|
||||
_ = v
|
||||
}
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
result_type, found := float_result_type(&hir_module, &symbols, "pass")
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, found)
|
||||
testing.expect(t, types.is_range(result_type, &hir_module.types))
|
||||
}
|
||||
|
||||
@(test)
|
||||
int_param_rejects_float_argument :: proc(t: ^testing.T) {
|
||||
text := `take :: func(x int) int {
|
||||
return x
|
||||
}
|
||||
main :: func() void {
|
||||
_ = take(1.5)
|
||||
}
|
||||
`
|
||||
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_reject := false
|
||||
for diagnostic in diagnostics.items {
|
||||
found_reject = found_reject ||
|
||||
strings.contains(diagnostic.message, "cannot pass f64 to 'int' parameter 'x'")
|
||||
}
|
||||
|
||||
testing.expect(t, found_reject)
|
||||
}
|
||||
|
||||
@(test)
|
||||
float_param_accepts_integer_literal_argument :: proc(t: ^testing.T) {
|
||||
text := `take :: func(x float) float {
|
||||
return x
|
||||
}
|
||||
main :: func() void {
|
||||
y f64 = take(3)
|
||||
_ = y
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
result_type, found := float_result_type(&hir_module, &symbols, "take")
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, found)
|
||||
testing.expect_value(t, result_type, types.F64)
|
||||
}
|
||||
|
||||
@(test)
|
||||
undefined_accepts_concrete_runtime_annotations :: proc(t: ^testing.T) {
|
||||
text := `Point :: struct {
|
||||
|
||||
Reference in New Issue
Block a user