allocation related primitives

This commit is contained in:
2026-07-08 20:29:25 +02:00
parent 5e18df9bc1
commit 2cda024614
11 changed files with 617 additions and 98 deletions
+85 -3
View File
@@ -277,6 +277,26 @@ is_ptr_cast_call :: proc(checker: ^Checker, expr: ast.Expr) -> bool {
symbol_text(checker, expr.name) == "ptr_cast"
}
Layout_Builtin :: enum u8 {
None,
Size_Of,
Align_Of,
}
layout_builtin_call :: proc(checker: ^Checker, expr: ast.Expr) -> Layout_Builtin {
if expr.kind != .Call || expr.left != ast.INVALID_EXPR || symbol.is_valid(expr.qualifier) {
return .None
}
name := symbol_text(checker, expr.name)
if name == "size_of" {
return .Size_Of
}
if name == "align_of" {
return .Align_Of
}
return .None
}
valid_ptr_cast_child :: proc(checker: ^Checker, value: types.Type) -> bool {
return types.is_valid(value) &&
!types.is_void(value) &&
@@ -286,6 +306,49 @@ valid_ptr_cast_child :: proc(checker: ^Checker, value: types.Type) -> bool {
types.is_opaque_struct(value, &checker.module.types))
}
valid_layout_type :: proc(checker: ^Checker, value: types.Type) -> bool {
return types.is_runtime_value(value, &checker.module.types)
}
layout_builtin_value :: proc(checker: ^Checker, kind: Layout_Builtin, value: types.Type) -> i128 {
#partial switch kind {
case .Size_Of:
return i128(types.size(value, &checker.module.types, checker.target))
case .Align_Of:
return i128(types.alignment_of(value, &checker.module.types, checker.target))
case:
return 0
}
}
build_layout_builtin :: proc(
checker: ^Checker,
expr: ast.Expr,
kind: Layout_Builtin,
pkg: ast.Package_Id,
file: ast.File_Id,
) -> hir.Expr_Id {
if len(expr.args) != 1 {
id := source.addf(checker.diagnostics, expr.span, "%s expects 1 argument, got %d", symbol_text(checker, expr.name), len(expr.args))
return invalid_hir_expr(checker, expr.span, id, types.USIZE)
}
target, target_ok := resolve_type_argument(checker, expr.args[0], pkg, file)
if !target_ok {
id := source.add(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "layout target must be a type")
return invalid_hir_expr(checker, expr.span, id, types.USIZE)
}
if !valid_layout_type(checker, target) {
id := source.addf(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "layout target must be a sized runtime value type, got %s", type_label(checker, target))
return invalid_hir_expr(checker, expr.span, id, types.USIZE)
}
return build_constant_expr(
checker,
expr,
Constant{kind=.Value, value=layout_builtin_value(checker, kind, target)},
types.USIZE,
)
}
is_type_metatype_syntax :: proc(checker: ^Checker, value: ast.Type_Syntax) -> bool {
item, ok := types.node(&checker.module.types, value)
return ok && item.name == u32(checker.type_symbol) && item.qualifier == 0
@@ -1828,7 +1891,7 @@ infer_compound_expr :: proc(
case .Slice:
value := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types)
item, ok := types.container(value, store)
if !ok || item.kind == .Pointer {
if !ok || (item.kind == .Pointer && expr.args[1] == ast.INVALID_EXPR) {
return types.INVALID
}
for bound in expr.args {
@@ -2098,6 +2161,11 @@ infer_expr :: proc(
}
continue
}
if builtin := layout_builtin_call(checker, expr); builtin != .None {
last = types.USIZE
_ = pop(&stack)
continue
}
if is_ptr_cast_call(checker, expr) {
if len(expr.args) != 2 {
last = types.INVALID
@@ -3080,6 +3148,11 @@ infer_all :: proc(checker: ^Checker) {
if global.external {
continue
}
if global.expr != ast.INVALID_EXPR && int(global.expr) < len(checker.ast_module.exprs) &&
layout_builtin_call(checker, checker.ast_module.exprs[global.expr]) != .None {
checker.global_types[index] = types.USIZE
continue
}
constant := eval_integer_constant_in_context(checker, global.expr, global.pkg, global.file)
if constant.kind == .Value && fits_i64(constant.value) {
checker.global_open_const[index] = true
@@ -4227,8 +4300,12 @@ build_compound_expr :: proc(
container := build_nested_expr(checker, expr.left, locals, global_reads, calls, types.INVALID, pkg, file)
container_type := checker.module.exprs[container].type
item, ok := types.container(container_type, store)
if !ok || item.kind == .Pointer {
id := source.add(checker.diagnostics, expr.span, "slicing requires an array, slice, or pointer-to-array")
if !ok {
id := source.add(checker.diagnostics, expr.span, "slicing requires an array, slice, pointer-to-array, or many-item pointer")
return invalid_hir_expr(checker, expr.span, id)
}
if item.kind == .Pointer && expr.args[1] == ast.INVALID_EXPR {
id := source.add(checker.diagnostics, expr.span, "many-item pointer slicing requires an explicit end bound")
return invalid_hir_expr(checker, expr.span, id)
}
bounds := make([]hir.Expr_Id, 2, checker.allocator)
@@ -4881,6 +4958,11 @@ build_expr :: proc(
append(&stack, Build_Expr_Frame{expr=expr.left, expected=types.INVALID, template=ast.INVALID_FUNCTION})
continue
}
if builtin := layout_builtin_call(checker, expr); builtin != .None {
last = build_layout_builtin(checker, expr, builtin, pkg, file)
_ = pop(&stack)
continue
}
if is_ptr_cast_call(checker, expr) {
if len(expr.args) != 2 {
id := source.addf(checker.diagnostics, expr.span, "ptr_cast expects 2 arguments, got %d", len(expr.args))