From 1035de3b3675d069de68655334d4fccaf55a85cf Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 4 Mar 2023 22:14:29 +0100 Subject: [PATCH] Remove all locations when enums are implicitly lowered to integers. Remove the menagerie of flattening functions. Incidentally this also fixes a bunch of not-yet tested errors with distinct types. --- src/compiler/codegen_internal.h | 34 ++++++++-- src/compiler/compiler_internal.h | 67 +++++++++---------- src/compiler/headers.c | 14 ++-- src/compiler/llvm_codegen_expr.c | 8 +-- src/compiler/llvm_codegen_type.c | 4 +- src/compiler/parse_global.c | 9 ++- src/compiler/sema_casts.c | 22 +++--- src/compiler/sema_decls.c | 37 +++++----- src/compiler/sema_expr.c | 65 ++++++++++-------- src/compiler/sema_initializers.c | 2 +- src/compiler/sema_stmts.c | 8 ++- src/compiler/sema_types.c | 2 +- src/compiler/types.c | 12 ++-- src/version.h | 2 +- .../compile_time/ct_switch_more_checks.c3 | 2 +- test/test_suite/types/enum_inference.c3 | 2 +- 16 files changed, 167 insertions(+), 123 deletions(-) diff --git a/src/compiler/codegen_internal.h b/src/compiler/codegen_internal.h index 1bfadc2f5..4d3f7fd26 100644 --- a/src/compiler/codegen_internal.h +++ b/src/compiler/codegen_internal.h @@ -18,13 +18,33 @@ static inline bool abi_type_is_valid(AbiType type); static inline Type *type_lowering(Type *type) { - Type *canonical = type_flatten(type); - if (canonical->type_kind == TYPE_ENUM) return canonical->decl->enums.type_info->type->canonical; - if (canonical->type_kind == TYPE_TYPEID) return type_iptr->canonical; - if (canonical->type_kind == TYPE_ANYERR) return type_iptr->canonical; - if (canonical->type_kind == TYPE_FAULTTYPE) return type_iptr->canonical; - if (canonical->type_kind == TYPE_BITSTRUCT) return type_lowering(canonical->decl->bitstruct.base_type->type); - return canonical; + while (1) + { + type = type->canonical; + switch (type->type_kind) + { + case TYPE_TYPEDEF: + UNREACHABLE + case TYPE_OPTIONAL: + type = type->optional; + continue; + case TYPE_DISTINCT: + type = type->decl->distinct_decl.base_type; + continue; + case TYPE_ENUM: + type = type->decl->enums.type_info->type; + continue; + case TYPE_ANYERR: + case TYPE_TYPEID: + case TYPE_FAULTTYPE: + return type_iptr->canonical; + case TYPE_BITSTRUCT: + type = type->decl->bitstruct.base_type->type; + continue; + default: + return type; + } + } } static inline Type *type_reduced_from_expr(Expr *expr) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 61d881778..3a90f3203 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2390,6 +2390,7 @@ INLINE bool type_is_integer_or_bool_kind(Type *type); INLINE bool type_is_numeric(Type *type); INLINE bool type_is_inferred(Type *type); INLINE bool type_underlying_is_numeric(Type *type); +INLINE bool type_underlying_may_add_sub(Type *type); INLINE bool type_is_pointer(Type *type); INLINE bool type_is_arraylike(Type *type); INLINE bool type_is_any_arraylike(Type *type); @@ -2408,9 +2409,8 @@ INLINE Type *type_vector_type(Type *type); static inline CanonicalType *type_pointer_type(Type *type); static inline Type *type_flatten(Type *type); -static inline Type *type_flatten_distinct(Type *type); -static inline Type *type_flatten_distinct_optional(Type *type); static inline bool type_flat_is_char_array(Type *type); +static inline Type *type_base(Type *type); INLINE TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span); INLINE TypeInfo *type_info_new_base(Type *type, SourceSpan span); @@ -2741,37 +2741,7 @@ INLINE Type *type_flatten_for_bitstruct(Type *type) return type; } -static inline Type *type_flatten_distinct_optional(Type *type) -{ - while (1) - { - switch (type->type_kind) - { - case TYPE_TYPEDEF: - type = type->canonical; - continue; - case TYPE_OPTIONAL: - type = type->optional; - continue; - case TYPE_DISTINCT: - type = type->decl->distinct_decl.base_type; - continue; - default: - return type; - } - } -} -static inline Type *type_flatten_distinct(Type *type) -{ - type = type->canonical; - while (type->type_kind == TYPE_DISTINCT) - { - type = type->decl->distinct_decl.base_type; - } - return type; -} - -static inline Type *type_flatten(Type *type) +static inline Type *type_base(Type *type) { while (1) { @@ -2797,9 +2767,32 @@ static inline Type *type_flatten(Type *type) } } +static inline Type *type_flatten(Type *type) +{ + while (1) + { + type = type->canonical; + switch (type->type_kind) + { + case TYPE_DISTINCT: + type = type->decl->distinct_decl.base_type; + break; + case TYPE_OPTIONAL: + type = type->optional; + break; + case TYPE_OPTIONAL_ANY: + return type_void; + case TYPE_TYPEDEF: + UNREACHABLE + default: + return type; + } + } +} + static inline bool type_flat_is_char_array(Type *type) { - type = type_flatten_distinct(type); + type = type_flatten(type); if (type->type_kind != TYPE_ARRAY) return false; switch (type->array.base->type_kind) { @@ -2860,6 +2853,12 @@ INLINE bool type_underlying_is_numeric(Type *type) return type_is_numeric(type_flatten(type)); } +INLINE bool type_underlying_may_add_sub(Type *type) +{ + type = type_flatten(type); + return type->type_kind == TYPE_ENUM || type_is_numeric(type_flatten(type)); +} + INLINE bool type_flat_is_vector(Type *type) { return type_flatten(type)->type_kind == TYPE_VECTOR; diff --git a/src/compiler/headers.c b/src/compiler/headers.c index d6ce875dd..8d046b465 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -14,7 +14,7 @@ static void header_gen_maybe_generate_type(FILE *file, HTable *table, Type *type static bool type_is_func_pointer(Type *type) { if (type->type_kind != TYPE_DISTINCT && type->type_kind != TYPE_TYPEDEF) return false; - type = type_flatten_distinct(type); + type = type_flatten(type); if (type->type_kind != TYPE_POINTER) return false; return type->pointer->type_kind == TYPE_FUNC; } @@ -41,14 +41,13 @@ static void header_print_type(FILE *file, Type *type) OUTPUT("%s", decl_get_extname(type->decl)); return; } - type = type_flatten_distinct(type); + assert(!type_is_optional(type)); + type = type_flatten(type); switch (type->type_kind) { case CT_TYPES: - UNREACHABLE case TYPE_OPTIONAL: case TYPE_OPTIONAL_ANY: - // If this is reachable then we are not doing the proper lowering. UNREACHABLE case TYPE_VOID: OUTPUT("void"); @@ -161,7 +160,7 @@ static void header_print_type(FILE *file, Type *type) static void header_gen_function_ptr(FILE *file, HTable *table, Type *type) { - TypeFunction *fun = &type_flatten_distinct(type)->pointer->function; + TypeFunction *fun = &type_flatten(type)->pointer->function; Signature *sig = fun->signature; Type *rtype = typeinfotype(sig->rtype); Type *extra_ret = NULL; @@ -356,7 +355,8 @@ static void header_gen_maybe_generate_type(FILE *file, HTable *table, Type *type return; } RETRY: - type = type_flatten_distinct(type); + if (type_is_optional(type)) return; + type = type_flatten(type); switch (type->type_kind) { case TYPE_POISONED: @@ -468,7 +468,7 @@ static void header_gen_global_var(FILE *file, FILE *file_type, HTable *table, De Type *type = decl->type->canonical; // Optionals are ignored. if (type_is_optional(type)) return; - type = type_flatten_distinct(type); + type = type_flatten(type); // Flatten bitstructs. if (type->type_kind == TYPE_BITSTRUCT) type = type->decl->bitstruct.base_type->type->canonical; // We will lower some consts to defines, if they are: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 0af614fea..94a1e7a3f 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1058,7 +1058,7 @@ static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Ex llvm_emit_expr(c, be_value, exprptr(expr->binary_expr.right)); } - Type *parent_type = type_flatten_distinct(parent_expr->type); + Type *parent_type = type_flatten(parent_expr->type); if (type_lowering(parent_type)->type_kind == TYPE_ARRAY) { llvm_emit_bitassign_array(c, be_value, parent, parent_type->decl, member); @@ -1092,7 +1092,7 @@ static inline void llvm_emit_access_addr(GenContext *c, BEValue *be_value, Expr llvm_emit_expr(c, be_value, parent); Decl *member = expr->access_expr.ref; - Type *flat_type = type_flatten_distinct_optional(parent->type); + Type *flat_type = type_flatten(parent->type); if (flat_type->type_kind == TYPE_ENUM) { llvm_value_rvalue(c, be_value); @@ -2572,7 +2572,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r Expr *start = exprptr(slice->subscript_expr.range.start); Expr *end = exprptrzero(slice->subscript_expr.range.end); - Type *parent_type = type_flatten_distinct(parent_expr->type); + Type *parent_type = type_flatten(parent_expr->type); BEValue parent_addr_x; llvm_emit_expr(c, &parent_addr_x, parent_expr); llvm_value_addr(c, &parent_addr_x); @@ -4400,7 +4400,7 @@ static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Float f) static inline void llvm_emit_const_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr) { - if (llvm_is_global_eval(c) || type_flat_is_vector(expr->type) || type_flatten_distinct(expr->type)->type_kind == TYPE_BITSTRUCT) + if (llvm_is_global_eval(c) || type_flat_is_vector(expr->type) || type_flatten(expr->type)->type_kind == TYPE_BITSTRUCT) { llvm_value_set(value, llvm_emit_const_initializer(c, expr->const_expr.initializer), expr->type); return; diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 524ac266a..8ee4672b9 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -307,7 +307,7 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) assert(LLVMGetTypeContext(any_type->backend_type) == c->context && "Should have been purged"); return any_type->backend_type; } - Type *type = type_flatten(any_type); + Type *type = type_lowering(any_type); if (type != any_type) { return any_type->backend_type = llvm_get_type(c, type); @@ -523,7 +523,7 @@ static LLVMValueRef llvm_get_introspection_for_enum(GenContext *c, Type *type) } LLVMValueRef names = llvm_get_array(c->chars_type, values, elements); - LLVMValueRef val = llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_ENUM, type_flatten(type), elements, names, is_external); + LLVMValueRef val = llvm_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_ENUM, type_base(type), elements, names, is_external); LLVMTypeRef val_type; diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 9461f92fb..b5e86dc1c 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -2268,8 +2268,12 @@ static inline Decl *parse_fault_declaration(ParseContext *c, bool is_private) static inline bool parse_enum_spec(ParseContext *c, TypeInfo **type_ref, Decl*** parameters_ref) { - ASSIGN_TYPE_OR_RET(*type_ref, parse_type(c), false); - + ASSIGN_TYPE_OR_RET(*type_ref, parse_optional_type(c), false); + if ((*type_ref)->optional) + { + SEMA_ERROR(*type_ref, "An enum can't have an optional type."); + return false; + } if (!try_consume(c, TOKEN_LPAREN)) return true; while (!try_consume(c, TOKEN_RPAREN)) { @@ -2330,6 +2334,7 @@ static inline Decl *parse_enum_declaration(ParseContext *c, bool is_private) CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl); decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span); + while (!try_consume(c, TOKEN_RBRACE)) { Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, symstr(c), c->span); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 48f7c2cb4..1de54677e 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -438,8 +438,8 @@ static bool integer_to_pointer(Expr *expr, Type *type) */ static void enum_to_int_lowering(Expr* expr) { - assert(type_flatten_distinct_optional(expr->type)->type_kind == TYPE_ENUM); - Type *underlying_type = type_flatten_distinct_optional(expr->type)->decl->enums.type_info->type; + assert(type_flatten(expr->type)->type_kind == TYPE_ENUM); + Type *underlying_type = type_base(expr->type); if (expr->expr_kind == EXPR_CONST) { assert(expr->const_expr.const_kind == CONST_ENUM); @@ -962,8 +962,8 @@ static bool cast_from_pointer(SemaContext *context, Expr *expr, Type *from, Type Type *from_base = pointee->array.base; if (is_explicit) { - subarray_base = type_flatten_distinct(subarray_base); - from_base = type_flatten_distinct(from_base); + subarray_base = type_flatten(subarray_base); + from_base = type_flatten(from_base); } // Same base type? E.g. int[2]* -> int[], then we're done. if (subarray_base == from_base) return cast_with_optional(expr, to_type, add_optional); @@ -1335,7 +1335,7 @@ RETRY: // The only conversion works if the expr is const. if (expr_is_const(expr) && type_is_integer(from)) { - to = type_flatten_distinct(to); + to = type_flatten(to); goto RETRY; } // Failure @@ -1416,7 +1416,7 @@ RETRY: case TYPE_DISTINCT: if (expr_is_const(expr)) { - to = type_flatten_distinct(to); + to = type_flatten(to); goto RETRY; } else @@ -1462,7 +1462,7 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo return cast(expr, to_type); } - Type *to = is_explicit ? type_flatten_distinct_optional(to_type) : type_no_optional(to_type)->canonical; + Type *to = is_explicit ? type_flatten(to_type) : type_no_optional(to_type)->canonical; // Step one, cast from optional. // This handles: @@ -1528,7 +1528,7 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo from_type = type_no_optional(from_type); // Grab the underlying expression type. - Type *from = is_explicit ? type_flatten_distinct(from_type) : from_type->canonical; + Type *from = is_explicit ? type_flatten(from_type) : from_type->canonical; // We may already be done. if (from == to) @@ -1543,7 +1543,7 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo if (cast_maybe_string_lit_to_char_array(expr, from, to, to_type)) return true; // For constant pointers cast into anything pointer-like: - if (expr_is_const_pointer(expr) && from == type_voidptr && type_flatten_distinct(to)->type_kind == TYPE_POINTER) + if (expr_is_const_pointer(expr) && from == type_voidptr && type_flatten(to)->type_kind == TYPE_POINTER) { assert(!add_optional); expr->type = to_type; @@ -1873,7 +1873,7 @@ bool cast(Expr *expr, Type *to_type) assert(!type_is_optional(to_type)); Type *from_type = expr->type; bool from_is_optional = false; - Type *to = type_flatten_distinct(to_type); + Type *to = type_flatten(to_type); // Special case *! => error if (to == type_anyerr || to->type_kind == TYPE_FAULTTYPE) @@ -1892,7 +1892,7 @@ bool cast(Expr *expr, Type *to_type) from_type = from_type->optional; from_is_optional = true; } - from_type = type_flatten_distinct(from_type); + from_type = type_flatten(from_type); if (type_len_is_inferred(to_type)) { to_type = from_type; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 07919e3ee..0ee54efe7 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -154,7 +154,7 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent if (!sema_resolve_type_info_maybe_inferred(context, decl->var.type_info, true)) return decl_poison(decl); decl->type = decl->var.type_info->type; decl->resolve_status = RESOLVE_DONE; - Type *member_type = type_flatten_distinct(decl->type); + Type *member_type = type_flatten(decl->type); if (member_type->type_kind == TYPE_ARRAY) { if (member_type->array.len == 0) @@ -302,7 +302,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl * } continue; } - Type *member_type = type_flatten_distinct(member->type); + Type *member_type = type_flatten(member->type); if (member_type->type_kind == TYPE_STRUCT && member_type->decl->has_variable_array) { if (i != member_count - 1) @@ -911,7 +911,12 @@ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl) } TypeInfo *info = decl->distinct_decl.typedef_decl.type_info; if (!sema_resolve_type_info(context, info)) return false; - Type *base = type_flatten_distinct(info->type); + if (type_is_optional(info->type)) + { + SEMA_ERROR(decl, "You cannot create a distinct type from an optional."); + return false; + } + Type *base = type_flatten(info->type); decl->distinct_decl.base_type = base; switch (base->type_kind) { @@ -924,8 +929,7 @@ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl) return false; case TYPE_OPTIONAL_ANY: case TYPE_OPTIONAL: - SEMA_ERROR(decl, "You cannot create a distinct type from am optional."); - return false; + UNREACHABLE case TYPE_FAULTTYPE: SEMA_ERROR(decl, "You cannot create a distinct type from a fault type."); return false; @@ -1014,7 +1018,9 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl) if (!sema_resolve_type_info(context, decl->enums.type_info)) return false; Type *type = decl->enums.type_info->type; - Type *flat_underlying_type = type_flatten_distinct(type); + assert(!type_is_optional(type) && "Already stopped when parsing."); + + Type *flat_underlying_type = type_flatten(type); // Require an integer type if (!type_is_integer(flat_underlying_type)) { @@ -1980,13 +1986,13 @@ static inline MainType sema_find_main_type(SemaContext *context, Signature *sig, return MAIN_TYPE_NO_ARGS; break; case 1: - arg_type = type_flatten_distinct(params[0]->type); + arg_type = type_flatten(params[0]->type); if (arg_type == type_get_subarray(type_get_subarray(type_char))) return MAIN_TYPE_ARGS; SEMA_ERROR(params[0], "Expected a parameter of type 'String[]'."); return MAIN_TYPE_ERROR; case 2: - arg_type = type_flatten_distinct(params[0]->type); - arg_type2 = type_flatten_distinct(params[1]->type); + arg_type = type_flatten(params[0]->type); + arg_type2 = type_flatten(params[1]->type); if (arg_type != type_cint) { SEMA_ERROR(params[0], @@ -2007,8 +2013,8 @@ static inline MainType sema_find_main_type(SemaContext *context, Signature *sig, return MAIN_TYPE_RAW; case 3: if (!is_win32 || is_winmain) break; - arg_type = type_flatten_distinct(params[0]->type); - arg_type2 = type_flatten_distinct(params[1]->type); + arg_type = type_flatten(params[0]->type); + arg_type2 = type_flatten(params[1]->type); if (arg_type != type_voidptr) { SEMA_ERROR(params[0], "Expected a parameter of type 'void*' (HINSTANCE)"); @@ -2019,7 +2025,7 @@ static inline MainType sema_find_main_type(SemaContext *context, Signature *sig, SEMA_ERROR(params[1], "Expected a parameter of type 'String[]'."); return MAIN_TYPE_ERROR; } - if (type_flatten_distinct(params[2]->type) != type_cint) + if (type_flatten(params[2]->type) != type_cint) { SEMA_ERROR(params[2], "Expected a parameter of type %s for the 'showCmd' parameter.", type_quoted_error_string(type_cint)); @@ -2193,7 +2199,7 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl) } Signature *signature = &decl->func_decl.signature; TypeInfo *rtype_info = type_infoptr(signature->rtype); - Type *rtype = type_flatten_distinct(rtype_info->type); + Type *rtype = rtype_info->type; bool is_int_return = true; bool is_err_return = false; if (rtype->type_kind == TYPE_OPTIONAL_ANY) is_err_return = true; @@ -2207,9 +2213,10 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl) is_int_return = false; is_err_return = true; } + if (type_is_void(rtype)) is_int_return = false; - if (type_is_integer(rtype) && rtype != type_cint) + if (is_int_return && type_flatten(rtype) != type_cint) { SEMA_ERROR(rtype_info, "Expected a return type of 'void' or %s.", type_quoted_error_string(type_cint)); return false; @@ -2537,7 +2544,7 @@ bool sema_analyse_decl_type(SemaContext *context, Type *type, SourceSpan span) break; } if (!type_is_optional(type)) return true; - if (type_is_optional_any(type) || type_flatten_distinct(type->optional) == type_void) + if (type_is_optional_any(type) || type->optional == type_void) { sema_error_at(span, "The use of 'void!' as a variable type is not permitted, use %s instead.", type_quoted_error_string(type_anyerr)); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 36ae218a5..c6ad586a2 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2030,7 +2030,7 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl if (decl == NULL) { return sema_expr_analyse_var_call(context, expr, - type_flatten_distinct_optional(exprptr(expr->call_expr.function)->type), optional); + type_flatten(exprptr(expr->call_expr.function)->type), optional); } switch (decl->decl_kind) { @@ -2104,7 +2104,7 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr) return false; default: { - Type *type = type_flatten_distinct(func_expr->type); + Type *type = type_flatten(func_expr->type); if (type->type_kind == TYPE_POINTER) { decl = NULL; @@ -2658,7 +2658,7 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr) // Retain the original type when doing distinct slices. Type *result_type = type_get_subarray(inner_type); Type *original_type_canonical = original_type->canonical; - if (original_type_canonical->type_kind == TYPE_DISTINCT && type_flatten_distinct(original_type_canonical) == result_type) + if (original_type_canonical->type_kind == TYPE_DISTINCT && type_base(original_type_canonical) == result_type) { result_type = original_type; } @@ -2932,7 +2932,7 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e break; } - Type *underlying_type = type_flatten_distinct(decl->type); + Type *underlying_type = type_flatten(decl->type); if (!type_is_union_or_strukt(underlying_type) && underlying_type->type_kind != TYPE_BITSTRUCT) { @@ -2975,16 +2975,27 @@ static inline bool sema_create_const_kind(Expr *expr, Type *type) { Module *module = global_context_find_module(kw_std__core__types); Decl *type_kind = module ? module_find_symbol(module, kw_typekind) : NULL; - Type *type_for_kind = type_kind ? type_kind->type : type_char; unsigned val = type_get_introspection_kind(type->type_kind); - assert(type_for_kind->type_kind == TYPE_ENUM); - expr_rewrite_const_int(expr, type_flatten(type_for_kind), val); - return cast(expr, type_for_kind); + if (!type_kind) + { + // No TypeKind defined, fallback to char. + expr_rewrite_const_int(expr, type_char, val); + return true; + } + Decl **values = type_kind->enums.values; + assert(vec_size(values) > val); + expr->type = type_kind->type; + expr->expr_kind = EXPR_CONST; + expr->const_expr = (ExprConst) { + .const_kind = CONST_ENUM, + .enum_err_val = values[val] + }; + return true; } static inline bool sema_create_const_len(SemaContext *context, Expr *expr, Type *type) { - assert(type == type_flatten_distinct(type) && "Should be flattened already."); + assert(type == type_flatten(type) && "Should be flattened already."); size_t len; switch (type->type_kind) { @@ -3347,7 +3358,7 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, assert(type == type->canonical); if (property == TYPE_PROPERTY_NONE) return false; - Type *flat = type_flatten_distinct(type); + Type *flat = type_flatten(type); switch (property) { case TYPE_PROPERTY_INF: @@ -3572,7 +3583,7 @@ CHECK_DEEPER: if (sema_expr_rewrite_to_typeid_property(context, expr, parent, kw)) return true; } - if (type_flat_is_vector(flat_type)) + if (flat_type->type_kind == TYPE_VECTOR) { unsigned len = strlen(kw); if (len <= 4) @@ -3603,7 +3614,7 @@ CHECK_DEEPER: if (kw == kw_ordinal) { - if (type->type_kind == TYPE_ENUM) + if (flat_type->type_kind == TYPE_ENUM) { if (!cast(current_parent, type->decl->enums.type_info->type)) return false; expr_replace(expr, current_parent); @@ -3612,7 +3623,7 @@ CHECK_DEEPER: } if (kw == kw_nameof) { - if (type->type_kind == TYPE_ENUM) + if (flat_type->type_kind == TYPE_ENUM) { if (current_parent->expr_kind == EXPR_CONST) { @@ -3625,7 +3636,7 @@ CHECK_DEEPER: return true; } } - if (type->type_kind == TYPE_FAULTTYPE || type->type_kind == TYPE_ANYERR) + if (flat_type->type_kind == TYPE_FAULTTYPE || flat_type->type_kind == TYPE_ANYERR) { if (current_parent->expr_kind == EXPR_CONST) { @@ -4215,7 +4226,7 @@ static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr * if (!sema_expr_check_assign(context, left)) return false; Type *no_fail = type_no_optional(left->type); - Type *flat = type_flatten_distinct(no_fail); + Type *flat = type_flatten(no_fail); // 3. If this is only defined for ints (*%, ^= |= &= %=) verify that this is an int. if (int_only && !type_flat_is_intlike(flat)) @@ -4338,10 +4349,10 @@ static bool sema_expr_analyse_add_sub_assign(SemaContext *context, Expr *expr, E return true; } - Type *lhs_flat = type_flatten_distinct(left_type_canonical); + Type *lhs_flat = type_flatten(left_type_canonical); if (lhs_flat->type_kind == TYPE_ENUM) { - if (!cast_implicit(context, right, lhs_flat->decl->enums.type_info->type)) return false; + if (!cast_implicit(context, right, type_base(lhs_flat))) return false; expr->type = type_add_optional(expr->type, optional); return true; } @@ -4350,7 +4361,7 @@ static bool sema_expr_analyse_add_sub_assign(SemaContext *context, Expr *expr, E if (!cast_implicit(context, right, left->type)) return false; // 9. We expect a numeric type on both left and right - if (!type_underlying_is_numeric(left->type)) + if (!type_underlying_may_add_sub(left->type)) { SEMA_ERROR(left, "Expected a numeric type here."); return false; @@ -5091,7 +5102,7 @@ static bool sema_binary_is_unsigned_always_false_comparison(SemaContext *context if (context->active_scope.flags & SCOPE_MACRO) return true; if (!expr_is_const(left) && !expr_is_const(right)) return true; if (!type_is_integer(left->type)) return true; - if (expr_is_const(left) && type_is_unsigned(type_flatten_distinct(right->type))) + if (expr_is_const(left) && type_is_unsigned(type_flatten(right->type))) { if (int_is_neg(left->const_expr.ixx)) { @@ -5113,7 +5124,7 @@ static bool sema_binary_is_unsigned_always_false_comparison(SemaContext *context return true; } } - if (!expr_is_const(right) || !type_is_unsigned(type_flatten_distinct(left->type))) return true; + if (!expr_is_const(right) || !type_is_unsigned(type_flatten(left->type))) return true; if (int_is_neg(right->const_expr.ixx)) { SEMA_ERROR(right, "Comparing an unsigned value with a negative constant is only allowed inside of macros."); @@ -5148,7 +5159,7 @@ static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, bool is_equality_type_op = expr->binary_expr.operator == BINARYOP_NE || expr->binary_expr.operator == BINARYOP_EQ; - // Flatten enum/distinct/optional + // Flatten distinct/optional Type *left_type = type_flatten(left->type); Type *right_type = type_flatten(right->type); @@ -5505,7 +5516,7 @@ static inline bool sema_expr_analyse_bit_not(SemaContext *context, Expr *expr) // 2. Check that it's a vector, bool Type *canonical = type_no_optional(inner->type)->canonical; - Type *flat = type_flatten_distinct(canonical); + Type *flat = type_flatten(canonical); if (!type_is_integer_or_bool_kind(flat) && flat->type_kind != TYPE_BITSTRUCT) { Type *vector_type = type_vector_type(canonical); @@ -5547,7 +5558,7 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr) // 2. Check whether the type is a vector Type *type = type_no_optional(inner->type); - Type *flat = type_flatten_distinct(type); + Type *flat = type_flatten(type); if (type_kind_is_any_vector(flat->type_kind)) { // This may be some form of bool vector. @@ -5658,7 +5669,7 @@ static inline bool sema_expr_analyse_incdec(SemaContext *context, Expr *expr) Type *type = type_flatten(inner->type); // 5. We can only inc/dec numbers or pointers. - if (!type_underlying_is_numeric(type) && type->type_kind != TYPE_POINTER) + if (!type_underlying_may_add_sub(type) && type->type_kind != TYPE_POINTER) { SEMA_ERROR(inner, "The expression must be a number or a pointer."); return false; @@ -6273,7 +6284,7 @@ static inline bool sema_expr_analyse_flat_element(SemaContext *context, ExprFlat bool *is_missing) { Expr *inner = element->inner; - Type *actual_type = type_flatten_distinct(type); + Type *actual_type = type_flatten(type); if (element->array) { if (!type_is_arraylike(actual_type) && actual_type->type_kind != TYPE_POINTER) @@ -7296,8 +7307,8 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo if (!sema_analyse_inferred_expr(context, to, expr)) return false; if (to && allow_optional && to->canonical != expr->type->canonical && expr->type->canonical->type_kind == TYPE_FAULTTYPE) { - Type *canonical = type_flatten_distinct(to); - if (canonical != type_anyerr && canonical->type_kind != TYPE_FAULTTYPE && expr->expr_kind == EXPR_CONST) + Type *flat = type_flatten(to); + if (flat != type_anyerr && flat->type_kind != TYPE_FAULTTYPE && expr->expr_kind == EXPR_CONST) { sema_error_at_after(expr->span, "You need to add a trailing '!' here to make this an optional."); return false; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 81a59e99c..621151bf1 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -172,7 +172,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte initializer->resolve_status = RESOLVE_DONE; if (expr_is_constant_eval(initializer, env_eval_type(context))) { - bool is_union = type_flatten_distinct(initializer->type)->type_kind == TYPE_UNION; + bool is_union = type_flatten(initializer->type)->type_kind == TYPE_UNION; assert(!is_union || vec_size(elements) == 1); ConstInitializer *const_init = CALLOCS(ConstInitializer); const_init->kind = is_union ? CONST_INIT_UNION : CONST_INIT_STRUCT; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 4717b491d..9c77c988a 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2064,8 +2064,9 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc sema_error_at(expr_span, "You cannot test '%s' for equality, and only values that supports '==' for comparison can be used in a switch.", type_to_error_string(switch_type)); return false; } - // We need an if chain if this isn't an integer type. - bool if_chain = !type_is_integer(type_flatten(switch_type)); + // We need an if-chain if this isn't an enum/integer type. + TypeKind flat_switch_type_kind = type_flatten(switch_type)->type_kind; + bool if_chain = flat_switch_type_kind != TYPE_ENUM && !type_kind_is_any_integer(flat_switch_type_kind); Ast *default_case = NULL; assert(context->active_scope.defer_start == context->active_scope.defer_last); @@ -2189,6 +2190,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem case TYPE_TYPEID: is_type = true; FALLTHROUGH; + case TYPE_ENUM: case ALL_INTS: case ALL_FLOATS: case TYPE_BOOL: @@ -2197,7 +2199,7 @@ static inline bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statem if (expr_is_const_string(cond)) break; FALLTHROUGH; default: - SEMA_ERROR(cond, "Only types, strings, integers, floats and booleans may be used with '$switch'."); + SEMA_ERROR(cond, "Only types, strings, enums, integers, floats and booleans may be used with '$switch'."); goto FAILED; } diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 52a16924a..c6fafbb8c 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -120,7 +120,7 @@ static inline bool sema_resolve_array_type(SemaContext *context, TypeInfo *type, return type_info_poison(type); } } - Type *distinct_base = type_flatten_distinct(type->array.base->type); + Type *distinct_base = type_flatten(type->array.base->type); if (distinct_base->type_kind == TYPE_STRUCT) { if (distinct_base->decl->has_variable_array) diff --git a/src/compiler/types.c b/src/compiler/types.c index da9e787cb..013898a5a 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1689,8 +1689,8 @@ bool type_array_element_is_equivalent(Type *element1, Type *element2, bool is_ex { if (is_explicit) { - element1 = type_flatten_distinct(element1); - element2 = type_flatten_distinct(element2); + element1 = type_flatten(element1); + element2 = type_flatten(element2); } else { @@ -1721,8 +1721,8 @@ bool type_is_pointer_equivalent(Type *pointer1, Type *pointer2, bool flatten_dis RETRY: if (flatten_distinct) { - pointer1 = type_flatten_distinct(pointer1); - pointer2 = type_flatten_distinct(pointer2); + pointer1 = type_flatten(pointer1); + pointer2 = type_flatten(pointer2); } if (pointer1 == pointer2) return true; if (pointer1 == type_voidptr || pointer2 == type_voidptr) return true; @@ -1730,8 +1730,8 @@ RETRY: Type *pointee2 = pointer2->pointer->canonical; if (flatten_distinct) { - pointee1 = type_flatten_distinct(pointee1); - pointee2 = type_flatten_distinct(pointee2); + pointee1 = type_flatten(pointee1); + pointee2 = type_flatten(pointee2); } if (pointee1 == pointee2) return true; if (type_is_subtype(pointee2, pointee1)) return true; diff --git a/src/version.h b/src/version.h index cecbcd7d2..a9a63f1fe 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.96" \ No newline at end of file +#define COMPILER_VERSION "0.4.97" \ No newline at end of file diff --git a/test/test_suite/compile_time/ct_switch_more_checks.c3 b/test/test_suite/compile_time/ct_switch_more_checks.c3 index 45f5b9791..177409faa 100644 --- a/test/test_suite/compile_time/ct_switch_more_checks.c3 +++ b/test/test_suite/compile_time/ct_switch_more_checks.c3 @@ -26,7 +26,7 @@ fn void foo2() fn void foo3() { int a; - $switch ({ 1, 3 }): // #error: Only types, strings, integers, floats and booleans + $switch ({ 1, 3 }): // #error: Only types, strings, enums, integers, floats and booleans $case 1: io::printn("Hello"); $default: diff --git a/test/test_suite/types/enum_inference.c3 b/test/test_suite/types/enum_inference.c3 index 78c104e3e..4d965c71e 100644 --- a/test/test_suite/types/enum_inference.c3 +++ b/test/test_suite/types/enum_inference.c3 @@ -25,7 +25,7 @@ fn void enumInferenceTest() bool y = x1 == x1; Inf2 z = C; if (z == Inf2.A) return; - if (z == 1) return; + if (z == (Inf2)1) return; z = (Inf2)(2); switch (z) {