aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2026-03-13 14:07:29 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2026-03-13 14:09:53 +0200
commited7da0d9e31e8dd6847e2e603f0d1943330cf4d0 (patch)
tree16e4785bd92f43a37bed6b0028b0f239faa00d51 /src
parent25b8db28cf87708808744b97774c2a8427e129e2 (diff)
downloadfwd-ed7da0d9e31e8dd6847e2e603f0d1943330cf4d0.tar.gz
fwd-ed7da0d9e31e8dd6847e2e603f0d1943330cf4d0.zip
add initial reference invalidation
+ Makes vec example actually memory safe, which is cool + Specify owner > sub relationships with ">" in closure parameter lists, uses the same group idea as closure calls + Relies on users implementing functions in a consistent manner, since you can kind of do whatever with pointers. Presumably there would be a stdlib of vec/map/set etc. which applications could then use and by proxy be memory safe. Although some more checks wouldn't hurt, I suppose? + Not sure I like having reference invalidation be 'just a move', seems to work alright but the semantics of it are a bit muddy.
Diffstat (limited to 'src')
-rw-r--r--src/analyze.c5
-rw-r--r--src/ast.c12
-rw-r--r--src/move.c14
-rw-r--r--src/parser.y1
4 files changed, 31 insertions, 1 deletions
diff --git a/src/analyze.c b/src/analyze.c
index c05542a..fc94e15 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -252,7 +252,12 @@ static int deduce_closure_types(struct scope *scope, struct ast *node, struct ty
return -1;
}
+ /* use same loop to deduce ownership rules */
for (; param && t; param = param->n, t = t->n) {
+ /* if this param owns the next, reflect that in our variables */
+ if (t->or)
+ param->or = param->n;
+
if (var_type(param))
continue;
diff --git a/src/ast.c b/src/ast.c
index d7d97e0..4573d3e 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -123,6 +123,8 @@ struct ast *gen_ast(enum ast_kind kind,
n->s = s;
n->v = v;
n->d = d;
+ n->or = NULL;
+ n->ol = NULL;
n->loc = loc;
return n;
}
@@ -139,6 +141,7 @@ struct type *tgen_type(enum type_kind kind,
n->k = kind;
n->t0 = t0;
n->id = id;
+ n->or = NULL;
n->loc = loc;
return n;
}
@@ -378,6 +381,7 @@ struct type *clone_type(struct type *type)
if (type->t0)
new->t0 = clone_type_list(type->t0);
+ new->or = type->or;
new->group = type->group;
new->loc = type->loc;
return new;
@@ -752,3 +756,11 @@ void opt_group(struct ast *a, struct ast *b)
a->or = b;
b->ol = a;
}
+
+void own_type_group(struct type *owner, struct type *sub)
+{
+ /* sub does not get a reference to owner so if owner is moved, only the
+ * sub is marked as used. sub is still allowed to be passed around
+ * freely */
+ owner->or = sub;
+}
diff --git a/src/move.c b/src/move.c
index 5137719..a76ffd5 100644
--- a/src/move.c
+++ b/src/move.c
@@ -372,6 +372,19 @@ static int mvcheck_id(struct state *state, struct ast *node)
if (def->k != AST_VAR_DEF)
return 0;
+ struct ast_pair *prev = find_move(state, def);
+
+ /* a reference invalidation is represented as a 'moved'
+ * reference, which is not expressible within the
+ * language but is constructed as part of
+ * opt_group_left/opt_group_right forcing a move to
+ * happen. Hack? */
+ if (def->t->k == TYPE_REF && prev) {
+ /** @todo a more fitting error message? */
+ move_error(node, prev->use);
+ return -1;
+ }
+
if (is_trivially_copyable(def->t))
return 0;
@@ -381,7 +394,6 @@ static int mvcheck_id(struct state *state, struct ast *node)
return -1;
}
- struct ast_pair *prev = find_move(state, def);
if (prev) {
/* error messages for opt groups could be improved */
move_error(node, prev->use);
diff --git a/src/parser.y b/src/parser.y
index 6210a95..776e1c9 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -289,6 +289,7 @@ type
rev_types
: rev_types "," type { $$ = $3; $$->n = $1; }
+ | rev_types ">" type { $$ = $3; $$->n = $1; own_type_group($1, $3); }
| type
types