harec

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

commit cc42fcfe62355e614d451e9ae8e207b2658cb4ad
parent 3a0fc82e5d96c77f77db53ee8f9f1ffa3458f40a
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Mon, 11 Jan 2021 09:12:10 -0500

check: implement type aliases

Diffstat:
Minclude/scope.h | 1+
Minclude/type_store.h | 2++
Minclude/types.h | 6++++++
Msrc/check.c | 61++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/gen.c | 1+
Msrc/type_store.c | 49++++++++++++++++++++++++++++++++++++++++++-------
Msrc/types.c | 15++++++++++++---
7 files changed, 104 insertions(+), 31 deletions(-)

diff --git a/include/scope.h b/include/scope.h @@ -7,6 +7,7 @@ enum object_type { O_BIND, O_CONST, O_DECL, + O_TYPE, }; // XXX: This might be better as a hash map diff --git a/include/type_store.h b/include/type_store.h @@ -17,6 +17,8 @@ struct type_store { struct context *check_context; }; +const struct type *type_dealias(const struct type *type); + bool type_is_assignable(struct type_store *store, const struct type *to, const struct type *from); bool type_is_castable(const struct type *to, const struct type *from); diff --git a/include/types.h b/include/types.h @@ -43,6 +43,11 @@ struct type; #define SIZE_UNDEFINED ((size_t)-1) #define ALIGN_UNDEFINED ((size_t)-1) +struct type_alias { + struct identifier ident; + const struct type *type; +}; + struct type_array { size_t length; // SIZE_UNDEFINED for [*] or slices const struct type *members; @@ -106,6 +111,7 @@ struct type { unsigned int flags; size_t size, align; union { + struct type_alias alias; struct type_array array; struct type_func func; struct type_pointer pointer; diff --git a/src/check.c b/src/check.c @@ -72,12 +72,18 @@ check_expr_access(struct context *ctx, char buf[1024]; identifier_unparse_static(&aexpr->access.ident, buf, sizeof(buf)); expect(&aexpr->loc, obj, "Unknown object '%s'", buf); - if (obj->otype == O_CONST) { + switch (obj->otype) { + case O_CONST: // Lower constants *expr = *obj->value; - } else { + break; + case O_BIND: + case O_DECL: expr->result = obj->type; expr->access.object = obj; + break; + case O_TYPE: + expect(&aexpr->loc, false, "Expected identifier, got type"); } break; case ACCESS_INDEX: @@ -85,19 +91,19 @@ check_expr_access(struct context *ctx, expr->access.index = xcalloc(1, sizeof(struct expression)); check_expression(ctx, aexpr->access.array, expr->access.array); check_expression(ctx, aexpr->access.index, expr->access.index); - const struct type *atype = expr->access.array->result; - const struct type *itype = expr->access.index->result; - while (atype->storage == TYPE_STORAGE_POINTER) { - expect(&aexpr->access.array->loc, - !(atype->pointer.flags & PTR_NULLABLE), - "Cannot index nullable pointer"); - atype = atype->pointer.referent; - } + const struct type *atype = + type_dereference(expr->access.array->result); + expect(&aexpr->access.array->loc, atype, + "Cannot dereference nullable pointer for indexing"); + const struct type *itype = + type_dealias(expr->access.index->result); expect(&aexpr->access.array->loc, atype->storage == TYPE_STORAGE_ARRAY || atype->storage == TYPE_STORAGE_SLICE, - "Cannot index non-array, non-slice object"); + "Cannot index non-array, non-slice %s object", + type_storage_unparse(atype->storage)); expect(&aexpr->access.index->loc, type_is_integer(itype), - "Cannot use non-integer type as slice/array index"); + "Cannot use non-integer %s type as slice/array index", + type_storage_unparse(itype->storage)); expr->access.index = lower_implicit_cast( &builtin_type_size, expr->access.index); expr->result = type_store_lookup_with_flags(&ctx->store, @@ -106,13 +112,10 @@ check_expr_access(struct context *ctx, case ACCESS_FIELD: expr->access._struct = xcalloc(1, sizeof(struct expression)); check_expression(ctx, aexpr->access._struct, expr->access._struct); - const struct type *stype = expr->access._struct->result; - while (stype->storage == TYPE_STORAGE_POINTER) { - expect(&aexpr->access.array->loc, - !(stype->pointer.flags & PTR_NULLABLE), - "Cannot dereference nullable pointer for field selection"); - stype = stype->pointer.referent; - } + const struct type *stype = + type_dereference(expr->access._struct->result); + expect(&aexpr->access._struct->loc, stype, + "Cannot dereference nullable pointer for field selection"); expect(&aexpr->access._struct->loc, stype->storage == TYPE_STORAGE_STRUCT || stype->storage == TYPE_STORAGE_UNION, "Cannot index non-struct, non-union object"); @@ -323,6 +326,8 @@ check_expr_call(struct context *ctx, expr->call.lvalue = lvalue; const struct type *fntype = type_dereference(lvalue->result); + expect(&aexpr->loc, fntype, + "Cannot dereference nullable pointer type for function call"); expect(&aexpr->loc, fntype->storage == TYPE_STORAGE_FUNCTION, "Cannot call non-function type"); @@ -939,7 +944,7 @@ check_declarations(struct context *ctx, decl = check_function(ctx, adecl); break; case AST_DECL_TYPE: - assert(0); // TODO + break; // Handled in scan case AST_DECL_GLOBAL: assert(0); // TODO case AST_DECL_CONST: @@ -1020,6 +1025,19 @@ scan_const(struct context *ctx, const struct ast_global_decl *decl) } static void +scan_type(struct context *ctx, const struct ast_type_decl *decl) +{ + trenter(TR_SCAN, "type"); + const struct type *type = + type_store_lookup_atype(&ctx->store, decl->type); + + struct identifier ident = {0}; + mkident(ctx, &ident, &decl->ident); + scope_insert(ctx->unit, O_TYPE, &ident, &decl->ident, type, NULL); + trleave(TR_SCAN, NULL); +} + +static void scan_declarations(struct context *ctx, const struct ast_decls *decls) { trenter(TR_SCAN, "declarations"); @@ -1030,7 +1048,8 @@ scan_declarations(struct context *ctx, const struct ast_decls *decls) scan_function(ctx, &decl->function); break; case AST_DECL_TYPE: - assert(0); // TODO + scan_type(ctx, &decl->type); + break; case AST_DECL_GLOBAL: assert(0); // TODO case AST_DECL_CONST: diff --git a/src/gen.c b/src/gen.c @@ -111,6 +111,7 @@ qval_for_object(struct gen_context *ctx, val->name = ident_to_sym(&obj->ident); break; case O_CONST: + case O_TYPE: assert(0); // Invariant (lowered in check) } diff --git a/src/type_store.c b/src/type_store.c @@ -3,6 +3,7 @@ #include <string.h> #include "check.h" #include "eval.h" +#include "scope.h" #include "type_store.h" #include "util.h" @@ -25,6 +26,15 @@ ast_array_len(struct type_store *store, const struct ast_type *atype) return (size_t)out.constant.uval; } +const struct type * +type_dealias(const struct type *type) +{ + while (type->storage == TYPE_STORAGE_ALIAS) { + type = type->alias.type; + } + return type; +} + bool type_is_assignable(struct type_store *store, const struct type *to, @@ -96,6 +106,7 @@ type_is_assignable(struct type_store *store, } assert(0); // Unreachable case TYPE_STORAGE_ALIAS: + return type_is_assignable(store, to->alias.type, from); case TYPE_STORAGE_ENUM: case TYPE_STORAGE_TAGGED_UNION: assert(0); // TODO @@ -121,9 +132,10 @@ type_is_assignable(struct type_store *store, } bool -type_is_castable(const struct type *to, - const struct type *from) +type_is_castable(const struct type *to, const struct type *from) { + to = type_dealias(to); + from = type_dealias(from); switch (from->storage) { case TYPE_STORAGE_CHAR: return to->storage == TYPE_STORAGE_U8; @@ -166,7 +178,6 @@ type_is_castable(const struct type *to, case TYPE_STORAGE_ARRAY: return to->storage == TYPE_STORAGE_SLICE || to->storage == TYPE_STORAGE_ARRAY; - case TYPE_STORAGE_ALIAS: case TYPE_STORAGE_TAGGED_UNION: assert(0); // TODO case TYPE_STORAGE_STRING: @@ -181,6 +192,8 @@ type_is_castable(const struct type *to, case TYPE_STORAGE_STRUCT: case TYPE_STORAGE_UNION: return false; + case TYPE_STORAGE_ALIAS: + assert(0); // Handled above } assert(0); // Unreachable @@ -273,7 +286,12 @@ type_hash(struct type_store *store, const struct type *type) case TYPE_STORAGE_STRING: break; // built-ins case TYPE_STORAGE_ALIAS: - assert(0); // TODO + for (const struct identifier *ident = &type->alias.ident; ident; + ident = ident->ns) { + hash = djb2_s(hash, ident->name); + } + hash = djb2(hash, type_hash(store, type->alias.type)); + break; case TYPE_STORAGE_ARRAY: hash = djb2(hash, type_hash(store, type->array.members)); hash = djb2(hash, type->array.length); @@ -358,7 +376,11 @@ type_eq_type(struct type_store *store, case TYPE_STORAGE_STRING: return true; case TYPE_STORAGE_ALIAS: - assert(0); // TODO + if (!identifier_eq(&a->alias.ident, &b->alias.ident)) { + return false; + } + assert(type_eq_type(store, a->alias.type, b->alias.type)); + return true; case TYPE_STORAGE_ARRAY: return a->array.length == b->array.length && a->array.expandable == b->array.expandable @@ -485,6 +507,7 @@ type_init_from_atype(struct type_store *store, type->storage = atype->storage; type->flags = atype->flags; + const struct scope_object *obj; switch (type->storage) { case TYPE_STORAGE_BOOL: case TYPE_STORAGE_CHAR: @@ -508,7 +531,14 @@ type_init_from_atype(struct type_store *store, case TYPE_STORAGE_VOID: assert(0); // Invariant case TYPE_STORAGE_ALIAS: - assert(0); // TODO + obj = scope_lookup(store->check_context->scope, &atype->alias); + // TODO: Bubble this up: + assert(obj && obj->otype == O_TYPE); + identifier_dup(&type->alias.ident, &atype->alias); + type->alias.type = obj->type; + type->size = type->alias.type->size; + type->align = type->alias.type->align; + break; case TYPE_STORAGE_ARRAY: type->array.length = ast_array_len(store, atype); type->array.members = type_store_lookup_atype( @@ -594,7 +624,12 @@ type_init_from_type(struct type_store *store, case TYPE_STORAGE_VOID: assert(0); // Invariant case TYPE_STORAGE_ALIAS: - assert(0); // TODO + new->size = old->size; + new->align = old->align; + identifier_dup(&new->alias.ident, &old->alias.ident); + new->alias.type = + type_store_lookup_type(store, old->alias.type); + break; case TYPE_STORAGE_ARRAY: new->array.members = type_store_lookup_type(store, old->array.members); diff --git a/src/types.c b/src/types.c @@ -2,14 +2,22 @@ #include <stdbool.h> #include <string.h> #include "types.h" +#include "type_store.h" const struct type * type_dereference(const struct type *type) { - if (type->storage != TYPE_STORAGE_POINTER) { + switch (type->storage) { + case TYPE_STORAGE_ALIAS: + return type_dereference(type_dealias(type)); + case TYPE_STORAGE_POINTER: + if (type->pointer.flags & PTR_NULLABLE) { + return NULL; + } + return type_dereference(type->pointer.referent); + default: return type; } - return type_dereference(type->pointer.referent); } const struct struct_field * @@ -184,7 +192,6 @@ type_is_signed(const struct type *type) { switch (type->storage) { case TYPE_STORAGE_VOID: - case TYPE_STORAGE_ALIAS: case TYPE_STORAGE_ARRAY: case TYPE_STORAGE_FUNCTION: case TYPE_STORAGE_POINTER: @@ -213,6 +220,8 @@ type_is_signed(const struct type *type) case TYPE_STORAGE_F32: case TYPE_STORAGE_F64: return true; + case TYPE_STORAGE_ALIAS: + return type_is_signed(type_dealias(type)); case TYPE_STORAGE_ENUM: assert(0); // TODO }