summaryrefslogtreecommitdiff
path: root/types.c
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-04-19 17:13:26 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-04-19 17:13:26 -0400
commitb79c4e942dba34ee1b2e5ce907629c7f77f88f07 (patch)
treeb89f880afde67f1dd6256a1df4bd772f67c1513a /types.c
parent30caeaab671f7fe7d7582ce7e645302a139c15a0 (diff)
annotating index type for loops
Diffstat (limited to 'types.c')
-rw-r--r--types.c197
1 files changed, 125 insertions, 72 deletions
diff --git a/types.c b/types.c
index ba52b75..9c83a87 100644
--- a/types.c
+++ b/types.c
@@ -33,6 +33,12 @@ static inline void typer_block_exit(Typer *tr) {
tr->block = *(Block **)arr_last(tr->blocks);
}
+static inline void construct_resolved_builtin_type(Type *t, BuiltinType builtin) {
+ t->kind = TYPE_BUILTIN;
+ t->builtin = builtin;
+ t->was_expr = NULL;
+ t->flags = TYPE_IS_RESOLVED;
+}
static size_t compiler_sizeof_builtin(BuiltinType b) {
switch (b) {
@@ -820,16 +826,41 @@ static Status type_resolve(Typer *tr, Type *t, Location where) {
} break;
case TYPE_EXPR: {
Value typeval;
- if (!types_expr(tr, t->expr))
+ Expression *expr = t->expr;
+ if (!types_expr(tr, expr))
return false;
- if (t->expr->type.kind == TYPE_UNKNOWN && tr->err_ctx->have_errored)
+ if (expr->type.kind == TYPE_UNKNOWN && tr->err_ctx->have_errored)
return false; /* silently fail (e.g. if a function couldn't be typed) */
- if (!type_is_builtin(&t->expr->type, BUILTIN_TYPE)) {
- err_print(t->expr->where, "This expression is not a type, but it's being used as one.");
- return false;
+ if (!type_is_builtin(&expr->type, BUILTIN_TYPE)) {
+ /* ok maybe it's a tuple of types, which we'll convert to a TYPE_TUPLE */
+ bool is_tuple_of_types = false;
+ if (expr->kind == EXPR_TUPLE) {
+ Type *tuple = NULL;
+ is_tuple_of_types = true;
+ arr_foreach(expr->tuple, Expression, sub) {
+ if (!type_is_builtin(&sub->type, BUILTIN_TYPE)) {
+ is_tuple_of_types = false;
+ break;
+ }
+ if (!eval_expr(tr->evalr, sub, &typeval))
+ return false;
+ Type *subtype = typer_arr_add(tr, &tuple);
+ *subtype = *typeval.type;
+ }
+ if (is_tuple_of_types) {
+ t->kind = TYPE_TUPLE;
+ t->was_expr = expr;
+ t->flags = TYPE_IS_RESOLVED;
+ t->tuple = tuple;
+ break;
+ }
+ }
+ if (!is_tuple_of_types) {
+ err_print(expr->where, "This expression is not a type, but it's being used as one.");
+ return false;
+ }
}
- Expression *expr = t->expr;
- if (!eval_expr(tr->evalr, t->expr, &typeval))
+ if (!eval_expr(tr->evalr, expr, &typeval))
return false;
*t = *typeval.type;
if (t->kind == TYPE_STRUCT) {
@@ -1521,7 +1552,10 @@ static Status types_expr(Typer *tr, Expression *e) {
case EXPR_FOR: {
ForExpr *fo = e->for_;
Declaration *header = &fo->header;
+
*(Declaration **)typer_arr_add(tr, &tr->in_decls) = header;
+ fo->body.uses = NULL;
+ typer_block_enter(tr, &fo->body);
bool in_header = true;
bool annotated_index = true;
{
@@ -1538,16 +1572,50 @@ static Status types_expr(Typer *tr, Expression *e) {
*(Identifier *)arr_add(&header->idents) = ident_insert_with_len(typer_get_idents(tr), "_", 1);
}
}
+
+ Type *fo_type_tuple = NULL;
+ /* fo_type is (val_type, index_type) */
+ arr_set_lena(&fo_type_tuple, 2, tr->allocr);
+ memset(fo_type_tuple, 0, 2*sizeof *fo_type_tuple);
+ Type *val_type = &fo_type_tuple[0];
+ Type *index_type = &fo_type_tuple[1];
+
if (header->flags & DECL_ANNOTATES_TYPE) {
- fo->type = &header->type;
- if (!type_resolve(tr, fo->type, header->where))
- goto for_fail;
- } else {
- fo->type = NULL;
+ Type *header_type = &header->type;
+ if (!type_resolve(tr, header_type, header->where))
+ return false;
+ if (annotated_index) {
+ if (header_type->kind != TYPE_TUPLE || arr_len(header_type->tuple) != 2) {
+ char *s = type_to_str(header_type);
+ err_print(header->where, "Expected annotated for loop type to be (val_type, index_type), but got %s instead.", s);
+ free(s);
+ goto for_fail;
+ }
+ fo_type_tuple = header_type->tuple;
+ val_type = &fo_type_tuple[0];
+ index_type = &fo_type_tuple[1];
+ if (!type_is_int(index_type)) {
+ char *s = type_to_str(index_type);
+ err_print(header->where, "Expected index type of for loop to be a builtin integer type, but it's %s.", s);
+ free(s);
+ goto for_fail;
+ }
+ } else {
+ *val_type = header->type;
+ }
+ }
+ Type *fo_type = &header->type;
+ fo_type->flags = TYPE_IS_RESOLVED;
+ fo_type->was_expr = NULL;
+ fo_type->kind = TYPE_TUPLE;
+ fo_type->tuple = fo_type_tuple;
+
+ assert(fo_type->flags & TYPE_IS_RESOLVED);
+
+ if (!index_type->flags) {
+ construct_resolved_builtin_type(index_type, BUILTIN_I64);
}
- fo->body.uses = NULL;
- typer_block_enter(tr, &fo->body);
if (fo->flags & FOR_IS_RANGE) {
if (!types_expr(tr, fo->range.from)) goto for_fail;
{
@@ -1581,46 +1649,54 @@ static Status types_expr(Typer *tr, Expression *e) {
}
}
- if (fo->type) {
- if (!type_eq(fo->type, &fo->range.from->type)) {
- char *exp = type_to_str(fo->type);
+ if (val_type->flags) {
+ if (!type_eq(val_type, &fo->range.from->type)) {
+ char *exp = type_to_str(val_type);
char *got = type_to_str(&fo->range.from->type);
err_print(e->where, "Type of for loop does not match the type of the from expression. Expected %s, but got %s.", exp, got);
free(exp); free(got);
goto for_fail;
}
- if ((fo->type->flags & TYPE_IS_FLEXIBLE))
- fo->type = &fo->range.from->type;
} else {
- fo->type = &fo->range.from->type;
+ *val_type = fo->range.from->type;
}
- if (fo->range.step && !type_eq(fo->type, &fo->range.step->type)) {
- char *exp = type_to_str(fo->type);
- char *got = type_to_str(&fo->range.step->type);
- err_print(e->where, "Type of for loop does not match the type of the step expression. Expected %s, but got %s.", exp, got);
- free(exp); free(got);
- goto for_fail;
- }
-
- if ((fo->type->flags & TYPE_IS_FLEXIBLE) && fo->range.step)
- fo->type = &fo->range.step->type;
+ if (fo->range.step) {
+ if (!type_eq(val_type, &fo->range.step->type)) {
+ char *exp = type_to_str(val_type);
+ char *got = type_to_str(&fo->range.step->type);
+ err_print(e->where, "Type of for loop does not match the type of the step expression. Expected %s, but got %s.", exp, got);
+ free(exp); free(got);
+ goto for_fail;
+ }
+ if (val_type->flags & TYPE_IS_FLEXIBLE)
+ *val_type = fo->range.step->type;
- if (fo->range.to && !type_eq(fo->type, &fo->range.to->type)) {
- char *exp = type_to_str(fo->type);
- char *got = type_to_str(&fo->range.to->type);
- err_print(e->where, "Type of for loop does not match the type of the to expression. Expected %s, but got %s.", exp, got);
- free(exp); free(got);
- goto for_fail;
+ Value *stepval = typer_malloc(tr, sizeof *fo->range.stepval);
+ if (!eval_expr(tr->evalr, fo->range.step, stepval)) {
+ info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant.");
+ goto for_fail;
+ }
+ val_cast(stepval, &fo->range.step->type, stepval, val_type);
+ fo->range.stepval = stepval;
}
- if (fo->type->flags & TYPE_IS_FLEXIBLE) {
- if (fo->range.to)
- fo->type = &fo->range.to->type;
- fo->type->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE;
+
+ if (fo->range.to) {
+ if (!type_eq(val_type, &fo->range.to->type)) {
+ char *exp = type_to_str(val_type);
+ char *got = type_to_str(&fo->range.to->type);
+ err_print(e->where, "Type of for loop does not match the type of the to expression. Expected %s, but got %s.", exp, got);
+ free(exp); free(got);
+ goto for_fail;
+ }
+ if (val_type->flags & TYPE_IS_FLEXIBLE)
+ *val_type = fo->range.to->type;
}
+ val_type->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE;
} else {
if (!types_expr(tr, fo->of))
goto for_fail;
+
Type *iter_type = &fo->of->type;
bool uses_ptr = false;
@@ -1757,46 +1833,23 @@ static Status types_expr(Typer *tr, Expression *e) {
iter_type = ptr_type;
}
if (header->flags & DECL_ANNOTATES_TYPE) {
- if (!type_eq(iter_type, fo->type)) {
+ if (!type_eq(iter_type, val_type)) {
char *exp = type_to_str(iter_type);
- char *got = type_to_str(fo->type);
- err_print(e->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s.");
+ char *got = type_to_str(val_type);
+ err_print(e->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s.", exp, got);
free(exp); free(got);
goto for_fail;
}
- } else fo->type = iter_type;
- }
- if ((fo->flags & FOR_IS_RANGE) && fo->range.step) {
- Value *stepval = typer_malloc(tr, sizeof *fo->range.stepval);
- if (!eval_expr(tr->evalr, fo->range.step, stepval)) {
- info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant.");
- goto for_fail;
- }
- val_cast(stepval, &fo->range.step->type, stepval, fo->type);
- fo->range.stepval = stepval;
+ } else *val_type = *iter_type;
}
+
arr_remove_lasta(&tr->in_decls, tr->allocr);
in_header = false;
- /* now we need to fix the type of the declaration to (fo->type, i64) */
- if ((header->flags & DECL_ANNOTATES_TYPE) && annotated_index) {
- /* we're good; they fully annotated this */
- } else {
- Type *type = &header->type;
- if (fo->type == type) fo->type = &fo->of->type; /* make sure we don't point to something that's about to be overriden */
- type->kind = TYPE_TUPLE;
- type->flags = TYPE_IS_RESOLVED;
- type->was_expr = NULL;
- type->tuple = NULL;
- arr_set_lena(&type->tuple, 2, tr->allocr);
- assert(fo->type->flags & TYPE_IS_RESOLVED);
- type->tuple[0] = *fo->type;
- Type *index_type = &type->tuple[1];
- index_type->flags = TYPE_IS_RESOLVED;
- index_type->was_expr = NULL;
- index_type->kind = TYPE_BUILTIN;
- index_type->builtin = BUILTIN_I64;
- }
+ assert(header->type.flags & TYPE_IS_RESOLVED);
+ assert(index_type->flags & TYPE_IS_RESOLVED);
+ assert(val_type->flags & TYPE_IS_RESOLVED);
+
header->flags |= DECL_FOUND_TYPE;
if (!types_block(tr, &fo->body)) goto for_fail;