Skip to content

Commit 04cdd72

Browse files
committed
.
1 parent c72f01b commit 04cdd72

File tree

1 file changed

+50
-6
lines changed

1 file changed

+50
-6
lines changed

zjit/src/hir_type/mod.rs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -455,16 +455,19 @@ impl Type {
455455

456456
/// Subtract `other` from `self`, preserving specialization if possible.
457457
pub fn subtract(&self, other: Type) -> Type {
458+
// If self is a subtype of other, the result is empty (no negative types).
458459
if self.is_subtype(other) { return types::Empty; }
459-
// If self's specialization is not a subtype of other's specialization (eg Int,Double or
460-
// Top,Int or Int,Empty or Int[5],Int[4]), subtracting has no effect.
460+
// Self is not a subtype of other. That means either:
461+
// * Their type bits do not overlap at all (eg Int vs String)
462+
// * Their type bits overlap but self's specialization is not a subtype of other's (eg
463+
// Fixnum[5] vs Fixnum[4])
464+
// Check for the latter case, returning self unchanged if so.
461465
if !self.spec_is_subtype_of(other) {
462466
return *self;
463467
}
464-
// Now the specializations overlap: self's specialization is a subtype of other's
465-
// specialization (eg Int,Top or Int[4],Int[4], but NOT Empty,Int because that would mean
466-
// self is a subtype of other). Keep self's specialization.
467-
// Subtract the bits
468+
// Now self is either a supertype of other (eg Object vs String or Fixnum vs Fixnum[5]) or
469+
// their type bits do not overlap at all (eg Int vs String).
470+
// Just subtract the bits and keep self's specialization.
468471
let bits = self.bits & !other.bits;
469472
Type { bits, spec: self.spec }
470473
}
@@ -1076,4 +1079,45 @@ mod tests {
10761079
assert!(!types::CBool.has_value(Const::CBool(true)));
10771080
assert!(!types::CShape.has_value(Const::CShape(crate::cruby::ShapeId(0x1234))));
10781081
}
1082+
1083+
#[test]
1084+
fn test_subtract_with_superset_returns_empty() {
1085+
let left = types::NilClass;
1086+
let right = types::BasicObject;
1087+
let result = left.subtract(right);
1088+
assert_bit_equal(result, types::Empty);
1089+
}
1090+
1091+
#[test]
1092+
fn test_subtract_with_subset_removes_bits() {
1093+
let left = types::BasicObject;
1094+
let right = types::NilClass;
1095+
let result = left.subtract(right);
1096+
assert_subtype(result, types::BasicObject);
1097+
assert_not_subtype(types::NilClass, result);
1098+
}
1099+
1100+
#[test]
1101+
fn test_subtract_with_no_overlap_returns_self() {
1102+
let left = types::Fixnum;
1103+
let right = types::StringExact;
1104+
let result = left.subtract(right);
1105+
assert_bit_equal(result, left);
1106+
}
1107+
1108+
#[test]
1109+
fn test_subtract_with_no_specialization_overlap_returns_self() {
1110+
let left = Type::fixnum(4);
1111+
let right = Type::fixnum(5);
1112+
let result = left.subtract(right);
1113+
assert_bit_equal(result, left);
1114+
}
1115+
1116+
#[test]
1117+
fn test_subtract_with_specialization_subset_removes_specialization() {
1118+
let left = types::Fixnum;
1119+
let right = Type::fixnum(42);
1120+
let result = left.subtract(right);
1121+
assert_bit_equal(result, types::Fixnum);
1122+
}
10791123
}

0 commit comments

Comments
 (0)