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:
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];