summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--copy.c10
-rw-r--r--parse.c6
-rw-r--r--types.c18
3 files changed, 20 insertions, 14 deletions
diff --git a/copy.c b/copy.c
index 279abf6..1677a7d 100644
--- a/copy.c
+++ b/copy.c
@@ -56,6 +56,7 @@ static void copy_type(Allocator *a, Type *out, Type *in) {
} break;
case TYPE_TUPLE: {
size_t ntypes = arr_len(in->tuple);
+ out->tuple = NULL;
arr_set_lena(&out->tuple, ntypes, a);
for (size_t i = 0; i < ntypes; i++) {
copy_type(a, &out->tuple[i], &in->tuple[i]);
@@ -75,9 +76,9 @@ static void copy_type(Allocator *a, Type *out, Type *in) {
out->ptr = allocr_malloc(a, sizeof *out->slice);
copy_type(a, out->slice, in->slice);
break;
- case TYPE_STRUCT:
- out->struc.fields = NULL;
+ case TYPE_STRUCT: {
size_t nfields = arr_len(in->struc.fields);
+ out->struc.fields = NULL;
arr_set_lena(&out->struc.fields, nfields, a);
for (size_t i = 0; i < nfields; i++) {
Field *fout = &out->struc.fields[i];
@@ -85,14 +86,14 @@ static void copy_type(Allocator *a, Type *out, Type *in) {
*fout = *fin;
copy_type(a, fout->type, fin->type);
}
- break;
+ } break;
}
}
static void copy_fn_expr(Allocator *a, FnExpr *fout, FnExpr *fin, bool copy_body) {
size_t i;
- fout->params = NULL;
size_t nparam_decls = arr_len(fin->params);
+ fout->params = NULL;
arr_set_lena(&fout->params, nparam_decls, a);
for (i = 0; i < nparam_decls; i++)
copy_decl(a, fout->params + i, fin->params + i);
@@ -249,6 +250,7 @@ static void copy_stmt(Allocator *a, Statement *out, Statement *in) {
static void copy_block(Allocator *a, Block *out, Block *in) {
*out = *in;
size_t nstmts = arr_len(in->stmts);
+ out->stmts = NULL;
arr_set_lena(&out->stmts, nstmts, a);
for (size_t i = 0; i < nstmts; i++) {
copy_stmt(a, &out->stmts[i], &in->stmts[i]);
diff --git a/parse.c b/parse.c
index 0d79f8f..97d5f09 100644
--- a/parse.c
+++ b/parse.c
@@ -801,6 +801,12 @@ static bool parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end
static bool parse_fn_expr(Parser *p, FnExpr *f) {
Tokenizer *t = p->tokr;
f->ret_decls = NULL;
+
+ {
+ /* help types.c */
+ HashTable z = {0};
+ f->instances = z;
+ }
/* only called when token is fn */
assert(token_is_kw(t->token, KW_FN));
t->token++;
diff --git a/types.c b/types.c
index 300438f..89587f3 100644
--- a/types.c
+++ b/types.c
@@ -181,12 +181,14 @@ static bool expr_must_lval(Expression *e) {
return false;
}
-static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t) {
+#define TYPE_OF_FN_NO_COPY_EVEN_IF_CONST 0x01
+
+static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) {
t->kind = TYPE_FN;
t->fn.types = NULL;
t->fn.constness = NULL; /* OPTIM: constant doesn't need to be a dynamic array */
FnExpr *newf = NULL;
- if (fn_has_any_const_params(f)) {
+ if (!(flags & TYPE_OF_FN_NO_COPY_EVEN_IF_CONST) && fn_has_any_const_params(f)) {
/* OPTIM don't copy so much */
newf = typer_malloc(tr, sizeof *newf);
copy_fn_expr(tr->allocr, newf, f, false);
@@ -324,7 +326,7 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
} else {
if ((d->flags & DECL_HAS_EXPR) && (d->expr.kind == EXPR_FN)) {
/* allow using a function before declaring it */
- if (!type_of_fn(tr, &d->expr.fn, d->expr.where, t)) return false;
+ if (!type_of_fn(tr, &d->expr.fn, d->expr.where, t, 0)) return false;
return true;
} else {
if (location_after(d->where, where)) {
@@ -602,14 +604,8 @@ static bool types_fn(Typer *tr, FnExpr *f, Type *t, Location where,
Instance *instance) {
FnExpr *prev_fn = tr->fn;
bool success = true;
- {
- HashTable z = {0};
- f->instances = z;
- }
assert(t->kind == TYPE_FN);
-
-
if (instance) {
copy_fn_expr(tr->allocr, &instance->fn, f, true);
f = &instance->fn;
@@ -632,6 +628,8 @@ static bool types_fn(Typer *tr, FnExpr *f, Type *t, Location where,
semi_const_arg_idx++;
}
}
+ if (!type_of_fn(tr, f, where, t, TYPE_OF_FN_NO_COPY_EVEN_IF_CONST))
+ return false;
} else {
if (t->fn.constness)
return true; /* don't type function body yet; we need to do that for every instance */
@@ -700,7 +698,7 @@ static bool types_expr(Typer *tr, Expression *e) {
e->flags |= EXPR_FOUND_TYPE; /* even if failed, pretend we found the type */
switch (e->kind) {
case EXPR_FN: {
- if (!type_of_fn(tr, &e->fn, e->where, &e->type))
+ if (!type_of_fn(tr, &e->fn, e->where, &e->type, 0))
return false;
if (fn_has_any_const_params(&e->fn)) {
HashTable z = {0};