diff --git a/lib/std/collections/enummap.c3 b/lib/std/collections/enummap.c3 index a41d4cd24..268ed2179 100644 --- a/lib/std/collections/enummap.c3 +++ b/lib/std/collections/enummap.c3 @@ -22,7 +22,7 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic foreach (i, &value : self.values) { if (i != 0) formatter.print(", ")!; - n += formatter.printf("%s: %s", (Enum)i, *value)!; + n += formatter.printf("%s: %s", Enum.from_ordinal(i), *value)!; } n += formatter.print(" }")!; return n; diff --git a/lib/std/collections/enumset.c3 b/lib/std/collections/enumset.c3 index fcd656629..3821ebd71 100644 --- a/lib/std/collections/enumset.c3 +++ b/lib/std/collections/enumset.c3 @@ -16,9 +16,9 @@ distinct EnumSet (Printable) = EnumSetType; fn void EnumSet.add(&self, Enum v) { $if IS_CHAR_ARRAY: - (*self)[(usz)v / 8] |= (char)(1u << ((usz)v % 8)); + (*self)[(usz)v.ordinal / 8] |= (char)(1u << ((usz)v.ordinal % 8)); $else - *self = (EnumSet)((EnumSetType)*self | 1u << (EnumSetType)v); + *self = (EnumSet)((EnumSetType)*self | 1u << (EnumSetType)v.ordinal); $endif } @@ -35,11 +35,11 @@ fn bool EnumSet.remove(&self, Enum v) { $if IS_CHAR_ARRAY: if (!self.has(v) @inline) return false; - (*self)[(usz)v / 8] &= (char)~(1u << ((usz)v % 8)); + (*self)[(usz)v.ordinal / 8] &= (char)~(1u << ((usz)v.ordinal % 8)); return true; $else EnumSetType old = (EnumSetType)*self; - EnumSetType new = old & ~(1u << (EnumSetType)v); + EnumSetType new = old & ~(1u << (EnumSetType)v.ordinal); *self = (EnumSet)new; return old != new; $endif @@ -48,9 +48,9 @@ fn bool EnumSet.remove(&self, Enum v) fn bool EnumSet.has(&self, Enum v) { $if IS_CHAR_ARRAY: - return (bool)(((*self)[(usz)v / 8] << ((usz)v % 8)) & 0x01); + return (bool)(((*self)[(usz)v.ordinal / 8] << ((usz)v.ordinal % 8)) & 0x01); $else - return ((EnumSetType)*self & (1u << (EnumSetType)v)) != 0; + return ((EnumSetType)*self & (1u << (EnumSetType)v.ordinal)) != 0; $endif } diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index e8aea39d3..28afdc2d5 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -230,7 +230,7 @@ macro enum_by_name($Type, String enum_name) @builtin typeid x = $Type.typeid; foreach (i, name : x.names) { - if (name == enum_name) return ($Type)i; + if (name == enum_name) return $Type.from_ordinal(i); } return SearchResult.MISSING?; } diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3 index 06650385e..d6af97c00 100644 --- a/lib/std/core/env.c3 +++ b/lib/std/core/env.c3 @@ -117,13 +117,13 @@ enum ArchType const String COMPILER_BUILD_HASH = $$BUILD_HASH; const String COMPILER_BUILD_DATE = $$BUILD_DATE; -const OsType OS_TYPE = (OsType)$$OS_TYPE; -const ArchType ARCH_TYPE = (ArchType)$$ARCH_TYPE; +const OsType OS_TYPE = OsType.from_ordinal($$OS_TYPE); +const ArchType ARCH_TYPE = ArchType.from_ordinal($$ARCH_TYPE); const bool ARCH_32_BIT = $$REGISTER_SIZE == 32; const bool ARCH_64_BIT = $$REGISTER_SIZE == 64; const bool LIBC = $$COMPILER_LIBC_AVAILABLE; const bool NO_LIBC = !$$COMPILER_LIBC_AVAILABLE; -const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)$$COMPILER_OPT_LEVEL; +const CompilerOptLevel COMPILER_OPT_LEVEL = CompilerOptLevel.from_ordinal($$COMPILER_OPT_LEVEL); const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN; const bool I128_NATIVE_SUPPORT = $$PLATFORM_I128_SUPPORTED; const bool F16_SUPPORT = $$PLATFORM_F16_SUPPORTED; @@ -135,7 +135,7 @@ const bool BACKTRACE = $$BACKTRACE; const usz LLVM_VERSION = $$LLVM_VERSION; const bool BENCHMARKING = $$BENCHMARKING; const bool TESTING = $$TESTING; -const MemoryEnvironment MEMORY_ENV = (MemoryEnvironment)$$MEMORY_ENVIRONMENT; +const MemoryEnvironment MEMORY_ENV = MemoryEnvironment.from_ordinal($$MEMORY_ENVIRONMENT); const bool TRACK_MEMORY = DEBUG_SYMBOLS && (COMPILER_SAFE_MODE || TESTING); const bool X86_64 = ARCH_TYPE == X86_64; const bool X86 = ARCH_TYPE == X86; diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index dae2a21a0..1c90b3833 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -224,7 +224,7 @@ enum AtomicOrdering : int *> macro @atomic_load(&x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin { - return $$atomic_load(x, $volatile, (int)$ordering); + return $$atomic_load(x, $volatile, $ordering.ordinal); } <* @@ -239,7 +239,7 @@ macro @atomic_load(&x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = fa *> macro void @atomic_store(&x, value, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin { - $$atomic_store(x, value, $volatile, (int)$ordering); + $$atomic_store(x, value, $volatile, $ordering.ordinal); } <* diff --git a/lib/std/io/os/file_libc.c3 b/lib/std/io/os/file_libc.c3 index 58cdcd769..30b878452 100644 --- a/lib/std/io/os/file_libc.c3 +++ b/lib/std/io/os/file_libc.c3 @@ -60,7 +60,7 @@ fn void*! native_freopen(void* file, String filename, String mode) @inline fn void! native_fseek(void* file, isz offset, Seek seek_mode) @inline { - if (libc::fseek(file, (SeekIndex)offset, (CInt)seek_mode)) return file_seek_errno()?; + if (libc::fseek(file, (SeekIndex)offset, seek_mode.ordinal)) return file_seek_errno()?; } diff --git a/lib/std/time/datetime.c3 b/lib/std/time/datetime.c3 index 060cc2248..f7c3cb534 100644 --- a/lib/std/time/datetime.c3 +++ b/lib/std/time/datetime.c3 @@ -44,9 +44,9 @@ fn TzDateTime DateTime.to_local(&self) dt.min = (char)tm.tm_min; dt.hour = (char)tm.tm_hour; dt.day = (char)tm.tm_mday; - dt.month = (Month)tm.tm_mon; + dt.month = Month.from_ordinal(tm.tm_mon); dt.year = tm.tm_year + 1900; - dt.weekday = !tm.tm_wday ? Weekday.SUNDAY : (Weekday)tm.tm_wday - 1; + dt.weekday = !tm.tm_wday ? Weekday.SUNDAY : Weekday.from_ordinal(tm.tm_wday - 1); dt.year_day = (ushort)tm.tm_yday; dt.time = self.time; $if $defined(tm.tm_gmtoff): @@ -142,9 +142,9 @@ fn void DateTime.set_time(&self, Time time) self.min = (char)tm.tm_min; self.hour = (char)tm.tm_hour; self.day = (char)tm.tm_mday; - self.month = (Month)tm.tm_mon; + self.month = Month.from_ordinal(tm.tm_mon); self.year = tm.tm_year + 1900; - self.weekday = !tm.tm_wday ? Weekday.SUNDAY : (Weekday)tm.tm_wday - 1; + self.weekday = !tm.tm_wday ? Weekday.SUNDAY : Weekday.from_ordinal(tm.tm_wday - 1); self.year_day = (ushort)tm.tm_yday; self.time = time; } @@ -183,7 +183,7 @@ fn DateTime DateTime.add_months(&self, int months) year += month / 12; month %= 12; } - return from_date(year, (Month)month, self.day, self.hour, self.min, self.sec, self.usec); + return from_date(year, Month.from_ordinal(month), self.day, self.hour, self.min, self.sec, self.usec); } diff --git a/releasenotes.md b/releasenotes.md index e039b8138..9c6fc36c8 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -5,6 +5,9 @@ ### Changes / improvements - Split help into normal and "full" help, #1703 - Removed 'headers' command line option. +- Add `enum.from_ordinal` and `fault.from_ordinal` +- Deprecate cast-style conversion from integer to enum. +- Make deprecation an error in test mode. ### Fixes - Fix case trying to initialize a `char[*]*` from a String. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 68c1add6b..9db64fcd2 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -65,7 +65,7 @@ typedef uint16_t FileId; #define PRINT_ERROR_LAST(...) print_error_at(c->prev_span, __VA_ARGS__) #define RETURN_PRINT_ERROR_LAST(...) do { print_error_at(c->prev_span, __VA_ARGS__); return false; } while (0) #define SEMA_NOTE(_node, ...) sema_note_prev_at((_node)->span, __VA_ARGS__) -#define SEMA_DEPRECATED(_node, ...) do { if (!compiler.build.silence_deprecation) \ +#define SEMA_DEPRECATED(_node, ...) do { if (compiler.build.test_output) print_error_at((_node)->span, __VA_ARGS__); if (!compiler.build.silence_deprecation) \ sema_note_prev_at((_node)->span, __VA_ARGS__); } while (0) #define EXPAND_EXPR_STRING(str_) (str_)->const_expr.bytes.len, (str_)->const_expr.bytes.ptr @@ -2306,6 +2306,7 @@ Expr **sema_expand_vasplat_exprs(SemaContext *context, Expr **exprs); bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool optional, bool *no_match_ref); +void sema_expr_convert_enum_to_int(SemaContext *context, Expr *expr); Decl *sema_decl_stack_resolve_symbol(const char *symbol); Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name); bool unit_resolve_parameterized_symbol(SemaContext *context, NameResolve *name_resolve); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 1524c1bab..d13627242 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -573,7 +573,6 @@ typedef enum CAST_STINLINE, CAST_VECARR, CAST_VOID, - CAST_INTERR, CAST_INTPTR, CAST_EXPVEC, } CastKind; @@ -1368,6 +1367,7 @@ typedef enum TYPE_PROPERTY_ASSOCIATED, TYPE_PROPERTY_ELEMENTS, TYPE_PROPERTY_EXTNAMEOF, + TYPE_PROPERTY_FROM_ORDINAL, TYPE_PROPERTY_GET, TYPE_PROPERTY_INF, TYPE_PROPERTY_IS_EQ, diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 89f95b001..5a38017d7 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -336,7 +336,6 @@ static inline bool expr_cast_is_runtime_const(Expr *expr) case CAST_EUBOOL: case CAST_EUER: case CAST_EREU: - case CAST_INTERR: case CAST_STRPTR: case CAST_PTRBOOL: case CAST_BOOLINT: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 6c84564f8..f8a27327c 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1498,11 +1498,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu case CAST_ANYPTR: llvm_emit_any_pointer(c, value, value); break; - case CAST_INTERR: - to_type = type_lowering(to_type); - llvm_value_rvalue(c, value); - value->value = llvm_zext_trunc(c, value->value, llvm_get_type(c, to_type)); - break; case CAST_ERROR: UNREACHABLE case CAST_STRPTR: diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 4ed303eb8..ba027f708 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -626,7 +626,7 @@ bool cast_to_index(SemaContext *context, Expr *index, Type *subscripted_type) SEMA_ERROR(index, "You need to explicitly cast this to a uint or ulong."); return false; case TYPE_I128: - SEMA_ERROR(index, "index->type->canonical this to an int or long."); + SEMA_ERROR(index, "You need to explicitly cast this to an int or long."); return false; case TYPE_ENUM: type = type->decl->enums.type_info->type; @@ -1598,6 +1598,7 @@ static void cast_float_to_int(SemaContext *context, Expr *expr, Type *type) */ static void cast_int_to_enum(SemaContext *context, Expr *expr, Type *type) { + SEMA_DEPRECATED(expr, "Using casts to convert integers to enums is deprecated in favour of using 'MyEnum.from_ordinal(i)`."); Type *canonical = type_flatten(type); ASSERT0(canonical->type_kind == TYPE_ENUM); if (insert_runtime_cast_unless_const(expr, CAST_INTENUM, type)) return; @@ -1751,18 +1752,7 @@ static void cast_int_to_float(SemaContext *context, Expr *expr, Type *type) static void cast_enum_to_int(SemaContext *context, Expr* expr, Type *to_type) { - ASSERT0(type_flatten(expr->type)->type_kind == TYPE_ENUM); - Type *underlying_type = type_base(expr->type); - if (sema_cast_const(expr)) - { - ASSERT0(expr->const_expr.const_kind == CONST_ENUM); - expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal); - } - if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_INTENUM) - { - *expr = *exprptr(expr->cast_expr.expr); - } - expr->type = type_add_optional(underlying_type, IS_OPTIONAL(expr)); + sema_expr_convert_enum_to_int(context, expr); cast_int_to_int(context, expr, to_type); } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 482d46190..430db4c7b 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2503,6 +2503,22 @@ static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *c return true; } +void sema_expr_convert_enum_to_int(SemaContext *context, Expr *expr) +{ + ASSERT0(type_flatten(expr->type)->type_kind == TYPE_ENUM); + Type *underlying_type = type_base(expr->type); + if (sema_cast_const(expr)) + { + ASSERT0(expr->const_expr.const_kind == CONST_ENUM); + expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal); + } + if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_INTENUM) + { + *expr = *exprptr(expr->cast_expr.expr); + } + expr->type = type_add_optional(underlying_type, IS_OPTIONAL(expr)); +} + bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool optional, bool *no_match_ref) { @@ -2540,12 +2556,60 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl } } -static inline bool sema_expr_analyse_typecall(SemaContext *context, Expr *expr) +INLINE bool sema_expr_analyse_from_ordinal(SemaContext *context, Expr *expr, Expr *tag) { - expr->call_expr.arguments = sema_expand_vasplat_exprs(context, expr->call_expr.arguments); Expr **args = expr->call_expr.arguments; unsigned arg_count = vec_size(args); + Decl *decl = tag->type_call_expr.type; + if (arg_count != 1) RETURN_SEMA_ERROR(expr, "Expected a single string argument to 'from_ordinal'."); + Expr *key = args[0]; + if (!sema_analyse_expr(context, key)) return false; + if (!type_is_integer(key->type)) + { + RETURN_SEMA_ERROR(key, "The ordinal should be an integer."); + } + + if (sema_cast_const(key)) + { + Int to_convert = key->const_expr.ixx; + if (int_is_neg(to_convert)) + { + RETURN_SEMA_ERROR(key, "'from_ordinal' doesn't work on negative numbers."); + } + unsigned max_enums = vec_size(decl->enums.values); + Int max = {.i.low = max_enums, .type = TYPE_U32}; + if (int_comp(to_convert, max, BINARYOP_GE)) + { + RETURN_SEMA_ERROR(key, "The ordinal '%s' exceeds the max ordinal '%u'.", int_to_str(max, 10, false), max_enums - 1); + } + expr->expr_kind = EXPR_CONST; + expr->const_expr = (ExprConst) { + .enum_err_val = decl->enums.values[to_convert.i.low], + .const_kind = decl->decl_kind == DECL_FAULT ? CONST_ERR : CONST_ENUM + }; + expr->type = decl->type; + return true; + } + if (decl->decl_kind == DECL_FAULT) RETURN_SEMA_ERROR(key, "For faults you can only use 'from_ordinal' with constant arguments.", decl->name); + + expr->expr_kind = EXPR_CAST; + expr->cast_expr.kind = CAST_INTENUM; + expr->cast_expr.expr = exprid(key); + expr->cast_expr.type_info = 0; + expr->type = decl->type; + return true; +} + +static inline bool sema_expr_analyse_typecall(SemaContext *context, Expr *expr) +{ Expr *tag = exprptr(expr->call_expr.function); + expr->call_expr.arguments = sema_expand_vasplat_exprs(context, expr->call_expr.arguments); + if (tag->type_call_expr.property == TYPE_PROPERTY_FROM_ORDINAL) + { + return sema_expr_analyse_from_ordinal(context, expr, tag); + } + Expr **args = expr->call_expr.arguments; + unsigned arg_count = vec_size(args); Decl *decl = tag->type_call_expr.type; bool is_has = tag->type_call_expr.property == TYPE_PROPERTY_HAS_TAGOF; const char *name = is_has ? "has_tagof" : "tagof"; @@ -2826,11 +2890,11 @@ static bool sema_subscript_rewrite_index_const_list(Expr *const_list, ArraySize } /** - * Find index type or overload for subscript. + * Find subscript type or overload for subscript. */ -static Expr *sema_expr_find_index_type_or_overload_for_subscript(SemaContext *context, Expr *current_expr, - CheckType check, Type **index_type_ptr, - Decl **overload_ptr) +static Expr *sema_expr_find_subscript_type_or_overload_for_subscript(SemaContext *context, Expr *current_expr, + CheckType check, Type **subscript_type_ptr, + Decl **overload_ptr) { Decl *overload = NULL; switch (check) @@ -2847,7 +2911,7 @@ static Expr *sema_expr_find_index_type_or_overload_for_subscript(SemaContext *co { *overload_ptr = overload; ASSERT0(vec_size(overload->func_decl.signature.params) == 3); - *index_type_ptr = overload->func_decl.signature.params[2]->type; + *subscript_type_ptr = overload->func_decl.signature.params[2]->type; return current_expr; } break; @@ -2858,22 +2922,23 @@ static Expr *sema_expr_find_index_type_or_overload_for_subscript(SemaContext *co { *overload_ptr = overload; ASSERT0(overload->func_decl.signature.rtype); - *index_type_ptr = type_infoptr(overload->func_decl.signature.rtype)->type; + *subscript_type_ptr = type_infoptr(overload->func_decl.signature.rtype)->type; return current_expr; } // Otherwise, see if we have an indexed type. Type *inner_type = type_get_indexed_type(current_expr->type); if (inner_type) { - *index_type_ptr = inner_type; + *subscript_type_ptr = inner_type; *overload_ptr = NULL; return current_expr; } if (type_is_substruct(current_expr->type)) { Expr *embedded_struct = expr_access_inline_member(current_expr, current_expr->type->decl); - return sema_expr_find_index_type_or_overload_for_subscript(context, embedded_struct, check, index_type_ptr, - overload_ptr); + return sema_expr_find_subscript_type_or_overload_for_subscript(context, embedded_struct, check, + subscript_type_ptr, + overload_ptr); } return NULL; } @@ -2898,7 +2963,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, bool optional = IS_OPTIONAL(subscripted); Decl *overload = NULL; - Type *index_type = NULL; + Type *subscript_type = NULL; Expr *current_expr; Type *current_type = subscripted->type->canonical; if (current_type == type_untypedlist) @@ -2907,11 +2972,14 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, } else { - current_expr = sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, check, &index_type, &overload); - if (!overload && !index_type && is_eval_ref) + current_expr = sema_expr_find_subscript_type_or_overload_for_subscript(context, subscripted, check, + &subscript_type, + &overload); + if (!overload && !subscript_type && is_eval_ref) { // Maybe there is a [] overload? - if (sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, check, &index_type, &overload)) + if (sema_expr_find_subscript_type_or_overload_for_subscript(context, subscripted, check, &subscript_type, + &overload)) { if (check_valid) goto VALID_FAIL_POISON; RETURN_SEMA_ERROR(expr, "A function or macro with '@operator(&[])' is not defined for %s, " @@ -2919,7 +2987,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, type_quoted_error_string(subscripted->type)); } } - if (!index_type) + if (!subscript_type) { if (check_valid) goto VALID_FAIL_POISON; RETURN_SEMA_ERROR(expr, "Indexing a value of type %s is not possible.", type_quoted_error_string(subscripted->type)); @@ -2936,6 +3004,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, RETURN_SEMA_ERROR(index, "Indexing from the end is not allowed for pointers " "and flexible array members."); } + int64_t size; if (expr_is_const_int(index) && (size = expr_get_index_max(subscripted)) >= 0) { @@ -3031,7 +3100,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, if (check == CHECK_LVALUE) { expr->expr_kind = EXPR_SUBSCRIPT_ASSIGN; - expr->type = index_type; + expr->type = subscript_type; expr->subscript_assign_expr.expr = exprid(current_expr); expr->subscript_assign_expr.index = exprid(index); expr->subscript_assign_expr.method = declid(overload); @@ -3056,7 +3125,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, if (is_eval_ref) { - index_type = type_get_ptr(index_type); + subscript_type = type_get_ptr(subscript_type); } else { @@ -3102,7 +3171,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, } else { - expr->type = type_add_optional(index_type, optional); + expr->type = type_add_optional(subscript_type, optional); } return true; VALID_FAIL_POISON: @@ -3809,6 +3878,7 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e { case TYPE_PROPERTY_TAGOF: case TYPE_PROPERTY_HAS_TAGOF: + case TYPE_PROPERTY_FROM_ORDINAL: expr->expr_kind = EXPR_TYPECALL; expr->type_call_expr = (ExprTypeCall) { .type = decl, .property = type_property }; return true; @@ -4313,6 +4383,7 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp case TYPE_PROPERTY_ASSOCIATED: case TYPE_PROPERTY_ELEMENTS: case TYPE_PROPERTY_EXTNAMEOF: + case TYPE_PROPERTY_FROM_ORDINAL: case TYPE_PROPERTY_GET: case TYPE_PROPERTY_HAS_TAGOF: case TYPE_PROPERTY_INF: @@ -4506,6 +4577,8 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper default: return false; } + case TYPE_PROPERTY_FROM_ORDINAL: + return type_kind_is_enumlike(type->canonical->type_kind); case TYPE_PROPERTY_MIN: case TYPE_PROPERTY_MAX: return type_is_float(type) || type_is_integer(type); @@ -4657,6 +4730,7 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, return true; case TYPE_PROPERTY_TAGOF: case TYPE_PROPERTY_HAS_TAGOF: + case TYPE_PROPERTY_FROM_ORDINAL: expr->expr_kind = EXPR_TYPECALL; expr->type_call_expr = (ExprTypeCall) { .type = type->type_kind == TYPE_FUNC_PTR @@ -4938,7 +5012,7 @@ CHECK_DEEPER: { if (flat_type->type_kind == TYPE_ENUM) { - if (!cast_explicit(context, current_parent, type->decl->enums.type_info->type)) return false; + sema_expr_convert_enum_to_int(context, current_parent); expr_replace(expr, current_parent); return true; } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index e440a7a4e..a94aebe7b 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -162,6 +162,7 @@ void symtab_init(uint32_t capacity) type_property_list[TYPE_PROPERTY_ASSOCIATED] = KW_DEF("associated"); type_property_list[TYPE_PROPERTY_ELEMENTS] = KW_DEF("elements"); type_property_list[TYPE_PROPERTY_EXTNAMEOF] = KW_DEF("extnameof"); + type_property_list[TYPE_PROPERTY_FROM_ORDINAL] = KW_DEF("from_ordinal"); type_property_list[TYPE_PROPERTY_GET] = KW_DEF("get"); type_property_list[TYPE_PROPERTY_INF] = KW_DEF("inf"); type_property_list[TYPE_PROPERTY_INNER] = KW_DEF("inner"); diff --git a/test/test_suite/compile_time/ct_and_or.c3 b/test/test_suite/compile_time/ct_and_or.c3 index 3edbb498f..bd2dc0a12 100644 --- a/test/test_suite/compile_time/ct_and_or.c3 +++ b/test/test_suite/compile_time/ct_and_or.c3 @@ -1,6 +1,6 @@ fn void test() { - $assert $or(false, false, true, hello("")); - $assert !$and(false, hello("")); - $assert !$and(true, true, false, hello("")); + $assert false ||| false ||| true ||| hello(""); + $assert !(false &&& hello("")); + $assert !(true &&& true &&& false &&& hello("")); } \ No newline at end of file diff --git a/test/test_suite/compile_time/ct_enum_values.c3t b/test/test_suite/compile_time/ct_enum_values.c3t index b5ba1758e..c17c69701 100644 --- a/test/test_suite/compile_time/ct_enum_values.c3t +++ b/test/test_suite/compile_time/ct_enum_values.c3t @@ -10,7 +10,7 @@ macro elements($Type) { int x; $foreach ($x : $Type.values) - x = (int)$x; + x = $x.ordinal; $endforeach; } diff --git a/test/test_suite/enumerations/enum_cast_error.c3 b/test/test_suite/enumerations/enum_cast_error.c3 index 39cd3871d..3f8615e7f 100644 --- a/test/test_suite/enumerations/enum_cast_error.c3 +++ b/test/test_suite/enumerations/enum_cast_error.c3 @@ -2,23 +2,23 @@ enum Abc : char { ABC } fn void foo() { - Abc x = (Abc)10; // #error: exceeds the number of enums + Abc x = Abc.from_ordinal(10); // #error: exceeds the max } fn void bar() { int a; - Abc x = (Abc)a; + Abc x = Abc.from_ordinal(a); } fn void baz() { int a; - Abc x = (Abc)0; + Abc x = Abc.from_ordinal(0); } fn void abc() { int a; - Abc x = (Abc)-1; // #error: negative number + Abc x = Abc.from_ordinal(-1); // #error: negative number } \ No newline at end of file diff --git a/test/test_suite/enumerations/enum_conversions.c3t b/test/test_suite/enumerations/enum_conversions.c3t index 434d0f42f..9922feec3 100644 --- a/test/test_suite/enumerations/enum_conversions.c3t +++ b/test/test_suite/enumerations/enum_conversions.c3t @@ -6,13 +6,13 @@ enum Abc : char { ABC } fn void main() { int a; - Abc x = (Abc)a; + Abc x = Abc.from_ordinal(a); long z; - Abc y = (Abc)z; + Abc y = Abc.from_ordinal(z); a = 256; - y = (Abc)a; + y = Abc.from_ordinal(a); a = -1; - y = (Abc)a; + y = Abc.from_ordinal(a); } /* #expect: test.ll diff --git a/test/test_suite/enumerations/enum_signed_cast_swap.c3t b/test/test_suite/enumerations/enum_signed_cast_swap.c3t index 8b59417ca..f88545e7b 100644 --- a/test/test_suite/enumerations/enum_signed_cast_swap.c3t +++ b/test/test_suite/enumerations/enum_signed_cast_swap.c3t @@ -14,7 +14,7 @@ fn void foo(Mouse_Button button) fn int main() { uint x = 1; - foo((Mouse_Button)x); + foo(Mouse_Button.from_ordinal(x)); return 0; } diff --git a/test/test_suite/functions/named_arg_order.c3 b/test/test_suite/functions/named_arg_order.c3 index adf7c7389..6186df429 100644 --- a/test/test_suite/functions/named_arg_order.c3 +++ b/test/test_suite/functions/named_arg_order.c3 @@ -6,6 +6,5 @@ macro void test(int a, int $baz) fn void main() { - test(.$baz = 1, .a = 4); // #error: Named arguments must always test($baz: 1, a: 4); // #error: Named arguments must always } \ No newline at end of file diff --git a/test/test_suite/macros/macro_untyped_varargs_2.c3t b/test/test_suite/macros/macro_untyped_varargs_2.c3t index 1f44fb44d..c4e12f584 100644 --- a/test/test_suite/macros/macro_untyped_varargs_2.c3t +++ b/test/test_suite/macros/macro_untyped_varargs_2.c3t @@ -27,7 +27,7 @@ macro foo3(...) { var $x = 0; $for (var $i = 0; $i < $vacount; $i++) - $x += $vaconst($i); + $x += $vaconst[$i]; $endfor; return $x; } diff --git a/test/test_suite/statements/switch_errors.c3 b/test/test_suite/statements/switch_errors.c3 index bfc2af712..b9b2415f9 100644 --- a/test/test_suite/statements/switch_errors.c3 +++ b/test/test_suite/statements/switch_errors.c3 @@ -28,9 +28,9 @@ fn void test_check_nums() Foo f = A; switch (f) { - case (Foo)(1): + case Foo.from_ordinal(1): break; - case (Foo)(0): + case Foo.from_ordinal(0): break; } } @@ -66,7 +66,7 @@ fn void test_duplicate_case2(Foo i) { case A: break; - case (Foo)(1): + case Foo.from_ordinal(1): break; case A: // #error: same case value appears break; @@ -79,7 +79,7 @@ fn void test_duplicate_case3(Foo i) { case A: break; - case (Foo)(0): // #error: same case value appears + case Foo.from_ordinal(0): // #error: same case value appears break; } } diff --git a/test/test_suite/struct/const_zero_init_1360.c3t b/test/test_suite/struct/const_zero_init_1360.c3t index 84ac850d5..a1de635bc 100644 --- a/test/test_suite/struct/const_zero_init_1360.c3t +++ b/test/test_suite/struct/const_zero_init_1360.c3t @@ -2,7 +2,7 @@ module test; import std::collections::map; def Foo = HashMap()>); -fn void main() +macro test() { HashMap() map0; map0["c3c"] = {}; @@ -16,6 +16,10 @@ fn void main() map2["c3c"] = { {}, null, 1 ,2 ,2 }; } +fn void main() +{ + test(); +} /* #expect: test.ll diff --git a/test/test_suite/switch/switch_in_defer_macro.c3t b/test/test_suite/switch/switch_in_defer_macro.c3t index 92acf7dfc..34ba741c5 100644 --- a/test/test_suite/switch/switch_in_defer_macro.c3t +++ b/test/test_suite/switch/switch_in_defer_macro.c3t @@ -2,8 +2,8 @@ <* @require Token.kindof == ENUM && $typefrom(Token.inner).kindof == UNSIGNED_INT - @require $defined(((Token)0).token) - @require $defined(((Comment)0).start) && $defined(((Comment)0).end) + @require $defined(Token{}.token) + @require $defined(Comment{}.start) && $defined(Comment{}.end) *> module lexer(); import std::io; @@ -58,7 +58,7 @@ fn void! Lexer.init(&self, InStream reader, Ident ident, Allocator using = alloc { String name = tok.token; assert(name.len > 0 && name.len <= ushort.max); - trie.set(name, (Token)i)!; + trie.set(name, Token.from_ordinal(i))!; max_token = max(max_token, (ushort)name.len); } foreach (tok : Comment.values) diff --git a/test/test_suite/types/enum_inference.c3 b/test/test_suite/types/enum_inference.c3 index 49fb3bdad..880e1b90d 100644 --- a/test/test_suite/types/enum_inference.c3 +++ b/test/test_suite/types/enum_inference.c3 @@ -25,8 +25,8 @@ fn void enumInferenceTest() bool y = x1 == x1; Inf2 z = C; if (z == Inf2.A) return; - if (z == (Inf2)1) return; - z = (Inf2)(2); + if (z == Inf2.from_ordinal(1)) return; + z = Inf2.from_ordinal(2); switch (z) { case Inf2.A: @@ -34,7 +34,7 @@ fn void enumInferenceTest() return; case B: return; - case (Inf2)(2): + case Inf2.from_ordinal(2): x1 += 1; return; default: