Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f7de7a8d2 | |||
| 5dac5baa05 |
+2
-2
@@ -35,7 +35,7 @@ roadmap and milestone history.
|
|||||||
- arrays `[N]T`, inferred-count arrays `[_]T`, sentinel arrays `[N;S]T`, compile-time expression array counts, slices `[]T` / `[;S]T`, single-item pointers `@T`, many-item pointers `*T`, and sentinel many-item pointers `[*;S]T`
|
- arrays `[N]T`, inferred-count arrays `[_]T`, sentinel arrays `[N;S]T`, compile-time expression array counts, slices `[]T` / `[;S]T`, single-item pointers `@T`, many-item pointers `*T`, and sentinel many-item pointers `[*;S]T`
|
||||||
- pointer mutability via `mut`, optional pointers as nullable pointers, pointer arithmetic for many-item pointers, postfix dereference `^`, and trapping optional unwrap `?`
|
- pointer mutability via `mut`, optional pointers as nullable pointers, pointer arithmetic for many-item pointers, postfix dereference `^`, and trapping optional unwrap `?`
|
||||||
- pointer-to-array `.len`, indexing, slicing, `.ptr` on slices and pointers-to-arrays, implicit address-taking for array-variable slices, and pointer/slice sentinel weakening
|
- pointer-to-array `.len`, indexing, slicing, `.ptr` on slices and pointers-to-arrays, implicit address-taking for array-variable slices, and pointer/slice sentinel weakening
|
||||||
- `ptrcast!(T, ptr)` as a first-pass pointer-child retype that preserves optionality, pointer kind, mutability, and sentinel shape
|
- `ptrcast!(ptr)` infers its complete pointer result from context; `ptrcast!(P, ptr)` supplies `P` explicitly; both change the child type, then permit only ordinary implicit pointer conversions to the requested target
|
||||||
- unsafe `constcast!(value)` for restoring mutability to pointers, optional pointers, and slices without changing their child type or shape
|
- unsafe `constcast!(value)` for restoring mutability to pointers, optional pointers, and slices without changing their child type or shape
|
||||||
- UTF-8 string literals as immutable pointers to static zero-terminated byte arrays, supporting `\\`, `\"`, `\n`, `\r`, `\t`, `\0`, and `\xNN` escapes, plus raw backtick multiline strings
|
- UTF-8 string literals as immutable pointers to static zero-terminated byte arrays, supporting `\\`, `\"`, `\n`, `\r`, `\t`, `\0`, and `\xNN` escapes, plus raw backtick multiline strings
|
||||||
- narrow immutable zero-terminated byte pointer/slice conversion to `*c_char` / `?*c_char` without general `u8`/`c_char` interchange
|
- narrow immutable zero-terminated byte pointer/slice conversion to `*c_char` / `?*c_char` without general `u8`/`c_char` interchange
|
||||||
@@ -289,7 +289,7 @@ exactly once. Bare functions named `memcopy` or `memset` remain ordinary user fu
|
|||||||
- non-plain C record layouts such as bitfields, packed records, flexible arrays, qualified fields, and C variadic record arguments
|
- non-plain C record layouts such as bitfields, packed records, flexible arrays, qualified fields, and C variadic record arguments
|
||||||
- arenas, pools, build-mode heap policy, and escaping-allocation diagnostics
|
- arenas, pools, build-mode heap policy, and escaping-allocation diagnostics
|
||||||
- recursive type factories, reflection payloads beyond records/enums, and type-producing unions/enums
|
- recursive type factories, reflection payloads beyond records/enums, and type-producing unions/enums
|
||||||
- broader Zig-style pointer/result casts beyond V1 `ptrcast!(T, ptr)`
|
- pointer-shape-changing casts beyond the safe implicit conversions accepted by `ptrcast!`
|
||||||
- sum-type ABI/layout polish, including dynamic tag-width shrinking, all-void channel collapse, and cross-module global-id determinism
|
- sum-type ABI/layout polish, including dynamic tag-width shrinking, all-void channel collapse, and cross-module global-id determinism
|
||||||
- backed/C enum composition and must-consume fallible linting
|
- backed/C enum composition and must-consume fallible linting
|
||||||
- result-to-argument type-demand propagation through function call boundaries
|
- result-to-argument type-demand propagation through function call boundaries
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ Current prototype features:
|
|||||||
- `#` comments
|
- `#` comments
|
||||||
- Immutable inferred/typed `::` bindings, mutable inferred/typed `:=` locals/globals, and `_` sinks
|
- Immutable inferred/typed `::` bindings, mutable inferred/typed `:=` locals/globals, and `_` sinks
|
||||||
- Exact-width signed/unsigned integers, `f32`, `f64`, `isize`, `usize`, and loose integer-constrained `int`
|
- Exact-width signed/unsigned integers, `f32`, `f64`, `isize`, `usize`, and loose integer-constrained `int`
|
||||||
- Target-dependent atomic `c_*` primitive types, `c_func`, complete `c_struct`, `opaque`, `anyopaque`, and V1 `ptrcast!(T, ptr)`
|
- Target-dependent atomic `c_*` primitive types, `c_func`, complete `c_struct`, `opaque`, `anyopaque`, and contextual or explicit full-result `ptrcast!`
|
||||||
- Arrays, sentinel arrays, single-item pointers, many-item pointers, sentinel many-item pointers, slices, sentinel slices, strings, character literals, optionals, and native structs
|
- Arrays, sentinel arrays, single-item pointers, many-item pointers, sentinel many-item pointers, slices, sentinel slices, strings, character literals, optionals, and native structs
|
||||||
- String literals as immutable pointers to static zero-terminated byte arrays
|
- String literals as immutable pointers to static zero-terminated byte arrays
|
||||||
- Pointer-preserving `.ptr`/`.len`, pointer-to-array indexing and slicing, postfix pointer dereference and optional unwrap, and keyed struct literals
|
- Pointer-preserving `.ptr`/`.len`, pointer-to-array indexing and slicing, postfix pointer dereference and optional unwrap, and keyed struct literals
|
||||||
|
|||||||
@@ -176,8 +176,8 @@
|
|||||||
- `Name :: opaque` is the incomplete nominal record spelling; bodyless `c_struct` is invalid
|
- `Name :: opaque` is the incomplete nominal record spelling; bodyless `c_struct` is invalid
|
||||||
- `anyopaque` is the erased object type used behind pointers for C `void*` and allocator contexts
|
- `anyopaque` is the erased object type used behind pointers for C `void*` and allocator contexts
|
||||||
- C `void` function results remain `void`; C `void*` / `const void*` import and render as `?*mut anyopaque` / `?*anyopaque`
|
- C `void` function results remain `void`; C `void*` / `const void*` import and render as `?*mut anyopaque` / `?*anyopaque`
|
||||||
- `ptrcast!(T, ptr)` preserves pointer shape and only changes the child type in v1
|
- `ptrcast!(ptr)` infers its complete pointer result from context; `ptrcast!(P, ptr)` accepts an explicit complete pointer type
|
||||||
- future direction: generalize toward Zig-style arbitrary pointer-result casts once casts have a broader result-type story
|
- both forms change the child type, then permit only ordinary implicit pointer conversions to the requested target; broader pointer-shape changes remain deferred
|
||||||
|
|
||||||
12. `undefined` as inspired by zig (implemented):
|
12. `undefined` as inspired by zig (implemented):
|
||||||
- allow mutable local and global declarations with `undefined`
|
- allow mutable local and global declarations with `undefined`
|
||||||
@@ -973,7 +973,7 @@ For casts that bypass safety checks, Honey provides builtin functions:
|
|||||||
| -- | -- | -- |
|
| -- | -- | -- |
|
||||||
| `truncate(x, T)` | Keep low bits, discard rest | Never |
|
| `truncate(x, T)` | Keep low bits, discard rest | Never |
|
||||||
| `bitcast(x, T)` | Reinterpret bits, no cast | Sizes don't match (compile error) |
|
| `bitcast(x, T)` | Reinterpret bits, no cast | Sizes don't match (compile error) |
|
||||||
| `ptrcast!(T, p)` | Change a pointer's child type while preserving its shape | Invalid child or non-pointer operand (compile error) |
|
| `ptrcast!(p)` / `ptrcast!(P, p)` | Infer or explicitly supply a complete pointer target, changing the child before ordinary pointer coercion | Missing target context, invalid target, incompatible shape, or non-pointer operand (compile error) |
|
||||||
| `constcast!(p)` | Restore pointer or slice mutability | Non-pointer/slice operand (compile error) |
|
| `constcast!(p)` | Restore pointer or slice mutability | Non-pointer/slice operand (compile error) |
|
||||||
|
|
||||||
```honey
|
```honey
|
||||||
@@ -989,8 +989,10 @@ bits := bitcast(f, u32) # IEEE 754 representation
|
|||||||
|
|
||||||
# pointer casts
|
# pointer casts
|
||||||
buf *u8 := get_buffer()
|
buf *u8 := get_buffer()
|
||||||
ints *u32 := ptrcast!(u32, buf) # element type change, same pointer shape
|
ints *u32 := ptrcast!(buf) # target inferred from the declaration
|
||||||
writable *mut u8 := constcast!(buf) # explicit unsafe mutability restoration
|
raw ?*mut anyopaque := get_raw_buffer()
|
||||||
|
bytes := ptrcast!(?*mut u8, raw) # complete target supplied explicitly
|
||||||
|
writable *mut u8 := constcast!(buf) # explicit unsafe mutability restoration
|
||||||
```
|
```
|
||||||
|
|
||||||
## A word on multi-unwrap
|
## A word on multi-unwrap
|
||||||
|
|||||||
@@ -934,6 +934,30 @@ valid_ptrcast_child :: proc(checker: ^Checker, value: types.Type) -> bool {
|
|||||||
types.is_opaque_struct(value, &checker.module.types))
|
types.is_opaque_struct(value, &checker.module.types))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptrcast_target_child :: proc(checker: ^Checker, value: types.Type) -> (types.Type, bool) {
|
||||||
|
item, ok := types.node(&checker.module.types, types.resolve_alias(value, &checker.module.types))
|
||||||
|
if !ok {
|
||||||
|
return types.INVALID, false
|
||||||
|
}
|
||||||
|
if item.kind == .Optional {
|
||||||
|
item, ok = types.node(&checker.module.types, types.resolve_alias(item.child, &checker.module.types))
|
||||||
|
}
|
||||||
|
if !ok || item.kind != .Pointer || !valid_ptrcast_child(checker, item.child) {
|
||||||
|
return types.INVALID, false
|
||||||
|
}
|
||||||
|
return item.child, true
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrcast_retyped_source :: proc(checker: ^Checker, source, target: types.Type) -> (types.Type, bool) {
|
||||||
|
child, child_ok := ptrcast_target_child(checker, target)
|
||||||
|
if !child_ok {
|
||||||
|
return types.INVALID, false
|
||||||
|
}
|
||||||
|
retyped, retyped_ok := types.replace_pointer_child(&checker.module.types, source, child)
|
||||||
|
return retyped, retyped_ok &&
|
||||||
|
can_implicitly_convert_type(checker, retyped, target)
|
||||||
|
}
|
||||||
|
|
||||||
valid_layout_type :: proc(checker: ^Checker, value: types.Type) -> bool {
|
valid_layout_type :: proc(checker: ^Checker, value: types.Type) -> bool {
|
||||||
return types.is_runtime_value(value, &checker.module.types)
|
return types.is_runtime_value(value, &checker.module.types)
|
||||||
}
|
}
|
||||||
@@ -3032,6 +3056,15 @@ infer_call_comptime_values :: proc(
|
|||||||
{type_call=true, final=true},
|
{type_call=true, final=true},
|
||||||
}
|
}
|
||||||
for pass in evidence_passes {
|
for pass in evidence_passes {
|
||||||
|
if pass.final {
|
||||||
|
all_bound = true
|
||||||
|
for value_bound in bound {
|
||||||
|
all_bound = all_bound && value_bound
|
||||||
|
}
|
||||||
|
if all_bound {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
for arg_id, source_index in args {
|
for arg_id, source_index in args {
|
||||||
param_index := call_param_index(mapping, source_index)
|
param_index := call_param_index(mapping, source_index)
|
||||||
if param_index >= len(function.params) || param_index >= len(actual_args) {
|
if param_index >= len(function.params) || param_index >= len(actual_args) {
|
||||||
@@ -4540,6 +4573,12 @@ validate_type_nodes :: proc(checker: ^Checker) {
|
|||||||
node_count := len(checker.module.types.nodes)
|
node_count := len(checker.module.types.nodes)
|
||||||
for index in 0..<node_count {
|
for index in 0..<node_count {
|
||||||
item := checker.module.types.nodes[index]
|
item := checker.module.types.nodes[index]
|
||||||
|
if item.kind == .Distinct {
|
||||||
|
resolved := type_from_syntax(
|
||||||
|
checker, item.child, ast.Package_Id(item.pkg), ast.File_Id(item.file),
|
||||||
|
)
|
||||||
|
checker.module.types.nodes[index].child = resolved
|
||||||
|
}
|
||||||
if item.kind != .Struct && item.kind != .Union {
|
if item.kind != .Struct && item.kind != .Union {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -5640,18 +5679,20 @@ infer_expr :: proc(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if is_ptrcast_call(checker, expr) {
|
if is_ptrcast_call(checker, expr) {
|
||||||
if len(expr.args) != 2 {
|
if len(expr.args) != 1 && len(expr.args) != 2 {
|
||||||
last = types.INVALID
|
last = types.INVALID
|
||||||
_ = pop(&stack)
|
_ = pop(&stack)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
child, child_ok := resolve_type_argument(checker, expr.args[0], pkg, file)
|
target := frame.expected
|
||||||
operand := infer_nested_expr(checker, expr.args[1], locals, pkg, file, demanded, local_types)
|
operand_index := 0
|
||||||
result := types.INVALID
|
if len(expr.args) == 2 {
|
||||||
if child_ok && valid_ptrcast_child(checker, child) {
|
target, _ = resolve_type_argument(checker, expr.args[0], pkg, file)
|
||||||
result, _ = types.replace_pointer_child(&checker.module.types, operand, child)
|
operand_index = 1
|
||||||
}
|
}
|
||||||
last = result
|
operand := infer_nested_expr(checker, expr.args[operand_index], locals, pkg, file, demanded, local_types)
|
||||||
|
_, target_ok := ptrcast_retyped_source(checker, operand, target)
|
||||||
|
last = target if target_ok else types.INVALID
|
||||||
_ = pop(&stack)
|
_ = pop(&stack)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -7747,7 +7788,8 @@ sequence_item :: proc(value: types.Type, store: ^types.Store) -> (types.Node, bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
find_struct_field :: proc(checker: ^Checker, struct_type: types.Type, name: symbol.Id) -> (int, types.Field, bool) {
|
find_struct_field :: proc(checker: ^Checker, struct_type: types.Type, name: symbol.Id) -> (int, types.Field, bool) {
|
||||||
for field, index in types.fields_for(&checker.module.types, struct_type) {
|
record_type := types.runtime_representation(struct_type, &checker.module.types)
|
||||||
|
for field, index in types.fields_for(&checker.module.types, record_type) {
|
||||||
if field.name == u32(name) {
|
if field.name == u32(name) {
|
||||||
return index, field, true
|
return index, field, true
|
||||||
}
|
}
|
||||||
@@ -7811,20 +7853,22 @@ find_struct_field_default :: proc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
find_tuple_field :: proc(checker: ^Checker, tuple_type: types.Type, index: u64) -> (int, types.Field, bool) {
|
find_tuple_field :: proc(checker: ^Checker, tuple_type: types.Type, index: u64) -> (int, types.Field, bool) {
|
||||||
item, ok := types.node(&checker.module.types, tuple_type)
|
record_type := types.runtime_representation(tuple_type, &checker.module.types)
|
||||||
|
item, ok := types.node(&checker.module.types, record_type)
|
||||||
if !ok || item.kind != .Struct || !item.tuple || index >= u64(item.field_count) {
|
if !ok || item.kind != .Struct || !item.tuple || index >= u64(item.field_count) {
|
||||||
return 0, {}, false
|
return 0, {}, false
|
||||||
}
|
}
|
||||||
fields := types.fields_for(&checker.module.types, tuple_type)
|
fields := types.fields_for(&checker.module.types, record_type)
|
||||||
return int(index), fields[index], true
|
return int(index), fields[index], true
|
||||||
}
|
}
|
||||||
|
|
||||||
find_struct_field_slot :: proc(checker: ^Checker, struct_type: types.Type, name: symbol.Id) -> (int, types.Field, bool) {
|
find_struct_field_slot :: proc(checker: ^Checker, struct_type: types.Type, name: symbol.Id) -> (int, types.Field, bool) {
|
||||||
item, ok := types.node(&checker.module.types, struct_type)
|
record_type := types.runtime_representation(struct_type, &checker.module.types)
|
||||||
|
item, ok := types.node(&checker.module.types, record_type)
|
||||||
if !ok || (item.kind != .Struct && item.kind != .Union) {
|
if !ok || (item.kind != .Struct && item.kind != .Union) {
|
||||||
return -1, {}, false
|
return -1, {}, false
|
||||||
}
|
}
|
||||||
for field, index in types.fields_for(&checker.module.types, struct_type) {
|
for field, index in types.fields_for(&checker.module.types, record_type) {
|
||||||
if field.name == u32(name) {
|
if field.name == u32(name) {
|
||||||
return int(item.field_start)+index, field, true
|
return int(item.field_start)+index, field, true
|
||||||
}
|
}
|
||||||
@@ -9784,28 +9828,39 @@ build_expr :: proc(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if is_ptrcast_call(checker, expr) {
|
if is_ptrcast_call(checker, expr) {
|
||||||
if len(expr.args) != 2 {
|
if len(expr.args) != 1 && len(expr.args) != 2 {
|
||||||
id := source.addf(checker.diagnostics, expr.span, "ptrcast! expects 2 arguments, got %d", len(expr.args))
|
id := source.addf(checker.diagnostics, expr.span, "ptrcast! expects 1 or 2 arguments, got %d", len(expr.args))
|
||||||
last = invalid_hir_expr(checker, expr.span, id)
|
last = invalid_hir_expr(checker, expr.span, id)
|
||||||
_ = pop(&stack)
|
_ = pop(&stack)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
target, target_ok := resolve_type_argument(checker, expr.args[0], pkg, file)
|
target := frame.expected
|
||||||
if !target_ok {
|
operand_index := 0
|
||||||
id := source.add(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptrcast! target must be a type")
|
if len(expr.args) == 2 {
|
||||||
|
target_ok: bool
|
||||||
|
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, "ptrcast! target must be a type")
|
||||||
|
last = invalid_hir_expr(checker, expr.span, id)
|
||||||
|
_ = pop(&stack)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
operand_index = 1
|
||||||
|
} else if !types.is_valid(target) {
|
||||||
|
id := source.add(checker.diagnostics, expr.span, "cannot infer ptrcast! target type; pass a pointer type explicitly")
|
||||||
last = invalid_hir_expr(checker, expr.span, id)
|
last = invalid_hir_expr(checker, expr.span, id)
|
||||||
_ = pop(&stack)
|
_ = pop(&stack)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !valid_ptrcast_child(checker, target) {
|
if _, target_ok := ptrcast_target_child(checker, target); !target_ok {
|
||||||
id := source.addf(checker.diagnostics, checker.ast_module.exprs[expr.args[0]].span, "ptrcast! target must be a sized runtime object type, got %s", type_label(checker, target))
|
id := source.addf(checker.diagnostics, expr.span, "ptrcast! target must be a pointer or optional pointer to a sized runtime object type, got %s", type_label(checker, target))
|
||||||
last = invalid_hir_expr(checker, expr.span, id)
|
last = invalid_hir_expr(checker, expr.span, id)
|
||||||
_ = pop(&stack)
|
_ = pop(&stack)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
stack[frame_index].target_type = target
|
stack[frame_index].target_type = target
|
||||||
stack[frame_index].stage = 9
|
stack[frame_index].stage = 9
|
||||||
append(&stack, Build_Expr_Frame{expr=expr.args[1], expected=types.INVALID, template=ast.INVALID_FUNCTION})
|
append(&stack, Build_Expr_Frame{expr=expr.args[operand_index], expected=types.INVALID, template=ast.INVALID_FUNCTION})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if is_intrinsic_call(checker, expr, "constcast") {
|
if is_intrinsic_call(checker, expr, "constcast") {
|
||||||
@@ -10538,20 +10593,30 @@ build_expr :: proc(
|
|||||||
_ = pop(&stack)
|
_ = pop(&stack)
|
||||||
}
|
}
|
||||||
if frame.stage == 9 {
|
if frame.stage == 9 {
|
||||||
result, ok := types.replace_pointer_child(&checker.module.types, checker.module.exprs[last].type, frame.target_type)
|
actual := checker.module.exprs[last].type
|
||||||
if !ok {
|
retyped, ok := ptrcast_retyped_source(checker, actual, frame.target_type)
|
||||||
|
if !types.is_pointer(actual, &checker.module.types) &&
|
||||||
|
!types.is_optional_pointer(actual, &checker.module.types) {
|
||||||
id := source.add(checker.diagnostics, expr.span, "ptrcast! operand must be a pointer or optional pointer")
|
id := source.add(checker.diagnostics, expr.span, "ptrcast! operand must be a pointer or optional pointer")
|
||||||
last = invalid_hir_expr(checker, expr.span, id)
|
last = invalid_hir_expr(checker, expr.span, id)
|
||||||
|
} else if !ok {
|
||||||
|
id := source.addf(
|
||||||
|
checker.diagnostics, expr.span,
|
||||||
|
"ptrcast! cannot convert pointer shape from %s to %s",
|
||||||
|
type_label(checker, actual), type_label(checker, frame.target_type),
|
||||||
|
)
|
||||||
|
last = invalid_hir_expr(checker, expr.span, id)
|
||||||
} else {
|
} else {
|
||||||
last = add_hir_expr(checker, hir.Expr{
|
cast_expr := add_hir_expr(checker, hir.Expr{
|
||||||
kind=.Pointer_Cast,
|
kind=.Pointer_Cast,
|
||||||
span=expr.span,
|
span=expr.span,
|
||||||
type=result,
|
type=retyped,
|
||||||
left=last,
|
left=last,
|
||||||
target=hir.INVALID_REF,
|
target=hir.INVALID_REF,
|
||||||
right=hir.INVALID_EXPR,
|
right=hir.INVALID_EXPR,
|
||||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||||
})
|
})
|
||||||
|
last = coerce_expr(checker, cast_expr, frame.target_type, expr.span)
|
||||||
}
|
}
|
||||||
_ = pop(&stack)
|
_ = pop(&stack)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1332,6 +1332,7 @@ emit_instruction_stream :: proc(
|
|||||||
if types.is_pointer(base_type, &emitter.module.types) {
|
if types.is_pointer(base_type, &emitter.module.types) {
|
||||||
base_type = types.child_type(base_type, &emitter.module.types)
|
base_type = types.child_type(base_type, &emitter.module.types)
|
||||||
}
|
}
|
||||||
|
base_type = types.runtime_representation(base_type, &emitter.module.types)
|
||||||
if types.kind(base_type, &emitter.module.types) == .Fallible {
|
if types.kind(base_type, &emitter.module.types) == .Fallible {
|
||||||
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr i8, ptr %%v%d, i64 %d\n", instruction_index, instruction.a, types.fallible_payload_offset(base_type, &emitter.module.types, emitter.module.target))
|
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr i8, ptr %%v%d, i64 %d\n", instruction_index, instruction.a, types.fallible_payload_offset(base_type, &emitter.module.types, emitter.module.target))
|
||||||
continue
|
continue
|
||||||
|
|||||||
+88
-9
@@ -2498,19 +2498,21 @@ main func() void {
|
|||||||
opaque_anyopaque_and_ptrcast_compile_and_lower :: proc(t: ^testing.T) {
|
opaque_anyopaque_and_ptrcast_compile_and_lower :: proc(t: ^testing.T) {
|
||||||
text := `Handle :: opaque
|
text := `Handle :: opaque
|
||||||
take func(_ ?*mut anyopaque) void {}
|
take func(_ ?*mut anyopaque) void {}
|
||||||
|
take_bytes func(_ ?*mut u8) void {}
|
||||||
use_handle func(_ ?@mut Handle) void {}
|
use_handle func(_ ?@mut Handle) void {}
|
||||||
main func() void {
|
main func() void {
|
||||||
values [2]mut u8 := [1, 2]
|
values [2]mut u8 := [1, 2]
|
||||||
raw ?*mut anyopaque := (&values).ptr
|
raw ?*mut anyopaque := (&values).ptr
|
||||||
bytes ?*mut u8 := ptrcast!(u8, raw)
|
bytes ?*mut u8 := ptrcast!(raw)
|
||||||
take(bytes)
|
take(bytes)
|
||||||
|
take_bytes(ptrcast!(raw))
|
||||||
if bytes |p| {
|
if bytes |p| {
|
||||||
p[1] = 5
|
p[1] = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
one u8 := 1
|
one u8 := 1
|
||||||
single ?@mut anyopaque := &one
|
single ?@mut anyopaque := &one
|
||||||
typed ?@mut u8 := ptrcast!(u8, single)
|
typed ?@mut u8 := ptrcast!(?@mut u8, single)
|
||||||
if typed |p| {
|
if typed |p| {
|
||||||
p^ = 2
|
p^ = 2
|
||||||
}
|
}
|
||||||
@@ -2545,8 +2547,8 @@ main func() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testing.expect_value(t, len(diagnostics.items), 0)
|
testing.expect_value(t, len(diagnostics.items), 0)
|
||||||
testing.expect_value(t, hir_casts, 2)
|
testing.expect_value(t, hir_casts, 3)
|
||||||
testing.expect_value(t, ir_casts, 2)
|
testing.expect_value(t, ir_casts, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
@@ -2555,10 +2557,11 @@ anyopaque_by_value_and_invalid_ptrcasts_are_rejected :: proc(t: ^testing.T) {
|
|||||||
main func() void {
|
main func() void {
|
||||||
raw ?*mut anyopaque := null
|
raw ?*mut anyopaque := null
|
||||||
value anyopaque := undefined
|
value anyopaque := undefined
|
||||||
_ = ptrcast!(void, raw)
|
_ = ptrcast!(raw)
|
||||||
_ = ptrcast!(anyopaque, raw)
|
_ = ptrcast!(u8, raw)
|
||||||
_ = ptrcast!(Callback, raw)
|
_ = ptrcast!(?*mut void, raw)
|
||||||
_ = ptrcast!(u8, 1)
|
_ = ptrcast!(?@mut u8, raw)
|
||||||
|
_ = ptrcast!(?*mut u8, 1)
|
||||||
_ = ptrcast!(1, raw)
|
_ = ptrcast!(1, raw)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@@ -2575,19 +2578,25 @@ main func() void {
|
|||||||
defer hir.destroy_module(&hir_module)
|
defer hir.destroy_module(&hir_module)
|
||||||
|
|
||||||
found_by_value := false
|
found_by_value := false
|
||||||
|
found_inference := false
|
||||||
found_bad_target := false
|
found_bad_target := false
|
||||||
found_bad_operand := false
|
found_bad_operand := false
|
||||||
found_target_type := false
|
found_target_type := false
|
||||||
|
found_shape := false
|
||||||
for diagnostic in diagnostics.items {
|
for diagnostic in diagnostics.items {
|
||||||
found_by_value = found_by_value || strings.contains(diagnostic.message, "could not infer a concrete type")
|
found_by_value = found_by_value || strings.contains(diagnostic.message, "could not infer a concrete type")
|
||||||
found_bad_target = found_bad_target || strings.contains(diagnostic.message, "ptrcast! target must be a sized runtime object type")
|
found_inference = found_inference || strings.contains(diagnostic.message, "cannot infer ptrcast! target type")
|
||||||
|
found_bad_target = found_bad_target || strings.contains(diagnostic.message, "ptrcast! target must be a pointer or optional pointer")
|
||||||
found_bad_operand = found_bad_operand || strings.contains(diagnostic.message, "ptrcast! operand must be a pointer")
|
found_bad_operand = found_bad_operand || strings.contains(diagnostic.message, "ptrcast! operand must be a pointer")
|
||||||
found_target_type = found_target_type || strings.contains(diagnostic.message, "ptrcast! target must be a type")
|
found_target_type = found_target_type || strings.contains(diagnostic.message, "ptrcast! target must be a type")
|
||||||
|
found_shape = found_shape || strings.contains(diagnostic.message, "ptrcast! cannot convert pointer shape")
|
||||||
}
|
}
|
||||||
testing.expect(t, found_by_value)
|
testing.expect(t, found_by_value)
|
||||||
|
testing.expect(t, found_inference)
|
||||||
testing.expect(t, found_bad_target)
|
testing.expect(t, found_bad_target)
|
||||||
testing.expect(t, found_bad_operand)
|
testing.expect(t, found_bad_operand)
|
||||||
testing.expect(t, found_target_type)
|
testing.expect(t, found_target_type)
|
||||||
|
testing.expect(t, found_shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
@@ -5442,6 +5451,76 @@ main func() void {
|
|||||||
testing.expect(t, unrecoverable >= 3)
|
testing.expect(t, unrecoverable >= 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
distinct_type_factory_backings_reject_generic_calls_without_stalling :: proc(t: ^testing.T) {
|
||||||
|
text := `ArrayList func($T type) type {
|
||||||
|
return struct { items []mut T }
|
||||||
|
}
|
||||||
|
append func($T type, list @mut ArrayList(T), value T) void {
|
||||||
|
_ = list
|
||||||
|
_ = value
|
||||||
|
}
|
||||||
|
Item :: struct { value i32 }
|
||||||
|
Items :: distinct ArrayList(Item)
|
||||||
|
main func() void {
|
||||||
|
items Items := undefined
|
||||||
|
append(&items, Item { value = 1 })
|
||||||
|
}
|
||||||
|
`
|
||||||
|
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)
|
||||||
|
|
||||||
|
found_mismatch := false
|
||||||
|
found_backing_error := false
|
||||||
|
found_comptime_error := false
|
||||||
|
for diagnostic in diagnostics.items {
|
||||||
|
message := diagnostic.message
|
||||||
|
found_mismatch = found_mismatch || strings.contains(message, "cannot implicitly convert")
|
||||||
|
found_backing_error = found_backing_error || strings.contains(message, "requires a concrete runtime backing type")
|
||||||
|
found_comptime_error = found_comptime_error || strings.contains(message, "invalid comptime argument")
|
||||||
|
}
|
||||||
|
testing.expect(t, found_mismatch)
|
||||||
|
testing.expect(t, !found_backing_error)
|
||||||
|
testing.expect(t, !found_comptime_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
distinct_type_factory_backings_expose_record_fields :: proc(t: ^testing.T) {
|
||||||
|
directory := "/tmp/brolang-test-distinct-factory-fields"
|
||||||
|
main_path := "/tmp/brolang-test-distinct-factory-fields/main.bro"
|
||||||
|
output := "/tmp/brolang-test-distinct-factory-fields-output"
|
||||||
|
_ = os2.remove_all(directory)
|
||||||
|
defer _ = os2.remove_all(directory)
|
||||||
|
defer _ = os.remove(output)
|
||||||
|
testing.expect(t, os2.make_directory_all(directory) == nil)
|
||||||
|
text := `Box func($T type) type {
|
||||||
|
return struct { value T }
|
||||||
|
}
|
||||||
|
IntBox :: distinct Box(i32)
|
||||||
|
increment func(box @mut IntBox) void {
|
||||||
|
box.value += 1
|
||||||
|
}
|
||||||
|
main func() i32 {
|
||||||
|
box IntBox := IntBox(Box(i32) { value = 41 })
|
||||||
|
increment(&box)
|
||||||
|
return box.value - 42
|
||||||
|
}
|
||||||
|
`
|
||||||
|
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
|
||||||
|
testing.expect_value(t, compiler_core.compile_package(directory, output), 0)
|
||||||
|
state := run_executable(output)
|
||||||
|
testing.expect_value(t, state.exit_code, 0)
|
||||||
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
string_literals_are_contextual_comptime_type_inference_evidence :: proc(t: ^testing.T) {
|
string_literals_are_contextual_comptime_type_inference_evidence :: proc(t: ^testing.T) {
|
||||||
text := `pair func($T type, expected, actual T) T {
|
text := `pair func($T type, expected, actual T) T {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ mem :: import "@std/mem"
|
|||||||
|
|
||||||
@hide probe_count func(context ?@mut anyopaque) void {
|
@hide probe_count func(context ?@mut anyopaque) void {
|
||||||
if context |raw| {
|
if context |raw| {
|
||||||
count @mut usize :: ptrcast!(usize, raw)
|
count @mut usize :: ptrcast!(raw)
|
||||||
count^ += 1
|
count^ += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -98,7 +98,7 @@ writer func(file File) Writer {
|
|||||||
.read_write: flags = c.O_RDWR
|
.read_write: flags = c.O_RDWR
|
||||||
}
|
}
|
||||||
while true {
|
while true {
|
||||||
fd c_int :: c.open(ptrcast!(c_char, path.ptr), flags)
|
fd c_int :: c.open(ptrcast!(path.ptr), flags)
|
||||||
if fd >= 0 {
|
if fd >= 0 {
|
||||||
return Handle {file_desc = fd}
|
return Handle {file_desc = fd}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -317,7 +317,7 @@ print func(output Writer, $format []u8, $Args type, args Args) void ! WriteError
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@hide distinct_value func($Backing, $Distinct type, value Distinct) Backing {
|
@hide distinct_value func($Backing, $Distinct type, value Distinct) Backing {
|
||||||
return ptrcast!(Backing, &value)^
|
return ptrcast!(@Backing, &value)^
|
||||||
}
|
}
|
||||||
|
|
||||||
@hide scalar_or_distinct_type func($T type) bool {
|
@hide scalar_or_distinct_type func($T type) bool {
|
||||||
@@ -357,14 +357,14 @@ print func(output Writer, $format []u8, $Args type, args Args) void ! WriteError
|
|||||||
count c_int := 0
|
count c_int := 0
|
||||||
if sizeof!(T) == 4 {
|
if sizeof!(T) == 4 {
|
||||||
if scientific {
|
if scientific {
|
||||||
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.8e", value)
|
count = c.snprintf(ptrcast!((&buffer).ptr), c_ulong(buffer.len), "%.8e", value)
|
||||||
} else {
|
} else {
|
||||||
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.9g", value)
|
count = c.snprintf(ptrcast!((&buffer).ptr), c_ulong(buffer.len), "%.9g", value)
|
||||||
}
|
}
|
||||||
} else if scientific {
|
} else if scientific {
|
||||||
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.16e", value)
|
count = c.snprintf(ptrcast!((&buffer).ptr), c_ulong(buffer.len), "%.16e", value)
|
||||||
} else {
|
} else {
|
||||||
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.17g", value)
|
count = c.snprintf(ptrcast!((&buffer).ptr), c_ulong(buffer.len), "%.17g", value)
|
||||||
}
|
}
|
||||||
if count < 0 or usize(count) >= buffer.len {
|
if count < 0 or usize(count) >= buffer.len {
|
||||||
return .write_failed
|
return .write_failed
|
||||||
|
|||||||
+7
-8
@@ -48,7 +48,7 @@ alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
|
|||||||
|
|
||||||
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
|
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
|
||||||
if memory |bytes| {
|
if memory |bytes| {
|
||||||
pointer *mut T :: ptrcast!(T, bytes)
|
pointer *mut T :: ptrcast!(bytes)
|
||||||
return pointer[..count]
|
return pointer[..count]
|
||||||
}
|
}
|
||||||
return .out_of_memory
|
return .out_of_memory
|
||||||
@@ -78,7 +78,7 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
|
|||||||
old_memory ?*mut u8 := null
|
old_memory ?*mut u8 := null
|
||||||
old_size usize := 0
|
old_size usize := 0
|
||||||
if memory.len != 0 {
|
if memory.len != 0 {
|
||||||
old_memory = ptrcast!(u8, memory.ptr)
|
old_memory = ptrcast!(memory.ptr)
|
||||||
old_size = memory.len * element_size
|
old_size = memory.len * element_size
|
||||||
}
|
}
|
||||||
resized ?*mut u8 := raw_realloc(
|
resized ?*mut u8 := raw_realloc(
|
||||||
@@ -89,7 +89,7 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
|
|||||||
alignof!(T),
|
alignof!(T),
|
||||||
)
|
)
|
||||||
if resized |bytes| {
|
if resized |bytes| {
|
||||||
pointer *mut T :: ptrcast!(T, bytes)
|
pointer *mut T :: ptrcast!(bytes)
|
||||||
return pointer[..new_count]
|
return pointer[..new_count]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,6 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
|
|||||||
free func($T type, allocator Allocator, memory []T) void {
|
free func($T type, allocator Allocator, memory []T) void {
|
||||||
if (memory.len == 0 or sizeof!(T) == 0) return
|
if (memory.len == 0 or sizeof!(T) == 0) return
|
||||||
raw_free(allocator, ptrcast!(
|
raw_free(allocator, ptrcast!(
|
||||||
u8,
|
|
||||||
constcast!(memory).ptr),
|
constcast!(memory).ptr),
|
||||||
memory.len * sizeof!(T),
|
memory.len * sizeof!(T),
|
||||||
alignof!(T),
|
alignof!(T),
|
||||||
@@ -110,7 +109,7 @@ free func($T type, allocator Allocator, memory []T) void {
|
|||||||
|
|
||||||
#! get an empty slice of type `T` with `count` elements.
|
#! get an empty slice of type `T` with `count` elements.
|
||||||
empty_slice func($T type, count usize) []mut T {
|
empty_slice func($T type, count usize) []mut T {
|
||||||
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
|
pointer *mut T :: ptrcast!((&empty_storage).ptr)
|
||||||
return pointer[..count]
|
return pointer[..count]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,14 +137,14 @@ empty func($T type) []mut T {
|
|||||||
if (power_of_two(alignment) == false) return null
|
if (power_of_two(alignment) == false) return null
|
||||||
|
|
||||||
if alignment <= malloc_alignment {
|
if alignment <= malloc_alignment {
|
||||||
return ptrcast!(u8, c.malloc(c_ulong(size)))
|
return ptrcast!(c.malloc(c_ulong(size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
memory [1]mut ?*mut anyopaque := [null]
|
memory [1]mut ?*mut anyopaque := [null]
|
||||||
status c_int := c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
|
status c_int := c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
|
||||||
if (status != 0) return null
|
if (status != 0) return null
|
||||||
|
|
||||||
return ptrcast!(u8, memory[0])
|
return ptrcast!(memory[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
@hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
|
@hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
|
||||||
@@ -158,7 +157,7 @@ empty func($T type) []mut T {
|
|||||||
|
|
||||||
if memory |old_memory| {
|
if memory |old_memory| {
|
||||||
if alignment <= malloc_alignment {
|
if alignment <= malloc_alignment {
|
||||||
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
|
return ptrcast!(c.realloc(old_memory, c_ulong(new_size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
|
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ eql func($T type, left, right []T) bool {
|
|||||||
@hide empty_storage [1]mut u64 := [0]
|
@hide empty_storage [1]mut u64 := [0]
|
||||||
|
|
||||||
@hide empty_slice func($T type, count usize) []mut T {
|
@hide empty_slice func($T type, count usize) []mut T {
|
||||||
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
|
pointer *mut T :: ptrcast!((&empty_storage).ptr)
|
||||||
return pointer[..count]
|
return pointer[..count]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
|
|||||||
|
|
||||||
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
|
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
|
||||||
if memory |bytes| {
|
if memory |bytes| {
|
||||||
pointer *mut T :: ptrcast!(T, bytes)
|
pointer *mut T :: ptrcast!(bytes)
|
||||||
return pointer[..count]
|
return pointer[..count]
|
||||||
}
|
}
|
||||||
return .out_of_memory
|
return .out_of_memory
|
||||||
@@ -93,7 +93,7 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
|
|||||||
old_memory ?*mut u8 := null
|
old_memory ?*mut u8 := null
|
||||||
old_size usize := 0
|
old_size usize := 0
|
||||||
if memory.len != 0 {
|
if memory.len != 0 {
|
||||||
old_memory = ptrcast!(u8, memory.ptr)
|
old_memory = ptrcast!(memory.ptr)
|
||||||
old_size = memory.len * element_size
|
old_size = memory.len * element_size
|
||||||
}
|
}
|
||||||
resized ?*mut u8 := raw_realloc(
|
resized ?*mut u8 := raw_realloc(
|
||||||
@@ -104,7 +104,7 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
|
|||||||
alignof!(T),
|
alignof!(T),
|
||||||
)
|
)
|
||||||
if resized |bytes| {
|
if resized |bytes| {
|
||||||
pointer *mut T :: ptrcast!(T, bytes)
|
pointer *mut T :: ptrcast!(bytes)
|
||||||
return pointer[..new_count]
|
return pointer[..new_count]
|
||||||
}
|
}
|
||||||
return .out_of_memory
|
return .out_of_memory
|
||||||
@@ -112,7 +112,7 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
|
|||||||
|
|
||||||
free func($T type, allocator Allocator, memory []mut T) void {
|
free func($T type, allocator Allocator, memory []mut T) void {
|
||||||
if memory.len != 0 and sizeof!(T) != 0 {
|
if memory.len != 0 and sizeof!(T) != 0 {
|
||||||
raw_free(allocator, ptrcast!(u8, memory.ptr), memory.len * sizeof!(T), alignof!(T))
|
raw_free(allocator, ptrcast!(memory.ptr), memory.len * sizeof!(T), alignof!(T))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ free func($T type, allocator Allocator, memory []mut T) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if alignment <= malloc_alignment {
|
if alignment <= malloc_alignment {
|
||||||
return ptrcast!(u8, c.malloc(c_ulong(size)))
|
return ptrcast!(c.malloc(c_ulong(size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
memory [1]mut ?*mut anyopaque := [null]
|
memory [1]mut ?*mut anyopaque := [null]
|
||||||
@@ -150,7 +150,7 @@ free func($T type, allocator Allocator, memory []mut T) void {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptrcast!(u8, memory[0])
|
return ptrcast!(memory[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
@hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
|
@hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
|
||||||
@@ -165,7 +165,7 @@ free func($T type, allocator Allocator, memory []mut T) void {
|
|||||||
|
|
||||||
if memory |old_memory| {
|
if memory |old_memory| {
|
||||||
if alignment <= malloc_alignment {
|
if alignment <= malloc_alignment {
|
||||||
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
|
return ptrcast!(c.realloc(old_memory, c_ulong(new_size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
|
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ raw_free func(allocator Allocator, memory ?*mut u8, size usize, alignment usize)
|
|||||||
@hide empty_storage [1]mut u64 := [0]
|
@hide empty_storage [1]mut u64 := [0]
|
||||||
|
|
||||||
@hide empty_slice func($T type, count usize) []mut T {
|
@hide empty_slice func($T type, count usize) []mut T {
|
||||||
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
|
pointer *mut T :: ptrcast!((&empty_storage).ptr)
|
||||||
return pointer[..count]
|
return pointer[..count]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
|
|||||||
|
|
||||||
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
|
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
|
||||||
if memory |bytes| {
|
if memory |bytes| {
|
||||||
pointer *mut T :: ptrcast!(T, bytes)
|
pointer *mut T :: ptrcast!(bytes)
|
||||||
return pointer[..count]
|
return pointer[..count]
|
||||||
}
|
}
|
||||||
return .out_of_memory
|
return .out_of_memory
|
||||||
@@ -57,7 +57,7 @@ alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
|
|||||||
|
|
||||||
free func($T type, allocator Allocator, memory []mut T) void {
|
free func($T type, allocator Allocator, memory []mut T) void {
|
||||||
if memory.len != 0 and sizeof!(T) != 0 {
|
if memory.len != 0 and sizeof!(T) != 0 {
|
||||||
raw_free(allocator, ptrcast!(u8, memory.ptr), memory.len * sizeof!(T), alignof!(T))
|
raw_free(allocator, ptrcast!(memory.ptr), memory.len * sizeof!(T), alignof!(T))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ free func($T type, allocator Allocator, memory []mut T) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if alignment <= malloc_alignment {
|
if alignment <= malloc_alignment {
|
||||||
return ptrcast!(u8, c.malloc(c_ulong(size)))
|
return ptrcast!(c.malloc(c_ulong(size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
memory [1]mut ?*mut anyopaque := [null]
|
memory [1]mut ?*mut anyopaque := [null]
|
||||||
@@ -95,7 +95,7 @@ free func($T type, allocator Allocator, memory []mut T) void {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptrcast!(u8, memory[0])
|
return ptrcast!(memory[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
@hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
|
@hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
|
||||||
@@ -110,7 +110,7 @@ free func($T type, allocator Allocator, memory []mut T) void {
|
|||||||
|
|
||||||
if memory |old_memory| {
|
if memory |old_memory| {
|
||||||
if alignment <= malloc_alignment {
|
if alignment <= malloc_alignment {
|
||||||
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
|
return ptrcast!(c.realloc(old_memory, c_ulong(new_size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
|
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
|
||||||
|
|||||||
Reference in New Issue
Block a user