···862862 /// pattern where the size is a variable with a negative value will never
863863 /// match. So we check this to make sure the test will fail.
864864 ///
865865- VariableIsNotNegative {
866866- variable: VariableUsage,
865865+ ReadSizeIsNotNegative {
866866+ size: ReadSize,
867867 },
868868869869 /// This test checks that the segment read by the given read action is a
···871871 ///
872872 /// We need this check as `NaN` and `Infinity` will not match with float
873873 /// segments (like `<<_:32-float>>`) on the Erlang target and we must
874874- /// replicate the same behavious on the JavaScript target as well.
874874+ /// replicate the same behaviours on the JavaScript target as well.
875875 ///
876876 SegmentIsFiniteFloat {
877877 read_action: ReadAction,
···891891892892 pub(crate) fn referenced_segment_patterns(&self) -> Vec<(&EcoString, &ReadAction)> {
893893 match self {
894894- BitArrayTest::VariableIsNotNegative { variable } => match variable {
895895- VariableUsage::PatternSegment(segment_value, read_action) => {
896896- vec![(segment_value, read_action)]
897897- }
898898- VariableUsage::OutsideVariable(..) => vec![],
899899- },
894894+ BitArrayTest::ReadSizeIsNotNegative { size } => {
895895+ let mut references = Vec::new();
896896+ size.referenced_segment_patterns(&mut references);
897897+ references
898898+ }
900899901900 BitArrayTest::Size(SizeTest { operator: _, size })
902901 | BitArrayTest::CatchAllIsBytes { size_so_far: size } => {
···1479147814801479 ReadSize::ConstantBits(..) | ReadSize::RemainingBits | ReadSize::RemainingBytes => (),
14811480 };
14811481+ }
14821482+14831483+ fn can_be_negative(&self) -> bool {
14841484+ match self {
14851485+ ReadSize::ConstantBits(value) => *value < BigInt::ZERO,
14861486+ ReadSize::VariableBits { variable, .. } => match variable.as_ref() {
14871487+ VariableUsage::PatternSegment(_, read_action) => read_action.signed,
14881488+ VariableUsage::OutsideVariable(_) => true,
14891489+ },
14901490+ ReadSize::BinaryOperator {
14911491+ left,
14921492+ right,
14931493+ operator,
14941494+ } => {
14951495+ *operator == IntOperator::Subtract
14961496+ || left.can_be_negative()
14971497+ || right.can_be_negative()
14981498+ }
14991499+ ReadSize::RemainingBits | ReadSize::RemainingBytes => false,
15001500+ }
14821501 }
14831502}
14841503···2910292929112930 // If we're reading a variable number of bits we need to make sure
29122931 // that that variable is not negative!
29132913- if let ReadSize::VariableBits { variable, .. } = &segment_size {
29142914- match variable.as_ref() {
29152915- // If the size variable comes from reading an unsigned
29162916- // number we know that it can't be negative! So we can skip
29172917- // checking it.
29182918- VariableUsage::PatternSegment(_, read_action) if !read_action.signed => (),
29192919-29202920- // Otherwise we must make sure that the read size is not
29212921- // negative.
29222922- VariableUsage::PatternSegment(..) | VariableUsage::OutsideVariable(_) => tests
29232923- .push_back(BitArrayTest::VariableIsNotNegative {
29242924- variable: variable.as_ref().clone(),
29252925- }),
29262926- }
29322932+ if segment_size.can_be_negative() {
29332933+ tests.push_back(BitArrayTest::ReadSizeIsNotNegative {
29342934+ size: segment_size.clone(),
29352935+ });
29272936 }
2928293729292938 // All segments but the last will require the original bit array to