aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-php-shim/src/var.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-07-24 20:23:28 +0900
committernsfisis <nsfisis@gmail.com>2026-07-24 20:23:28 +0900
commit9a1838a32b77740f787a7a097af294842ed9cfdd (patch)
treeba6c482b26a320e1b54276a8f1d05c92fe76771a /crates/shirabe-php-shim/src/var.rs
parent7392662eed92f00b41e173809fb51f6a21572003 (diff)
downloadphp-shirabe-9a1838a32b77740f787a7a097af294842ed9cfdd.tar.gz
php-shirabe-9a1838a32b77740f787a7a097af294842ed9cfdd.tar.zst
php-shirabe-9a1838a32b77740f787a7a097af294842ed9cfdd.zip
fix(solver-problems): compare RULE_LEARNED sort keys like PHP's <=>
Problem::getPrettyString sorts same-priority reasons by getSortableString(), whose RULE_LEARNED key is a '-'-joined literal id string (e.g. "-95"). PHP's <=> compares two numeric strings numerically, but the port used plain String::cmp (byte-wise), which reverses relative order for same-length negative-number keys. Added shirabe_php_shim::loosely_compare to approximate PHP's <=> for this pattern (numeric compare when both sides parse as numbers, else byte compare) and switched the sort comparator to use it. The diagnosis this replaces (from the commit being amended) blamed Pool package-id assignment order diverging from PHP under COMPOSER_POOL_OPTIMIZER=0. That was disproven this session: direct instrumentation of both PHP and the Rust port confirmed identical relative package-id order, including on the ~335-package github-issues-7665 fixture (ids matched up to a constant +2 offset from a platform-mock package count difference). The sort comparator was the actual bug, not package loading order. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-php-shim/src/var.rs')
-rw-r--r--crates/shirabe-php-shim/src/var.rs21
1 files changed, 21 insertions, 0 deletions
diff --git a/crates/shirabe-php-shim/src/var.rs b/crates/shirabe-php-shim/src/var.rs
index 513c3e88..dd0592f8 100644
--- a/crates/shirabe-php-shim/src/var.rs
+++ b/crates/shirabe-php-shim/src/var.rs
@@ -185,6 +185,27 @@ pub fn is_numeric_to_int(value: &PhpMixed) -> i64 {
}
}
+/// Approximates PHP's `<=>` for two strings: if both are numeric strings, compare numerically
+/// (as PHP does), otherwise fall back to a byte-wise comparison.
+///
+/// TODO: this only covers the string/string case of PHP's loose comparison. PHP's `<=>` has many
+/// more special-cased rules across other operand type combinations (bool, array, null, object,
+/// numeric-string-vs-non-numeric-string, ...). Extend this if a new caller needs those.
+pub fn loosely_compare(a: &str, b: &str) -> std::cmp::Ordering {
+ if is_numeric_string(a) && is_numeric_string(b) {
+ match (a.trim().parse::<i64>(), b.trim().parse::<i64>()) {
+ (Ok(na), Ok(nb)) => na.cmp(&nb),
+ _ => {
+ let na: f64 = a.trim().parse().unwrap_or(0.0);
+ let nb: f64 = b.trim().parse().unwrap_or(0.0);
+ na.partial_cmp(&nb).unwrap_or(std::cmp::Ordering::Equal)
+ }
+ }
+ } else {
+ a.cmp(b)
+ }
+}
+
pub fn instance_of<T>(_value: &PhpMixed) -> bool {
// TODO(phase-d): PHP `instanceof` needs the runtime class of the value, which PhpMixed::Object
// does not carry.