harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

commit 8531f739e8471beb24c532292a67de518c030524
parent fd5d8f4d39b4428781caa098f4ce36b9dd6b7153
Author: Pierre Curto <pierre.curto@gmail.com>
Date:   Thu, 17 Nov 2022 15:42:37 +0100

Permit type inference for globals

Fixes: https://todo.sr.ht/~sircmpwn/hare/560

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

Diffstat:
Msrc/check.c | 96++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/eval.c | 2+-
Msrc/parse.c | 11+++++++----
Mtests/11-globals.ha | 17+++++++++++++++++
4 files changed, 86 insertions(+), 40 deletions(-)

diff --git a/src/check.c b/src/check.c @@ -2543,8 +2543,15 @@ check_expr_struct(struct context *ctx, return; } - // Do we want globals without type hints? - assert(obj->otype != O_SCAN); + if (obj->otype == O_SCAN) { + // resolve the unknown type + obj = wrap_resolver(ctx, obj, resolve_type); + if (!obj) { + error(ctx, aexpr->loc, expr, + "Unknown type"); + return; + } + } if (obj->otype != O_TYPE) { error(ctx, aexpr->loc, expr, @@ -3154,8 +3161,10 @@ static struct declaration * check_const(struct context *ctx, const struct ast_global_decl *adecl) { - const struct type *type = type_store_lookup_atype( - ctx->store, adecl->type); + const struct type *type = NULL; + if (adecl->type) { + type = type_store_lookup_atype(ctx->store, adecl->type); + } struct declaration *decl = xcalloc(1, sizeof(struct declaration)); const struct scope_object *obj = scope_lookup( ctx->unit, &adecl->ident); @@ -3275,8 +3284,10 @@ static struct declaration * check_global(struct context *ctx, const struct ast_global_decl *adecl) { - const struct type *type = type_store_lookup_atype( - ctx->store, adecl->type); + const struct type *type = NULL; + if (adecl->type) { + type = type_store_lookup_atype(ctx->store, adecl->type); + } struct declaration *decl = xcalloc(1, sizeof(struct declaration)); decl->type = DECL_GLOBAL; @@ -3298,19 +3309,21 @@ check_global(struct context *ctx, check_expression(ctx, adecl->init, initializer, type); // TODO: Pass errors up and deal with them at the end of check - char *typename1 = gen_typename(initializer->result); - char *typename2 = gen_typename(type); - expect(ctx, &adecl->init->loc, - type_is_assignable(type, initializer->result), - "Initializer type %s is not assignable to constant type %s", - typename1, typename2); - free(typename1); - free(typename2); + if (type) { + char *typename1 = gen_typename(initializer->result); + char *typename2 = gen_typename(type); + expect(ctx, &adecl->init->loc, + type_is_assignable(type, initializer->result), + "Initializer type %s is not assignable to constant type %s", + typename1, typename2); + free(typename1); + free(typename2); + } bool context = adecl->type && adecl->type->storage == STORAGE_ARRAY && adecl->type->array.contextual; - if (context) { + if (context || !type) { // XXX: Do we need to do anything more here type = initializer->result; } @@ -3325,6 +3338,8 @@ check_global(struct context *ctx, decl->global.value = value; + free(initializer); + return decl; } @@ -3532,16 +3547,17 @@ scan_const(struct context *ctx, const struct ast_global_decl *decl) { assert(!decl->symbol); // Invariant - const struct type *type = type_store_lookup_atype( - ctx->store, decl->type); - expect(ctx, &decl->type->loc, type != NULL, "Unable to resolve type"); - // TODO: Free the initializer + const struct type *type = NULL; + if (decl->type) { + type = type_store_lookup_atype(ctx->store, decl->type); + expect(ctx, &decl->type->loc, type != NULL, "Unable to resolve type"); + } struct expression *initializer = xcalloc(1, sizeof(struct expression)); check_expression(ctx, decl->init, initializer, type); bool context = decl->type && decl->type->storage == STORAGE_ARRAY && decl->type->array.contextual; - if (context) { + if (context || !decl->type) { // XXX: Do we need to do anything more here type = initializer->result; } @@ -3562,6 +3578,7 @@ scan_const(struct context *ctx, const struct ast_global_decl *decl) "Unable to evaluate constant initializer at compile time"); expect(ctx, &decl->init->loc, type->storage != STORAGE_NULL, "Null is not a valid type for a constant"); + free(initializer); struct identifier ident = {0}; mkident(ctx, &ident, &decl->ident); @@ -3598,25 +3615,34 @@ scan_function(struct context *ctx, const struct ast_function_decl *decl) const struct scope_object * scan_global(struct context *ctx, const struct ast_global_decl *decl) { - const struct type *type = type_store_lookup_atype( - ctx->store, decl->type); - - if (decl->type->storage == STORAGE_ARRAY - && decl->type->array.contextual) { - expect(ctx, &decl->type->loc, decl->init, - "Cannot infer array length without an initializer"); - - // TODO: Free initializer + const struct type *type = NULL; + if (decl->type) { + type = type_store_lookup_atype(ctx->store, decl->type); + if (decl->type->storage == STORAGE_ARRAY + && decl->type->array.contextual) { + expect(ctx, &decl->type->loc, decl->init, + "Cannot infer array length without an initializer"); + + struct expression *initializer = + xcalloc(1, sizeof(struct expression)); + check_expression(ctx, decl->init, initializer, type); + expect(ctx, &decl->init->loc, + initializer->result->storage == STORAGE_ARRAY, + "Cannot infer array length from non-array type"); + expect(ctx, &decl->init->loc, + initializer->result->array.members == type->array.members, + "Initializer is not assignable to binding type"); + type = initializer->result; + free(initializer); + } + } else { + // the type is set by the expression struct expression *initializer = xcalloc(1, sizeof(struct expression)); check_expression(ctx, decl->init, initializer, type); - expect(ctx, &decl->init->loc, - initializer->result->storage == STORAGE_ARRAY, - "Cannot infer array length from non-array type"); - expect(ctx, &decl->init->loc, - initializer->result->array.members == type->array.members, - "Initializer is not assignable to binding type"); type = initializer->result; + assert(type); + free(initializer); } expect(ctx, &decl->init->loc, type->storage != STORAGE_NULL, diff --git a/src/eval.c b/src/eval.c @@ -951,7 +951,7 @@ eval_expr(struct context *ctx, struct expression *in, struct expression *out) case EXPR_VAEND: case EXPR_VASTART: case EXPR_YIELD: - error(ctx, in->loc, "unvailable at translation time"); + error(ctx, in->loc, "unavailable at translation time"); return EVAL_INVALID; } assert(0); // Unreachable diff --git a/src/parse.c b/src/parse.c @@ -2443,10 +2443,13 @@ parse_global_decl(struct lexer *lexer, enum lexical_token mode, } } parse_identifier(lexer, &i->ident, false); - want(lexer, T_COLON, NULL); - i->type = parse_type(lexer); - if (mode == T_CONST) { - i->type->flags |= TYPE_CONST; + if (lex(lexer, &tok) == T_COLON) { + i->type = parse_type(lexer); + if (mode == T_CONST) { + i->type->flags |= TYPE_CONST; + } + } else { + unlex(lexer, &tok); } if (mode == T_DEF) { diff --git a/tests/11-globals.ha b/tests/11-globals.ha @@ -1,11 +1,28 @@ use rt::{compile, exited, EXIT_SUCCESS}; +// globals without type hint +def NOHINT = 1234z; +let nohint = 12z; +const nohintconst = 123z; +// with type defined afterwards +const nhval = nh { + field = 1, +}; +type nh = struct { + field: int, +}; + let x: int = 42, y: int = 69; fn write() void = { assert(x == 42 && y == 69); x = 1337; assert(x == 1337); + + assert(nohint == 12); + assert(nohintconst == 123); + assert(NOHINT == 1234); + assert(nhval.field == 1); }; let ar: [3]int = [1, 2, 3];