comptime storage and function values

This commit is contained in:
2026-07-03 23:23:36 +02:00
parent ee41a54e41
commit 4ebe9c90e9
8 changed files with 1255 additions and 119 deletions
+42 -20
View File
@@ -903,13 +903,16 @@ function_value_signature :: proc(
return nil, types.INVALID, false
}
function := checker.ast_module.functions[template]
if !function.c_abi || types.is_valid(function.error) {
return nil, types.INVALID, false
}
if function_has_comptime_params(function) {
return nil, types.INVALID, false
}
result = type_from_syntax(checker, function.result, function.pkg, function.file)
if function.c_abi && types.is_valid(function.error) {
return nil, types.INVALID, false
}
if !function.c_abi && (!function.has_body || function.variadic) {
return nil, types.INVALID, false
}
result = function_channel_type(checker, function)
if !types.is_void(result) && !is_runtime_type(checker, result) {
return nil, types.INVALID, false
}
@@ -929,6 +932,7 @@ function_pointer_type_for_template :: proc(
checker: ^Checker,
template: ast.Function_Id,
demanded: ^[dynamic]Spec_Id = nil,
demand_spec := true,
) -> (types.Type, Spec_Id, bool) {
params, result, ok := function_value_signature(checker, template)
if !ok {
@@ -936,16 +940,20 @@ function_pointer_type_for_template :: proc(
}
defer delete(params, checker.allocator)
function := checker.ast_module.functions[template]
function_type := types.function(&checker.module.types, params, result, true, function.variadic)
function_type := types.function(&checker.module.types, params, result, function.c_abi, function.variadic)
pointer_type := types.pointer(&checker.module.types, function_type, false, true)
spec := INVALID_SPEC
if demanded == nil {
spec = ensure_spec(checker, template, params)
if demand_spec {
spec = ensure_spec(checker, template, params)
} else {
spec = find_spec(checker, template, params)
}
} else {
spec = find_spec(checker, template, params)
mark_spec_demanded(checker, spec, demanded)
}
return pointer_type, spec, spec != INVALID_SPEC
return pointer_type, spec, spec != INVALID_SPEC || !demand_spec
}
contains_name :: proc(names: []symbol.Id, name: symbol.Id) -> bool {
@@ -1391,16 +1399,30 @@ validate_type_nodes :: proc(checker: ^Checker) {
}
}
if item.kind == .Function {
if !item.c_abi {
source.add(checker.diagnostics, source.Span{}, "only c_func function pointer types are supported")
}
for param in types.params_for(&checker.module.types, id) {
if types.is_void(param.type) || !types.is_c_signature_type(param.type, &checker.module.types) {
source.add(checker.diagnostics, source.Span{}, "function pointer parameters must be concrete C signature types")
if item.c_abi {
if types.kind(item.child, &checker.module.types) == .Fallible {
source.add(checker.diagnostics, source.Span{}, "c_func pointer results cannot be fallible")
}
for param in types.params_for(&checker.module.types, id) {
if types.is_void(param.type) || !types.is_c_signature_type(param.type, &checker.module.types) {
source.add(checker.diagnostics, source.Span{}, "c_func pointer parameters must be concrete C signature types")
}
}
if !types.is_c_signature_type(item.child, &checker.module.types, true) {
source.add(checker.diagnostics, source.Span{}, "c_func pointer results must be concrete C signature types or void")
}
} else {
if item.variadic {
source.add(checker.diagnostics, source.Span{}, "native function pointer types do not support variadic parameters")
}
for param in types.params_for(&checker.module.types, id) {
if types.is_void(param.type) || !is_runtime_type(checker, param.type) {
source.add(checker.diagnostics, source.Span{}, "native function pointer parameters must be concrete runtime types")
}
}
if !types.is_void(item.child) && !is_runtime_type(checker, item.child) {
source.add(checker.diagnostics, source.Span{}, "native function pointer results must be concrete runtime types or void")
}
}
if !types.is_c_signature_type(item.child, &checker.module.types, true) {
source.add(checker.diagnostics, source.Span{}, "function pointer results must be concrete C signature types or void")
}
}
}
@@ -1597,7 +1619,7 @@ infer_compound_expr :: proc(
store := &checker.module.types
#partial switch expr.kind {
case .Comptime:
return infer_comptime_expr_type(checker, expr, pkg, file)
return infer_comptime_expr_type(checker, expr, pkg, file, demanded)
case .Bool:
return types.BOOL
case .Not:
@@ -3535,13 +3557,13 @@ build_function_value :: proc(
id := source.addf(
checker.diagnostics,
span,
"function '%s' cannot be used as a C callback; expected a concrete c_func",
"function '%s' cannot be used as a function value; expected a concrete non-comptime signature",
symbol_text(checker, function.name),
)
return invalid_hir_expr(checker, span, id)
}
defer delete(params, checker.allocator)
function_type := types.function(&checker.module.types, params, result, true, function.variadic)
function_type := types.function(&checker.module.types, params, result, function.c_abi, function.variadic)
pointer_type := types.pointer(&checker.module.types, function_type, false, true)
spec := find_spec(checker, template, params)
if spec == INVALID_SPEC {
@@ -4444,7 +4466,7 @@ build_expr :: proc(
last = build_global_reference(checker, global, expr.span, global_reads)
} else {
template := find_template(checker, expr.name, target_pkg)
if template != ast.INVALID_FUNCTION && checker.ast_module.functions[template].c_abi {
if template != ast.INVALID_FUNCTION {
last = build_function_value(checker, template, expr.span, frame.expected)
} else {
id := add_unsupported_diagnostic(checker, expr.span, target_pkg, expr.name)
File diff suppressed because it is too large Load Diff
+13 -4
View File
@@ -113,7 +113,7 @@ is_type_token :: proc(kind: token.Kind) -> bool {
.Keyword_C_Short, .Keyword_C_Ushort, .Keyword_C_Int, .Keyword_C_Uint,
.Keyword_C_Long, .Keyword_C_Ulong, .Keyword_C_Longlong, .Keyword_C_Ulonglong,
.Keyword_C_Float, .Keyword_C_Double, .Keyword_C_Longdouble,
.Keyword_Void, .Keyword_Bool, .Keyword_C_Func, .Identifier, .Question, .At, .Star, .Left_Bracket:
.Keyword_Void, .Keyword_Bool, .Keyword_Func, .Keyword_C_Func, .Identifier, .Question, .At, .Star, .Left_Bracket:
return true
}
return false
@@ -329,10 +329,11 @@ parse_type_atom :: proc(parser: ^Parser) -> ast.Type_Syntax {
case .Keyword_Bool:
advance(parser)
return types.BOOL
case .Keyword_C_Func:
case .Keyword_Func, .Keyword_C_Func:
c_abi := tok.kind == .Keyword_C_Func
advance(parser)
if _, ok := allow(parser, .Left_Paren); !ok {
source.add(parser.diagnostics, current(parser).span, "expected '(' after c_func type")
source.add(parser.diagnostics, current(parser).span, "expected '(' after function type")
return types.INVALID
}
params, variadic := parse_params(parser)
@@ -340,11 +341,19 @@ parse_type_atom :: proc(parser: ^Parser) -> ast.Type_Syntax {
source.add(parser.diagnostics, current(parser).span, "expected ')' after function type parameters")
}
result := parse_type(parser)
if _, ok := allow(parser, .Bang); ok {
error_type := parse_error_type(parser)
if c_abi {
source.add(parser.diagnostics, current(parser).span, "c_func pointer types cannot be fallible")
} else {
result = types.fallible(&parser.module.type_store, result, error_type)
}
}
param_types := make([]types.Type, len(params), parser.module.allocator)
for param, index in params {
param_types[index] = param.type
}
function_type := types.function(&parser.module.type_store, param_types, result, true, variadic)
function_type := types.function(&parser.module.type_store, param_types, result, c_abi, variadic)
delete(param_types, parser.module.allocator)
delete(params, parser.module.allocator)
return function_type