summaryrefslogtreecommitdiff
path: root/types.c
diff options
context:
space:
mode:
Diffstat (limited to 'types.c')
-rw-r--r--types.c284
1 files changed, 214 insertions, 70 deletions
diff --git a/types.c b/types.c
index 7756585..7b8e9fb 100644
--- a/types.c
+++ b/types.c
@@ -102,12 +102,15 @@ static bool expr_arr_must_mut(Expression *e) {
switch (e->kind) {
case EXPR_IDENT: {
IdentDecl *idecl = ident_decl(e->ident);
- Declaration *d = idecl->decl;
- if (d->flags & DECL_FLAG_CONST) {
- err_print(e->where, "Cannot modify a constant array.");
- return false;
+ if (idecl->kind == IDECL_DECL) {
+ Declaration *d = idecl->decl;
+ if (d->flags & DECL_FLAG_CONST) {
+ err_print(e->where, "Cannot modify a constant array.");
+ return false;
+ }
}
- } return true;
+ return true;
+ }
case EXPR_CAST:
case EXPR_CALL:
case EXPR_NEW:
@@ -119,6 +122,8 @@ static bool expr_arr_must_mut(Expression *e) {
case EXPR_WHILE:
assert(e->while_.body.ret_expr);
return expr_arr_must_mut(e->while_.body.ret_expr);
+ case EXPR_EACH:
+ return expr_arr_must_mut(e->each.body.ret_expr);
case EXPR_IF:
for (IfExpr *i = &e->if_; i; i->next_elif ? i = &i->next_elif->if_ : (i = NULL)) {
assert(i->body.ret_expr);
@@ -155,12 +160,15 @@ static bool expr_must_lval(Expression *e) {
case EXPR_IDENT: {
IdentDecl *id_decl = ident_decl(e->ident);
assert(id_decl);
- Declaration *d = id_decl->decl;
- if (d->flags & DECL_FLAG_CONST) {
- char *istr = ident_to_str(e->ident);
- err_print(e->where, "Use of constant %s as a non-constant expression.", istr);
- info_print(d->where, "%s was declared here.", istr);
- return false;
+ if (id_decl->kind == IDECL_DECL) {
+ Declaration *d = id_decl->decl;
+ if (d->flags & DECL_FLAG_CONST) {
+ char *istr = ident_to_str(e->ident);
+ err_print(e->where, "Use of constant %s as a non-constant expression.", istr);
+ info_print(d->where, "%s was declared here.", istr);
+ return false;
+ }
+
}
return true;
}
@@ -203,6 +211,7 @@ static bool expr_must_lval(Expression *e) {
case EXPR_LITERAL_BOOL:
case EXPR_IF:
case EXPR_WHILE:
+ case EXPR_EACH:
case EXPR_CALL:
case EXPR_C:
case EXPR_DALIGNOF:
@@ -243,6 +252,7 @@ static bool type_of_fn(Typer *tr, Expression *e, Type *t) {
}
static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
+ t->flags = 0;
IdentDecl *decl = ident_decl(i);
if (!decl) {
char *s = ident_to_str(i);
@@ -250,73 +260,93 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
free(s);
return false;
}
- Declaration *d = decl->decl;
- bool captured = false;
- if (decl->scope != NULL)
- for (Block *block = tr->block; block != decl->scope; block = block->parent) {
- if (block->flags & BLOCK_FLAG_FN) {
- captured = true;
- break;
+ switch (decl->kind) {
+ case IDECL_DECL: {
+ Declaration *d = decl->decl;
+ bool captured = false;
+ if (decl->scope != NULL)
+ for (Block *block = tr->block; block != decl->scope; block = block->parent) {
+ if (block->flags & BLOCK_FLAG_FN) {
+ captured = true;
+ break;
+ }
}
+ if (captured && !(d->flags & DECL_FLAG_CONST)) {
+ err_print(where, "Variables cannot be captured into inner functions (but constants can).");
+ return false;
}
- if (captured && !(d->flags & DECL_FLAG_CONST)) {
- err_print(where, "Variables cannot be captured into inner functions (but constants can).");
- return false;
- }
- /* are we inside this declaration? */
- typedef Declaration *DeclarationPtr;
- arr_foreach(tr->in_decls, DeclarationPtr, in_decl) {
- if (d == *in_decl) {
- assert(d->flags & DECL_FLAG_HAS_EXPR); /* we can only be in decls with an expr */
- if (d->expr.kind != EXPR_FN) { /* it's okay if a function references itself */
- /* if we've complained about it before when we were figuring out the type, don't complain again */
- if (!(d->flags & DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE)) {
- char *s = ident_to_str(i);
- err_print(where, "Use of identifier %s within its own declaration.", s);
- free(s);
- info_print(d->where, "Declaration was here.");
- d->flags |= DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE;
+ /* are we inside this declaration? */
+ typedef Declaration *DeclarationPtr;
+ arr_foreach(tr->in_decls, DeclarationPtr, in_decl) {
+ if (d == *in_decl) {
+ assert(d->flags & DECL_FLAG_HAS_EXPR); /* we can only be in decls with an expr */
+ if (d->expr.kind != EXPR_FN) { /* it's okay if a function references itself */
+ /* if we've complained about it before when we were figuring out the type, don't complain again */
+ if (!(d->flags & DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE)) {
+ char *s = ident_to_str(i);
+ err_print(where, "Use of identifier %s within its own declaration.", s);
+ free(s);
+ info_print(d->where, "Declaration was here.");
+ d->flags |= DECL_FLAG_ERRORED_ABOUT_SELF_REFERENCE;
+ }
+ return false;
}
- return false;
}
}
- }
- if (d->flags & DECL_FLAG_FOUND_TYPE) {
- if (d->type.kind == TYPE_TUPLE) {
- /* get correct item in tuple */
- long index = 0;
- arr_foreach(d->idents, Identifier, decl_i) {
- if (*decl_i == i) {
- break;
+ if (d->flags & DECL_FLAG_FOUND_TYPE) {
+ if (d->type.kind == TYPE_TUPLE) {
+ /* get correct item in tuple */
+ long index = 0;
+ arr_foreach(d->idents, Identifier, decl_i) {
+ if (*decl_i == i) {
+ break;
+ }
+ index++;
+ assert(index < (long)arr_len(d->idents)); /* identifier got its declaration set to here, but it's not here */
}
- index++;
- assert(index < (long)arr_len(d->idents)); /* identifier got its declaration set to here, but it's not here */
+ *t = d->type.tuple[index];
+ } else {
+ *t = d->type;
}
- *t = d->type.tuple[index];
- } else {
- *t = d->type;
- }
- return true;
- } else {
- if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->expr.kind == EXPR_FN)) {
- /* allow using a function before declaring it */
- if (!type_of_fn(tr, &d->expr, t)) return false;
return true;
} else {
- if (location_after(d->where, where)) {
- char *s = ident_to_str(i);
- err_print(where, "Use of identifier %s before its declaration.\nNote that it is only possible to use a constant function before it is directly declared (e.g. x @= fn() {}).", s);
- info_print(d->where, "%s will be declared here.", s);
- free(s);
+ if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->expr.kind == EXPR_FN)) {
+ /* allow using a function before declaring it */
+ if (!type_of_fn(tr, &d->expr, t)) return false;
+ return true;
} else {
- /* let's type the declaration, and redo this (for evaling future functions) */
- if (!types_decl(tr, d)) return false;
- return type_of_ident(tr, where, i, t);
+ if (location_after(d->where, where)) {
+ char *s = ident_to_str(i);
+ err_print(where, "Use of identifier %s before its declaration.\nNote that it is only possible to use a constant function before it is directly declared (e.g. x @= fn() {}).", s);
+ info_print(d->where, "%s will be declared here.", s);
+ free(s);
+ } else {
+ /* let's type the declaration, and redo this (for evaling future functions) */
+ if (!types_decl(tr, d)) return false;
+ return type_of_ident(tr, where, i, t);
+ }
+ return false;
}
- return false;
}
+ } break;
+ case IDECL_EXPR: {
+ Expression *e = decl->expr;
+ switch (e->kind) {
+ case EXPR_EACH:
+ if (i == e->each.index) {
+ t->kind = TYPE_BUILTIN;
+ t->builtin = BUILTIN_I64;
+ } else {
+ assert(i == e->each.value);
+ *t = e->each.type;
+ }
+ break;
+ default: assert(0); return false;
+ }
+ } break;
}
+ return true;
}
/* fixes the type (replaces [5+3]int with [8]int, etc.) */
@@ -389,6 +419,7 @@ static bool type_resolve(Typer *tr, Type *t, Location where) {
free(s);
return false;
}
+ assert(idecl->kind == IDECL_DECL);
Declaration *decl = idecl->decl;
/* now, type the declaration (in case we are using it before its declaration) */
if (!types_decl(tr, decl))
@@ -558,7 +589,8 @@ static bool types_expr(Typer *tr, Expression *e) {
tr->ret_type = t->fn.types[0];
}
tr->can_ret = true;
- fn_enter(f, SCOPE_FLAG_CHECK_REDECL);
+ if (!fn_enter(f, SCOPE_FLAG_CHECK_REDECL))
+ return false;
bool block_success = true;
block_success = types_block(tr, &e->fn.body);
fn_exit(f);
@@ -634,6 +666,116 @@ static bool types_expr(Typer *tr, Expression *e) {
t->kind = TYPE_BUILTIN;
t->builtin = BUILTIN_CHAR;
break;
+ case EXPR_EACH: {
+ EachExpr *ea = &e->each;
+ if (ea->flags & EACH_IS_RANGE) {
+ /* TODO: allow user-defined numerical types */
+ if (!types_expr(tr, ea->range.from)) return false;
+ {
+ Type *ft = &ea->range.from->type;
+ if (ft->kind != TYPE_BUILTIN || !type_builtin_is_numerical(ft->builtin)) {
+ char *s = type_to_str(ft);
+ err_print(e->where, "from expression of each must be a builtin numerical type, not %s", s);
+ free(s);
+ }
+ }
+ if (ea->range.step) {
+ if (!types_expr(tr, ea->range.step)) return false;
+ Type *st = &ea->range.step->type;
+ if (st->kind != TYPE_BUILTIN || !type_builtin_is_numerical(st->builtin)) {
+ char *s = type_to_str(st);
+ err_print(e->where, "step expression of each must be a builtin numerical type, not %s", s);
+ free(s);
+ }
+ }
+ if (ea->range.to) {
+ if (!types_expr(tr, ea->range.to)) return false;
+ Type *tt = &ea->range.to->type;
+ if (tt->kind != TYPE_BUILTIN || !type_builtin_is_numerical(tt->builtin)) {
+ char *s = type_to_str(tt);
+ err_print(e->where, "to expression of each must be a builtin numerical type, not %s", s);
+ free(s);
+ }
+ }
+
+ if (!(ea->flags & EACH_ANNOTATED_TYPE)) {
+ ea->type = ea->range.from->type;
+ }
+
+ if (!type_eq(&ea->type, &ea->range.from->type)) {
+ char *exp = type_to_str(&ea->type);
+ char *got = type_to_str(&ea->range.from->type);
+ err_print(e->where, "Type of each does not match the type of the from expression. Expected %s, but got %s.", exp, got);
+ free(exp); free(got);
+ return false;
+ }
+
+ if (ea->range.step && !type_eq(&ea->type, &ea->range.step->type)) {
+ char *exp = type_to_str(&ea->type);
+ char *got = type_to_str(&ea->range.step->type);
+ err_print(e->where, "Type of each does not match the type of the step expression. Expected %s, but got %s.", exp, got);
+ free(exp); free(got);
+ return false;
+ }
+
+ if ((ea->type.flags & TYPE_FLAG_FLEXIBLE) && ea->range.step)
+ ea->type = ea->range.step->type;
+
+ if (ea->range.to && !type_eq(&ea->type, &ea->range.to->type)) {
+ char *exp = type_to_str(&ea->type);
+ char *got = type_to_str(&ea->range.to->type);
+ err_print(e->where, "Type of each does not match the type of the to expression. Expected %s, but got %s.", exp, got);
+ free(exp); free(got);
+ return false;
+ }
+
+ if ((ea->type.flags & TYPE_FLAG_FLEXIBLE) && ea->range.to)
+ ea->type = ea->range.to->type;
+
+ } else {
+ if (!types_expr(tr, ea->of))
+ return false;
+ Type *of_type = NULL;
+ switch (ea->of->type.kind) {
+ case TYPE_SLICE:
+ of_type = ea->of->type.slice;
+ break;
+ case TYPE_ARR:
+ of_type = ea->of->type.arr.of;
+ break;
+ default: {
+ char *s = type_to_str(&ea->of->type);
+ err_print(e->where, "Cannot iterate over non-array non-slice type %s.", s);
+ free(s);
+ return false;
+ }
+ }
+ if (ea->flags & EACH_ANNOTATED_TYPE) {
+ if (!type_eq(of_type, &ea->type)) {
+ char *exp = type_to_str(of_type);
+ char *got = type_to_str(&ea->type);
+ err_print(e->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s.");
+ free(exp); free(got);
+ return false;
+ }
+ } else ea->type = *of_type;
+ }
+ if ((ea->flags & EACH_IS_RANGE) && ea->range.step) {
+ Value *stepval = typer_malloc(tr, sizeof *ea->range.stepval);
+ if (!eval_expr(tr->evalr, ea->range.step, stepval)) {
+ info_print(ea->range.step->where, "Note that the step of an each loop must be a compile-time constant.");
+ return false;
+ }
+ ea->range.stepval = stepval;
+ }
+ if (!each_enter(e, SCOPE_FLAG_CHECK_REDECL)) return false;
+ if (!types_block(tr, &ea->body)) return false;
+ each_exit(e);
+ if (ea->body.ret_expr)
+ *t = ea->body.ret_expr->type;
+ else
+ t->kind = TYPE_VOID;
+ } break;
case EXPR_IDENT: {
if (!type_of_ident(tr, e->where, e->ident, t)) return false;
} break;
@@ -785,10 +927,12 @@ static bool types_expr(Typer *tr, Expression *e) {
if (f->kind == EXPR_IDENT) {
IdentDecl *decl = ident_decl(f->ident);
assert(decl);
- if (decl->decl->flags & DECL_FLAG_HAS_EXPR) {
- Expression *expr = &decl->decl->expr;
- if (expr->kind == EXPR_FN)
- fn_decl = &decl->decl->expr.fn;
+ if (decl->kind == IDECL_DECL) {
+ if (decl->decl->flags & DECL_FLAG_HAS_EXPR) {
+ Expression *expr = &decl->decl->expr;
+ if (expr->kind == EXPR_FN)
+ fn_decl = &decl->decl->expr.fn;
+ }
}
}
if (!fn_decl && nargs != nparams) {
@@ -819,7 +963,7 @@ static bool types_expr(Typer *tr, Expression *e) {
char *s = ident_to_str(args[p].name);
err_print(args[p].where, "Argument '%s' does not appear in declaration of function.", s);
free(s);
- info_print(ident_decl(f->ident)->decl->where, "Declaration is here.");
+ info_print(idecl_where(ident_decl(f->ident)), "Declaration is here.");
return false;
}
new_args[arg_index] = args[p].val;