allocation related primitives
This commit is contained in:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user