harec

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

commit 39d4cd337cc14b36482c00d837f112a3ef3b2359
parent 62c4357d7aba7223c18cf032cc8005d30414ea44
Author: Ember Sawady <ecs@d2evs.net>
Date:   Sun, 27 Nov 2022 01:08:58 +0000

Add dedicated error type

In order to avoid spurious errors

Signed-off-by: Ember Sawady <ecs@d2evs.net>

Diffstat:
Minclude/types.h | 3+++
Msrc/check.c | 11++++++-----
Msrc/eval.c | 4++++
Msrc/gen.c | 2++
Msrc/lex.c | 1+
Msrc/parse.c | 2++
Msrc/qinstr.c | 2++
Msrc/qtype.c | 4++++
Msrc/type_store.c | 48+++++++++++++++++++++++++-----------------------
Msrc/typedef.c | 2++
Msrc/types.c | 54+++++++++++++++++++++++++++++++++++-------------------
11 files changed, 86 insertions(+), 47 deletions(-)

diff --git a/include/types.h b/include/types.h @@ -42,6 +42,8 @@ enum type_storage { STORAGE_FCONST, STORAGE_ICONST, STORAGE_RCONST, + // For internal use only + STORAGE_ERROR, }; struct type; @@ -201,6 +203,7 @@ extern struct type // Primitive builtin_type_bool, builtin_type_char, + builtin_type_error, builtin_type_f32, builtin_type_f64, builtin_type_i8, diff --git a/src/check.c b/src/check.c @@ -69,9 +69,7 @@ verror(struct context *ctx, const struct location loc, struct expression *expr, { if (expr) { expr->type = EXPR_CONSTANT; - // TODO: We should have a separate type for errors, to avoid - // spurious errors - expr->result = &builtin_type_void; + expr->result = &builtin_type_error; expr->terminates = false; expr->loc = loc; } @@ -848,6 +846,8 @@ type_promote(struct type_store *store, return b; } return NULL; + case STORAGE_ERROR: + return b; // Cannot be promoted case STORAGE_BOOL: case STORAGE_FUNCTION: @@ -1711,6 +1711,7 @@ check_expr_constant(struct context *ctx, break; case STORAGE_CHAR: case STORAGE_ENUM: + case STORAGE_ERROR: case STORAGE_UINTPTR: case STORAGE_ALIAS: case STORAGE_FUNCTION: @@ -2879,7 +2880,7 @@ check_expr_tuple(struct context *ctx, } else { expr->result = type_store_lookup_tuple(ctx->store, aexpr->loc, &result); - if (expr->result == &builtin_type_void) { + if (expr->result == &builtin_type_error) { // an error occured return; } @@ -3033,7 +3034,7 @@ check_expr_vaend(struct context *ctx, "Expected vaend operand to be valist"); return; } - expr->result = &builtin_type_void; + expr->result = &builtin_type_error; } void diff --git a/src/eval.c b/src/eval.c @@ -134,6 +134,7 @@ itrunc(const struct type *type, uintmax_t val) return itrunc(type_dealias(type), val); case STORAGE_ENUM: return itrunc(type->alias.type, val); + case STORAGE_ERROR: case STORAGE_F32: case STORAGE_F64: case STORAGE_FCONST: @@ -406,6 +407,7 @@ eval_const(struct context *ctx, struct expression *in, struct expression *out) assert(0); // TODO case STORAGE_BOOL: case STORAGE_CHAR: + case STORAGE_ERROR: case STORAGE_F32: case STORAGE_F64: case STORAGE_FCONST: @@ -602,6 +604,7 @@ eval_cast(struct context *ctx, struct expression *in, struct expression *out) case STORAGE_UNION: case STORAGE_VALIST: assert(0); // Invariant + case STORAGE_ERROR: case STORAGE_VOID: break; // no-op } @@ -662,6 +665,7 @@ constant_default(struct context *ctx, struct expression *v) { struct expression b = {0}; switch (type_dealias(v->result)->storage) { + case STORAGE_ERROR: case STORAGE_POINTER: case STORAGE_I16: case STORAGE_I32: diff --git a/src/gen.c b/src/gen.c @@ -1801,6 +1801,7 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr) break; case STORAGE_ALIAS: case STORAGE_BOOL: + case STORAGE_ERROR: case STORAGE_FCONST: case STORAGE_FUNCTION: case STORAGE_ICONST: @@ -3756,6 +3757,7 @@ gen_data_item(struct gen_context *ctx, struct expression *expr, break; case STORAGE_UNION: case STORAGE_ALIAS: + case STORAGE_ERROR: case STORAGE_FCONST: case STORAGE_FUNCTION: case STORAGE_ICONST: diff --git a/src/lex.c b/src/lex.c @@ -1181,6 +1181,7 @@ token_str(const struct token *tok) case STORAGE_BOOL: case STORAGE_CHAR: case STORAGE_ENUM: + case STORAGE_ERROR: case STORAGE_FUNCTION: case STORAGE_POINTER: case STORAGE_NULL: diff --git a/src/parse.c b/src/parse.c @@ -852,6 +852,8 @@ parse_constant(struct lexer *lexer) case STORAGE_UNION: case STORAGE_VALIST: assert(0); // Handled in a different nonterminal + case STORAGE_ERROR: + assert(0); // Invariant } return exp; } diff --git a/src/qinstr.c b/src/qinstr.c @@ -69,6 +69,7 @@ store_for_type(struct gen_context *ctx, const struct type *type) case STORAGE_ALIAS: return store_for_type(ctx, type->alias.type); case STORAGE_ARRAY: + case STORAGE_ERROR: case STORAGE_FCONST: case STORAGE_FUNCTION: case STORAGE_ICONST: @@ -136,6 +137,7 @@ load_for_type(struct gen_context *ctx, const struct type *type) case STORAGE_ALIAS: return load_for_type(ctx, type->alias.type); case STORAGE_ARRAY: + case STORAGE_ERROR: case STORAGE_FCONST: case STORAGE_FUNCTION: case STORAGE_ICONST: diff --git a/src/qtype.c b/src/qtype.c @@ -158,6 +158,7 @@ aggregate_lookup(struct gen_context *ctx, const struct type *type) } break; case STORAGE_ENUM: + case STORAGE_ERROR: case STORAGE_ALIAS: case STORAGE_CHAR: case STORAGE_I8: @@ -238,6 +239,7 @@ qtype_lookup(struct gen_context *ctx, return ctx->arch.ptr; case STORAGE_VALIST: return ctx->arch.ptr; + case STORAGE_ERROR: case STORAGE_VOID: abort(); // Invariant case STORAGE_FCONST: @@ -293,6 +295,8 @@ type_is_aggregate(const struct type *type) case STORAGE_RCONST: lower_const(type, NULL); return false; + case STORAGE_ERROR: + assert(0); // Invariant } assert(0); // Unreachable } diff --git a/src/type_store.c b/src/type_store.c @@ -79,6 +79,8 @@ builtin_type_for_storage(enum type_storage storage, bool is_const) return is_const ? &builtin_type_const_bool : &builtin_type_bool; case STORAGE_CHAR: return is_const ? &builtin_type_const_char : &builtin_type_char; + case STORAGE_ERROR: + return &builtin_type_error; case STORAGE_F32: return is_const ? &builtin_type_const_f32 : &builtin_type_f32; case STORAGE_F64: @@ -367,7 +369,7 @@ tagged_or_atagged_member(struct type_store *store, error(store->check_context, _atype->loc, "Unknown object '%s'", identifier_unparse(&_atype->alias)); - *type = &builtin_type_void; + *type = &builtin_type_error; return; } if (obj->otype != O_SCAN) { @@ -378,7 +380,7 @@ tagged_or_atagged_member(struct type_store *store, error(store->check_context, _atype->loc, "Object '%s' is not a type", identifier_unparse(&obj->ident)); - *type = &builtin_type_void; + *type = &builtin_type_error; return; } } @@ -389,7 +391,7 @@ tagged_or_atagged_member(struct type_store *store, error(store->check_context, _atype->loc, "Object '%s' is not a type", identifier_unparse(&obj->ident)); - *type = &builtin_type_void; + *type = &builtin_type_error; return; } _atype = idecl->decl.type.type; @@ -520,7 +522,7 @@ tagged_init_from_atype(struct type_store *store, collect_atagged_memb(store, tu, &atype->tagged_union, &i); tagged_init(store, type, tu, nmemb); if (!enforce_tagged_invariants(store, atype->loc, type)) { - *type = builtin_type_void; + *type = builtin_type_error; }; } @@ -646,10 +648,10 @@ type_init_from_atype(struct type_store *store, type->storage = atype->storage; type->flags = atype->flags; - // TODO: Use a dedicated error type instead of void for errors const struct scope_object *obj = NULL; const struct type *builtin; switch (type->storage) { + case STORAGE_ERROR: case STORAGE_FCONST: case STORAGE_ICONST: case STORAGE_RCONST: @@ -686,7 +688,7 @@ type_init_from_atype(struct type_store *store, error(store->check_context, atype->loc, "Unresolvable identifier '%s'", identifier_unparse(&atype->alias)); - *type = builtin_type_void; + *type = builtin_type_error; return (struct dimensions){0}; } @@ -709,7 +711,7 @@ type_init_from_atype(struct type_store *store, error(store->check_context, atype->loc, "Object '%s' is not a type", identifier_unparse(&obj->ident)); - *type = builtin_type_void; + *type = builtin_type_error; return (struct dimensions){0}; } @@ -742,13 +744,13 @@ type_init_from_atype(struct type_store *store, if (type->array.length != SIZE_UNDEFINED && memb.size == 0) { error(store->check_context, atype->loc, "Type of size 0 is not a valid array member"); - *type = builtin_type_void; + *type = builtin_type_error; return (struct dimensions){0}; } if (memb.size == SIZE_UNDEFINED) { error(store->check_context, atype->loc, "Type of undefined size is not a valid array member"); - *type = builtin_type_void; + *type = builtin_type_error; return (struct dimensions){0}; } @@ -777,13 +779,13 @@ type_init_from_atype(struct type_store *store, if (param->type->size == 0) { error(store->check_context, atype->loc, "Function parameter types must have nonzero size"); - *type = builtin_type_void; + *type = builtin_type_error; return (struct dimensions){0}; } if (param->type->size == SIZE_UNDEFINED) { error(store->check_context, atype->loc, "Function parameter types must have defined size"); - *type = builtin_type_void; + *type = builtin_type_error; return (struct dimensions){0}; } if (atype->func.variadism == VARIADISM_HARE @@ -970,7 +972,7 @@ type_store_lookup_pointer(struct type_store *store, struct location loc, if (referent->storage == STORAGE_NULL) { error(store->check_context, loc, "Null type not allowed in this context"); - return &builtin_type_void; + return &builtin_type_error; } referent = lower_const(referent, NULL); @@ -993,7 +995,7 @@ type_store_lookup_array(struct type_store *store, struct location loc, if (members->storage == STORAGE_NULL) { error(store->check_context, loc, "Null type not allowed in this context"); - return &builtin_type_void; + return &builtin_type_error; } members = lower_const(members, NULL); // XXX: I'm not sure these checks are *exactly* right, we might still @@ -1001,12 +1003,12 @@ type_store_lookup_array(struct type_store *store, struct location loc, if (len != SIZE_UNDEFINED && members->size == 0) { error(store->check_context, loc, "Type of size 0 is not a valid array member"); - return &builtin_type_void; + return &builtin_type_error; } if (members->size == SIZE_UNDEFINED) { error(store->check_context, loc, "Type of undefined size is not a valid member of a bounded array"); - return &builtin_type_void; + return &builtin_type_error; } assert(members->align != 0); assert(members->align != ALIGN_UNDEFINED); @@ -1033,18 +1035,18 @@ type_store_lookup_slice(struct type_store *store, struct location loc, if (members->storage == STORAGE_NULL) { error(store->check_context, loc, "Null type not allowed in this context"); - return &builtin_type_void; + return &builtin_type_error; } members = lower_const(members, NULL); if (members->size == 0) { error(store->check_context, loc, "Type of size 0 is not a valid slice member"); - return &builtin_type_void; + return &builtin_type_error; } if (members->size == SIZE_UNDEFINED) { error(store->check_context, loc, "Type of undefined size is not a valid slice member"); - return &builtin_type_void; + return &builtin_type_error; } assert(members->align != 0); assert(members->align != ALIGN_UNDEFINED); @@ -1109,7 +1111,7 @@ type_store_lookup_tagged(struct type_store *store, struct location loc, { const struct type *type = lookup_tagged(store, tags); if (!enforce_tagged_invariants(store, loc, type)) { - return &builtin_type_void; + return &builtin_type_error; } return type_store_lookup_type(store, type); } @@ -1158,18 +1160,18 @@ type_store_lookup_tuple(struct type_store *store, struct location loc, if (t->type->storage == STORAGE_NULL) { error(store->check_context, loc, "Null type not allowed in this context"); - return &builtin_type_void; + return &builtin_type_error; } t->type = lower_const(t->type, NULL); if (t->type->size == 0) { error(store->check_context, loc, "Type of size 0 is not a valid tuple member"); - return &builtin_type_void; + return &builtin_type_error; } if (t->type->size == SIZE_UNDEFINED) { error(store->check_context, loc, "Type of undefined size is not a valid tuple member"); - return &builtin_type_void; + return &builtin_type_error; } assert(t->type->align != 0); assert(t->type->align != ALIGN_UNDEFINED); @@ -1200,7 +1202,7 @@ type_store_lookup_enum(struct type_store *store, const struct ast_type *atype, && type.alias.type->storage != STORAGE_RUNE) { error(store->check_context, atype->loc, "Enum storage must be an integer or rune"); - return &builtin_type_void; + return &builtin_type_error; } type.size = type.alias.type->size; type.align = type.alias.type->size; diff --git a/src/typedef.c b/src/typedef.c @@ -169,6 +169,7 @@ emit_const(const struct expression *expr, FILE *out) assert(0); // TODO case STORAGE_ALIAS: case STORAGE_CHAR: + case STORAGE_ERROR: case STORAGE_FUNCTION: case STORAGE_POINTER: case STORAGE_VALIST: @@ -235,6 +236,7 @@ emit_type(const struct type *type, FILE *out) switch (type->storage) { case STORAGE_BOOL: case STORAGE_CHAR: + case STORAGE_ERROR: case STORAGE_F32: case STORAGE_F64: case STORAGE_FCONST: diff --git a/src/types.c b/src/types.c @@ -119,6 +119,8 @@ type_storage_unparse(enum type_storage storage) return "f32"; case STORAGE_F64: return "f64"; + case STORAGE_ERROR: + return "invalid"; case STORAGE_FCONST: return "fconst"; case STORAGE_FUNCTION: @@ -202,6 +204,7 @@ type_is_integer(const struct type *type) return false; case STORAGE_CHAR: case STORAGE_ENUM: + case STORAGE_ERROR: case STORAGE_I8: case STORAGE_I16: case STORAGE_I32: @@ -243,6 +246,7 @@ type_is_numeric(const struct type *type) case STORAGE_NULL: case STORAGE_VALIST: return false; + case STORAGE_ERROR: case STORAGE_ENUM: case STORAGE_I8: case STORAGE_I16: @@ -272,7 +276,8 @@ type_is_float(const struct type *type) { type = type_dealias(type); return type->storage == STORAGE_F32 || type->storage == STORAGE_F64 - || type->storage == STORAGE_FCONST; + || type->storage == STORAGE_FCONST + || type->storage == STORAGE_ERROR; } bool @@ -286,6 +291,7 @@ type_is_signed(const struct type *type) case STORAGE_VOID: case STORAGE_ARRAY: case STORAGE_ENUM: + case STORAGE_ERROR: // XXX? case STORAGE_FUNCTION: case STORAGE_POINTER: case STORAGE_SLICE: @@ -343,6 +349,7 @@ type_hash(const struct type *type) switch (type->storage) { case STORAGE_BOOL: case STORAGE_CHAR: + case STORAGE_ERROR: case STORAGE_F32: case STORAGE_F64: case STORAGE_I8: @@ -855,6 +862,8 @@ type_is_assignable(const struct type *to, const struct type *from) case STORAGE_UNION: case STORAGE_VALIST: return false; + case STORAGE_ERROR: + return true; } assert(0); // Unreachable @@ -970,6 +979,8 @@ type_is_castable(const struct type *to, const struct type *from) case STORAGE_UNION: case STORAGE_VALIST: return false; + case STORAGE_ERROR: + return true; case STORAGE_TAGGED: case STORAGE_ALIAS: assert(0); // Handled above @@ -1067,24 +1078,24 @@ builtin_types_init(const char *target) exit(EXIT_FAILURE); } struct type *builtins[] = { - &builtin_type_bool, &builtin_type_char, &builtin_type_f32, - &builtin_type_f64, &builtin_type_i8, &builtin_type_i16, - &builtin_type_i32, &builtin_type_i64, &builtin_type_int, - &builtin_type_u8, &builtin_type_u16, &builtin_type_u32, - &builtin_type_u64, &builtin_type_uint, &builtin_type_uintptr, - &builtin_type_null, &builtin_type_rune, &builtin_type_size, - &builtin_type_void, &builtin_type_const_bool, - &builtin_type_const_char, &builtin_type_const_f32, - &builtin_type_const_f64, &builtin_type_const_i8, - &builtin_type_const_i16, &builtin_type_const_i32, - &builtin_type_const_i64, &builtin_type_const_int, - &builtin_type_const_u8, &builtin_type_const_u16, - &builtin_type_const_u32, &builtin_type_const_u64, - &builtin_type_const_uint, &builtin_type_const_uintptr, - &builtin_type_const_rune, &builtin_type_const_size, - &builtin_type_const_void, &builtin_type_ptr_const_char, - &builtin_type_str, &builtin_type_const_str, - &builtin_type_valist, + &builtin_type_bool, &builtin_type_char, &builtin_type_error, + &builtin_type_f32, &builtin_type_f64, &builtin_type_i8, + &builtin_type_i16, &builtin_type_i32, &builtin_type_i64, + &builtin_type_int, &builtin_type_u8, &builtin_type_u16, + &builtin_type_u32, &builtin_type_u64, &builtin_type_uint, + &builtin_type_uintptr, &builtin_type_null, &builtin_type_rune, + &builtin_type_size, &builtin_type_void, + &builtin_type_const_bool, &builtin_type_const_char, + &builtin_type_const_f32, &builtin_type_const_f64, + &builtin_type_const_i8, &builtin_type_const_i16, + &builtin_type_const_i32, &builtin_type_const_i64, + &builtin_type_const_int, &builtin_type_const_u8, + &builtin_type_const_u16, &builtin_type_const_u32, + &builtin_type_const_u64, &builtin_type_const_uint, + &builtin_type_const_uintptr, &builtin_type_const_rune, + &builtin_type_const_size, &builtin_type_const_void, + &builtin_type_ptr_const_char, &builtin_type_str, + &builtin_type_const_str, &builtin_type_valist, }; for (size_t i = 0; i < sizeof(builtins) / sizeof(builtins[0]); ++i) { builtins[i]->id = type_hash(builtins[i]); @@ -1102,6 +1113,11 @@ builtin_type_char = { .size = 1, .align = 1, }, +builtin_type_error = { + .storage = STORAGE_ERROR, + .size = 1, + .align = 1, +}, builtin_type_f32 = { .storage = STORAGE_F32, .size = 4,