weak contextual string-literal inference

This commit is contained in:
2026-07-22 02:30:39 +02:00
parent c389c19a81
commit 63f000dd42
2 changed files with 54 additions and 4 deletions
+5 -4
View File
@@ -2804,9 +2804,9 @@ infer_call_comptime_values :: proc(
for value_bound in bound {
all_bound = all_bound && value_bound
}
// Concrete arguments bind first. Numeric constants and `null` are contextual and
// therefore only contribute after stronger evidence has had a chance to bind the
// parameter type.
// Concrete arguments bind first. Numeric constants, string literals, and `null`
// are contextual and therefore only contribute after stronger evidence has had a
// chance to bind the parameter type.
weak_passes := [2]bool{false, true}
for weak in weak_passes {
for arg_id, source_index in args {
@@ -2819,7 +2819,8 @@ infer_call_comptime_values :: proc(
}
arg_expr := checker.ast_module.exprs[arg_id]
is_null := arg_expr.kind == .Null
is_weak := is_numeric_constant_expr(checker, arg_id) || is_null
is_weak := is_numeric_constant_expr(checker, arg_id) ||
arg_expr.kind == .String || is_null
if is_weak != weak {
continue
}
+49
View File
@@ -4686,6 +4686,55 @@ main func() void {
testing.expect(t, unrecoverable >= 3)
}
@(test)
string_literals_are_contextual_comptime_type_inference_evidence :: proc(t: ^testing.T) {
text := `pair func($T type, expected, actual T) T {
_ = expected
return actual
}
identity func($T type, value T) T {
return value
}
main func() void {
actual []u8 :: "hello"
contextual :: pair("hello", actual)
exact :: identity("hello")
_ = contextual
_ = exact
}
`
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)
pair_found := false
identity_found := false
for function in hir_module.functions {
name := symbol.resolve(&symbols, function.name)
if name == "pair" {
pair_found = true
testing.expect(t, types.is_slice(function.result, &hir_module.types))
} else if name == "identity" {
identity_found = true
_, array, ok := types.array_pointer(function.result, &hir_module.types)
testing.expect(t, ok && array.child == types.U8 && array.count == 5 &&
array.has_sentinel && array.sentinel == 0)
}
}
testing.expect_value(t, len(diagnostics.items), 0)
testing.expect(t, pair_found)
testing.expect(t, identity_found)
}
@(test)
comptime_params_may_be_interleaved_and_are_erased_from_the_abi :: proc(t: ^testing.T) {
text := `valid func($T type, $N usize, value T) [N]T {