diff options
| author | gingerBill <bill@gingerbill.org> | 2021-10-31 19:39:01 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-10-31 19:39:01 +0000 |
| commit | 141299eb02bc9a7330daa30d75d279e84ba28cc3 (patch) | |
| tree | b0c429d86cb6f96db2ae0f6a012ed0d979835e83 /src | |
| parent | efe05b3e1382d569201709a1d1c5f39878516a0f (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.cpp | 54 |
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; } } - } + } } |