feat: execute value-returning compile-time metadata helpers

This commit is contained in:
2026-10-31 03:27:47 +01:00
parent ebae8e712c
commit ee7eeac894
6 changed files with 152 additions and 9 deletions
+8
View File
@@ -1405,6 +1405,7 @@ tagged_type_metadata_recompiles_owned_private_nominal_payloads test {
` Selected :: lib.Selected(lib.make())
` value Selected :: { value = 40 }
` if (lib.read(lib.make(), value) != 42) return -4
` if (lib.score(lib.make(), 40) != 42) return -6
` snapshot Storage() :: {
` original = { values = [{ value = 19 }, { value = 21 }] },
` nested = { values = [true] },
@@ -1460,6 +1461,13 @@ tagged_type_metadata_recompiles_owned_private_nominal_payloads test {
`read proc($input Metadata, value Selected(input)) i16 {
` return value.value + i16(input.payload.count)
`}
`score proc(input Metadata, bias i16) i16 {
` saved :: input
` changed := input
` changed.payload.children[0] = bool
` if (saved.payload.children[0]? != Child) return -1
` return i16(saved.payload.count) + bias
`}
,
)
defer arraylist.deinit(&imported)
+20 -9
View File
@@ -143,6 +143,11 @@ elaborate proc(
if (class == .function) {
if (type_storage_annotation(&original, resolution.storage.bindings,
ast.function_decl(&original, id).return_type, 0)) needed = true
for (0..ast.function_param_count(&original, id)) |position| {
parameter :: ast.param(&original, ast.function_param(&original, id, position))
if (!parameter.comptime and type_storage_annotation(&original,
resolution.storage.bindings, parameter.type, 0)) needed = true
}
}
if (class == .statement and ast.stmt_kind(&original, id) == .declaration
and type_storage_annotation(&original, resolution.storage.bindings,
@@ -1853,8 +1858,13 @@ type_storage_annotation proc(tree @ast.Tree, bindings []sema.Binding, input ast.
}
@hide:file
compiletime_result proc(state @State, annotation ast.NodeId) bool {
return type_record_storage(state, annotation, 0)
compiletime_call proc(state @State, function ast.NodeId) bool {
if (type_record_storage(state, ast.function_decl(&state.tree, function).return_type, 0)) return true
for (0..ast.function_param_count(&state.tree, function)) |i| {
parameter :: ast.param(&state.tree, ast.function_param(&state.tree, function, i))
if (!parameter.comptime and type_record_storage(state, parameter.type, 0)) return true
}
return false
}
@hide:file
@@ -1907,8 +1917,8 @@ specialize_call proc(state @mut State, call, function, expected ast.NodeId) void
state.depth += 1
defer state.depth -= 1
count :: ast.function_param_count(&state.tree, function)
# type-containing results have no runtime call: every input is specialized.
type_result :: compiletime_result(state, ast.function_decl(&state.tree, function).return_type)
# ordinary metadata inputs and metadata results require a fully constant call.
type_result :: compiletime_call(state, function)
runtime := usize(0)
for (0..count) |i| {
if (!type_result and !ast.param(&state.tree, ast.function_param(&state.tree, function, i)).comptime) runtime += 1
@@ -2110,7 +2120,7 @@ specialize_call proc(state @mut State, call, function, expected ast.NodeId) void
@hide:file
instantiate proc(state @mut State, index usize, call ast.NodeId) void ! Error {
function :: state.instances.items[index].function
type_result :: compiletime_result(state, ast.function_decl(&state.tree, function).return_type)
type_result :: compiletime_call(state, function)
count :: state.original_count
clone_start :: ast.node_count(&state.tree)
mapping :: state.mapping
@@ -3027,8 +3037,9 @@ return_type_value proc(state @mut State, block, first_owned, result_type ast.Nod
@hide:file
type_void_completion proc(state @mut State, annotation, at ast.NodeId) ast.NodeId ! Error {
type :: try canonical_type(state, annotation)
if (type == no_node or ast.expr_kind(&state.tree, type) != .fallible_type) return no_node
child :: try canonical_type(state, ast.binary_expr(&state.tree, type).left)
if (type == no_node) return no_node
child :: if (ast.expr_kind(&state.tree, type) == .fallible_type)
try canonical_type(state, ast.binary_expr(&state.tree, type).left) else type
resolved :: binding(state, child)
if (resolved.kind != .builtin or resolved.data.builtin != .void) return no_node
value :: try ast.add_literal(state.builder, .void, ast.node_span(&state.tree, at))
@@ -5258,7 +5269,7 @@ execute_type_statement_body proc(state @mut State, execution @mut TypeExecution,
execution.returned = try type_execution_value(state, expression, execution.result_type)
if (execution.returned != no_node
and !try type_array_initialized(state, execution.returned, value)) return .invalid
if (execution.returned != no_node and type_record_storage(state, execution.result_type, 0)) {
if (execution.returned != no_node) {
type :: try canonical_type(state, execution.result_type)
if (type != no_node and ast.expr_kind(&state.tree, type) == .fallible_type) {
payload :: ast.typed_constant(&state.tree, execution.returned).value
@@ -6788,5 +6799,5 @@ flexible proc(state @State, id ast.NodeId) bool {
@hide:file
template proc(state @State, id ast.NodeId) bool {
return ast.function_generic(&state.tree, id) or compiletime_result(state, ast.function_decl(&state.tree, id).return_type)
return ast.function_generic(&state.tree, id) or compiletime_call(state, id)
}