Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spec for heap specifier #603

Merged
merged 1 commit into from
Jun 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions media/specs/heap-specifier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Technical Specification for the heap specifier

## Implementation steps:

- [x] Add basic support
- [x] Move all std data structures to use the heap specifier
- [x] Add tests for this feature
- [x] Generate default dtor for structs with heap fields where free is called on those fields
- [x] Make copy ctor mandatory for structs with heap fields
- [ ] Allow assignment from heap to non-heap pointers to create non-owning pointers
- [ ] Perform a swap when assigning from heap to heap pointers

## Syntax

```spice
// As struct field
type TestStruct struct {
heap int* ptr
}

// As local variable
f<int> foo() {
heap int* ptr = sAlloc(sizeof(type int));
*ptr = 5;
return ptr;
}
```

## Functionality

### General introduction

The `heap` specifier can only be applied to pointer variables/fields and is used to indicate that the memory for the
variable/field was or is going to be allocated on the heap. It acts similar to a `unique_ptr` would in C++, but builtin
into the language.

The heap specifier can be used in the following ways:

- As a field type specifier in a struct
- As a local variable type specifier
- As a function return type specifier
- As a parameter type specifier

When the `heap` specifier is used for a struct field, the compiler will automatically generate a destructor for that
struct, that will free the memory allocated for the field. The `heap` specifier can also be used in local variables
and function return types. When a function returns a `heap` pointer, the caller is responsible for freeing the memory
allocated for the pointer. The `heap` specifier can also be used in function parameters. When a function parameter is
declared as `heap`, the callee is responsible for freeing the memory allocated for the parameter.

### Assignment semantics

When assigning a `heap` pointer to a non-heap pointer, the non-heap pointer becomes a non-owning pointer. This means
that the non-heap pointer does not have to free its memory, as it does not own it. The memory is still owned by the
`heap` pointer, and the memory will be freed when the `heap` pointer goes out of scope.

When assigning a `heap` pointer to another `heap` pointer, the memory is not copied, but the ownership gets
transferred to the left hand side variable. This means that the original `heap` pointer will get the value `nil` and is
no longer responsible for freeing the memory. This is done to prevent double freeing of the memory.

Assigning a non-heap pointer to a `heap` pointer is not allowed, as the non-heap pointer does not own the memory which
it points to.

### Struct implications

When a struct has a field with the `heap` specifier, the compiler will automatically generate a destructor for the
struct. The destructor will free the memory allocated for the `heap` field. The compiler will also make the copy
constructor mandatory for the struct. This is done to prevent double freeing of the memory.