aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-10-31 19:39:01 +0000
committergingerBill <bill@gingerbill.org>2021-10-31 19:39:01 +0000
commit141299eb02bc9a7330daa30d75d279e84ba28cc3 (patch)
treeb0c429d86cb6f96db2ae0f6a012ed0d979835e83 /src
parentefe05b3e1382d569201709a1d1c5f39878516a0f (diff)
Change the behaviour change is for when a `bit_set` of range/enum and the underlying type has been specified
* If the lower bound is greater than zero, it will become zero (thus removing the compatification) * If the lower bound is negative, it is an error This means that an integer value N, maps directly to the N-th bit. Example ``` foo :: enum u8 { a = 2, b = 3, c = 4, } set0: bit_set[foo] set0 += {.a, .b} // internally set0 == 1<<(2-2) | 1<<(3-2) set1: bit_set[foo; u32] set1 += {.a, .b} // internally set1 == 1<<(2-0) | 1<<(3-0) ```
Diffstat (limited to 'src')
-rw-r--r--src/check_type.cpp54
1 files changed, 47 insertions, 7 deletions
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 813990020..7c01bd5ba 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -921,26 +921,51 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no
}
i64 lower = big_int_to_i64(&i);
i64 upper = big_int_to_i64(&j);
-
+
+ bool lower_changed = false;
i64 bits = MAX_BITS;
if (type->BitSet.underlying != nullptr) {
bits = 8*type_size_of(type->BitSet.underlying);
+
+ if (lower > 0) {
+ lower = 0;
+ lower_changed = true;
+ } else if (lower < 0) {
+ error(bs->elem, "bit_set does not allow a negative lower bound (%lld) when an underlying type is set", lower);
+ }
+ }
+
+ i64 bits_required = upper-lower;
+ switch (be->op.kind) {
+ case Token_Ellipsis:
+ case Token_RangeFull:
+ bits_required += 1;
+ break;
}
+ bool is_valid = true;
switch (be->op.kind) {
case Token_Ellipsis:
case Token_RangeFull:
if (upper - lower >= bits) {
- error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, (upper-lower+1));
+ is_valid = false;
}
break;
case Token_RangeHalf:
if (upper - lower > bits) {
- error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, (upper-lower));
+ is_valid = false;
}
upper -= 1;
break;
}
+ if (!is_valid) {
+ if (lower_changed) {
+ error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required (internal the lower changed was changed 0 as an underlying type was set)", bits, bits_required);
+ } else {
+ error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, bits_required);
+ }
+ }
+
type->BitSet.elem = t;
type->BitSet.lower = lower;
type->BitSet.upper = upper;
@@ -996,7 +1021,8 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no
}
GB_ASSERT(lower <= upper);
-
+
+ bool lower_changed = false;
i64 bits = MAX_BITS
; if (bs->underlying != nullptr) {
Type *u = check_type(c, bs->underlying);
@@ -1008,17 +1034,31 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no
}
type->BitSet.underlying = u;
bits = 8*type_size_of(u);
+
+ if (lower > 0) {
+ lower = 0;
+ lower_changed = true;
+ } else if (lower < 0) {
+ gbString s = type_to_string(elem);
+ error(bs->elem, "bit_set does not allow a negative lower bound (%lld) of the element type '%s' when an underlying type is set", lower, s);
+ gb_string_free(s);
+ }
}
- if (upper - lower >= MAX_BITS) {
- error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", MAX_BITS, (upper-lower+1));
+ if (upper - lower >= bits) {
+ i64 bits_required = upper-lower+1;
+ if (lower_changed) {
+ error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required (internal the lower changed was changed 0 as an underlying type was set)", bits, bits_required);
+ } else {
+ error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, bits_required);
+ }
}
type->BitSet.lower = lower;
type->BitSet.upper = upper;
}
}
- }
+ }
}