commit 20c786e75ade06281a003645740915edce78688c
parent 4a97bd2bafbd6e89f692c18477a08d8112dbd6e1
Author: Sebastian <sebastian@sebsite.pw>
Date: Fri, 6 May 2022 22:45:42 -0400
Allow literal arrays to be copied by alloc()
alloc([1, 2, 3]...) now works.
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
3 files changed, 51 insertions(+), 16 deletions(-)
diff --git a/src/check.c b/src/check.c
@@ -293,6 +293,9 @@ check_expr_alloc_init(struct context *ctx,
case STORAGE_SLICE:
inithint = hint;
break;
+ case STORAGE_TAGGED:
+ // TODO
+ break;
default:
// The user's code is wrong here, but we'll let it fail
// later.
@@ -375,17 +378,28 @@ check_expr_alloc_copy(struct context *ctx,
// alloc(init...) case
check_expression(ctx, aexpr->alloc.init, expr->alloc.init, hint);
- const struct type *result = expr->alloc.init->result;
- if (hint && result != hint) {
- // TODO: We might be able to be less strict on this. We could
- // copy slices of types which differ only based on the flag, or
- // copy an array into a new slice.
+ const struct type *result = type_dealias(expr->alloc.init->result);
+ if (result->storage != STORAGE_ARRAY
+ && result->storage != STORAGE_SLICE) {
error(ctx, aexpr->alloc.init->loc, expr,
- "Cannot copy a slice to a slice of another type");
+ "Slice initializer must be of slice or array type, not %s",
+ type_storage_unparse(result->storage));
return;
}
+ if (hint) {
+ const struct type *htype = type_dealias(hint);
+ if (htype->storage != STORAGE_SLICE
+ && htype->storage != STORAGE_TAGGED) {
+ error(ctx, aexpr->alloc.init->loc, expr,
+ "Hint must be a slice type, not %s",
+ type_storage_unparse(htype->storage));
+ return;
+ }
+ }
- expr->result = result;
+ check_expression(ctx, aexpr->alloc.init, expr->alloc.init, hint);
+ result = type_dealias(expr->alloc.init->result);
+ expr->result = type_store_lookup_slice(ctx->store, result->array.members);
}
static void
diff --git a/src/gen.c b/src/gen.c
@@ -553,6 +553,8 @@ gen_expr_alloc_copy_with(struct gen_context *ctx,
const struct expression *expr, struct gen_value *out)
{
// alloc(init...) case
+ assert(expr->alloc.cap == NULL);
+
struct gen_value ret = gv_void;
if (out == NULL) {
ret = mkgtemp(ctx, expr->result, "object.%d");
@@ -568,15 +570,27 @@ gen_expr_alloc_copy_with(struct gen_context *ctx,
enum qbe_instr store = store_for_type(ctx, &builtin_type_size);
struct gen_value src = gen_expr(ctx, expr->alloc.init);
- struct qbe_value sbase = mkcopy(ctx, &src, ".%d");
struct qbe_value dbase = mkcopy(ctx, out, ".%d");
- struct qbe_value srcdata = mkqtmp(ctx, ctx->arch.sz, ".%d");
- pushi(ctx->current, &srcdata, load, &sbase, NULL);
struct qbe_value offs = constl(builtin_type_size.size);
- pushi(ctx->current, &sbase, Q_ADD, &sbase, &offs, NULL);
- struct qbe_value length = mkqtmp(ctx, ctx->arch.sz, ".%d");
- pushi(ctx->current, &length, load, &sbase, NULL);
+ const struct type *initres = type_dealias(expr->alloc.init->result);
+ struct qbe_value srcdata;
+ struct qbe_value length;
+ if (initres->storage == STORAGE_SLICE) {
+ assert(initres->array.length == SIZE_UNDEFINED);
+ srcdata = mkqtmp(ctx, ctx->arch.sz, ".%d");
+ struct qbe_value sbase = mkcopy(ctx, &src, ".%d");
+ pushi(ctx->current, &srcdata, load, &sbase, NULL);
+ pushi(ctx->current, &sbase, Q_ADD, &sbase, &offs, NULL);
+ length = mkqtmp(ctx, ctx->arch.sz, ".%d");
+ pushi(ctx->current, &length, load, &sbase, NULL);
+ } else if (initres->storage == STORAGE_ARRAY) {
+ assert(initres->array.length != SIZE_UNDEFINED);
+ srcdata = mkcopy(ctx, &src, ".%d"); // TODO: object.%d
+ length = constl(initres->array.length);
+ } else {
+ abort();
+ }
struct qbe_statement linvalid, lvalid, lalloc;
struct qbe_value balloc = mklabel(ctx, &lalloc, ".%d");
@@ -589,10 +603,10 @@ gen_expr_alloc_copy_with(struct gen_context *ctx,
pushi(ctx->current, NULL, Q_JNZ, &length, &balloc, &bvalid, NULL);
push(&ctx->current->body, &lalloc);
- const struct type *membtype =
- type_dealias(expr->alloc.init->result)->array.members;
+ const struct type *result = type_dealias(expr->result);
+ assert(result->storage == STORAGE_SLICE);
struct qbe_value sz = mkqtmp(ctx, ctx->arch.sz, ".%d");
- struct qbe_value membsz = constl(membtype->size);
+ struct qbe_value membsz = constl(result->array.members->size);
pushi(ctx->current, &sz, Q_MUL, &membsz, &length, NULL);
struct qbe_value rtfunc = mkrtfunc(ctx, "rt.malloc");
diff --git a/tests/17-alloc.ha b/tests/17-alloc.ha
@@ -106,6 +106,13 @@ fn slice_copy() void = {
let q: *[]int = alloc(x);
defer free(q);
assert((*q): *[*]int == x: *[*]int);
+
+ let r: []int = alloc([1, 2, 3]...);
+ defer free(r);
+ assert(len(x) == len(r));
+ for (let i = 0z; i < len(x); i += 1) {
+ assert(x[i] == r[i]);
+ };
};
fn string() void = {