From a61fd6d280e2c9903b6dc97aa11c163f17c3f29d Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 5 Dec 2025 20:18:32 +0100 Subject: [PATCH] - Casting bitstruct to wider base type should be single step #2616. - Experimental accept of ~ and ^ for optionals. --- lib/std/collections/anylist.c3 | 4 ++-- lib/std/collections/elastic_array.c3 | 16 ++++++++-------- lib/std/collections/object.c3 | 13 ++++++------- releasenotes.md | 1 + src/compiler/parse_expr.c | 27 +++++++++++++++++++++++++-- src/compiler/sema_casts.c | 13 +++++++++++-- 6 files changed, 53 insertions(+), 21 deletions(-) diff --git a/lib/std/collections/anylist.c3 b/lib/std/collections/anylist.c3 index f497cf59d..ed4dab283 100644 --- a/lib/std/collections/anylist.c3 +++ b/lib/std/collections/anylist.c3 @@ -70,7 +70,7 @@ fn any? AnyList.last_any(&self) @inline => InterfaceList {any}.last(self); *> macro AnyList.pop(&self, $Type) { - if (!self.size) return NO_MORE_ELEMENT?; + if (!self.size) return NO_MORE_ELEMENT~; defer self.free_element(self.entries[self.size]); return *anycast(self.entries[--self.size], $Type); } @@ -85,7 +85,7 @@ macro AnyList.pop(&self, $Type) *> macro AnyList.pop_first(&self, $Type) { - if (!self.size) return NO_MORE_ELEMENT?; + if (!self.size) return NO_MORE_ELEMENT~; defer self.remove_at(0); return *anycast(self.entries[0], $Type); } diff --git a/lib/std/collections/elastic_array.c3 b/lib/std/collections/elastic_array.c3 index 176d64eec..0a0fef789 100644 --- a/lib/std/collections/elastic_array.c3 +++ b/lib/std/collections/elastic_array.c3 @@ -46,7 +46,7 @@ fn String ElasticArray.to_tstring(&self) fn void? ElasticArray.push_try(&self, Type element) @inline { - if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY?; + if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY~; self.entries[self.size++] = element; } @@ -60,7 +60,7 @@ fn void ElasticArray.push(&self, Type element) @inline fn Type? ElasticArray.pop(&self) { - if (!self.size) return NO_MORE_ELEMENT?; + if (!self.size) return NO_MORE_ELEMENT~; return self.entries[--self.size]; } @@ -74,7 +74,7 @@ fn void ElasticArray.clear(&self) *> fn Type? ElasticArray.pop_first(&self) { - if (!self.size) return NO_MORE_ELEMENT?; + if (!self.size) return NO_MORE_ELEMENT~; defer self.remove_at(0); return self.entries[0]; } @@ -241,7 +241,7 @@ fn void? ElasticArray.push_front_try(&self, Type type) @inline *> fn void? ElasticArray.insert_at_try(&self, usz index, Type value) { - if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY?; + if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY~; self.insert_at(index, value); } @@ -269,25 +269,25 @@ fn void ElasticArray.set_at(&self, usz index, Type type) fn void? ElasticArray.remove_last(&self) @maydiscard { - if (!self.size) return NO_MORE_ELEMENT?; + if (!self.size) return NO_MORE_ELEMENT~; self.size--; } fn void? ElasticArray.remove_first(&self) @maydiscard { - if (!self.size) return NO_MORE_ELEMENT?; + if (!self.size) return NO_MORE_ELEMENT~; self.remove_at(0); } fn Type? ElasticArray.first(&self) { - if (!self.size) return NO_MORE_ELEMENT?; + if (!self.size) return NO_MORE_ELEMENT~; return self.entries[0]; } fn Type? ElasticArray.last(&self) { - if (!self.size) return NO_MORE_ELEMENT?; + if (!self.size) return NO_MORE_ELEMENT~; return self.entries[self.size - 1]; } diff --git a/lib/std/collections/object.c3 b/lib/std/collections/object.c3 index 0e7013377..a523e0e64 100644 --- a/lib/std/collections/object.c3 +++ b/lib/std/collections/object.c3 @@ -242,8 +242,7 @@ macro Object* Object.push(&self, value) <* @require self.is_keyable() *> -fn Object*? Object.get(&self, String key) => self.is_empty() ? NOT_FOUND? : self.map.get(key); - +fn Object*? Object.get(&self, String key) => self.is_empty() ? NOT_FOUND~ : self.map.get(key); fn bool Object.has_key(&self, String key) => self.is_map() && self.map.has_key(key); @@ -308,7 +307,7 @@ macro get_integer_value(Object* value, $Type) return ($Type)value.s.to_uint128(); $endif } - if (!value.is_int()) return string::MALFORMED_INTEGER?; + if (!value.is_int()) return string::MALFORMED_INTEGER~; return ($Type)value.i; } @@ -361,7 +360,7 @@ fn uint128? Object.get_uint128_at(&self, usz index) => self.get_integer_at(uint1 fn String? Object.get_string(&self, String key) { Object* value = self.get(key)!; - if (!value.is_string()) return TYPE_MISMATCH?; + if (!value.is_string()) return TYPE_MISMATCH~; return value.s; } @@ -371,7 +370,7 @@ fn String? Object.get_string(&self, String key) fn String? Object.get_string_at(&self, usz index) { Object* value = self.get_at(index); - if (!value.is_string()) return TYPE_MISMATCH?; + if (!value.is_string()) return TYPE_MISMATCH~; return value.s; } @@ -381,7 +380,7 @@ fn String? Object.get_string_at(&self, usz index) macro String? Object.get_enum(&self, $EnumType, String key) { Object value = self.get(key)!; - if ($EnumType.typeid != value.type) return TYPE_MISMATCH?; + if ($EnumType.typeid != value.type) return TYPE_MISMATCH~; return ($EnumType)value.i; } @@ -391,7 +390,7 @@ macro String? Object.get_enum(&self, $EnumType, String key) macro String? Object.get_enum_at(&self, $EnumType, usz index) { Object value = self.get_at(index); - if ($EnumType.typeid != value.type) return TYPE_MISMATCH?; + if ($EnumType.typeid != value.type) return TYPE_MISMATCH~; return ($EnumType)value.i; } diff --git a/releasenotes.md b/releasenotes.md index 855308a35..2be845fc8 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -7,6 +7,7 @@ ### Fixes - Regression with npot vector in struct triggering an assert #2219. +- Casting bitstruct to wider base type should be single step #2616. ### Stdlib changes diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 28018df03..92d50f2ee 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -716,6 +716,29 @@ static Expr *parse_unary_expr(ParseContext *c, Expr *left, SourceSpan lhs_start return unary; } +static Expr *parse_raise_expr_suffix(ParseContext *c, Expr *left_side, SourceSpan lhs_start) +{ + ASSERT(expr_ok(left_side)); + advance_and_verify(c, TOKEN_BIT_NOT); + Expr *expr = expr_new(EXPR_OPTIONAL, lhs_start); + expr->inner_expr = left_side; + RANGE_EXTEND_PREV(expr); + return expr; +} + +static Expr *parse_raise_expr(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED) +{ + ASSERT(!left && "Did not expect a left hand side!"); + + Expr *opt = EXPR_NEW_TOKEN(EXPR_OPTIONAL); + advance(c); + Expr *right_side = parse_precedence(c, PREC_UNARY); + CHECK_EXPR_OR_RET(right_side); + opt->inner_expr = right_side; + RANGE_EXTEND_PREV(opt); + return opt; +} + /** * post_unary_expr ::= unary_op */ @@ -2196,8 +2219,8 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_DOT] = { NULL, parse_access_expr, PREC_CALL }, [TOKEN_BANG] = { parse_unary_expr, parse_rethrow_expr, PREC_CALL }, [TOKEN_BYTES] = { parse_bytes_expr, NULL, PREC_NONE }, - [TOKEN_BIT_NOT] = { parse_unary_expr, NULL, PREC_UNARY }, - [TOKEN_BIT_XOR] = { NULL, parse_binary, PREC_BIT }, + [TOKEN_BIT_NOT] = { parse_unary_expr, parse_raise_expr_suffix, PREC_CALL }, + [TOKEN_BIT_XOR] = { parse_raise_expr, parse_binary, PREC_BIT }, [TOKEN_BIT_OR] = { NULL, parse_binary, PREC_BIT }, [TOKEN_AMP] = { parse_unary_expr, parse_binary, PREC_BIT }, [TOKEN_EQEQ] = { NULL, parse_binary, PREC_RELATIONAL }, diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 1636f7afc..95efc24d8 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1683,7 +1683,7 @@ RETRY: base_type = base_type->decl->distinct->type->canonical; goto RETRY; } - if (!type_is_integer(base_type) || type_size(to) != type_size(base_type)) + if (!type_is_integer(base_type) || type_size(to) < type_size(base_type)) { return sema_cast_error(cc, false, is_silent); } @@ -1891,7 +1891,16 @@ static void cast_expand_to_vec(Expr *expr, Type *type) expr->resolve_status = RESOLVE_DONE; } -static void cast_bitstruct_to_int_arr(Expr *expr, Type *type) { expr_rewrite_recast(expr, type); } +static void cast_bitstruct_to_int_arr(Expr *expr, Type *type) +{ + if (type_size(expr->type) < type_size(type)) + { + expr_rewrite_recast(expr, type_flatten(expr->type)->decl->strukt.container_type->type); + cast_int_to_int(expr, type); + return; + } + expr_rewrite_recast(expr, type); +} static void cast_int_arr_to_bitstruct(Expr *expr, Type *type) { if (expr_is_const_int(expr))