Browse Source

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)
```
gingerBill 3 years ago
parent
commit
141299eb02
1 changed files with 47 additions and 7 deletions
  1. 47 7
      src/check_type.cpp

+ 47 - 7
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 lower = big_int_to_i64(&i);
 		i64 upper = big_int_to_i64(&j);
 		i64 upper = big_int_to_i64(&j);
-
+		
+		bool lower_changed = false;
 		i64 bits = MAX_BITS;
 		i64 bits = MAX_BITS;
 		if (type->BitSet.underlying != nullptr) {
 		if (type->BitSet.underlying != nullptr) {
 			bits = 8*type_size_of(type->BitSet.underlying);
 			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) {
 		switch (be->op.kind) {
 		case Token_Ellipsis:
 		case Token_Ellipsis:
 		case Token_RangeFull:
 		case Token_RangeFull:
 			if (upper - lower >= bits) {
 			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;
 			break;
 		case Token_RangeHalf:
 		case Token_RangeHalf:
 			if (upper - lower > bits) {
 			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;
 			upper -= 1;
 			break;
 			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.elem  = t;
 		type->BitSet.lower = lower;
 		type->BitSet.lower = lower;
 		type->BitSet.upper = upper;
 		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);
 				GB_ASSERT(lower <= upper);
-
+				
+				bool lower_changed = false;
 				i64 bits = MAX_BITS
 				i64 bits = MAX_BITS
 ;				if (bs->underlying != nullptr) {
 ;				if (bs->underlying != nullptr) {
 					Type *u = check_type(c, bs->underlying);
 					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;
 					type->BitSet.underlying = u;
 					bits = 8*type_size_of(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.lower = lower;
 				type->BitSet.upper = upper;
 				type->BitSet.upper = upper;
 			}
 			}
 		}
 		}
-	}
+	}	
 }
 }