mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Add enum.from_ordinal and fault.from_ordinal
- Deprecate cast-style conversion from integer to enum. - Make deprecation an error in test mode.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
<*
|
||||
|
||||
@@ -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()?;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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(""));
|
||||
}
|
||||
@@ -10,7 +10,7 @@ macro elements($Type)
|
||||
{
|
||||
int x;
|
||||
$foreach ($x : $Type.values)
|
||||
x = (int)$x;
|
||||
x = $x.ordinal;
|
||||
$endforeach;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ module test;
|
||||
import std::collections::map;
|
||||
|
||||
def Foo = HashMap(<String, HashMap(<String, String>)>);
|
||||
fn void main()
|
||||
macro test()
|
||||
{
|
||||
HashMap(<String, String>) map0;
|
||||
map0["c3c"] = {};
|
||||
@@ -16,6 +16,10 @@ fn void main()
|
||||
map2["c3c"] = { {}, null, 1 ,2 ,2 };
|
||||
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
test();
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
@@ -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(<Token, Comment>);
|
||||
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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user