harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 452068984f2d6e599a3007569c02d3d304354f51
parent 4b2ce356d1f6c195a578ee13733a08f23cbd451e
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun,  3 Oct 2021 11:28:56 +0200

all: fixes for forward references and type info

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mrt/types.ha | 6+++---
Msrc/check.c | 255+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
2 files changed, 181 insertions(+), 80 deletions(-)

diff --git a/rt/types.ha b/rt/types.ha @@ -8,7 +8,7 @@ type types::typeinfo = struct { repr: types::repr, }; -type types::flags = enum u8 { +type types::flags = enum uint { NONE = 0, CONST = 1 << 0, ERROR = 1 << 1, @@ -28,7 +28,7 @@ type types::array = struct { members: type, }; -type types::builtin = enum u8 { +type types::builtin = enum uint { BOOL, CHAR, ENUM, F32, F64, I16, I32, I64, I8, INT, NULL, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, VOID, TYPE, }; @@ -55,7 +55,7 @@ type types::func = struct { params: []type, }; -type types::pointer_flags = enum u8 { +type types::pointer_flags = enum uint { NONE = 0, NULLABLE = 1 << 0, }; diff --git a/src/check.c b/src/check.c @@ -2977,7 +2977,11 @@ check_type(struct context *ctx, const struct ast_decl *adecl) { struct declaration *decl = xcalloc(1, sizeof(struct declaration)); - mkident(ctx, &decl->ident, &adecl->type.ident); + if (!adecl->type.ident.ns) { + mkident(ctx, &decl->ident, &adecl->type.ident); + } else { + decl->ident = adecl->type.ident; + } decl->type = DECL_TYPE; const struct type *type = type_store_lookup_atype(ctx->store, adecl->type.type); @@ -3044,16 +3048,102 @@ check_declarations(struct context *ctx, return next; } +// Set is_static = true if you intend to evaluate this expression and +// statically allocate the result right away. static bool expr_is_specified(struct context *ctx, - const struct ast_expression *aexpr); + const struct ast_expression *aexpr, bool is_static); static bool -type_is_specified(struct context *ctx, const struct ast_type *atype) +type_is_specified(const struct type *type, bool is_static) { + assert(type); + switch (type->storage) { + case STORAGE_BOOL: + case STORAGE_CHAR: + case STORAGE_F32: + case STORAGE_F64: + case STORAGE_FCONST: + case STORAGE_I16: + case STORAGE_I32: + case STORAGE_I64: + case STORAGE_I8: + case STORAGE_ICONST: + case STORAGE_INT: + case STORAGE_NULL: + case STORAGE_RUNE: + case STORAGE_SIZE: + case STORAGE_STRING: + case STORAGE_TYPE: + case STORAGE_U16: + case STORAGE_U32: + case STORAGE_U64: + case STORAGE_U8: + case STORAGE_UINT: + case STORAGE_UINTPTR: + case STORAGE_VOID: + return true; + case STORAGE_ALIAS: + if (type->alias.type == NULL) { + return false; + } + return type_is_specified(type->alias.type, is_static); + case STORAGE_ARRAY: + return type_is_specified(type->array.members, is_static); + case STORAGE_SLICE: + if (!is_static) { + return true; + } + return type_is_specified(type->array.members, is_static); + case STORAGE_ENUM: + return true; + case STORAGE_FUNCTION: + for (struct type_func_param *param = type->func.params; + param; param = param->next) { + if (!type_is_specified(param->type, is_static)) { + return false; + } + } + return type_is_specified(type->func.result, is_static); + case STORAGE_POINTER: + return true; + case STORAGE_STRUCT: + case STORAGE_UNION: + for (const struct struct_field *field = + type->struct_union.fields; + field; field = field->next) { + if (!type_is_specified(field->type, is_static)) { + return false; + } + } + return true; + case STORAGE_TAGGED: + for (const struct type_tagged_union *ttype = &type->tagged; + ttype; ttype = ttype->next) { + if (!type_is_specified(ttype->type, is_static)) { + return false; + } + } + return true; + case STORAGE_TUPLE: + for (const struct type_tuple *ttype = &type->tuple; + ttype; ttype = ttype->next) { + if (!type_is_specified(ttype->type, is_static)) { + return false; + } + } + return true; + } + abort(); // Unreachable +} + +static bool +atype_is_specified(struct context *ctx, + const struct ast_type *atype, bool is_static) { if (!atype) { return true; } + const struct scope_object *object; switch (atype->storage) { case STORAGE_BOOL: case STORAGE_CHAR: @@ -3070,6 +3160,7 @@ type_is_specified(struct context *ctx, const struct ast_type *atype) case STORAGE_RUNE: case STORAGE_SIZE: case STORAGE_STRING: + case STORAGE_TYPE: case STORAGE_U16: case STORAGE_U32: case STORAGE_U64: @@ -3079,16 +3170,26 @@ type_is_specified(struct context *ctx, const struct ast_type *atype) case STORAGE_VOID: return true; case STORAGE_ALIAS: - return scope_lookup(ctx->scope, &atype->alias) != NULL; + object = scope_lookup(ctx->scope, &atype->alias); + if (object == NULL) { + return false; + } + assert(object->otype == O_TYPE); + const struct type *secondary = object->type; + assert(secondary->storage == STORAGE_ALIAS); + return type_is_specified(secondary->alias.type, is_static); case STORAGE_ARRAY: - return type_is_specified(ctx, atype->array.members) - && expr_is_specified(ctx, atype->array.length); + return atype_is_specified(ctx, atype->array.members, is_static) + && expr_is_specified(ctx, atype->array.length, is_static); case STORAGE_SLICE: - return true; + if (!is_static) { + return true; + } + return atype_is_specified(ctx, atype->array.members, is_static); case STORAGE_ENUM: for (struct ast_enum_field *field = atype->_enum.values; field; field = field->next) { - if (!expr_is_specified(ctx, field->value)) { + if (!expr_is_specified(ctx, field->value, is_static)) { return false; } } @@ -3096,11 +3197,11 @@ type_is_specified(struct context *ctx, const struct ast_type *atype) case STORAGE_FUNCTION: for (struct ast_function_parameters *param = atype->func.params; param; param = param->next) { - if (!type_is_specified(ctx, param->type)) { + if (!atype_is_specified(ctx, param->type, is_static)) { return false; } } - return type_is_specified(ctx, atype->func.result); + return atype_is_specified(ctx, atype->func.result, is_static); case STORAGE_POINTER: return true; case STORAGE_STRUCT: @@ -3108,10 +3209,10 @@ type_is_specified(struct context *ctx, const struct ast_type *atype) for (const struct ast_struct_union_type *stype = &atype->struct_union; stype; stype = stype->next) { - if (!expr_is_specified(ctx, stype->offset)) { + if (!expr_is_specified(ctx, stype->offset, is_static)) { return false; } - if (!type_is_specified(ctx, stype->type)) { + if (!atype_is_specified(ctx, stype->type, is_static)) { return false; } } @@ -3120,7 +3221,7 @@ type_is_specified(struct context *ctx, const struct ast_type *atype) for (const struct ast_tagged_union_type *ttype = &atype->tagged_union; ttype; ttype = ttype->next) { - if (!type_is_specified(ctx, ttype->type)) { + if (!atype_is_specified(ctx, ttype->type, is_static)) { return false; } } @@ -3128,19 +3229,19 @@ type_is_specified(struct context *ctx, const struct ast_type *atype) case STORAGE_TUPLE: for (const struct ast_tuple_type *ttype = &atype->tuple; ttype; ttype = ttype->next) { - if (!type_is_specified(ctx, ttype->type)) { + if (!atype_is_specified(ctx, ttype->type, is_static)) { return false; } } return true; - case STORAGE_TYPE: - return true; } - assert(0); // Unreachable + abort(); // Unreachable } static bool -expr_is_specified(struct context *ctx, const struct ast_expression *aexpr) +expr_is_specified(struct context *ctx, + const struct ast_expression *aexpr, + bool is_static) { if (!aexpr) { return true; @@ -3154,45 +3255,45 @@ expr_is_specified(struct context *ctx, const struct ast_expression *aexpr) //return scope_lookup(ctx->scope, &aexpr->access.ident); return true; case ACCESS_INDEX: - return expr_is_specified(ctx, aexpr->access.array) - && expr_is_specified(ctx, aexpr->access.index); + return expr_is_specified(ctx, aexpr->access.array, is_static) + && expr_is_specified(ctx, aexpr->access.index, is_static); case ACCESS_FIELD: - return expr_is_specified(ctx, aexpr->access._struct); + return expr_is_specified(ctx, aexpr->access._struct, is_static); case ACCESS_TUPLE: - return expr_is_specified(ctx, aexpr->access.tuple) - && expr_is_specified(ctx, aexpr->access.value); + return expr_is_specified(ctx, aexpr->access.tuple, is_static) + && expr_is_specified(ctx, aexpr->access.value, is_static); } assert(0); case EXPR_ALLOC: - return expr_is_specified(ctx, aexpr->alloc.expr) - && expr_is_specified(ctx, aexpr->alloc.cap); + return expr_is_specified(ctx, aexpr->alloc.expr, is_static) + && expr_is_specified(ctx, aexpr->alloc.cap, is_static); case EXPR_APPEND: for (const struct ast_append_values *value = aexpr->append.values; value; value = value->next) { - if (!expr_is_specified(ctx, value->expr)) { + if (!expr_is_specified(ctx, value->expr, is_static)) { return false; } } - return expr_is_specified(ctx, aexpr->append.expr) - && expr_is_specified(ctx, aexpr->append.variadic); + return expr_is_specified(ctx, aexpr->append.expr, is_static) + && expr_is_specified(ctx, aexpr->append.variadic, is_static); case EXPR_ASSERT: - return expr_is_specified(ctx, aexpr->assert.cond) - && expr_is_specified(ctx, aexpr->assert.message); + return expr_is_specified(ctx, aexpr->assert.cond, is_static) + && expr_is_specified(ctx, aexpr->assert.message, is_static); case EXPR_ASSIGN: - return expr_is_specified(ctx, aexpr->assign.object) - && expr_is_specified(ctx, aexpr->assign.value); + return expr_is_specified(ctx, aexpr->assign.object, is_static) + && expr_is_specified(ctx, aexpr->assign.value, is_static); case EXPR_BINARITHM: - return expr_is_specified(ctx, aexpr->binarithm.lvalue) - && expr_is_specified(ctx, aexpr->binarithm.rvalue); + return expr_is_specified(ctx, aexpr->binarithm.lvalue, is_static) + && expr_is_specified(ctx, aexpr->binarithm.rvalue, is_static); case EXPR_BINDING: for (const struct ast_expression_binding *binding = &aexpr->binding; binding; binding = binding->next) { - if (!expr_is_specified(ctx, binding->initializer)) { + if (!expr_is_specified(ctx, binding->initializer, is_static)) { return false; } - if (!type_is_specified(ctx, binding->type)) { + if (!atype_is_specified(ctx, binding->type, is_static)) { return false; } } @@ -3200,7 +3301,7 @@ expr_is_specified(struct context *ctx, const struct ast_expression *aexpr) case EXPR_COMPOUND: for (const struct ast_expression_list *list = &aexpr->compound.list; list; list = list->next) { - if (!expr_is_specified(ctx, list->expr)) { + if (!expr_is_specified(ctx, list->expr, is_static)) { return false; } } @@ -3211,81 +3312,81 @@ expr_is_specified(struct context *ctx, const struct ast_expression *aexpr) case EXPR_CALL: for (struct ast_call_argument *arg = aexpr->call.args; arg; arg = arg->next) { - if (!expr_is_specified(ctx, arg->value)) { + if (!expr_is_specified(ctx, arg->value, is_static)) { return false; } } - return expr_is_specified(ctx, aexpr->call.lvalue); + return expr_is_specified(ctx, aexpr->call.lvalue, is_static); case EXPR_CAST: - return expr_is_specified(ctx, aexpr->cast.value) - && type_is_specified(ctx, aexpr->cast.type); + return expr_is_specified(ctx, aexpr->cast.value, is_static) + && atype_is_specified(ctx, aexpr->cast.type, is_static); case EXPR_CONSTANT: if (aexpr->constant.storage == STORAGE_ARRAY) { for (struct ast_array_constant *aconst = aexpr->constant.array; aconst; aconst = aconst->next) { - if (!expr_is_specified(ctx, aconst->value)) { + if (!expr_is_specified(ctx, aconst->value, is_static)) { return false; } } } return true; case EXPR_DEFER: - return expr_is_specified(ctx, aexpr->defer.deferred); + return expr_is_specified(ctx, aexpr->defer.deferred, is_static); case EXPR_DELETE: - return expr_is_specified(ctx, aexpr->delete.expr); + return expr_is_specified(ctx, aexpr->delete.expr, is_static); case EXPR_FOR: - return expr_is_specified(ctx, aexpr->_for.bindings) - && expr_is_specified(ctx, aexpr->_for.cond) - && expr_is_specified(ctx, aexpr->_for.afterthought) - && expr_is_specified(ctx, aexpr->_for.body); + return expr_is_specified(ctx, aexpr->_for.bindings, is_static) + && expr_is_specified(ctx, aexpr->_for.cond, is_static) + && expr_is_specified(ctx, aexpr->_for.afterthought, is_static) + && expr_is_specified(ctx, aexpr->_for.body, is_static); case EXPR_FREE: - return expr_is_specified(ctx, aexpr->free.expr); + return expr_is_specified(ctx, aexpr->free.expr, is_static); case EXPR_IF: - return expr_is_specified(ctx, aexpr->_if.cond) - && expr_is_specified(ctx, aexpr->_if.true_branch) - && expr_is_specified(ctx, aexpr->_if.false_branch); + return expr_is_specified(ctx, aexpr->_if.cond, is_static) + && expr_is_specified(ctx, aexpr->_if.true_branch, is_static) + && expr_is_specified(ctx, aexpr->_if.false_branch, is_static); case EXPR_INSERT: assert(0); // TODO case EXPR_MATCH: for (struct ast_match_case *mcase = aexpr->match.cases; mcase; mcase = mcase->next) { - if (!type_is_specified(ctx, mcase->type)) { + if (!atype_is_specified(ctx, mcase->type, is_static)) { return false; } for (const struct ast_expression_list *list = &mcase->exprs; list; list = list->next) { - if (!expr_is_specified(ctx, list->expr)) { + if (!expr_is_specified(ctx, list->expr, is_static)) { return false; } } } - return expr_is_specified(ctx, aexpr->match.value); + return expr_is_specified(ctx, aexpr->match.value, is_static); case EXPR_MEASURE: switch (aexpr->measure.op) { case M_LEN: - return expr_is_specified(ctx, aexpr->measure.value); + return expr_is_specified(ctx, aexpr->measure.value, is_static); case M_SIZE: - return type_is_specified(ctx, aexpr->measure.type); + return atype_is_specified(ctx, aexpr->measure.type, is_static); case M_OFFSET: assert(0); // TODO } assert(0); case EXPR_PROPAGATE: - return expr_is_specified(ctx, aexpr->propagate.value); + return expr_is_specified(ctx, aexpr->propagate.value, is_static); case EXPR_RETURN: - return expr_is_specified(ctx, aexpr->_return.value); + return expr_is_specified(ctx, aexpr->_return.value, is_static); case EXPR_SLICE: - return expr_is_specified(ctx, aexpr->slice.object) - && expr_is_specified(ctx, aexpr->slice.start) - && expr_is_specified(ctx, aexpr->slice.end); + return expr_is_specified(ctx, aexpr->slice.object, is_static) + && expr_is_specified(ctx, aexpr->slice.start, is_static) + && expr_is_specified(ctx, aexpr->slice.end, is_static); case EXPR_STRUCT: for (struct ast_field_value *field = aexpr->_struct.fields; field; field = field->next) { - if (field->type && !type_is_specified(ctx, field->type)) { + if (field->type && !atype_is_specified(ctx, field->type, is_static)) { return false; } - if (!expr_is_specified(ctx, field->initializer)) { + if (!expr_is_specified(ctx, field->initializer, is_static)) { return false; } } @@ -3300,32 +3401,32 @@ expr_is_specified(struct context *ctx, const struct ast_expression *aexpr) scase; scase =scase->next) { for (struct ast_case_option *opt = scase->options; opt; opt = opt->next) { - if (!expr_is_specified(ctx, opt->value)) { + if (!expr_is_specified(ctx, opt->value, is_static)) { return false; } } for (const struct ast_expression_list *list = &scase->exprs; list; list = list->next) { - if (!expr_is_specified(ctx, list->expr)) { + if (!expr_is_specified(ctx, list->expr, is_static)) { return false; } } } - return expr_is_specified(ctx, aexpr->_switch.value); + return expr_is_specified(ctx, aexpr->_switch.value, is_static); case EXPR_TUPLE: for (const struct ast_expression_tuple *tuple = &aexpr->tuple; tuple; tuple = tuple->next) { - if (!expr_is_specified(ctx, tuple->expr)) { + if (!expr_is_specified(ctx, tuple->expr, is_static)) { return false; } } return true; case EXPR_TYPE: - return type_is_specified(ctx, aexpr->_type.type); + return atype_is_specified(ctx, aexpr->_type.type, is_static); case EXPR_UNARITHM: - return expr_is_specified(ctx, aexpr->unarithm.operand); + return expr_is_specified(ctx, aexpr->unarithm.operand, is_static); case EXPR_YIELD: - return expr_is_specified(ctx, aexpr->control.value); + return expr_is_specified(ctx, aexpr->control.value, is_static); } assert(0); // Unreachable } @@ -3335,8 +3436,8 @@ scan_const(struct context *ctx, const struct ast_global_decl *decl) { // TODO: Get rid of this once the type store bubbles up errors for (const struct ast_global_decl *d = decl; d; d = d->next) { - if (!type_is_specified(ctx, d->type) - || !expr_is_specified(ctx, d->init)) { + if (!atype_is_specified(ctx, d->type, true) + || !expr_is_specified(ctx, d->init, true)) { return false; } } @@ -3381,7 +3482,7 @@ scan_function(struct context *ctx, const struct ast_function_decl *decl) }; // TODO: Get rid of this once the type store bubbles up errors // TODO: Do we want to do something on !expr_is_specified(ctx, decl->body)? - if (!type_is_specified(ctx, &fn_atype)) { + if (!atype_is_specified(ctx, &fn_atype, false)) { return false; } const struct type *fntype = type_store_lookup_atype( @@ -3409,8 +3510,8 @@ static bool scan_global(struct context *ctx, const struct ast_global_decl *decl) { // TODO: Get rid of this once the type store bubbles up errors - if (!type_is_specified(ctx, decl->type) - || !expr_is_specified(ctx, decl->init)) { + if (!atype_is_specified(ctx, decl->type, true) + || !expr_is_specified(ctx, decl->init, true)) { return false; } @@ -3450,7 +3551,7 @@ static bool scan_type(struct context *ctx, const struct ast_type_decl *decl, bool exported) { // TODO: Get rid of this once the type store bubbles up errors - if (!type_is_specified(ctx, decl->type)) { + if (!atype_is_specified(ctx, decl->type, false)) { return false; } const struct type *type =