broaden type inference from context (arithmetic expressions)
This commit is contained in:
@@ -6629,3 +6629,120 @@ contextual_inference_rejects_local_constant_that_does_not_fit :: proc(t: ^testin
|
||||
}
|
||||
testing.expect(t, found)
|
||||
}
|
||||
|
||||
@(test)
|
||||
contextual_inference_flows_through_numeric_arithmetic :: proc(t: ^testing.T) {
|
||||
text := `take_u16 :: func(v u16) void {}
|
||||
take_f32 :: func(v f32) void {}
|
||||
G :: 10
|
||||
H u16 :: G + 2
|
||||
GF :: 1.5
|
||||
HF f32 :: GF + 2.5
|
||||
CG :: 5
|
||||
CFG :: 1.0
|
||||
get :: func() f32 {
|
||||
seed f32 :: 2.0
|
||||
c :: seed + 3.0
|
||||
d :: 4.0 + seed
|
||||
return c + d
|
||||
}
|
||||
main :: func() void {
|
||||
a :: 10
|
||||
b u16 :: a + 2
|
||||
x :: 1.5
|
||||
y f32 :: x + 2.5
|
||||
z f32 :: 2.5 + x
|
||||
call_i :: 7
|
||||
call_f :: 1.25
|
||||
take_u16(call_i + 3)
|
||||
take_f32(call_f + 3.0)
|
||||
take_u16(CG + 1)
|
||||
take_f32(CFG + 1.0)
|
||||
_ = b
|
||||
_ = y
|
||||
_ = z
|
||||
_ = H
|
||||
_ = HF
|
||||
_ = get()
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
global_ok := 0
|
||||
for global in hir_module.globals {
|
||||
name := symbol.resolve(&symbols, global.name)
|
||||
switch name {
|
||||
case "G", "H", "CG":
|
||||
global_ok += 1 if types.equal(global.type, types.U16) else 0
|
||||
case "GF", "HF", "CFG":
|
||||
global_ok += 1 if types.equal(global.type, types.F32) else 0
|
||||
}
|
||||
}
|
||||
testing.expect_value(t, global_ok, 6)
|
||||
|
||||
main_ok := 0
|
||||
get_ok := false
|
||||
for function in hir_module.functions {
|
||||
name := symbol.resolve(&symbols, function.name)
|
||||
if name == "get" {
|
||||
get_ok = types.equal(function.result, types.F32)
|
||||
for local in function.locals {
|
||||
local_name := symbol.resolve(&symbols, local.name)
|
||||
if local_name == "c" || local_name == "d" {
|
||||
main_ok += 1 if types.equal(local.type, types.F32) else 0
|
||||
}
|
||||
}
|
||||
} else if name == "main" {
|
||||
for local in function.locals {
|
||||
local_name := symbol.resolve(&symbols, local.name)
|
||||
switch local_name {
|
||||
case "a", "call_i":
|
||||
main_ok += 1 if types.equal(local.type, types.U16) else 0
|
||||
case "x", "call_f":
|
||||
main_ok += 1 if types.equal(local.type, types.F32) else 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
testing.expect(t, get_ok)
|
||||
testing.expect_value(t, main_ok, 6)
|
||||
}
|
||||
|
||||
@(test)
|
||||
contextual_inference_rejects_non_fitting_arithmetic_demand :: proc(t: ^testing.T) {
|
||||
text := `BIG :: 100000
|
||||
C u8 :: BIG + 1
|
||||
main :: func() void {
|
||||
_ = C
|
||||
}
|
||||
`
|
||||
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 := false
|
||||
for diagnostic in diagnostics.items {
|
||||
found = found || strings.contains(diagnostic.message, "cannot implicitly convert i32 to u8")
|
||||
}
|
||||
testing.expect(t, found)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user